changeset 435:878273a984c4

Improve Matrix representation, using float[16] instead of imbricated python lists.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Wed, 07 Aug 2013 11:34:40 +0200
parents 18e4b121646b
children cb5c68598ab0
files pytouhou/ui/background.pyx pytouhou/ui/gamerenderer.pyx pytouhou/ui/gamerunner.pyx pytouhou/ui/renderer.pyx pytouhou/ui/shader.pyx pytouhou/ui/sprite.pyx pytouhou/utils/maths.pyx pytouhou/utils/matrix.pxd pytouhou/utils/matrix.pyx
diffstat 9 files changed, 126 insertions(+), 103 deletions(-) [+]
line wrap: on
line diff
--- a/pytouhou/ui/background.pyx
+++ b/pytouhou/ui/background.pyx
@@ -79,7 +79,7 @@ cdef class BackgroundRenderer:
             for ox2, oy2, oz2, width_override, height_override, sprite in model:
                 #TODO: view frustum culling
                 key, (vertices, uvs, colors) = get_sprite_rendering_data(sprite)
-                (x1, y1, z1), (x2, y2, z2), (x3, y3, z3), (x4, y4, z4) = vertices
+                x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4 = vertices
                 left, right, bottom, top = uvs
                 r, g, b, a = colors
 
--- a/pytouhou/ui/gamerenderer.pyx
+++ b/pytouhou/ui/gamerenderer.pyx
@@ -12,7 +12,6 @@
 ## GNU General Public License for more details.
 ##
 
-from libc.stdlib cimport malloc, free
 from itertools import chain
 
 from pytouhou.lib.opengl cimport \
@@ -21,7 +20,7 @@ from pytouhou.lib.opengl cimport \
           GL_PROJECTION, GL_MODELVIEW, GL_FOG, GL_FOG_MODE, GL_LINEAR,
           GL_FOG_START, GL_FOG_END, GL_FOG_COLOR, GL_COLOR_BUFFER_BIT, GLfloat)
 
-from pytouhou.utils.matrix cimport Matrix, matrix_to_floats
+from pytouhou.utils.matrix cimport Matrix
 from pytouhou.utils.maths cimport setup_camera
 
 from .renderer import Renderer
@@ -34,7 +33,8 @@ class GameRenderer(Renderer):
 
 
     def render(self):
-        cdef float* fog_data
+        cdef float fog_data[4]
+        cdef Matrix view, mvp
 
         back = self.background
         game = self.game
@@ -46,7 +46,7 @@ class GameRenderer(Renderer):
         if game is not None and game.spellcard_effect is not None:
             if self.use_fixed_pipeline:
                 glMatrixMode(GL_MODELVIEW)
-                glLoadMatrixf(matrix_to_floats(self.game_mvp))
+                glLoadMatrixf((<Matrix>self.game_mvp).data)
                 glDisable(GL_FOG)
             else:
                 self.game_shader.bind()
@@ -68,26 +68,26 @@ class GameRenderer(Renderer):
             fog_end -= 101010101./2010101.
 
             model = Matrix()
-            model.data[3] = [-x, -y, -z, 1]
+            model.data[12] = -x
+            model.data[13] = -y
+            model.data[14] = -z
             view = setup_camera(dx, dy, dz)
             mvp = model * view * self.proj
 
             if self.use_fixed_pipeline:
                 glMatrixMode(GL_MODELVIEW)
-                glLoadMatrixf(matrix_to_floats(mvp))
+                glLoadMatrixf(mvp.data)
 
                 glEnable(GL_FOG)
                 glFogi(GL_FOG_MODE, GL_LINEAR)
                 glFogf(GL_FOG_START, fog_start)
                 glFogf(GL_FOG_END,  fog_end)
 
-                fog_data = <float*>malloc(4 * sizeof(float))
                 fog_data[0] = fog_r / 255.
                 fog_data[1] = fog_g / 255.
                 fog_data[2] = fog_b / 255.
                 fog_data[3] = 1.
                 glFogfv(GL_FOG_COLOR, fog_data)
-                free(fog_data)
             else:
                 self.background_shader.bind()
                 self.background_shader.uniform_matrix('mvp', mvp)
@@ -103,7 +103,7 @@ class GameRenderer(Renderer):
         if game is not None:
             if self.use_fixed_pipeline:
                 glMatrixMode(GL_MODELVIEW)
-                glLoadMatrixf(matrix_to_floats(self.game_mvp))
+                glLoadMatrixf((<Matrix>self.game_mvp).data)
                 glDisable(GL_FOG)
             else:
                 self.game_shader.bind()
