xref: /aosp_15_r20/external/deqp/modules/gles31/scripts/genutil.py (revision 35238bce31c2a825756842865a792f8cf7f89930)
1# -*- coding: utf-8 -*-
2
3#-------------------------------------------------------------------------
4# drawElements Quality Program utilities
5# --------------------------------------
6#
7# Copyright 2016 The Android Open Source Project
8#
9# Licensed under the Apache License, Version 2.0 (the "License");
10# you may not use this file except in compliance with the License.
11# You may obtain a copy of the License at
12#
13#      http://www.apache.org/licenses/LICENSE-2.0
14#
15# Unless required by applicable law or agreed to in writing, software
16# distributed under the License is distributed on an "AS IS" BASIS,
17# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18# See the License for the specific language governing permissions and
19# limitations under the License.
20#
21#-------------------------------------------------------------------------
22
23import re
24import math
25import random
26
27PREAMBLE = """
28# WARNING: This file is auto-generated. Do NOT modify it manually, but rather
29# modify the generating script file. Otherwise changes will be lost!
30"""[1:]
31
32class CaseGroup(object):
33    def __init__(self, name, description, children):
34        self.name = name
35        self.description = description
36        self.children = children
37
38class ShaderCase(object):
39    def __init__(self):
40        pass
41
42g_processedCases = {}
43
44def indentTextBlock(text, indent):
45    indentStr = indent * "\t"
46    lines = text.split("\n")
47    lines = [indentStr + line for line in lines]
48    lines = [ ["", line][line.strip() != ""] for line in lines]
49    return "\n".join(lines)
50
51def writeCase(f, case, indent, prefix):
52    print("    %s" % (prefix + case.name))
53    if isinstance(case, CaseGroup):
54        f.write(indentTextBlock('group %s "%s"\n\n' % (case.name, case.description), indent))
55        for child in case.children:
56            writeCase(f, child, indent + 1, prefix + case.name + ".")
57        f.write(indentTextBlock("\nend # %s\n" % case.name, indent))
58    else:
59        # \todo [petri] Fix hack.
60        fullPath = prefix + case.name
61        assert (fullPath not in g_processedCases)
62        g_processedCases[fullPath] = None
63        f.write(indentTextBlock(str(case) + "\n", indent))
64
65def writeAllCases(fileName, caseList):
66    # Write all cases to file.
67    print("  %s.." % fileName)
68    f = file(fileName, "wb")
69    f.write(PREAMBLE + "\n")
70    for case in caseList:
71        writeCase(f, case, 0, "")
72    f.close()
73
74    print("done! (%d cases written)" % len(g_processedCases))
75
76# Template operations.
77
78def genValues(inputs, outputs):
79    res = []
80    for (name, values) in inputs:
81        res.append("input %s = [ %s ];" % (name, " | ".join([str(v) for v in values]).lower()))
82    for (name, values) in outputs:
83        res.append("output %s = [ %s ];" % (name, " | ".join([str(v) for v in values]).lower()))
84    return ("\n".join(res))
85
86def fillTemplate(template, params):
87    s = template
88
89    for (key, value) in params.items():
90        m = re.search(r"^(\s*)\$\{\{%s\}\}$" % key, s, re.M)
91        if m is not None:
92            start = m.start(0)
93            end = m.end(0)
94            ws = m.group(1)
95            if value is not None:
96                repl = "\n".join(["%s%s" % (ws, line) for line in value.split("\n")])
97                s = s[:start] + repl + s[end:]
98            else:
99                s = s[:start] + s[end+1:] # drop the whole line
100        else:
101            s = s.replace("${{%s}}" % key, value)
102    return s
103
104# Return shuffled version of list
105def shuffled(lst):
106    tmp = lst[:]
107    random.shuffle(tmp)
108    return tmp
109
110def repeatToLength(lst, toLength):
111    return (toLength / len(lst)) * lst + lst[: toLength % len(lst)]
112
113# Helpers to convert a list of Scalar/Vec values into another type.
114
115def toFloat(lst): return [Scalar(float(v.x)) for v in lst]
116def toInt(lst): return [Scalar(int(v.x)) for v in lst]
117def toUint(lst): return [Uint(int(v.x)) for v in lst]
118def toBool(lst): return [Scalar(bool(v.x)) for v in lst]
119def toVec4(lst): return [v.toFloat().toVec4() for v in lst]
120def toVec3(lst): return [v.toFloat().toVec3() for v in lst]
121def toVec2(lst): return [v.toFloat().toVec2() for v in lst]
122def toIVec4(lst): return [v.toInt().toVec4() for v in lst]
123def toIVec3(lst): return [v.toInt().toVec3() for v in lst]
124def toIVec2(lst): return [v.toInt().toVec2() for v in lst]
125def toBVec4(lst): return [v.toBool().toVec4() for v in lst]
126def toBVec3(lst): return [v.toBool().toVec3() for v in lst]
127def toBVec2(lst): return [v.toBool().toVec2() for v in lst]
128def toUVec4(lst): return [v.toUint().toUVec4() for v in lst]
129def toUVec3(lst): return [v.toUint().toUVec3() for v in lst]
130def toUVec2(lst): return [v.toUint().toUVec2() for v in lst]
131def toMat2(lst): return [v.toMat2() for v in lst]
132def toMat2x3(lst): return [v.toMat2x3() for v in lst]
133def toMat2x4(lst): return [v.toMat2x4() for v in lst]
134def toMat3x2(lst): return [v.toMat3x2() for v in lst]
135def toMat3(lst): return [v.toMat3() for v in lst]
136def toMat3x4(lst): return [v.toMat3x4() for v in lst]
137def toMat4x2(lst): return [v.toMat4x2() for v in lst]
138def toMat4x3(lst): return [v.toMat4x3() for v in lst]
139def toMat4(lst): return [v.toMat4() for v in lst]
140
141# Random value generation.
142
143class GenRandom(object):
144    def __init__(self):
145        pass
146
147    def uniformVec4(self, count, mn, mx):
148        ret = [Vec4(random.uniform(mn, mx), random.uniform(mn, mx), random.uniform(mn, mx), random.uniform(mn, mx)) for x in xrange(count)]
149        ret[0].x = mn
150        ret[1].x = mx
151        ret[2].x = (mn + mx) * 0.5
152        return ret
153
154    def uniformBVec4(self, count):
155        ret = [Vec4(random.random() >= 0.5, random.random() >= 0.5, random.random() >= 0.5, random.random() >= 0.5) for x in xrange(count)]
156        ret[0].x = True
157        ret[1].x = False
158        return ret
159
160#    def uniform(self,
161
162# Math operating on Scalar/Vector types.
163
164def glslSign(a): return 0.0 if (a == 0) else +1.0 if (a > 0.0) else -1.0
165def glslMod(x, y): return x - y*math.floor(x/y)
166def glslClamp(x, mn, mx): return mn if (x < mn) else mx if (x > mx) else x
167
168class GenMath(object):
169    @staticmethod
170    def unary(func): return lambda val: val.applyUnary(func)
171
172    @staticmethod
173    def binary(func): return lambda a, b: (b.expandVec(a)).applyBinary(func, a.expandVec(b))
174
175    @staticmethod
176    def frac(val): return val.applyUnary(lambda x: x - math.floor(x))
177
178    @staticmethod
179    def exp2(val): return val.applyUnary(lambda x: math.pow(2.0, x))
180
181    @staticmethod
182    def log2(val): return val.applyUnary(lambda x: math.log(x, 2.0))
183
184    @staticmethod
185    def rsq(val): return val.applyUnary(lambda x: 1.0 / math.sqrt(x))
186
187    @staticmethod
188    def sign(val): return val.applyUnary(glslSign)
189
190    @staticmethod
191    def isEqual(a, b): return Scalar(a.isEqual(b))
192
193    @staticmethod
194    def isNotEqual(a, b): return Scalar(not a.isEqual(b))
195
196    @staticmethod
197    def step(a, b): return (b.expandVec(a)).applyBinary(lambda edge, x: [1.0, 0.0][x < edge], a.expandVec(b))
198
199    @staticmethod
200    def length(a): return a.length()
201
202    @staticmethod
203    def distance(a, b): return a.distance(b)
204
205    @staticmethod
206    def dot(a, b): return a.dot(b)
207
208    @staticmethod
209    def cross(a, b): return a.cross(b)
210
211    @staticmethod
212    def normalize(a): return a.normalize()
213
214    @staticmethod
215    def boolAny(a): return a.boolAny()
216
217    @staticmethod
218    def boolAll(a): return a.boolAll()
219
220    @staticmethod
221    def boolNot(a): return a.boolNot()
222
223    @staticmethod
224    def abs(a): return a.abs()
225
226# ..
227
228class Scalar(object):
229    def __init__(self, x):
230        self.x = x
231
232    def applyUnary(self, func): return Scalar(func(self.x))
233    def applyBinary(self, func, other): return Scalar(func(self.x, other.x))
234
235    def isEqual(self, other): assert isinstance(other, Scalar); return (self.x == other.x)
236
237    def expandVec(self, val): return val
238    def toScalar(self): return Scalar(self.x)
239    def toVec2(self): return Vec2(self.x, self.x)
240    def toVec3(self): return Vec3(self.x, self.x, self.x)
241    def toVec4(self): return Vec4(self.x, self.x, self.x, self.x)
242    def toUVec2(self): return UVec2(self.x, self.x)
243    def toUVec3(self): return UVec3(self.x, self.x, self.x)
244    def toUVec4(self): return UVec4(self.x, self.x, self.x, self.x)
245    def toMat2(self): return Mat.fromScalar(2, 2, float(self.x))
246    def toMat2x3(self): return Mat.fromScalar(2, 3, float(self.x))
247    def toMat2x4(self): return Mat.fromScalar(2, 4, float(self.x))
248    def toMat3x2(self): return Mat.fromScalar(3, 2, float(self.x))
249    def toMat3(self): return Mat.fromScalar(3, 3, float(self.x))
250    def toMat3x4(self): return Mat.fromScalar(3, 4, float(self.x))
251    def toMat4x2(self): return Mat.fromScalar(4, 2, float(self.x))
252    def toMat4x3(self): return Mat.fromScalar(4, 3, float(self.x))
253    def toMat4(self): return Mat.fromScalar(4, 4, float(self.x))
254
255    def toFloat(self): return Scalar(float(self.x))
256    def toInt(self): return Scalar(int(self.x))
257    def toUint(self): return Uint(int(self.x))
258    def toBool(self): return Scalar(bool(self.x))
259
260    def getNumScalars(self): return 1
261    def getScalars(self): return [self.x]
262
263    def typeString(self):
264        if isinstance(self.x, bool):
265            return "bool"
266        elif isinstance(self.x, int):
267            return "int"
268        elif isinstance(self.x, float):
269            return "float"
270        else:
271            assert False
272
273    def vec4Swizzle(self):
274        return ""
275
276    def __str__(self):
277        return str(self.x).lower()
278
279    def __float__(self):
280        return float(self.x)
281
282    def length(self):
283        return Scalar(abs(self.x))
284
285    def distance(self, v):
286        assert isinstance(v, Scalar)
287        return Scalar(abs(self.x - v.x))
288
289    def dot(self, v):
290        assert isinstance(v, Scalar)
291        return Scalar(self.x * v.x)
292
293    def normalize(self):
294        return Scalar(glslSign(self.x))
295
296    def abs(self):
297        if isinstance(self.x, bool):
298            return Scalar(self.x)
299        else:
300            return Scalar(abs(self.x))
301
302    def __neg__(self):
303        return Scalar(-self.x)
304
305    def __add__(self, val):
306        if not isinstance(val, Scalar):
307            print(val)
308        assert isinstance(val, Scalar)
309        return Scalar(self.x + val.x)
310
311    def __sub__(self, val):
312        return self + (-val)
313
314    def __mul__(self, val):
315        if isinstance(val, Scalar):
316            return Scalar(self.x * val.x)
317        elif isinstance(val, Vec2):
318            return Vec2(self.x * val.x, self.x * val.y)
319        elif isinstance(val, Vec3):
320            return Vec3(self.x * val.x, self.x * val.y, self.x * val.z)
321        elif isinstance(val, Vec4):
322            return Vec4(self.x * val.x, self.x * val.y, self.x * val.z, self.x * val.w)
323        else:
324            assert False
325
326    def __div__(self, val):
327        if isinstance(val, Scalar):
328            return Scalar(self.x / val.x)
329        elif isinstance(val, Vec2):
330            return Vec2(self.x / val.x, self.x / val.y)
331        elif isinstance(val, Vec3):
332            return Vec3(self.x / val.x, self.x / val.y, self.x / val.z)
333        elif isinstance(val, Vec4):
334            return Vec4(self.x / val.x, self.x / val.y, self.x / val.z, self.x / val.w)
335        else:
336            assert False
337
338class Uint(Scalar):
339    def __init__(self, x):
340        assert x >= 0
341        self.x = x
342
343    def typeString(self):
344        return "uint"
345
346    def abs(self):
347        return Scalar.abs(self).toUint()
348
349    def __neg__(self):
350        return Scalar.__neg__(self).toUint()
351
352    def __add__(self, val):
353        return Scalar.__add__(self, val).toUint()
354
355    def __sub__(self, val):
356        return self + (-val)
357
358    def __mul__(self, val):
359        return Scalar.__mul__(self, val).toUint()
360
361    def __div__(self, val):
362        return Scalar.__div__(self, val).toUint()
363
364class Vec(object):
365    @staticmethod
366    def fromScalarList(lst):
367        assert (len(lst) >= 1 and len(lst) <= 4)
368        if (len(lst) == 1): return Scalar(lst[0])
369        elif (len(lst) == 2): return Vec2(lst[0], lst[1])
370        elif (len(lst) == 3): return Vec3(lst[0], lst[1], lst[2])
371        else: return Vec4(lst[0], lst[1], lst[2], lst[3])
372
373    def isEqual(self, other):
374        assert isinstance(other, Vec);
375        return (self.getScalars() == other.getScalars())
376
377    def length(self):
378        return Scalar(math.sqrt(self.dot(self).x))
379
380    def normalize(self):
381        return self * Scalar(1.0 / self.length().x)
382
383    def swizzle(self, indexList):
384        inScalars = self.getScalars()
385        outScalars = map(lambda ndx: inScalars[ndx], indexList)
386        return Vec.fromScalarList(outScalars)
387
388    def __init__(self):
389        pass
390
391    def __eq__(self, other):
392        return self.isEqual(other)
393
394    def __ne__(self, other):
395        return not self.isEqual(other)
396
397class Vec2(Vec):
398    def __init__(self, x, y):
399        assert(x.__class__ == y.__class__)
400        self.x = x
401        self.y = y
402
403    def applyUnary(self, func): return Vec2(func(self.x), func(self.y))
404    def applyBinary(self, func, other): return Vec2(func(self.x, other.x), func(self.y, other.y))
405
406    def expandVec(self, val): return val.toVec2()
407    def toScalar(self): return Scalar(self.x)
408    def toVec2(self): return Vec2(self.x, self.y)
409    def toVec3(self): return Vec3(self.x, self.y, 0.0)
410    def toVec4(self): return Vec4(self.x, self.y, 0.0, 0.0)
411    def toUVec2(self): return UVec2(self.x, self.y)
412    def toUVec3(self): return UVec3(self.x, self.y, 0.0)
413    def toUVec4(self): return UVec4(self.x, self.y, 0.0, 0.0)
414    def toMat2(self): return Mat2(float(self.x), 0.0, 0.0, float(self.y));
415
416    def toFloat(self): return Vec2(float(self.x), float(self.y))
417    def toInt(self): return Vec2(int(self.x), int(self.y))
418    def toUint(self): return UVec2(int(self.x), int(self.y))
419    def toBool(self): return Vec2(bool(self.x), bool(self.y))
420
421    def getNumScalars(self): return 2
422    def getScalars(self): return [self.x, self.y]
423
424    def typeString(self):
425        if isinstance(self.x, bool):
426            return "bvec2"
427        elif isinstance(self.x, int):
428            return "ivec2"
429        elif isinstance(self.x, float):
430            return "vec2"
431        else:
432            assert False
433
434    def vec4Swizzle(self):
435        return ".xyxy"
436
437    def __str__(self):
438        if isinstance(self.x, bool):
439            return "bvec2(%s, %s)" % (str(self.x).lower(), str(self.y).lower())
440        elif isinstance(self.x, int):
441            return "ivec2(%i, %i)" % (self.x, self.y)
442        elif isinstance(self.x, float):
443            return "vec2(%s, %s)" % (self.x, self.y)
444        else:
445            assert False
446
447    def distance(self, v):
448        assert isinstance(v, Vec2)
449        return (self - v).length()
450
451    def dot(self, v):
452        assert isinstance(v, Vec2)
453        return Scalar(self.x*v.x + self.y*v.y)
454
455    def abs(self):
456        if isinstance(self.x, bool):
457            return Vec2(self.x, self.y)
458        else:
459            return Vec2(abs(self.x), abs(self.y))
460
461    def __neg__(self):
462        return Vec2(-self.x, -self.y)
463
464    def __add__(self, val):
465        if isinstance(val, Scalar):
466            return Vec2(self.x + val, self.y + val)
467        elif isinstance(val, Vec2):
468            return Vec2(self.x + val.x, self.y + val.y)
469        else:
470            assert False
471
472    def __sub__(self, val):
473        return self + (-val)
474
475    def __mul__(self, val):
476        if isinstance(val, Scalar):
477            val = val.toVec2()
478        assert isinstance(val, Vec2)
479        return Vec2(self.x * val.x, self.y * val.y)
480
481    def __div__(self, val):
482        if isinstance(val, Scalar):
483            return Vec2(self.x / val.x, self.y / val.x)
484        else:
485            assert isinstance(val, Vec2)
486            return Vec2(self.x / val.x, self.y / val.y)
487
488    def boolAny(self): return Scalar(self.x or self.y)
489    def boolAll(self): return Scalar(self.x and self.y)
490    def boolNot(self): return Vec2(not self.x, not self.y)
491
492class UVec2(Vec2):
493    def __init__(self, x, y):
494        assert isinstance(x, int) and isinstance(y, int)
495        assert x >= 0 and y >= 0
496        Vec2.__init__(self, x, y)
497
498    def typeString(self):
499        return "uvec2"
500
501    def __str__(self):
502        return "uvec2(%i, %i)" % (self.x, self.y)
503
504    def abs(self):
505        return Vec2.abs(self).toUint()
506
507class Vec3(Vec):
508    def __init__(self, x, y, z):
509        assert((x.__class__ == y.__class__) and (x.__class__ == z.__class__))
510        self.x = x
511        self.y = y
512        self.z = z
513
514    def applyUnary(self, func): return Vec3(func(self.x), func(self.y), func(self.z))
515    def applyBinary(self, func, other): return Vec3(func(self.x, other.x), func(self.y, other.y), func(self.z, other.z))
516
517    def expandVec(self, val): return val.toVec3()
518    def toScalar(self): return Scalar(self.x)
519    def toVec2(self): return Vec2(self.x, self.y)
520    def toVec3(self): return Vec3(self.x, self.y, self.z)
521    def toVec4(self): return Vec4(self.x, self.y, self.z, 0.0)
522    def toUVec2(self): return UVec2(self.x, self.y)
523    def toUVec3(self): return UVec3(self.x, self.y, self.z)
524    def toUVec4(self): return UVec4(self.x, self.y, self.z, 0.0)
525    def toMat3(self): return Mat3(float(self.x), 0.0, 0.0,  0.0, float(self.y), 0.0,  0.0, 0.0, float(self.z));
526
527    def toFloat(self): return Vec3(float(self.x), float(self.y), float(self.z))
528    def toInt(self): return Vec3(int(self.x), int(self.y), int(self.z))
529    def toUint(self): return UVec3(int(self.x), int(self.y), int(self.z))
530    def toBool(self): return Vec3(bool(self.x), bool(self.y), bool(self.z))
531
532    def getNumScalars(self): return 3
533    def getScalars(self): return [self.x, self.y, self.z]
534
535    def typeString(self):
536        if isinstance(self.x, bool):
537            return "bvec3"
538        elif isinstance(self.x, int):
539            return "ivec3"
540        elif isinstance(self.x, float):
541            return "vec3"
542        else:
543            assert False
544
545    def vec4Swizzle(self):
546        return ".xyzx"
547
548    def __str__(self):
549        if isinstance(self.x, bool):
550            return "bvec3(%s, %s, %s)" % (str(self.x).lower(), str(self.y).lower(), str(self.z).lower())
551        elif isinstance(self.x, int):
552            return "ivec3(%i, %i, %i)" % (self.x, self.y, self.z)
553        elif isinstance(self.x, float):
554            return "vec3(%s, %s, %s)" % (self.x, self.y, self.z)
555        else:
556            assert False
557
558    def distance(self, v):
559        assert isinstance(v, Vec3)
560        return (self - v).length()
561
562    def dot(self, v):
563        assert isinstance(v, Vec3)
564        return Scalar(self.x*v.x + self.y*v.y + self.z*v.z)
565
566    def cross(self, v):
567        assert isinstance(v, Vec3)
568        return Vec3(self.y*v.z - v.y*self.z,
569                    self.z*v.x - v.z*self.x,
570                    self.x*v.y - v.x*self.y)
571
572    def abs(self):
573        if isinstance(self.x, bool):
574            return Vec3(self.x, self.y, self.z)
575        else:
576            return Vec3(abs(self.x), abs(self.y), abs(self.z))
577
578    def __neg__(self):
579        return Vec3(-self.x, -self.y, -self.z)
580
581    def __add__(self, val):
582        if isinstance(val, Scalar):
583            return Vec3(self.x + val, self.y + val)
584        elif isinstance(val, Vec3):
585            return Vec3(self.x + val.x, self.y + val.y, self.z + val.z)
586        else:
587            assert False
588
589    def __sub__(self, val):
590        return self + (-val)
591
592    def __mul__(self, val):
593        if isinstance(val, Scalar):
594            val = val.toVec3()
595        assert isinstance(val, Vec3)
596        return Vec3(self.x * val.x, self.y * val.y, self.z * val.z)
597
598    def __div__(self, val):
599        if isinstance(val, Scalar):
600            return Vec3(self.x / val.x, self.y / val.x, self.z / val.x)
601        elif isinstance(val, Vec3):
602            return Vec3(self.x / val.x, self.y / val.y, self.z / val.z)
603        else:
604            assert False
605
606    def boolAny(self): return Scalar(self.x or self.y or self.z)
607    def boolAll(self): return Scalar(self.x and self.y and self.z)
608    def boolNot(self): return Vec3(not self.x, not self.y, not self.z)
609
610class UVec3(Vec3):
611    def __init__(self, x, y, z):
612        assert isinstance(x, int) and isinstance(y, int) and isinstance(z, int)
613        assert x >= 0 and y >= 0 and z >= 0
614        Vec3.__init__(self, x, y, z)
615
616    def typeString(self):
617        return "uvec3"
618
619    def __str__(self):
620        return "uvec3(%i, %i, %i)" % (self.x, self.y, self.z)
621
622    def abs(self):
623        return Vec3.abs(self).toUint()
624
625class Vec4(Vec):
626    def __init__(self, x, y, z, w):
627        assert((x.__class__ == y.__class__) and (x.__class__ == z.__class__) and (x.__class__ == w.__class__))
628        self.x = x
629        self.y = y
630        self.z = z
631        self.w = w
632
633    def applyUnary(self, func): return Vec4(func(self.x), func(self.y), func(self.z), func(self.w))
634    def applyBinary(self, func, other): return Vec4(func(self.x, other.x), func(self.y, other.y), func(self.z, other.z), func(self.w, other.w))
635
636    def expandVec(self, val): return val.toVec4()
637    def toScalar(self): return Scalar(self.x)
638    def toVec2(self): return Vec2(self.x, self.y)
639    def toVec3(self): return Vec3(self.x, self.y, self.z)
640    def toVec4(self): return Vec4(self.x, self.y, self.z, self.w)
641    def toUVec2(self): return UVec2(self.x, self.y)
642    def toUVec3(self): return UVec3(self.x, self.y, self.z)
643    def toUVec4(self): return UVec4(self.x, self.y, self.z, self.w)
644    def toMat2(self): return Mat2(float(self.x), float(self.y), float(self.z), float(self.w))
645    def toMat4(self): return Mat4(float(self.x), 0.0, 0.0, 0.0,  0.0, float(self.y), 0.0, 0.0,  0.0, 0.0, float(self.z), 0.0,  0.0, 0.0, 0.0, float(self.w));
646
647    def toFloat(self): return Vec4(float(self.x), float(self.y), float(self.z), float(self.w))
648    def toInt(self): return Vec4(int(self.x), int(self.y), int(self.z), int(self.w))
649    def toUint(self): return UVec4(int(self.x), int(self.y), int(self.z), int(self.w))
650    def toBool(self): return Vec4(bool(self.x), bool(self.y), bool(self.z), bool(self.w))
651
652    def getNumScalars(self): return 4
653    def getScalars(self): return [self.x, self.y, self.z, self.w]
654
655    def typeString(self):
656        if isinstance(self.x, bool):
657            return "bvec4"
658        elif isinstance(self.x, int):
659            return "ivec4"
660        elif isinstance(self.x, float):
661            return "vec4"
662        else:
663            assert False
664
665    def vec4Swizzle(self):
666        return ""
667
668    def __str__(self):
669        if isinstance(self.x, bool):
670            return "bvec4(%s, %s, %s, %s)" % (str(self.x).lower(), str(self.y).lower(), str(self.z).lower(), str(self.w).lower())
671        elif isinstance(self.x, int):
672            return "ivec4(%i, %i, %i, %i)" % (self.x, self.y, self.z, self.w)
673        elif isinstance(self.x, float):
674            return "vec4(%s, %s, %s, %s)" % (self.x, self.y, self.z, self.w)
675        else:
676            assert False
677
678    def distance(self, v):
679        assert isinstance(v, Vec4)
680        return (self - v).length()
681
682    def dot(self, v):
683        assert isinstance(v, Vec4)
684        return Scalar(self.x*v.x + self.y*v.y + self.z*v.z + self.w*v.w)
685
686    def abs(self):
687        if isinstance(self.x, bool):
688            return Vec4(self.x, self.y, self.z, self.w)
689        else:
690            return Vec4(abs(self.x), abs(self.y), abs(self.z), abs(self.w))
691
692    def __neg__(self):
693        return Vec4(-self.x, -self.y, -self.z, -self.w)
694
695    def __add__(self, val):
696        if isinstance(val, Scalar):
697            return Vec3(self.x + val, self.y + val)
698        elif isinstance(val, Vec4):
699            return Vec4(self.x + val.x, self.y + val.y, self.z + val.z, self.w + val.w)
700        else:
701            assert False
702
703    def __sub__(self, val):
704        return self + (-val)
705
706    def __mul__(self, val):
707        if isinstance(val, Scalar):
708            val = val.toVec4()
709        assert isinstance(val, Vec4)
710        return Vec4(self.x * val.x, self.y * val.y, self.z * val.z, self.w * val.w)
711
712    def __div__(self, val):
713        if isinstance(val, Scalar):
714            return Vec4(self.x / val.x, self.y / val.x, self.z / val.x, self.w / val.x)
715        elif isinstance(val, Vec4):
716            return Vec4(self.x / val.x, self.y / val.y, self.z / val.z, self.w / val.w)
717        else:
718            assert False
719
720    def boolAny(self): return Scalar(self.x or self.y or self.z or self.w)
721    def boolAll(self): return Scalar(self.x and self.y and self.z and self.w)
722    def boolNot(self): return Vec4(not self.x, not self.y, not self.z, not self.w)
723
724class UVec4(Vec4):
725    def __init__(self, x, y, z, w):
726        assert isinstance(x, int) and isinstance(y, int) and isinstance(z, int) and isinstance(w, int)
727        assert x >= 0 and y >= 0 and z >= 0 and w >= 0
728        Vec4.__init__(self, x, y, z, w)
729
730    def typeString(self):
731        return "uvec4"
732
733    def __str__(self):
734        return "uvec4(%i, %i, %i, %i)" % (self.x, self.y, self.z, self.w)
735
736    def abs(self):
737        return Vec4.abs(self).toUint()
738
739# \note Column-major storage.
740class Mat(object):
741    def __init__ (self, numCols, numRows, scalars):
742        assert len(scalars) == numRows*numCols
743        self.numCols = numCols
744        self.numRows = numRows
745        self.scalars = scalars
746
747    @staticmethod
748    def fromScalar (numCols, numRows, scalar):
749        scalars = []
750        for col in range(0, numCols):
751            for row in range(0, numRows):
752                scalars.append(scalar if col == row else 0.0)
753        return Mat(numCols, numRows, scalars)
754
755    @staticmethod
756    def identity (numCols, numRows):
757        return Mat.fromScalar(numCols, numRows, 1.0)
758
759    def get (self, colNdx, rowNdx):
760        assert 0 <= colNdx and colNdx < self.numCols
761        assert 0 <= rowNdx and rowNdx < self.numRows
762        return self.scalars[colNdx*self.numRows + rowNdx]
763
764    def set (self, colNdx, rowNdx, scalar):
765        assert 0 <= colNdx and colNdx < self.numCols
766        assert 0 <= rowNdx and rowNdx < self.numRows
767        self.scalars[colNdx*self.numRows + rowNdx] = scalar
768
769    def toMatrix (self, numCols, numRows):
770        res = Mat.identity(numCols, numRows)
771        for col in range(0, min(self.numCols, numCols)):
772            for row in range(0, min(self.numRows, numRows)):
773                res.set(col, row, self.get(col, row))
774        return res
775
776    def toMat2 (self): return self.toMatrix(2, 2)
777    def toMat2x3 (self): return self.toMatrix(2, 3)
778    def toMat2x4 (self): return self.toMatrix(2, 4)
779    def toMat3x2 (self): return self.toMatrix(3, 2)
780    def toMat3 (self): return self.toMatrix(3, 3)
781    def toMat3x4 (self): return self.toMatrix(3, 4)
782    def toMat4x2 (self): return self.toMatrix(4, 2)
783    def toMat4x3 (self): return self.toMatrix(4, 3)
784    def toMat4 (self): return self.toMatrix(4, 4)
785
786    def typeString(self):
787        if self.numRows == self.numCols:
788            return "mat%d" % self.numRows
789        else:
790            return "mat%dx%d" % (self.numCols, self.numRows)
791
792    def __str__(self):
793        return "%s(%s)" % (self.typeString(), ", ".join(["%s" % s for s in self.scalars]))
794
795    def isTypeEqual (self, other):
796        return isinstance(other, Mat) and self.numRows == other.numRows and self.numCols == other.numCols
797
798    def isEqual(self, other):
799        assert self.isTypeEqual(other)
800        return (self.scalars == other.scalars)
801
802    def compMul(self, val):
803        assert self.isTypeEqual(val)
804        return Mat(self.numRows, self.numCols, [self.scalars(i) * val.scalars(i) for i in range(self.numRows*self.numCols)])
805
806class Mat2(Mat):
807    def __init__(self, m00, m01, m10, m11):
808        Mat.__init__(self, 2, 2, [m00, m10, m01, m11])
809
810class Mat3(Mat):
811    def __init__(self, m00, m01, m02, m10, m11, m12, m20, m21, m22):
812        Mat.__init__(self, 3, 3, [m00, m10, m20,
813                                  m01, m11, m21,
814                                  m02, m12, m22])
815
816class Mat4(Mat):
817    def __init__(self, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33):
818        Mat.__init__(self, 4, 4, [m00, m10, m20, m30,
819                                  m01, m11, m21, m31,
820                                  m02, m12, m22, m32,
821                                  m03, m13, m23, m33])
822