changeset 28:f405b947624d

Massive sprite updating/matrix handling optimizations
author Thibaut Girka <thib@sitedethib.com>
date Fri, 12 Aug 2011 21:40:26 +0200
parents b65d6bc55793
children afa91be769ae
files pytouhou/game/sprite.py pytouhou/utils/matrix.py
diffstat 2 files changed, 91 insertions(+), 63 deletions(-) [+]
line wrap: on
line diff
--- a/pytouhou/game/sprite.py
+++ b/pytouhou/game/sprite.py
@@ -30,39 +30,29 @@ class Sprite(object):
 
 
     def update_uvs_vertices(self, override_width=0, override_height=0):
-        vertmat = Matrix()
-        vertmat.data[0][0] = -.5
-        vertmat.data[1][0] = -.5
-
-        vertmat.data[0][1] = .5
-        vertmat.data[1][1] = -.5
-
-        vertmat.data[0][2] = .5
-        vertmat.data[1][2] = .5
-
-        vertmat.data[0][3] = -.5
-        vertmat.data[1][3] = .5
-
-        for i in range(4):
-            vertmat.data[2][i] = 0.
-            vertmat.data[3][i] = 1.
+        vertmat = Matrix([[-.5,     .5,     .5,    -.5],
+                          [-.5,    -.5,     .5,     .5],
+                          [ .0,     .0,     .0,     .0],
+                          [ 1.,     1.,     1.,     1.]])
 
         tx, ty, tw, th = self.texcoords
         sx, sy = self.rescale
         width = override_width or (tw * sx)
         height = override_height or (th * sy)
 
-        transform = Matrix.get_scaling_matrix(width, height, 1.)
+        vertmat.scale(width, height, 1.)
         if self.mirrored:
-            transform = Matrix.get_scaling_matrix(-1., 1., 1.).mult(transform)
+            vertmat.flip()
         if self.rotations_3d != (0., 0., 0.):
             rx, ry, rz = self.rotations_3d
-            transform = Matrix.get_rotation_matrix(-rx, 'x').mult(transform)
-            transform = Matrix.get_rotation_matrix(ry, 'y').mult(transform)
-            transform = Matrix.get_rotation_matrix(-rz, 'z').mult(transform) #TODO: minus, really?
+            if rx:
+                vertmat.rotate_x(-rx)
+            if ry:
+                vertmat.rotate_y(ry)
+            if rz:
+                vertmat.rotate_z(-rz) #TODO: minus, really?
         if self.corner_relative_placement: # Reposition