--- a/pytouhou/ui/gamerunner.pyx
+++ b/pytouhou/ui/gamerunner.pyx
@@ -21,7 +21,7 @@ from pytouhou.lib.opengl cimport \
 
 from pytouhou.utils.helpers import get_logger
 from pytouhou.utils.maths cimport perspective, setup_camera, ortho_2d
-from pytouhou.utils.matrix cimport matrix_to_floats
+from pytouhou.utils.matrix cimport Matrix
 
 from .gamerenderer import GameRenderer
 from .background import BackgroundRenderer
@@ -182,7 +182,7 @@ class GameRunner(GameRenderer):
 
         if self.use_fixed_pipeline:
             glMatrixMode(GL_MODELVIEW)
-            glLoadMatrixf(matrix_to_floats(self.interface_mvp))
+            glLoadMatrixf((<Matrix>self.interface_mvp).data)
             glDisable(GL_FOG)
         else:
             self.interface_shader.bind()
--- a/pytouhou/ui/renderer.pyx
+++ b/pytouhou/ui/renderer.pyx
@@ -67,7 +67,7 @@ cdef class Renderer:
                 rec = indices_by_texture.setdefault(key, [])
 
                 # Pack data in buffer
-                (x1, y1, z1), (x2, y2, z2), (x3, y3, z3), (x4, y4, z4) = vertices
+                x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4 = vertices
                 left, right, bottom, top = uvs
                 r, g, b, a = colors
                 self.vertex_buffer[nb_vertices] = Vertex(x1 + ox, y1 + oy, z1, left, bottom, r, g, b, a)
--- a/pytouhou/ui/shader.pyx
+++ b/pytouhou/ui/shader.pyx
@@ -19,7 +19,7 @@ from pytouhou.lib.opengl cimport \
           GLuint, GLchar, GLfloat, GLenum)
 
 from libc.stdlib cimport malloc, free
-from pytouhou.utils.matrix cimport Matrix, matrix_to_floats
+from pytouhou.utils.matrix cimport Matrix
 
 
 class GLSLException(Exception):
@@ -145,4 +145,4 @@ cdef class Shader:
         # obtain the uniform location
         loc = self.get_uniform_location(name)
         # uplaod the 4x4 floating point matrix
