Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. #!/usr/bin/env python
  2.  
  3. '''
  4. /**************************************************************************
  5. *
  6. * Copyright 2009 VMware, Inc.
  7. * All Rights Reserved.
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining a
  10. * copy of this software and associated documentation files (the
  11. * "Software"), to deal in the Software without restriction, including
  12. * without limitation the rights to use, copy, modify, merge, publish,
  13. * distribute, sub license, and/or sell copies of the Software, and to
  14. * permit persons to whom the Software is furnished to do so, subject to
  15. * the following conditions:
  16. *
  17. * The above copyright notice and this permission notice (including the
  18. * next paragraph) shall be included in all copies or substantial portions
  19. * of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  22. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  24. * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
  25. * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  26. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  27. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. *
  29. **************************************************************************/
  30. '''
  31.  
  32.  
  33. import sys
  34.  
  35. VOID, UNSIGNED, SIGNED, FIXED, FLOAT = range(5)
  36.  
  37. SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W, SWIZZLE_0, SWIZZLE_1, SWIZZLE_NONE, = range(7)
  38.  
  39. PLAIN = 'plain'
  40.  
  41. RGB = 'rgb'
  42. SRGB = 'srgb'
  43. YUV = 'yuv'
  44. ZS = 'zs'
  45.  
  46.  
  47. # Not cross-compiler friendly
  48. is_big_endian = sys.byteorder == 'big'
  49.  
  50. def is_pot(x):
  51.    return (x & (x - 1)) == 0
  52.  
  53.  
  54. VERY_LARGE = 99999999999999999999999
  55.  
  56.  
  57. class Channel:
  58.     '''Describe the channel of a color channel.'''
  59.    
  60.     def __init__(self, type, norm, pure, size, name = ''):
  61.         self.type = type
  62.         self.norm = norm
  63.         self.pure = pure
  64.         self.size = size
  65.         self.sign = type in (SIGNED, FIXED, FLOAT)
  66.         self.name = name
  67.  
  68.     def __str__(self):
  69.         s = str(self.type)
  70.         if self.norm:
  71.             s += 'n'
  72.         if self.pure:
  73.             s += 'p'
  74.         s += str(self.size)
  75.         return s
  76.  
  77.     def __eq__(self, other):
  78.         return self.type == other.type and self.norm == other.norm and self.pure == other.pure and self.size == other.size
  79.  
  80.     def max(self):
  81.         '''Maximum representable number.'''
  82.         if self.type == FLOAT:
  83.             return VERY_LARGE
  84.         if self.type == FIXED:
  85.             return (1 << (self.size/2)) - 1
  86.         if self.norm:
  87.             return 1
  88.         if self.type == UNSIGNED:
  89.             return (1 << self.size) - 1
  90.         if self.type == SIGNED:
  91.             return (1 << (self.size - 1)) - 1
  92.         assert False
  93.    
  94.     def min(self):
  95.         '''Minimum representable number.'''
  96.         if self.type == FLOAT:
  97.             return -VERY_LARGE
  98.         if self.type == FIXED:
  99.             return -(1 << (self.size/2))
  100.         if self.type == UNSIGNED:
  101.             return 0
  102.         if self.norm:
  103.             return -1
  104.         if self.type == SIGNED:
  105.             return -(1 << (self.size - 1))
  106.         assert False
  107.  
  108.  
  109. class Format:
  110.     '''Describe a pixel format.'''
  111.  
  112.     def __init__(self, name, layout, block_width, block_height, channels, swizzles, colorspace):
  113.         self.name = name
  114.         self.layout = layout
  115.         self.block_width = block_width
  116.         self.block_height = block_height
  117.         self.channels = channels
  118.         self.swizzles = swizzles
  119.         self.name = name
  120.         self.colorspace = colorspace
  121.  
  122.     def __str__(self):
  123.         return self.name
  124.  
  125.     def short_name(self):
  126.         '''Make up a short norm for a format, suitable to be used as suffix in
  127.        function names.'''
  128.  
  129.         name = self.name
  130.         if name.startswith('PIPE_FORMAT_'):
  131.             name = name[len('PIPE_FORMAT_'):]
  132.         name = name.lower()
  133.         return name
  134.  
  135.     def block_size(self):
  136.         size = 0
  137.         for channel in self.channels:
  138.             size += channel.size
  139.         return size
  140.  
  141.     def nr_channels(self):
  142.         nr_channels = 0
  143.         for channel in self.channels:
  144.             if channel.size:
  145.                 nr_channels += 1
  146.         return nr_channels
  147.  
  148.     def is_array(self):
  149.         if self.layout != PLAIN:
  150.             return False
  151.         ref_channel = self.channels[0]
  152.         if ref_channel.type == VOID:
  153.            ref_channel = self.channels[1]
  154.         for channel in self.channels:
  155.             if channel.size and (channel.size != ref_channel.size or channel.size % 8):
  156.                 return False
  157.             if channel.type != VOID:
  158.                 if channel.type != ref_channel.type:
  159.                     return False
  160.                 if channel.norm != ref_channel.norm:
  161.                     return False
  162.                 if channel.pure != ref_channel.pure:
  163.                     return False
  164.         return True
  165.  
  166.     def is_mixed(self):
  167.         if self.layout != PLAIN:
  168.             return False
  169.         ref_channel = self.channels[0]
  170.         if ref_channel.type == VOID:
  171.            ref_channel = self.channels[1]
  172.         for channel in self.channels[1:]:
  173.             if channel.type != VOID:
  174.                 if channel.type != ref_channel.type:
  175.                     return True
  176.                 if channel.norm != ref_channel.norm:
  177.                     return True
  178.                 if channel.pure != ref_channel.pure:
  179.                     return True
  180.         return False
  181.  
  182.     def is_pot(self):
  183.         return is_pot(self.block_size())
  184.  
  185.     def is_int(self):
  186.         if self.layout != PLAIN:
  187.             return False
  188.         for channel in self.channels:
  189.             if channel.type not in (VOID, UNSIGNED, SIGNED):
  190.                 return False
  191.         return True
  192.  
  193.     def is_float(self):
  194.         if self.layout != PLAIN:
  195.             return False
  196.         for channel in self.channels:
  197.             if channel.type not in (VOID, FLOAT):
  198.                 return False
  199.         return True
  200.  
  201.     def is_bitmask(self):
  202.         if self.layout != PLAIN:
  203.             return False
  204.         if self.block_size() not in (8, 16, 32):
  205.             return False
  206.         for channel in self.channels:
  207.             if channel.type not in (VOID, UNSIGNED, SIGNED):
  208.                 return False
  209.         return True
  210.  
  211.     def inv_swizzles(self):
  212.         '''Return an array[4] of inverse swizzle terms'''
  213.         '''Only pick the first matching value to avoid l8 getting blue and i8 getting alpha'''
  214.         inv_swizzle = [None]*4
  215.         for i in range(4):
  216.             swizzle = self.swizzles[i]
  217.             if swizzle < 4 and inv_swizzle[swizzle] == None:
  218.                 inv_swizzle[swizzle] = i
  219.         return inv_swizzle
  220.  
  221.     def stride(self):
  222.         return self.block_size()/8
  223.  
  224.  
  225. _type_parse_map = {
  226.     '':  VOID,
  227.     'x': VOID,
  228.     'u': UNSIGNED,
  229.     's': SIGNED,
  230.     'h': FIXED,
  231.     'f': FLOAT,
  232. }
  233.  
  234. _swizzle_parse_map = {
  235.     'x': SWIZZLE_X,
  236.     'y': SWIZZLE_Y,
  237.     'z': SWIZZLE_Z,
  238.     'w': SWIZZLE_W,
  239.     '0': SWIZZLE_0,
  240.     '1': SWIZZLE_1,
  241.     '_': SWIZZLE_NONE,
  242. }
  243.  
  244. def parse(filename):
  245.     '''Parse the format descrition in CSV format in terms of the
  246.    Channel and Format classes above.'''
  247.  
  248.     stream = open(filename)
  249.     formats = []
  250.     for line in stream:
  251.         try:
  252.             comment = line.index('#')
  253.         except ValueError:
  254.             pass
  255.         else:
  256.             line = line[:comment]
  257.         line = line.strip()
  258.         if not line:
  259.             continue
  260.  
  261.         fields = [field.strip() for field in line.split(',')]
  262.        
  263.         name = fields[0]
  264.         layout = fields[1]
  265.         block_width, block_height = map(int, fields[2:4])
  266.  
  267.         swizzles = [_swizzle_parse_map[swizzle] for swizzle in fields[8]]
  268.         colorspace = fields[9]
  269.        
  270.         if layout == PLAIN:
  271.             names = ['']*4
  272.             if colorspace in (RGB, SRGB):
  273.                 for i in range(4):
  274.                     swizzle = swizzles[i]
  275.                     if swizzle < 4:
  276.                         names[swizzle] += 'rgba'[i]
  277.             elif colorspace == ZS:
  278.                 for i in range(4):
  279.                     swizzle = swizzles[i]
  280.                     if swizzle < 4:
  281.                         names[swizzle] += 'zs'[i]
  282.             else:
  283.                 assert False
  284.             for i in range(4):
  285.                 if names[i] == '':
  286.                     names[i] = 'x'
  287.         else:
  288.             names = ['x', 'y', 'z', 'w']
  289.  
  290.         channels = []
  291.         for i in range(0, 4):
  292.             field = fields[4 + i]
  293.             if field:
  294.                 type = _type_parse_map[field[0]]
  295.                 if field[1] == 'n':
  296.                     norm = True
  297.                     pure = False
  298.                     size = int(field[2:])
  299.                 elif field[1] == 'p':
  300.                     pure = True
  301.                     norm = False
  302.                     size = int(field[2:])
  303.                 else:
  304.                     norm = False
  305.                     pure = False
  306.                     size = int(field[1:])
  307.             else:
  308.                 type = VOID
  309.                 norm = False
  310.                 pure = False
  311.                 size = 0
  312.             channel = Channel(type, norm, pure, size, names[i])
  313.             channels.append(channel)
  314.  
  315.         shift = 0
  316.         for channel in channels[3::-1] if is_big_endian else channels:
  317.             channel.shift = shift
  318.             shift += channel.size
  319.  
  320.         format = Format(name, layout, block_width, block_height, channels, swizzles, colorspace)
  321.         formats.append(format)
  322.     return formats
  323.  
  324.