Home | History | Annotate | Download | only in scripts
      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 
     23 import re
     24 import math
     25 import random
     26 
     27 PREAMBLE = """
     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 
     32 class CaseGroup:
     33 	def __init__(self, name, description, children):
     34 		self.name			= name
     35 		self.description	= description
     36 		self.children		= children
     37 
     38 class ShaderCase:
     39 	def __init__(self):
     40 		pass
     41 
     42 g_processedCases = {}
     43 
     44 def 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 
     51 def 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 
     65 def 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 
     78 def 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 
     86 def 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
    105 def shuffled(lst):
    106 	tmp = lst[:]
    107 	random.shuffle(tmp)
    108 	return tmp
    109 
    110 def 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 
    115 def toFloat(lst):	return [Scalar(float(v.x)) for v in lst]
    116 def toInt(lst):		return [Scalar(int(v.x)) for v in lst]
    117 def toBool(lst):	return [Scalar(bool(v.x)) for v in lst]
    118 def toVec4(lst):	return [v.toFloat().toVec4() for v in lst]
    119 def toVec3(lst):	return [v.toFloat().toVec3() for v in lst]
    120 def toVec2(lst):	return [v.toFloat().toVec2() for v in lst]
    121 def toIVec4(lst):	return [v.toInt().toVec4() for v in lst]
    122 def toIVec3(lst):	return [v.toInt().toVec3() for v in lst]
    123 def toIVec2(lst):	return [v.toInt().toVec2() for v in lst]
    124 def toBVec4(lst):	return [v.toBool().toVec4() for v in lst]
    125 def toBVec3(lst):	return [v.toBool().toVec3() for v in lst]
    126 def toBVec2(lst):	return [v.toBool().toVec2() for v in lst]
    127 def toMat2(lst):	return [v.toMat2() for v in lst]
    128 def toMat3(lst):	return [v.toMat3() for v in lst]
    129 def toMat4(lst):	return [v.toMat4() for v in lst]
    130 
    131 # Random value generation.
    132 
    133 class 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 
    154 def glslSign(a):			return 0.0 if (a == 0) else +1.0 if (a > 0.0) else -1.0
    155 def glslMod(x, y):			return x - y*math.floor(x/y)
    156 def glslClamp(x, mn, mx):	return mn if (x < mn) else mx if (x > mx) else x
    157 
    158 class 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 
    215 class 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 
    304 class 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 
    331 class 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 
    416 class 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 
    507 class 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.
    595 class 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 
    657 class Mat2(Mat):
    658 	def __init__(self, m00, m01, m10, m11):
    659 		Mat.__init__(self, 2, 2, [m00, m10, m01, m11])
    660 
    661 class 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 
    667 class 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