-        glUniformMatrix4fv(loc, 1, False, matrix_to_floats(mat))
+        glUniformMatrix4fv(loc, 1, False, mat.data)
--- a/pytouhou/ui/sprite.pyx
+++ b/pytouhou/ui/sprite.pyx
@@ -24,10 +24,10 @@ cpdef object get_sprite_rendering_data(o
     if not sprite.changed:
         return sprite._rendering_data
 
-    vertmat = Matrix([[-.5,     .5,     .5,    -.5],
-                      [-.5,    -.5,     .5,     .5],
-                      [ .0,     .0,     .0,     .0],
-                      [ 1.,     1.,     1.,     1.]])
+    vertmat = Matrix([-.5,  .5,  .5, -.5,
+                      -.5, -.5,  .5,  .5,
+                       .0,  .0,  .0,  .0,
+                       1.,  1.,  1.,  1.])
 
     tx, ty, tw, th = sprite.texcoords
     sx, sy = sprite.rescale
@@ -64,11 +64,9 @@ cpdef object get_sprite_rendering_data(o
            ty * y_1 + toy,
            (ty + th) * y_1 + toy)
 
-    (x1, x2 , x3, x4), (y1, y2, y3, y4), (z1, z2, z3, z4), _ = vertmat.data
-
     key = sprite.anm.texture, sprite.blendfunc
     r, g, b = sprite.color
-    values = ((x1, y1, z1), (x2, y2, z2), (x3, y3, z3), (x4, y4, z4)), uvs, (r, g, b, sprite.alpha)
+    values = tuple([x for x in vertmat.data[:12]]), uvs, (r, g, b, sprite.alpha)
     sprite._rendering_data = key, values
     sprite.changed = False
 
--- a/pytouhou/utils/maths.pyx
+++ b/pytouhou/utils/maths.pyx
@@ -20,13 +20,15 @@ from .vector import Vector, normalize, c
 
 
 cpdef ortho_2d(left, right, bottom, top):
+    cdef float *data
+
     mat = Matrix()
     data = mat.data
-    data[0][0] = 2 / (right - left)
-    data[1][1] = 2 / (top - bottom)
-    data[2][2] = -1
-    data[3][0] = -(right + left) / (right - left)
-    data[3][1] = -(top + bottom) / (top - bottom)
+    data[4*0+0] = 2 / (right - left)
+    data[4*1+1] = 2 / (top - bottom)
+    data[4*2+2] = -1
+    data[4*3+0] = -(right + left) / (right - left)
+    data[4*3+1] = -(top + bottom) / (top - bottom)
     return mat
 
 
@@ -40,13 +42,15 @@ cpdef look_at(eye, center, up):
     s = normalize(cross(f, u))
     u = cross(s, f)
 
-    return Matrix([[s[0], u[0], -f[0], 0],
-                   [s[1], u[1], -f[1], 0],
-                   [s[2], u[2], -f[2], 0],
-                   [-dot(s, eye), -dot(u, eye), dot(f, eye), 1]])
+    return Matrix([s[0], u[0], -f[0], 0,
+                   s[1], u[1], -f[1], 0,
+                   s[2], u[2], -f[2], 0,
+                   -dot(s, eye), -dot(u, eye), dot(f, eye), 1])
 
 
 cpdef perspective(fovy, aspect, z_near, z_far):
+    cdef float *data
+
     top = tan(radians(fovy / 2)) * z_near
     bottom = -top
     left = -top * aspect
@@ -54,12 +58,12 @@ cpdef perspective(fovy, aspect, z_near, 
 
     mat = Matrix()
     data = mat.data
-    data[0][0] = (2 * z_near) / (right - left)
-    data[1][1] = (2 * z_near) / (top - bottom)
-    data[2][2] = -(z_far + z_near) / (z_far - z_near)
-    data[2][3] = -1
-    data[3][2] = -(2 * z_far * z_near) / (z_far - z_near)
-    data[3][3] = 0
+    data[4*0+0] = (2 * z_near) / (right - left)
+    data[4*1+1] = (2 * z_near) / (top - bottom)
+    data[4*2+2] = -(z_far + z_near) / (z_far - z_near)
+    data[4*2+3] = -1
+    data[4*3+2] = -(2 * z_far * z_near) / (z_far - z_near)
+    data[4*3+3] = 0
     return mat
 
 
--- a/pytouhou/utils/matrix.pxd
+++ b/pytouhou/utils/matrix.pxd
@@ -1,13 +1,10 @@
-cdef float* matrix_to_floats(Matrix self)
-
 cdef class Matrix:
-    cdef public list data
-    cdef float *c_data
+    cdef float data[16]
 
-    cpdef flip(self)
-    cpdef scale(self, x, y, z)
-    cpdef scale2d(self, x, y)
-    cpdef translate(self, x, y, z)
-    cpdef rotate_x(self, angle)
-    cpdef rotate_y(self, angle)
-    cpdef rotate_z(self, angle)
+    cdef void flip(self) nogil
+    cdef void scale(self, float x, float y, float z) nogil
+    cdef void scale2d(self, float x, float y) nogil
+    cdef void translate(self, float x, float y, float z) nogil
+    cdef void rotate_x(self, float angle) nogil
+    cdef void rotate_y(self, float angle) nogil
+    cdef void rotate_z(self, float angle) nogil
--- a/pytouhou/utils/matrix.pyx
+++ b/pytouhou/utils/matrix.pyx
@@ -16,92 +16,116 @@ from libc.math cimport sin, cos
 from libc.stdlib cimport malloc, free
 
 
-cdef float* matrix_to_floats(Matrix self):
-    for i in xrange(4):
-        for j in xrange(4):
-            self.c_data[i*4+j] = self.data[i][j]
-    return self.c_data
-
-
 cdef class Matrix:
-    def __cinit__(self):
-        self.c_data = <float*>malloc(16 * sizeof(float))
+    def __init__(self, data=None):
+        if data is None:
+            data = [1, 0, 0, 0,
+                    0, 1, 0, 0,
+                    0, 0, 1, 0,
+                    0, 0, 0, 1]
+        for i in xrange(4):
+            for j in xrange(4):
+                self.data[i*4+j] = data[4*i+j]
 
 
-    def __init__(self, data=None):
-        self.data = data or [[1, 0, 0, 0],
-                             [0, 1, 0, 0],
-                             [0, 0, 1, 0],
-                             [0, 0, 0, 1]]
+    def __mul__(Matrix self, Matrix other):
+        cdef float *d1, *d2, *d3
 
-
-    def __dealloc__(self):
-        free(self.c_data)
-
-
-    def __mul__(self, Matrix other):
         out = Matrix()
         d1 = self.data
         d2 = other.data
         d3 = out.data
         for i in xrange(4):
             for j in xrange(4):
-                d3[i][j] = sum(d1[i][k] * d2[k][j] for k in xrange(4))
+                d3[4*i+j] = 0
+                for k in xrange(4):
+                    d3[4*i+j] += d1[4*i+k] * d2[4*k+j]
         return out
 
 
-    cpdef flip(self):
+    cdef void flip(self) nogil:
+        cdef float *data
+
         data = self.data
-        a, b, c, d = data[0]
-        data[0] = [-a, -b, -c, -d]
+        for i in xrange(4):
+            data[i] = -data[i]
 
 
-    cpdef 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]]
+    cdef void scale(self, float x, float y, float z) nogil:
+        cdef float *data, coordinate[3]
+
+        data = self.data
+        coordinate[0] = x
+        coordinate[1] = y
+        coordinate[2] = z
+
+        for i in xrange(3):
+            for j in xrange(4):
+                data[4*i+j] *= coordinate[i]
 
 
-    cpdef scale2d(self, x, y):
+    cdef void scale2d(self, float x, float y) nogil:
+        cdef float *data
+
         data = self.data
