1import re 2import math 3import random 4 5PREAMBLE = """ 6# WARNING: This file is auto-generated. Do NOT modify it manually, but rather 7# modify the generating script file. Otherwise changes will be lost! 8"""[1:] 9 10class CaseGroup: 11 def __init__(self, name, description, children): 12 self.name = name 13 self.description = description 14 self.children = children 15 16class ShaderCase: 17 def __init__(self): 18 pass 19 20g_processedCases = {} 21 22def indentTextBlock(text, indent): 23 indentStr = indent * "\t" 24 lines = text.split("\n") 25 lines = [indentStr + line for line in lines] 26 lines = [ ["", line][line.strip() != ""] for line in lines] 27 return "\n".join(lines) 28 29def writeCase(f, case, indent, prefix): 30 print "\t%s" % (prefix + case.name) 31 if isinstance(case, CaseGroup): 32 f.write(indentTextBlock('group %s "%s"\n\n' % (case.name, case.description), indent)) 33 for child in case.children: 34 writeCase(f, child, indent + 1, prefix + case.name + ".") 35 f.write(indentTextBlock("\nend # %s\n" % case.name, indent)) 36 else: 37 # \todo [petri] Fix hack. 38 fullPath = prefix + case.name 39 assert (fullPath not in g_processedCases) 40 g_processedCases[fullPath] = None 41 f.write(indentTextBlock(str(case) + "\n", indent)) 42 43def writeAllCases(fileName, caseList): 44 # Write all cases to file. 45 print " %s.." % fileName 46 f = file(fileName, "wb") 47 f.write(PREAMBLE + "\n") 48 for case in caseList: 49 writeCase(f, case, 0, "") 50 f.close() 51 52 print "done! (%d cases written)" % len(g_processedCases) 53 54# Template operations. 55 56def genValues(inputs, outputs): 57 res = [] 58 for (name, values) in inputs: 59 res.append("input %s = [ %s ];" % (name, " | ".join([str(v) for v in values]).lower())) 60 for (name, values) in outputs: 61 res.append("output %s = [ %s ];" % (name, " | ".join([str(v) for v in values]).lower())) 62 return ("\n".join(res)) 63 64def fillTemplate(template, params): 65 s = template 66 67 for (key, value) in params.items(): 68 m = re.search(r"^(\s*)\$\{\{%s\}\}$" % key, s, re.M) 69 if m is not None: 70 start = m.start(0) 71 end = m.end(0) 72 ws = m.group(1) 73 if value is not None: 74 repl = "\n".join(["%s%s" % (ws, line) for line in value.split("\n")]) 75 s = s[:start] + repl + s[end:] 76 else: 77 s = s[:start] + s[end+1:] # drop the whole line 78 else: 79 s = s.replace("${{%s}}" % key, value) 80 return s 81 82# Return shuffled version of list 83def shuffled(lst): 84 tmp = lst[:] 85 random.shuffle(tmp) 86 return tmp 87 88def repeatToLength(lst, toLength): 89 return (toLength / len(lst)) * lst + lst[: toLength % len(lst)] 90 91# Helpers to convert a list of Scalar/Vec values into another type. 92 93def toFloat(lst): return [Scalar(float(v.x)) for v in lst] 94def toInt(lst): return [Scalar(int(v.x)) for v in lst] 95def toBool(lst): return [Scalar(bool(v.x)) for v in lst] 96def toVec4(lst): return [v.toFloat().toVec4() for v in lst] 97def toVec3(lst): return [v.toFloat().toVec3() for v in lst] 98def toVec2(lst): return [v.toFloat().toVec2() for v in lst] 99def toIVec4(lst): return [v.toInt().toVec4() for v in lst] 100def toIVec3(lst): return [v.toInt().toVec3() for v in lst] 101def toIVec2(lst): return [v.toInt().toVec2() for v in lst] 102def toBVec4(lst): return [v.toBool().toVec4() for v in lst] 103def toBVec3(lst): return [v.toBool().toVec3() for v in lst] 104def toBVec2(lst): return [v.toBool().toVec2() for v in lst] 105def toMat2(lst): return [v.toMat2() for v in lst] 106def toMat3(lst): return [v.toMat3() for v in lst] 107def toMat4(lst): return [v.toMat4() for v in lst] 108 109# Random value generation. 110 111class GenRandom: 112 def __init__(self): 113 pass 114 115 def uniformVec4(self, count, mn, mx): 116 ret = [Vec4(random.uniform(mn, mx), random.uniform(mn, mx), random.uniform(mn, mx), random.uniform(mn, mx)) for x in xrange(count)] 117 ret[0].x = mn 118 ret[1].x = mx 119 ret[2].x = (mn + mx) * 0.5 120 return ret 121 122 def uniformBVec4(self, count): 123 ret = [Vec4(random.random() >= 0.5, random.random() >= 0.5, random.random() >= 0.5, random.random() >= 0.5) for x in xrange(count)] 124 ret[0].x = True 125 ret[1].x = False 126 return ret 127 128# def uniform(self, 129 130# Math operating on Scalar/Vector types. 131 132def glslSign(a): return 0.0 if (a == 0) else +1.0 if (a > 0.0) else -1.0 133def glslMod(x, y): return x - y*math.floor(x/y) 134def glslClamp(x, mn, mx): return mn if (x < mn) else mx if (x > mx) else x 135 136class GenMath: 137 @staticmethod 138 def unary(func): return lambda val: val.applyUnary(func) 139 140 @staticmethod 141 def binary(func): return lambda a, b: (b.expandVec(a)).applyBinary(func, a.expandVec(b)) 142 143 @staticmethod 144 def frac(val): return val.applyUnary(lambda x: x - math.floor(x)) 145 146 @staticmethod 147 def exp2(val): return val.applyUnary(lambda x: math.pow(2.0, x)) 148 149 @staticmethod 150 def log2(val): return val.applyUnary(lambda x: math.log(x, 2.0)) 151 152 @staticmethod 153 def rsq(val): return val.applyUnary(lambda x: 1.0 / math.sqrt(x)) 154 155 @staticmethod 156 def sign(val): return val.applyUnary(glslSign) 157 158 @staticmethod 159 def isEqual(a, b): return Scalar(a.isEqual(b)) 160 161 @staticmethod 162 def isNotEqual(a, b): return Scalar(not a.isEqual(b)) 163 164 @staticmethod 165 def step(a, b): return (b.expandVec(a)).applyBinary(lambda edge, x: [1.0, 0.0][x < edge], a.expandVec(b)) 166 167 @staticmethod 168 def length(a): return a.length() 169 170 @staticmethod 171 def distance(a, b): return a.distance(b) 172 173 @staticmethod 174 def dot(a, b): return a.dot(b) 175 176 @staticmethod 177 def cross(a, b): return a.cross(b) 178 179 @staticmethod 180 def normalize(a): return a.normalize() 181 182 @staticmethod 183 def boolAny(a): return a.boolAny() 184 185 @staticmethod 186 def boolAll(a): return a.boolAll() 187 188 @staticmethod 189 def boolNot(a): return a.boolNot() 190 191# .. 192 193class Scalar: 194 def __init__(self, x): 195 self.x = x 196 197 def applyUnary(self, func): return Scalar(func(self.x)) 198 def applyBinary(self, func, other): return Scalar(func(self.x, other.x)) 199 200 def isEqual(self, other): assert isinstance(other, Scalar); return (self.x == other.x) 201 202 def expandVec(self, val): return val 203 def toScalar(self): return Scalar(self.x) 204 def toVec2(self): return Vec2(self.x, self.x) 205 def toVec3(self): return Vec3(self.x, self.x, self.x) 206 def toVec4(self): return Vec4(self.x, self.x, self.x, self.x) 207 def toMat2(self): return self.toVec2().toMat2() 208 def toMat3(self): return self.toVec3().toMat3() 209 def toMat4(self): return self.toVec4().toMat4() 210 211 def toFloat(self): return Scalar(float(self.x)) 212 def toInt(self): return Scalar(int(self.x)) 213 def toBool(self): return Scalar(bool(self.x)) 214 215 def getNumScalars(self): return 1 216 def getScalars(self): return [self.x] 217 218 def typeString(self): 219 if isinstance(self.x, bool): 220 return "bool" 221 elif isinstance(self.x, int): 222 return "int" 223 elif isinstance(self.x, float): 224 return "float" 225 else: 226 assert False 227 228 def vec4Swizzle(self): 229 return "" 230 231 def __str__(self): 232 return "%s" % self.x 233 234 def length(self): 235 return Scalar(abs(self.x)) 236 237 def distance(self, v): 238 assert isinstance(v, Scalar) 239 return Scalar(abs(self.x - v.x)) 240 241 def dot(self, v): 242 assert isinstance(v, Scalar) 243 return Scalar(self.x * v.x) 244 245 def normalize(self): 246 return Scalar(glslSign(self.x)) 247 248 def __neg__(self): 249 return Scalar(-self.x) 250 251 def __add__(self, val): 252 assert isinstance(val, Scalar) 253 return Scalar(self.x + val.x) 254 255 def __sub__(self, val): 256 return self + (-val) 257 258 def __mul__(self, val): 259 if isinstance(val, Scalar): 260 return Scalar(self.x * val.x) 261 elif isinstance(val, Vec2): 262 return Vec2(self.x * val.x, self.x * val.y) 263 elif isinstance(val, Vec3): 264 return Vec3(self.x * val.x, self.x * val.y, self.x * val.z) 265 elif isinstance(val, Vec4): 266 return Vec4(self.x * val.x, self.x * val.y, self.x * val.z, self.x * val.w) 267 else: 268 assert False 269 270 def __div__(self, val): 271 if isinstance(val, Scalar): 272 return Scalar(self.x / val.x) 273 elif isinstance(val, Vec2): 274 return Vec2(self.x / val.x, self.x / val.y) 275 elif isinstance(val, Vec3): 276 return Vec3(self.x / val.x, self.x / val.y, self.x / val.z) 277 elif isinstance(val, Vec4): 278 return Vec4(self.x / val.x, self.x / val.y, self.x / val.z, self.x / val.w) 279 else: 280 assert False 281 282class Vec: 283 @staticmethod 284 def fromScalarList(lst): 285 assert (len(lst) >= 1 and len(lst) <= 4) 286 if (len(lst) == 1): return Scalar(lst[0]) 287 elif (len(lst) == 2): return Vec2(lst[0], lst[1]) 288 elif (len(lst) == 3): return Vec3(lst[0], lst[1], lst[2]) 289 else: return Vec4(lst[0], lst[1], lst[2], lst[3]) 290 291 def isEqual(self, other): 292 assert isinstance(other, Vec); 293 return (self.getScalars() == other.getScalars()) 294 295 def length(self): 296 return Scalar(math.sqrt(self.dot(self).x)) 297 298 def normalize(self): 299 return self * Scalar(1.0 / self.length().x) 300 301 def swizzle(self, indexList): 302 inScalars = self.getScalars() 303 outScalars = map(lambda ndx: inScalars[ndx], indexList) 304 return Vec.fromScalarList(outScalars) 305 306 def __init__(self): 307 pass 308 309class Vec2(Vec): 310 def __init__(self, x, y): 311 assert(x.__class__ == y.__class__) 312 self.x = x 313 self.y = y 314 315 def applyUnary(self, func): return Vec2(func(self.x), func(self.y)) 316 def applyBinary(self, func, other): return Vec2(func(self.x, other.x), func(self.y, other.y)) 317 318 def expandVec(self, val): return val.toVec2() 319 def toScalar(self): return Scalar(self.x) 320 def toVec2(self): return Vec2(self.x, self.y) 321 def toVec3(self): return Vec3(self.x, self.y, 0.0) 322 def toVec4(self): return Vec4(self.x, self.y, 0.0, 0.0) 323 def toMat2(self): return Mat2(float(self.x), 0.0, 0.0, float(self.y)); 324 325 def toFloat(self): return Vec2(float(self.x), float(self.y)) 326 def toInt(self): return Vec2(int(self.x), int(self.y)) 327 def toBool(self): return Vec2(bool(self.x), bool(self.y)) 328 329 def getNumScalars(self): return 2 330 def getScalars(self): return [self.x, self.y] 331 332 def typeString(self): 333 if isinstance(self.x, bool): 334 return "bvec2" 335 elif isinstance(self.x, int): 336 return "ivec2" 337 elif isinstance(self.x, float): 338 return "vec2" 339 else: 340 assert False 341 342 def vec4Swizzle(self): 343 return ".xyxy" 344 345 def __str__(self): 346 if isinstance(self.x, bool): 347 return "bvec2(%s, %s)" % (str(self.x).lower(), str(self.y).lower()) 348 elif isinstance(self.x, int): 349 return "ivec2(%i, %i)" % (self.x, self.y) 350 elif isinstance(self.x, float): 351 return "vec2(%s, %s)" % (self.x, self.y) 352 else: 353 assert False 354 355 def distance(self, v): 356 assert isinstance(v, Vec2) 357 return (self - v).length() 358 359 def dot(self, v): 360 assert isinstance(v, Vec2) 361 return Scalar(self.x*v.x + self.y*v.y) 362 363 def __neg__(self): 364 return Vec2(-self.x, -self.y) 365 366 def __add__(self, val): 367 if isinstance(val, Scalar): 368 return Vec2(self.x + val, self.y + val) 369 elif isinstance(val, Vec2): 370 return Vec2(self.x + val.x, self.y + val.y) 371 else: 372 assert False 373 374 def __sub__(self, val): 375 return self + (-val) 376 377 def __mul__(self, val): 378 if isinstance(val, Scalar): 379 val = val.toVec2() 380 assert isinstance(val, Vec2) 381 return Vec2(self.x * val.x, self.y * val.y) 382 383 def __div__(self, val): 384 if isinstance(val, Scalar): 385 return Vec2(self.x / val.x, self.y / val.x) 386 else: 387 assert isinstance(val, Vec2) 388 return Vec2(self.x / val.x, self.y / val.y) 389 390 def boolAny(self): return Scalar(self.x or self.y) 391 def boolAll(self): return Scalar(self.x and self.y) 392 def boolNot(self): return Vec2(not self.x, not self.y) 393 394class Vec3(Vec): 395 def __init__(self, x, y, z): 396 assert((x.__class__ == y.__class__) and (x.__class__ == z.__class__)) 397 self.x = x 398 self.y = y 399 self.z = z 400 401 def applyUnary(self, func): return Vec3(func(self.x), func(self.y), func(self.z)) 402 def applyBinary(self, func, other): return Vec3(func(self.x, other.x), func(self.y, other.y), func(self.z, other.z)) 403 404 def expandVec(self, val): return val.toVec3() 405 def toScalar(self): return Scalar(self.x) 406 def toVec2(self): return Vec2(self.x, self.y) 407 def toVec3(self): return Vec3(self.x, self.y, self.z) 408 def toVec4(self): return Vec4(self.x, self.y, self.z, 0.0) 409 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)); 410 411 def toFloat(self): return Vec3(float(self.x), float(self.y), float(self.z)) 412 def toInt(self): return Vec3(int(self.x), int(self.y), int(self.z)) 413 def toBool(self): return Vec3(bool(self.x), bool(self.y), bool(self.z)) 414 415 def getNumScalars(self): return 3 416 def getScalars(self): return [self.x, self.y, self.z] 417 418 def typeString(self): 419 if isinstance(self.x, bool): 420 return "bvec3" 421 elif isinstance(self.x, int): 422 return "ivec3" 423 elif isinstance(self.x, float): 424 return "vec3" 425 else: 426 assert False 427 428 def vec4Swizzle(self): 429 return ".xyzx" 430 431 def __str__(self): 432 if isinstance(self.x, bool): 433 return "bvec3(%s, %s, %s)" % (str(self.x).lower(), str(self.y).lower(), str(self.z).lower()) 434 elif isinstance(self.x, int): 435 return "ivec3(%i, %i, %i)" % (self.x, self.y, self.z) 436 elif isinstance(self.x, float): 437 return "vec3(%s, %s, %s)" % (self.x, self.y, self.z) 438 else: 439 assert False 440 441 def distance(self, v): 442 assert isinstance(v, Vec3) 443 return (self - v).length() 444 445 def dot(self, v): 446 assert isinstance(v, Vec3) 447 return Scalar(self.x*v.x + self.y*v.y + self.z*v.z) 448 449 def cross(self, v): 450 assert isinstance(v, Vec3) 451 return Vec3(self.y*v.z - v.y*self.z, 452 self.z*v.x - v.z*self.x, 453 self.x*v.y - v.x*self.y) 454 455 def __neg__(self): 456 return Vec3(-self.x, -self.y, -self.z) 457 458 def __add__(self, val): 459 if isinstance(val, Scalar): 460 return Vec3(self.x + val, self.y + val) 461 elif isinstance(val, Vec3): 462 return Vec3(self.x + val.x, self.y + val.y, self.z + val.z) 463 else: 464 assert False 465 466 def __sub__(self, val): 467 return self + (-val) 468 469 def __mul__(self, val): 470 if isinstance(val, Scalar): 471 val = val.toVec3() 472 assert isinstance(val, Vec3) 473 return Vec3(self.x * val.x, self.y * val.y, self.z * val.z) 474 475 def __div__(self, val): 476 if isinstance(val, Scalar): 477 return Vec3(self.x / val.x, self.y / val.x, self.z / val.x) 478 else: 479 assert False 480 481 def boolAny(self): return Scalar(self.x or self.y or self.z) 482 def boolAll(self): return Scalar(self.x and self.y and self.z) 483 def boolNot(self): return Vec3(not self.x, not self.y, not self.z) 484 485class Vec4(Vec): 486 def __init__(self, x, y, z, w): 487 assert((x.__class__ == y.__class__) and (x.__class__ == z.__class__) and (x.__class__ == w.__class__)) 488 self.x = x 489 self.y = y 490 self.z = z 491 self.w = w 492 493 def applyUnary(self, func): return Vec4(func(self.x), func(self.y), func(self.z), func(self.w)) 494 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)) 495 496 def expandVec(self, val): return val.toVec4() 497 def toScalar(self): return Scalar(self.x) 498 def toVec2(self): return Vec2(self.x, self.y) 499 def toVec3(self): return Vec3(self.x, self.y, self.z) 500 def toVec4(self): return Vec4(self.x, self.y, self.z, self.w) 501 def toMat2(self): return Mat2(float(self.x), float(self.y), float(self.z), float(self.w)) 502 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)); 503 504 def toFloat(self): return Vec4(float(self.x), float(self.y), float(self.z), float(self.w)) 505 def toInt(self): return Vec4(int(self.x), int(self.y), int(self.z), int(self.w)) 506 def toBool(self): return Vec4(bool(self.x), bool(self.y), bool(self.z), bool(self.w)) 507 508 def getNumScalars(self): return 4 509 def getScalars(self): return [self.x, self.y, self.z, self.w] 510 511 def typeString(self): 512 if isinstance(self.x, bool): 513 return "bvec4" 514 elif isinstance(self.x, int): 515 return "ivec4" 516 elif isinstance(self.x, float): 517 return "vec4" 518 else: 519 assert False 520 521 def vec4Swizzle(self): 522 return "" 523 524 def __str__(self): 525 if isinstance(self.x, bool): 526 return "bvec4(%s, %s, %s, %s)" % (str(self.x).lower(), str(self.y).lower(), str(self.z).lower(), str(self.w).lower()) 527 elif isinstance(self.x, int): 528 return "ivec4(%i, %i, %i, %i)" % (self.x, self.y, self.z, self.w) 529 elif isinstance(self.x, float): 530 return "vec4(%s, %s, %s, %s)" % (self.x, self.y, self.z, self.w) 531 else: 532 assert False 533 534 def distance(self, v): 535 assert isinstance(v, Vec4) 536 return (self - v).length() 537 538 def dot(self, v): 539 assert isinstance(v, Vec4) 540 return Scalar(self.x*v.x + self.y*v.y + self.z*v.z + self.w*v.w) 541 542 def __neg__(self): 543 return Vec4(-self.x, -self.y, -self.z, -self.w) 544 545 def __add__(self, val): 546 if isinstance(val, Scalar): 547 return Vec3(self.x + val, self.y + val) 548 elif isinstance(val, Vec4): 549 return Vec4(self.x + val.x, self.y + val.y, self.z + val.z, self.w + val.w) 550 else: 551 assert False 552 553 def __sub__(self, val): 554 return self + (-val) 555 556 def __mul__(self, val): 557 if isinstance(val, Scalar): 558 val = val.toVec4() 559 assert isinstance(val, Vec4) 560 return Vec4(self.x * val.x, self.y * val.y, self.z * val.z, self.w * val.w) 561 562 def __div__(self, val): 563 if isinstance(val, Scalar): 564 return Vec4(self.x / val.x, self.y / val.x, self.z / val.x, self.w / val.x) 565 else: 566 assert False 567 568 def boolAny(self): return Scalar(self.x or self.y or self.z or self.w) 569 def boolAll(self): return Scalar(self.x and self.y and self.z and self.w) 570 def boolNot(self): return Vec4(not self.x, not self.y, not self.z, not self.w) 571 572# \note Column-major storage. 573class Mat: 574 def __init__ (self, numCols, numRows, scalars): 575 assert len(scalars) == numRows*numCols 576 self.numCols = numCols 577 self.numRows = numRows 578 self.scalars = scalars 579 580 @staticmethod 581 def identity (numCols, numRows): 582 scalars = [] 583 for col in range(0, numCols): 584 for row in range(0, numRows): 585 scalars.append(1.0 if col == row else 0.0) 586 return Mat(numCols, numRows, scalars) 587 588 def get (self, colNdx, rowNdx): 589 assert 0 <= colNdx and colNdx < self.numCols 590 assert 0 <= rowNdx and rowNdx < self.numRows 591 return self.scalars[colNdx*self.numRows + rowNdx] 592 593 def set (self, colNdx, rowNdx, scalar): 594 assert 0 <= colNdx and colNdx < self.numCols 595 assert 0 <= rowNdx and rowNdx < self.numRows 596 self.scalars[colNdx*self.numRows + rowNdx] = scalar 597 598 def toMatrix (self, numCols, numRows): 599 res = Mat.identity(numCols, numRows) 600 for col in range(0, min(self.numCols, numCols)): 601 for row in range(0, min(self.numRows, numRows)): 602 res.set(col, row, self.get(col, row)) 603 return res 604 605 def toMat2 (self): return self.toMatrix(2, 2) 606 def toMat2x3 (self): return self.toMatrix(2, 3) 607 def toMat2x4 (self): return self.toMatrix(2, 4) 608 def toMat3x2 (self): return self.toMatrix(3, 2) 609 def toMat3 (self): return self.toMatrix(3, 3) 610 def toMat3x4 (self): return self.toMatrix(3, 4) 611 def toMat4x2 (self): return self.toMatrix(4, 2) 612 def toMat4x3 (self): return self.toMatrix(4, 3) 613 def toMat4 (self): return self.toMatrix(4, 4) 614 615 def typeString(self): 616 if self.numRows == self.numCols: 617 return "mat%d" % self.numRows 618 else: 619 return "mat%dx%d" % (self.numCols, self.numRows) 620 621 def __str__(self): 622 return "%s(%s)" % (self.typeString(), ", ".join([str(s) for s in self.scalars])) 623 624 def isTypeEqual (self, other): 625 return isinstance(other, Mat) and self.numRows == other.numRows and self.numCols == other.numCols 626 627 def isEqual(self, other): 628 assert self.isTypeEqual(other) 629 return (self.scalars == other.scalars) 630 631 def compMul(self, val): 632 assert self.isTypeEqual(val) 633 return Mat(self.numRows, self.numCols, [self.scalars(i) * val.scalars(i) for i in range(self.numRows*self.numCols)]) 634 635class Mat2(Mat): 636 def __init__(self, m00, m01, m10, m11): 637 Mat.__init__(self, 2, 2, [m00, m10, m01, m11]) 638 639class Mat3(Mat): 640 def __init__(self, m00, m01, m02, m10, m11, m12, m20, m21, m22): 641 Mat.__init__(self, 3, 3, [m00, m10, m20, 642 m01, m11, m21, 643 m02, m12, m22]) 644 645class Mat4(Mat): 646 def __init__(self, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33): 647 Mat.__init__(self, 4, 4, [m00, m10, m20, m30, 648 m01, m11, m21, m31, 649 m02, m12, m22, m32, 650 m03, m13, m23, m33]) 651