-            transform = Matrix.get_translation_matrix(width / 2., height / 2., 0.).mult(transform)
-        vertmat = transform.mult(vertmat)
+            vertmat.translate(width / 2., height / 2., 0.)
 
         uvs = [(tx / self.anm.size[0],         1. - (ty / self.anm.size[1])),
                ((tx + tw) / self.anm.size[0],  1. - (ty / self.anm.size[1])),
--- a/pytouhou/utils/matrix.py
+++ b/pytouhou/utils/matrix.py
@@ -3,64 +3,102 @@
 from math import sin, cos
 
 class Matrix(object):
-    def __init__(self):
-        self.data = [[0] * 4 for i in xrange(4)]
+    def __init__(self, data=None):
+        self.data = data or [[0] * 4 for i in xrange(4)]
 
 
     def mult(self, other_matrix):
-        result = Matrix()
-        for i in xrange(4):
-            for j in xrange(4):
-                result.data[i][j] = sum(self.data[i][a] * other_matrix.data[a][j] for a in xrange(4))
-        return result
+        d1 = self.data
+        d2 = other_matrix.data
+        return Matrix([[sum(d1[i][a] * d2[a][j] for a in xrange(4)) for j in xrange(4)] for i in xrange(4)])
+
+
+    def flip(self):
+        self.data[0][:] = (-x for x in self.data[0])
+
+
+    def scale(self, x, y, z):
+        d1 = self.data
+        d1[0][:] = (a * x for a in d1[0])
+        d1[1][:] = (a * y for a in d1[1])
+        d1[2][:] = (a * z for a in d1[2])
+
+
+    def translate(self, x, y, z):
+        d1 = self.data
+        a, b, c = (v * m for v, m in zip(d1[3][:3], (x, y, z)))
+        d1[0][:] = (v + a for v in d1[0])
+        d1[1][:] = (v + b for v in d1[1])
+        d1[2][:] = (v + c for v in d1[2])
+
+
+    def rotate_x(self, angle):
+        d1 = self.data
+        cos_a = cos(angle)
+        sin_a = sin(angle)
+        a = [cos_a * d1[1][i] - sin_a * d1[2][i] for i in range(4)]
+        b = [sin_a * d1[1][i] + cos_a * d1[2][i] for i in range(4)]
+        d1[1][:] = a
+        d1[2][:] = b
+
+
+    def rotate_y(self, angle):
+        #TODO: check
+        d1 = self.data
+        cos_a = cos(angle)
+        sin_a = sin(angle)
+        a = [cos_a * d1[0][i] - sin_a * d1[2][i] for i in range(4)]
+        b = [sin_a * d1[0][i] + cos_a * d1[2][i] for i in range(4)]
+        d1[0][:] = a
+        d1[2][:] = b
+
+
+    def rotate_z(self, angle):
+        d1 = self.data
+        cos_a = cos(angle)
+        sin_a = sin(angle)
+        a = [cos_a * d1[0][i] - sin_a * d1[1][i] for i in range(4)]
+        b = [sin_a * d1[0][i] + cos_a * d1[1][i] for i in range(4)]
+        d1[0][:] = a
+        d1[1][:] = b
 
 
     @classmethod
     def get_translation_matrix(cls, x, y, z):
-        matrix = cls()
-        matrix.data[0][0] = 1
-        matrix.data[1][1] = 1
-        matrix.data[2][2] = 1
-        matrix.data[3][3] = 1
-        matrix.data[0][3] = x
-        matrix.data[1][3] = y
-        matrix.data[2][3] = z
-        return matrix
+        return cls([[1., 0., 0., x],
+                    [0., 1., 0., y],
+                    [0., 0., 1., z],
+                    [0., 0., 0., 1.]])
 
 
     @classmethod
     def get_scaling_matrix(cls, x, y, z):
-        matrix = cls()
-        matrix.data[0][0] = x
-        matrix.data[1][1] = y
-        matrix.data[2][2] = z
-        matrix.data[3][3] = 1
-        return matrix
+        return cls([[x,  0., 0., 0.],
+                    [0., y,  0., 0.],
+                    [0., 0., z,  0.],
+                    [0., 0., 0., 1.]])
 
 
     @classmethod
     def get_rotation_matrix(cls, angle, axis):
         """Only handles axis = x, y or z."""
-        matrix = cls()
-        matrix.data[3][3] = 1
+        cos_a = cos(angle)
+        sin_a = sin(angle)
         if axis == 'x':
-            matrix.data[0][0] = 1
-            matrix.data[1][1] = cos(angle)
-            matrix.data[1][2] = -sin(angle)
-            matrix.data[2][1] = sin(angle)
-            matrix.data[2][2] = cos(angle)
+            return Matrix([[    1.,     0.,     0.,     0.],
+                           [    0.,  cos_a, -sin_a,     0.],
+                           [    0.,  sin_a,  cos_a,     0.],
+                           [    0.,     0.,     0.,     1.]])
         elif axis == 'y':
-            matrix.data[0][0] = cos(angle)
-            matrix.data[0][2] = sin(angle)
-            matrix.data[2][0] = -sin(angle)
-            matrix.data[2][2] = cos(angle)
-            matrix.data[1][1] = 1
+            return Matrix([[ cos_a,     0.,  sin_a,     0.],
+                           [    0.,     1.,     0.,     0.],
+                           [-sin_a,     0.,  cos_a,     0.],
+                           [    0.,     0.,     0.,     1.]])
         elif axis == 'z':
-            matrix.data[0][0] = cos(angle)
-            matrix.data[0][1] = -sin(angle)
-            matrix.data[1][0] = sin(angle)
-            matrix.data[1][1] = cos(angle)
-            matrix.data[2][2] = 1
+            return Matrix([[ cos_a, -sin_a,     0.,     0.],
+                           [ sin_a,  cos_a,     0.,     0.],
+                           [    0.,     0.,     1.,     0.],
+                           [    0.,     0.,     0.,     1.]])
         else:
             raise Exception
-        return matrix
+