-        d1a, d1b, d1c, d1d = data[0]
-        d2a, d2b, d2c, d2d = data[1]
-        data[0] = [d1a * x, d1b * x, d1c * x, d1d * x]
-        data[1] = [d2a * y, d2b * y, d2c * y, d2d * y]
+        for i in xrange(4):
+            data[  i] *= x
+            data[4+i] *= y
 
 
-    cpdef translate(self, x, y, z):
+    cdef void translate(self, float x, float y, float z) nogil:
+        cdef float *data, coordinate[3], item[3]
+
         data = self.data
-        a, b, c = data[3][:3]
-        a, b, c = a * x, b * y, c * z
-        d1a, d1b, d1c, d1d = data[0]
-        d2a, d2b, d2c, d2d = data[1]
-        d3a, d3b, d3c, d3d = data[2]
-        data[0] = [d1a + a, d1b + a, d1c + a, d1d + a]
-        data[1] = [d2a + b, d2b + b, d2c + b, d2d + b]
-        data[2] = [d3a + c, d3b + c, d3c + c, d3d + c]
+        coordinate[0] = x
+        coordinate[1] = y
+        coordinate[2] = z
+        for i in xrange(3):
+            item[i] = data[12+i] * coordinate[i]
+
+        for i in xrange(3):
+            for j in xrange(4):
+                data[4*i+j] += item[i]
 
 
-    cpdef rotate_x(self, angle):
-        d1 = self.data
+    cdef void rotate_x(self, float angle) nogil:
+        cdef float cos_a, sin_a
+        cdef float lines[8], *data
+
+        data = self.data
         cos_a = cos(angle)
         sin_a = sin(angle)
-        d1[1], d1[2] = ([cos_a * d1[1][i] - sin_a * d1[2][i] for i in range(4)],
-                        [sin_a * d1[1][i] + cos_a * d1[2][i] for i in range(4)])
+        for i in xrange(8):
+            lines[i] = data[i+4]
+        for i in xrange(4):
+            data[4+i] = cos_a * lines[i] - sin_a * lines[4+i]
+            data[8+i] = sin_a * lines[i] + cos_a * lines[4+i]
 
 
-    cpdef rotate_y(self, angle):
-        d1 = self.data
+    cdef void rotate_y(self, float angle) nogil:
+        cdef float cos_a, sin_a
+        cdef float lines[8], *data
+
+        data = self.data
         cos_a = cos(angle)
         sin_a = sin(angle)
-        d1[0], d1[2] = ([cos_a * d1[0][i] + sin_a * d1[2][i] for i in range(4)],
-                        [- sin_a * d1[0][i] + cos_a * d1[2][i] for i in range(4)])
+        for i in xrange(4):
+            lines[i] = data[i]
+            lines[i+4] = data[i+8]
+        for i in xrange(4):
+            data[  i] =  cos_a * lines[i] + sin_a * lines[4+i]
+            data[8+i] = -sin_a * lines[i] + cos_a * lines[4+i]
 
 
-    cpdef rotate_z(self, angle):
-        d1 = self.data
+    cdef void rotate_z(self, float angle) nogil:
+        cdef float cos_a, sin_a
+        cdef float lines[8], *data
+
+        data = self.data
         cos_a = cos(angle)
         sin_a = sin(angle)
-        d1[0], d1[1] = ([cos_a * d1[0][i] - sin_a * d1[1][i] for i in range(4)],
-                        [sin_a * d1[0][i] + cos_a * d1[1][i] for i in range(4)])
+        for i in xrange(8):
+            lines[i] = data[i]
+        for i in xrange(4):
+            data[  i] = cos_a * lines[i] - sin_a * lines[4+i]
+            data[4+i] = sin_a * lines[i] + cos_a * lines[4+i]