Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 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