Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | 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. VOID, UNSIGNED, SIGNED, FIXED, FLOAT = range(5)
  34.  
  35. SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W, SWIZZLE_0, SWIZZLE_1, SWIZZLE_NONE, = range(7)
  36.  
  37. PLAIN = 'plain'
  38.  
  39. RGB = 'rgb'
  40. SRGB = 'srgb'
  41. YUV = 'yuv'
  42. ZS = 'zs'
  43.  
  44.  
  45. def is_pot(x):
  46.    return (x & (x - 1)) == 0
  47.  
  48.  
  49. VERY_LARGE = 99999999999999999999999
  50.  
  51.  
  52. class Channel:
  53.     '''Describe the channel of a color channel.'''
  54.    
  55.     def __init__(self, type, norm, pure, size, name = ''):
  56.         self.type = type
  57.         self.norm = norm
  58.         self.pure = pure
  59.         self.size = size
  60.         self.sign = type in (SIGNED, FIXED, FLOAT)
  61.         self.name = name
  62.  
  63.     def __str__(self):
  64.         s = str(self.type)
  65.         if self.norm:
  66.             s += 'n'
  67.         if self.pure:
  68.             s += 'p'
  69.         s += str(self.size)
  70.         return s
  71.  
  72.     def __eq__(self, other):
  73.         return self.type == other.type and self.norm == other.norm and self.pure == other.pure and self.size == other.size
  74.  
  75.     def max(self):
  76.         '''Maximum representable number.'''
  77.         if self.type == FLOAT:
  78.             return VERY_LARGE
  79.         if self.type == FIXED:
  80.             return (1 << (self.size/2)) - 1
  81.         if self.norm:
  82.             return 1
  83.         if self.type == UNSIGNED:
  84.             return (1 << self.size) - 1
  85.         if self.type == SIGNED:
  86.             return (1 << (self.size - 1)) - 1
  87.         assert False
  88.    
  89.     def min(self):
  90.         '''Minimum representable number.'''
  91.         if self.type == FLOAT:
  92.             return -VERY_LARGE
  93.         if self.type == FIXED:
  94.             return -(1 << (self.size/2))
  95.         if self.type == UNSIGNED:
  96.             return 0
  97.         if self.norm:
  98.             return -1
  99.         if self.type == SIGNED:
  100.             return -(1 << (self.size - 1))
  101.         assert False
  102.  
  103.  
  104. class Format:
  105.     '''Describe a pixel format.'''
  106.  
  107.     def __init__(self, name, layout, block_width, block_height, le_channels, le_swizzles, be_channels, be_swizzles, colorspace):
  108.         self.name = name
  109.         self.layout = layout
  110.         self.block_width = block_width
  111.         self.block_height = block_height
  112.         self.le_channels = le_channels
  113.         self.le_swizzles = le_swizzles
  114.         self.be_channels = be_channels
  115.         self.be_swizzles = be_swizzles
  116.         self.name = name
  117.         self.colorspace = colorspace
  118.  
  119.     def __str__(self):
  120.         return self.name
  121.  
  122.     def short_name(self):
  123.         '''Make up a short norm for a format, suitable to be used as suffix in
  124.        function names.'''
  125.  
  126.         name = self.name
  127.         if name.startswith('PIPE_FORMAT_'):
  128.             name = name[len('PIPE_FORMAT_'):]
  129.         name = name.lower()
  130.         return name
  131.  
  132.     def block_size(self):
  133.         size = 0
  134.         for channel in self.le_channels:
  135.             size += channel.size
  136.         return size
  137.  
  138.     def nr_channels(self):
  139.         nr_channels = 0
  140.         for channel in self.le_channels:
  141.             if channel.size:
  142.                 nr_channels += 1
  143.         return nr_channels
  144.  
  145.     def array_element(self):
  146.         if self.layout != PLAIN:
  147.             return None
  148.         ref_channel = self.le_channels[0]
  149.         if ref_channel.type == VOID:
  150.            ref_channel = self.le_channels[1]
  151.         for channel in self.le_channels:
  152.             if channel.size and (channel.size != ref_channel.size or channel.size % 8):
  153.                 return None
  154.             if channel.type != VOID:
  155.                 if channel.type != ref_channel.type:
  156.                     return None
  157.                 if channel.norm != ref_channel.norm:
  158.                     return None
  159.                 if channel.pure != ref_channel.pure:
  160.                     return None
  161.         return ref_channel
  162.  
  163.     def is_array(self):
  164.         return self.array_element() != None
  165.  
  166.     def is_mixed(self):
  167.         if self.layout != PLAIN:
  168.             return False
  169.         ref_channel = self.le_channels[0]
  170.         if ref_channel.type == VOID:
  171.            ref_channel = self.le_channels[1]
  172.         for channel in self.le_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.le_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.le_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.le_channels:
  207.             if channel.type not in (VOID, UNSIGNED, SIGNED):
  208.                 return False
  209.         return True
  210.  
  211.     def is_pure_color(self):
  212.         if self.layout != PLAIN or self.colorspace == ZS:
  213.             return False
  214.         pures = [channel.pure
  215.                  for channel in self.le_channels
  216.                  if channel.type != VOID]
  217.         for x in pures:
  218.            assert x == pures[0]
  219.         return pures[0]
  220.  
  221.     def channel_type(self):
  222.         types = [channel.type
  223.                  for channel in self.le_channels
  224.                  if channel.type != VOID]
  225.         for x in types:
  226.            assert x == types[0]
  227.         return types[0]
  228.  
  229.     def is_pure_signed(self):
  230.         return self.is_pure_color() and self.channel_type() == SIGNED
  231.  
  232.     def is_pure_unsigned(self):
  233.         return self.is_pure_color() and self.channel_type() == UNSIGNED
  234.  
  235.     def has_channel(self, id):
  236.         return self.le_swizzles[id] != SWIZZLE_NONE
  237.  
  238.     def has_depth(self):
  239.         return self.colorspace == ZS and self.has_channel(0)
  240.  
  241.     def has_stencil(self):
  242.         return self.colorspace == ZS and self.has_channel(1)
  243.  
  244.     def stride(self):
  245.         return self.block_size()/8
  246.  
  247.  
  248. _type_parse_map = {
  249.     '':  VOID,
  250.     'x': VOID,
  251.     'u': UNSIGNED,
  252.     's': SIGNED,
  253.     'h': FIXED,
  254.     'f': FLOAT,
  255. }
  256.  
  257. _swizzle_parse_map = {
  258.     'x': SWIZZLE_X,
  259.     'y': SWIZZLE_Y,
  260.     'z': SWIZZLE_Z,
  261.     'w': SWIZZLE_W,
  262.     '0': SWIZZLE_0,
  263.     '1': SWIZZLE_1,
  264.     '_': SWIZZLE_NONE,
  265. }
  266.  
  267. def _parse_channels(fields, layout, colorspace, swizzles):
  268.     if layout == PLAIN:
  269.         names = ['']*4
  270.         if colorspace in (RGB, SRGB):
  271.             for i in range(4):
  272.                 swizzle = swizzles[i]
  273.                 if swizzle < 4:
  274.                     names[swizzle] += 'rgba'[i]
  275.         elif colorspace == ZS:
  276.             for i in range(4):
  277.                 swizzle = swizzles[i]
  278.                 if swizzle < 4:
  279.                     names[swizzle] += 'zs'[i]
  280.         else:
  281.             assert False
  282.         for i in range(4):
  283.             if names[i] == '':
  284.                 names[i] = 'x'
  285.     else:
  286.         names = ['x', 'y', 'z', 'w']
  287.  
  288.     channels = []
  289.     for i in range(0, 4):
  290.         field = fields[i]
  291.         if field:
  292.             type = _type_parse_map[field[0]]
  293.             if field[1] == 'n':
  294.                 norm = True
  295.                 pure = False
  296.                 size = int(field[2:])
  297.             elif field[1] == 'p':
  298.                 pure = True
  299.                 norm = False
  300.                 size = int(field[2:])
  301.             else:
  302.                 norm = False
  303.                 pure = False
  304.                 size = int(field[1:])
  305.         else:
  306.             type = VOID
  307.             norm = False
  308.             pure = False
  309.             size = 0
  310.         channel = Channel(type, norm, pure, size, names[i])
  311.         channels.append(channel)
  312.  
  313.     return channels
  314.  
  315. def parse(filename):
  316.     '''Parse the format descrition in CSV format in terms of the
  317.    Channel and Format classes above.'''
  318.  
  319.     stream = open(filename)
  320.     formats = []
  321.     for line in stream:
  322.         try:
  323.             comment = line.index('#')
  324.         except ValueError:
  325.             pass
  326.         else:
  327.             line = line[:comment]
  328.         line = line.strip()
  329.         if not line:
  330.             continue
  331.  
  332.         fields = [field.strip() for field in line.split(',')]
  333.         if len (fields) == 10:
  334.            fields += fields[4:9]
  335.         assert len (fields) == 15
  336.        
  337.         name = fields[0]
  338.         layout = fields[1]
  339.         block_width, block_height = map(int, fields[2:4])
  340.         colorspace = fields[9]
  341.  
  342.         le_swizzles = [_swizzle_parse_map[swizzle] for swizzle in fields[8]]
  343.         le_channels = _parse_channels(fields[4:8], layout, colorspace, le_swizzles)
  344.  
  345.         be_swizzles = [_swizzle_parse_map[swizzle] for swizzle in fields[14]]
  346.         be_channels = _parse_channels(fields[10:14], layout, colorspace, be_swizzles)
  347.  
  348.         le_shift = 0
  349.         for channel in le_channels:
  350.             channel.shift = le_shift
  351.             le_shift += channel.size
  352.  
  353.         be_shift = 0
  354.         for channel in be_channels[3::-1]:
  355.             channel.shift = be_shift
  356.             be_shift += channel.size
  357.  
  358.         assert le_shift == be_shift
  359.         for i in range(4):
  360.             assert (le_swizzles[i] != SWIZZLE_NONE) == (be_swizzles[i] != SWIZZLE_NONE)
  361.  
  362.         format = Format(name, layout, block_width, block_height, le_channels, le_swizzles, be_channels, be_swizzles, colorspace)
  363.         formats.append(format)
  364.     return formats
  365.  
  366.