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:
33	def __init__(self, name, description, children):
34		self.name			= name
35		self.description	= description
36		self.children		= children
37
38class ShaderCase:
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 "\t%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 toBool(lst):	return [Scalar(bool(v.x)) for v in lst]
118def toVec4(lst):	return [v.toFloat().toVec4() for v in lst]
119def toVec3(lst):	return [v.toFloat().toVec3() for v in lst]
120def toVec2(lst):	return [v.toFloat().toVec2() for v in lst]
121def toIVec4(lst):	return [v.toInt().toVec4() for v in lst]
122def toIVec3(lst):	return [v.toInt().toVec3() for v in lst]
123def toIVec2(lst):	return [v.toInt().toVec2() for v in lst]
124def toBVec4(lst):	return [v.toBool().toVec4() for v in lst]
125def toBVec3(lst):	return [v.toBool().toVec3() for v in lst]
126def toBVec2(lst):	return [v.toBool().toVec2() for v in lst]
127def toMat2(lst):	return [v.toMat2() for v in lst]
128def toMat3(lst):	return [v.toMat3() for v in lst]
129def toMat4(lst):	return [v.toMat4() for v in lst]
130
131# Random value generation.
132
133class GenRandom:
134	def __init__(self):
135		pass
136
137	def uniformVec4(self, count, mn, mx):
138		ret = [Vec4(random.uniform(mn, mx), random.uniform(mn, mx), random.uniform(mn, mx), random.uniform(mn, mx)) for x in xrange(count)]
139		ret[0].x = mn
140		ret[1].x = mx
141		ret[2].x = (mn + mx) * 0.5
142		return ret
143
144	def uniformBVec4(self, count):
145		ret = [Vec4(random.random() >= 0.5, random.random() >= 0.5, random.random() >= 0.5, random.random() >= 0.5) for x in xrange(count)]
146		ret[0].x = True
147		ret[1].x = False
148		return ret
149
150#	def uniform(self,
151
152# Math operating on Scalar/Vector types.
153
154def glslSign(a):			return 0.0 if (a == 0) else +1.0 if (a > 0.0) else -1.0
155def glslMod(x, y):			return x - y*math.floor(x/y)
156def glslClamp(x, mn, mx):	return mn if (x < mn) else mx if (x > mx) else x
157
158class GenMath:
159	@staticmethod
160	def unary(func):	return lambda val: val.applyUnary(func)
161
162	@staticmethod
163	def binary(func):	return lambda a, b: (b.expandVec(a)).applyBinary(func, a.expandVec(b))
164
165	@staticmethod
166	def frac(val):		return val.applyUnary(lambda x: x - math.floor(x))
167
168	@staticmethod
169	def exp2(val):		return val.applyUnary(lambda x: math.pow(2.0, x))
170
171	@staticmethod
172	def log2(val):		return val.applyUnary(lambda x: math.log(x, 2.0))
173
174	@staticmethod
175	def rsq(val):		return val.applyUnary(lambda x: 1.0 / math.sqrt(x))
176
177	@staticmethod
178	def sign(val):		return val.applyUnary(glslSign)
179
180	@staticmethod
181	def isEqual(a, b):	return Scalar(a.isEqual(b))
182
183	@staticmethod
184	def isNotEqual(a, b):	return Scalar(not a.isEqual(b))
185
186	@staticmethod
187	def step(a, b):		return (b.expandVec(a)).applyBinary(lambda edge, x: [1.0, 0.0][x < edge], a.expandVec(b))
188
189	@staticmethod
190	def length(a):		return a.length()
191
192	@staticmethod
193	def distance(a, b):	return a.distance(b)
194
195	@staticmethod
196	def dot(a, b):		return a.dot(b)
197
198	@staticmethod
199	def cross(a, b):	return a.cross(b)
200
201	@staticmethod
202	def normalize(a):	return a.normalize()
203
204	@staticmethod
205	def boolAny(a):		return a.boolAny()
206
207	@staticmethod
208	def boolAll(a):		return a.boolAll()
209
210	@staticmethod
211	def boolNot(a):		return a.boolNot()
212
213# ..
214
215class Scalar:
216	def __init__(self, x):
217		self.x = x
218
219	def applyUnary(self, func):			return Scalar(func(self.x))
220	def applyBinary(self, func, other):	return Scalar(func(self.x, other.x))
221
222	def isEqual(self, other):	assert isinstance(other, Scalar); return (self.x == other.x)
223
224	def expandVec(self, val):	return val
225	def toScalar(self):			return Scalar(self.x)
226	def toVec2(self):			return Vec2(self.x, self.x)
227	def toVec3(self):			return Vec3(self.x, self.x, self.x)
228	def toVec4(self):			return Vec4(self.x, self.x, self.x, self.x)
229	def toMat2(self):			return self.toVec2().toMat2()
230	def toMat3(self):			return self.toVec3().toMat3()
231	def toMat4(self):			return self.toVec4().toMat4()
232
233	def toFloat(self):			return Scalar(float(self.x))
234	def toInt(self):			return Scalar(int(self.x))
235	def toBool(self):			return Scalar(bool(self.x))
236
237	def getNumScalars(self):	return 1
238	def getScalars(self):		return [self.x]
239
240	def typeString(self):
241		if isinstance(self.x, bool):
242			return "bool"
243		elif isinstance(self.x, int):
244			return "int"
245		elif isinstance(self.x, float):
246			return "float"
247		else:
248			assert False
249
250	def vec4Swizzle(self):
251		return ""
252
253	def __str__(self):
254		return "%s" % self.x
255
256	def length(self):
257		return Scalar(abs(self.x))
258
259	def distance(self, v):
260		assert isinstance(v, Scalar)
261		return Scalar(abs(self.x - v.x))
262
263	def dot(self, v):
264		assert isinstance(v, Scalar)
265		return Scalar(self.x * v.x)
266
267	def normalize(self):
268		return Scalar(glslSign(self.x))
269
270	def __neg__(self):
271		return Scalar(-self.x)
272
273	def __add__(self, val):
274		assert isinstance(val, Scalar)
275		return Scalar(self.x + val.x)
276
277	def __sub__(self, val):
278		return self + (-val)
279
280	def __mul__(self, val):
281		if isinstance(val, Scalar):
282			return Scalar(self.x * val.x)
283		elif isinstance(val, Vec2):
284			return Vec2(self.x * val.x, self.x * val.y)
285		elif isinstance(val, Vec3):
286			return Vec3(self.x * val.x, self.x * val.y, self.x * val.z)
287		elif isinstance(val, Vec4):
288			return Vec4(self.x * val.x, self.x * val.y, self.x * val.z, self.x * val.w)
289		else:
290			assert False
291
292	def __div__(self, val):
293		if isinstance(val, Scalar):
294			return Scalar(self.x / val.x)
295		elif isinstance(val, Vec2):
296			return Vec2(self.x / val.x, self.x / val.y)
297		elif isinstance(val, Vec3):
298			return Vec3(self.x / val.x, self.x / val.y, self.x / val.z)
299		elif isinstance(val, Vec4):
300			return Vec4(self.x / val.x, self.x / val.y, self.x / val.z, self.x / val.w)
301		else:
302			assert False
303
304class Vec:
305	@staticmethod
306	def fromScalarList(lst):
307		assert (len(lst) >= 1 and len(lst) <= 4)
308		if (len(lst) == 1):		return Scalar(lst[0])
309		elif (len(lst) == 2):	return Vec2(lst[0], lst[1])
310		elif (len(lst) == 3):	return Vec3(lst[0], lst[1], lst[2])
311		else:					return Vec4(lst[0], lst[1], lst[2], lst[3])
312
313	def isEqual(self, other):
314		assert isinstance(other, Vec);
315		return (self.getScalars() == other.getScalars())
316
317	def length(self):
318		return Scalar(math.sqrt(self.dot(self).x))
319
320	def normalize(self):
321		return self * Scalar(1.0 / self.length().x)
322
323	def swizzle(self, indexList):
324		inScalars = self.getScalars()
325		outScalars = map(lambda ndx: inScalars[ndx], indexList)
326		return Vec.fromScalarList(outScalars)
327
328	def __init__(self):
329		pass
330
331class Vec2(Vec):
332	def __init__(self, x, y):
333		assert(x.__class__ == y.__class__)
334		self.x = x
335		self.y = y
336
337	def applyUnary(self, func):			return Vec2(func(self.x), func(self.y))
338	def applyBinary(self, func, other):	return Vec2(func(self.x, other.x), func(self.y, other.y))
339
340	def expandVec(self, val):	return val.toVec2()
341	def toScalar(self):			return Scalar(self.x)
342	def toVec2(self):			return Vec2(self.x, self.y)
343	def toVec3(self):			return Vec3(self.x, self.y, 0.0)
344	def toVec4(self):			return Vec4(self.x, self.y, 0.0, 0.0)
345	def toMat2(self):			return Mat2(float(self.x), 0.0, 0.0, float(self.y));
346
347	def toFloat(self):			return Vec2(float(self.x), float(self.y))
348	def toInt(self):			return Vec2(int(self.x), int(self.y))
349	def toBool(self):			return Vec2(bool(self.x), bool(self.y))
350
351	def getNumScalars(self):	return 2
352	def getScalars(self):		return [self.x, self.y]
353
354	def typeString(self):
355		if isinstance(self.x, bool):
356			return "bvec2"
357		elif isinstance(self.x, int):
358			return "ivec2"
359		elif isinstance(self.x, float):
360			return "vec2"
361		else:
362			assert False
363
364	def vec4Swizzle(self):
365		return ".xyxy"
366
367	def __str__(self):
368		if isinstance(self.x, bool):
369			return "bvec2(%s, %s)" % (str(self.x).lower(), str(self.y).lower())
370		elif isinstance(self.x, int):
371			return "ivec2(%i, %i)" % (self.x, self.y)
372		elif isinstance(self.x, float):
373			return "vec2(%s, %s)" % (self.x, self.y)
374		else:
375			assert False
376
377	def distance(self, v):
378		assert isinstance(v, Vec2)
379		return (self - v).length()
380
381	def dot(self, v):
382		assert isinstance(v, Vec2)
383		return Scalar(self.x*v.x + self.y*v.y)
384
385	def __neg__(self):
386		return Vec2(-self.x, -self.y)
387
388	def __add__(self, val):
389		if isinstance(val, Scalar):
390			return Vec2(self.x + val, self.y + val)
391		elif isinstance(val, Vec2):
392			return Vec2(self.x + val.x, self.y + val.y)
393		else:
394			assert False
395
396	def __sub__(self, val):
397		return self + (-val)
398
399	def __mul__(self, val):
400		if isinstance(val, Scalar):
401			val = val.toVec2()
402		assert isinstance(val, Vec2)
403		return Vec2(self.x * val.x, self.y * val.y)
404
405	def __div__(self, val):
406		if isinstance(val, Scalar):
407			return Vec2(self.x / val.x, self.y / val.x)
408		else:
409			assert isinstance(val, Vec2)
410			return Vec2(self.x / val.x, self.y / val.y)
411
412	def boolAny(self):	return Scalar(self.x or self.y)
413	def boolAll(self):	return Scalar(self.x and self.y)
414	def boolNot(self):	return Vec2(not self.x, not self.y)
415
416class Vec3(Vec):
417	def __init__(self, x, y, z):
418		assert((x.__class__ == y.__class__) and (x.__class__ == z.__class__))
419		self.x = x
420		self.y = y
421		self.z = z
422
423	def applyUnary(self, func):			return Vec3(func(self.x), func(self.y), func(self.z))
424	def applyBinary(self, func, other):	return Vec3(func(self.x, other.x), func(self.y, other.y), func(self.z, other.z))
425
426	def expandVec(self, val):	return val.toVec3()
427	def toScalar(self):			return Scalar(self.x)
428	def toVec2(self):			return Vec2(self.x, self.y)
429	def toVec3(self):			return Vec3(self.x, self.y, self.z)
430	def toVec4(self):			return Vec4(self.x, self.y, self.z, 0.0)
431	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));
432
433	def toFloat(self):			return Vec3(float(self.x), float(self.y), float(self.z))
434	def toInt(self):			return Vec3(int(self.x), int(self.y), int(self.z))
435	def toBool(self):			return Vec3(bool(self.x), bool(self.y), bool(self.z))
436
437	def getNumScalars(self):	return 3
438	def getScalars(self):		return [self.x, self.y, self.z]
439
440	def typeString(self):
441		if isinstance(self.x, bool):
442			return "bvec3"
443		elif isinstance(self.x, int):
444			return "ivec3"
445		elif isinstance(self.x, float):
446			return "vec3"
447		else:
448			assert False
449
450	def vec4Swizzle(self):
451		return ".xyzx"
452
453	def __str__(self):
454		if isinstance(self.x, bool):
455			return "bvec3(%s, %s, %s)" % (str(self.x).lower(), str(self.y).lower(), str(self.z).lower())
456		elif isinstance(self.x, int):
457			return "ivec3(%i, %i, %i)" % (self.x, self.y, self.z)
458		elif isinstance(self.x, float):
459			return "vec3(%s, %s, %s)" % (self.x, self.y, self.z)
460		else:
461			assert False
462
463	def distance(self, v):
464		assert isinstance(v, Vec3)
465		return (self - v).length()
466
467	def dot(self, v):
468		assert isinstance(v, Vec3)
469		return Scalar(self.x*v.x + self.y*v.y + self.z*v.z)
470
471	def cross(self, v):
472		assert isinstance(v, Vec3)
473		return Vec3(self.y*v.z - v.y*self.z,
474					self.z*v.x - v.z*self.x,
475					self.x*v.y - v.x*self.y)
476
477	def __neg__(self):
478		return Vec3(-self.x, -self.y, -self.z)
479
480	def __add__(self, val):
481		if isinstance(val, Scalar):
482			return Vec3(self.x + val, self.y + val)
483		elif isinstance(val, Vec3):
484			return Vec3(self.x + val.x, self.y + val.y, self.z + val.z)
485		else:
486			assert False
487
488	def __sub__(self, val):
489		return self + (-val)
490
491	def __mul__(self, val):
492		if isinstance(val, Scalar):
493			val = val.toVec3()
494		assert isinstance(val, Vec3)
495		return Vec3(self.x * val.x, self.y * val.y, self.z * val.z)
496
497	def __div__(self, val):
498		if isinstance(val, Scalar):
499			return Vec3(self.x / val.x, self.y / val.x, self.z / val.x)
500		else:
501			assert False
502
503	def boolAny(self):	return Scalar(self.x or self.y or self.z)
504	def boolAll(self):	return Scalar(self.x and self.y and self.z)
505	def boolNot(self):	return Vec3(not self.x, not self.y, not self.z)
506
507class Vec4(Vec):
508	def __init__(self, x, y, z, w):
509		assert((x.__class__ == y.__class__) and (x.__class__ == z.__class__) and (x.__class__ == w.__class__))
510		self.x = x
511		self.y = y
512		self.z = z
513		self.w = w
514
515	def applyUnary(self, func):			return Vec4(func(self.x), func(self.y), func(self.z), func(self.w))
516	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))
517
518	def expandVec(self, val):	return val.toVec4()
519	def toScalar(self):			return Scalar(self.x)
520	def toVec2(self):			return Vec2(self.x, self.y)
521	def toVec3(self):			return Vec3(self.x, self.y, self.z)
522	def toVec4(self):			return Vec4(self.x, self.y, self.z, self.w)
523	def toMat2(self):			return Mat2(float(self.x), float(self.y), float(self.z), float(self.w))
524	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));
525
526	def toFloat(self):			return Vec4(float(self.x), float(self.y), float(self.z), float(self.w))
527	def toInt(self):			return Vec4(int(self.x), int(self.y), int(self.z), int(self.w))
528	def toBool(self):			return Vec4(bool(self.x), bool(self.y), bool(self.z), bool(self.w))
529
530	def getNumScalars(self):	return 4
531	def getScalars(self):		return [self.x, self.y, self.z, self.w]
532
533	def typeString(self):
534		if isinstance(self.x, bool):
535			return "bvec4"
536		elif isinstance(self.x, int):
537			return "ivec4"
538		elif isinstance(self.x, float):
539			return "vec4"
540		else:
541			assert False
542
543	def vec4Swizzle(self):
544		return ""
545
546	def __str__(self):
547		if isinstance(self.x, bool):
548			return "bvec4(%s, %s, %s, %s)" % (str(self.x).lower(), str(self.y).lower(), str(self.z).lower(), str(self.w).lower())
549		elif isinstance(self.x, int):
550			return "ivec4(%i, %i, %i, %i)" % (self.x, self.y, self.z, self.w)
551		elif isinstance(self.x, float):
552			return "vec4(%s, %s, %s, %s)" % (self.x, self.y, self.z, self.w)
553		else:
554			assert False
555
556	def distance(self, v):
557		assert isinstance(v, Vec4)
558		return (self - v).length()
559
560	def dot(self, v):
561		assert isinstance(v, Vec4)
562		return Scalar(self.x*v.x + self.y*v.y + self.z*v.z + self.w*v.w)
563
564	def __neg__(self):
565		return Vec4(-self.x, -self.y, -self.z, -self.w)
566
567	def __add__(self, val):
568		if isinstance(val, Scalar):
569			return Vec3(self.x + val, self.y + val)
570		elif isinstance(val, Vec4):
571			return Vec4(self.x + val.x, self.y + val.y, self.z + val.z, self.w + val.w)
572		else:
573			assert False
574
575	def __sub__(self, val):
576		return self + (-val)
577
578	def __mul__(self, val):
579		if isinstance(val, Scalar):
580			val = val.toVec4()
581		assert isinstance(val, Vec4)
582		return Vec4(self.x * val.x, self.y * val.y, self.z * val.z, self.w * val.w)
583
584	def __div__(self, val):
585		if isinstance(val, Scalar):
586			return Vec4(self.x / val.x, self.y / val.x, self.z / val.x, self.w / val.x)
587		else:
588			assert False
589
590	def boolAny(self):	return Scalar(self.x or self.y or self.z or self.w)
591	def boolAll(self):	return Scalar(self.x and self.y and self.z and self.w)
592	def boolNot(self):	return Vec4(not self.x, not self.y, not self.z, not self.w)
593
594# \note Column-major storage.
595class Mat:
596	def __init__ (self, numCols, numRows, scalars):
597		assert len(scalars) == numRows*numCols
598		self.numCols	= numCols
599		self.numRows	= numRows
600		self.scalars	= scalars
601
602	@staticmethod
603	def identity (numCols, numRows):
604		scalars = []
605		for col in range(0, numCols):
606			for row in range(0, numRows):
607				scalars.append(1.0 if col == row else 0.0)
608		return Mat(numCols, numRows, scalars)
609
610	def get (self, colNdx, rowNdx):
611		assert 0 <= colNdx and colNdx < self.numCols
612		assert 0 <= rowNdx and rowNdx < self.numRows
613		return self.scalars[colNdx*self.numRows + rowNdx]
614
615	def set (self, colNdx, rowNdx, scalar):
616		assert 0 <= colNdx and colNdx < self.numCols
617		assert 0 <= rowNdx and rowNdx < self.numRows
618		self.scalars[colNdx*self.numRows + rowNdx] = scalar
619
620	def toMatrix (self, numCols, numRows):
621		res = Mat.identity(numCols, numRows)
622		for col in range(0, min(self.numCols, numCols)):
623			for row in range(0, min(self.numRows, numRows)):
624				res.set(col, row, self.get(col, row))
625		return res
626
627	def toMat2 (self):		return self.toMatrix(2, 2)
628	def toMat2x3 (self):	return self.toMatrix(2, 3)
629	def toMat2x4 (self):	return self.toMatrix(2, 4)
630	def toMat3x2 (self):	return self.toMatrix(3, 2)
631	def toMat3 (self):		return self.toMatrix(3, 3)
632	def toMat3x4 (self):	return self.toMatrix(3, 4)
633	def toMat4x2 (self):	return self.toMatrix(4, 2)
634	def toMat4x3 (self):	return self.toMatrix(4, 3)
635	def toMat4 (self):		return self.toMatrix(4, 4)
636
637	def typeString(self):
638		if self.numRows == self.numCols:
639			return "mat%d" % self.numRows
640		else:
641			return "mat%dx%d" % (self.numCols, self.numRows)
642
643	def __str__(self):
644		return "%s(%s)" % (self.typeString(), ", ".join([str(s) for s in self.scalars]))
645
646	def isTypeEqual (self, other):
647		return isinstance(other, Mat) and self.numRows == other.numRows and self.numCols == other.numCols
648
649	def isEqual(self, other):
650		assert self.isTypeEqual(other)
651		return (self.scalars == other.scalars)
652
653	def compMul(self, val):
654		assert self.isTypeEqual(val)
655		return Mat(self.numRows, self.numCols, [self.scalars(i) * val.scalars(i) for i in range(self.numRows*self.numCols)])
656
657class Mat2(Mat):
658	def __init__(self, m00, m01, m10, m11):
659		Mat.__init__(self, 2, 2, [m00, m10, m01, m11])
660
661class Mat3(Mat):
662	def __init__(self, m00, m01, m02, m10, m11, m12, m20, m21, m22):
663		Mat.__init__(self, 3, 3, [m00, m10, m20,
664								  m01, m11, m21,
665								  m02, m12, m22])
666
667class Mat4(Mat):
668	def __init__(self, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33):
669		Mat.__init__(self, 4, 4, [m00, m10, m20, m30,
670								  m01, m11, m21, m31,
671								  m02, m12, m22, m32,
672								  m03, m13, m23, m33])
673