changeset 523:6e3b3d5d4691

Make matrix a struct.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Wed, 18 Dec 2013 17:53:29 +0100
parents e8496e5ba056
children 7f016dfbdfb1
files pytouhou/ui/opengl/gamerenderer.pxd pytouhou/ui/opengl/gamerenderer.pyx pytouhou/ui/opengl/shader.pxd pytouhou/ui/opengl/shader.pyx pytouhou/ui/opengl/sprite.pyx pytouhou/utils/maths.pxd pytouhou/utils/maths.pyx pytouhou/utils/matrix.pxd pytouhou/utils/matrix.pyx
diffstat 9 files changed, 177 insertions(+), 149 deletions(-) [+]
line wrap: on
line diff
--- a/pytouhou/ui/opengl/gamerenderer.pxd
+++ b/pytouhou/ui/opengl/gamerenderer.pxd
@@ -5,7 +5,7 @@ from .renderer cimport Renderer, Framebu
 from .shader cimport Shader
 
 cdef class GameRenderer(Renderer):
-    cdef Matrix game_mvp, interface_mvp, proj
+    cdef Matrix *game_mvp, *interface_mvp, *proj
     cdef Shader game_shader, background_shader, interface_shader, passthrough_shader
     cdef Framebuffer framebuffer
     cdef BackgroundRenderer background_renderer
--- a/pytouhou/ui/opengl/gamerenderer.pyx
+++ b/pytouhou/ui/opengl/gamerenderer.pyx
@@ -12,6 +12,7 @@
 ## GNU General Public License for more details.
 ##
 
+from libc.stdlib cimport free
 from itertools import chain
 
 from pytouhou.lib.opengl cimport \
@@ -21,6 +22,7 @@ from pytouhou.lib.opengl cimport \
           GL_FOG_COLOR, GL_COLOR_BUFFER_BIT, GLfloat, glViewport, glScissor,
           GL_SCISSOR_TEST, GL_DEPTH_BUFFER_BIT)
 
+from pytouhou.utils.matrix cimport mul, new_identity
 from pytouhou.utils.maths cimport perspective, setup_camera, ortho_2d
 from pytouhou.game.text cimport NativeText, GlyphCollection
 from .shaders.eosd import GameShader, BackgroundShader, PassthroughShader
@@ -46,6 +48,15 @@ cdef class GameRenderer(Renderer):
             self.framebuffer = Framebuffer(0, 0, 640, 480)
 
 
+    def __dealloc__(self):
+        if self.game_mvp != NULL:
+            free(self.game_mvp)
+        if self.interface_mvp != NULL:
+            free(self.interface_mvp)
+        if self.proj != NULL:
+            free(self.proj)
+
+
     property size:
         # We never need to get back the computed size, so size is write-only.
         def __set__(self, tuple size):
@@ -68,8 +79,8 @@ cdef class GameRenderer(Renderer):
     def start(self, common):
         self.proj = perspective(30, float(common.width) / float(common.height),
                                 101010101./2010101., 101010101./10101.)
-        game_view = setup_camera(0, 0, 1)
-        self.game_mvp = game_view * self.proj
+        self.game_mvp = setup_camera(0, 0, 1)
+        mul(self.game_mvp, self.proj)
         self.interface_mvp = ortho_2d(0., float(common.interface.width),
                                       float(common.interface.height), 0.)
 
@@ -92,7 +103,7 @@ cdef class GameRenderer(Renderer):
         cdef long game_x, game_y
         cdef float x, y, z, dx, dy, dz, fog_data[4], fog_start, fog_end
         cdef unsigned char fog_r, fog_g, fog_b
-        cdef Matrix mvp
+        cdef Matrix *mvp
 
         game_x, game_y = game.interface.game_pos
         glViewport(game_x, game_y, game.width, game.height)
@@ -107,7 +118,7 @@ cdef class GameRenderer(Renderer):
         if game is not None and game.spellcard_effect is not None:
             if self.use_fixed_pipeline:
                 glMatrixMode(GL_MODELVIEW)
-                glLoadMatrixf(self.game_mvp.data)
+                glLoadMatrixf(<GLfloat*>self.game_mvp)
                 glDisable(GL_FOG)
             else:
                 self.game_shader.bind()
@@ -129,16 +140,19 @@ cdef class GameRenderer(Renderer):
             fog_start -= 101010101./2010101.
             fog_end -= 101010101./2010101.
 
-            model = Matrix()
-            model.data[12] = -x
-            model.data[13] = -y
-            model.data[14] = -z
+            mvp = new_identity()
+            mvp_data = <GLfloat*>mvp
+            mvp_data[12] = -x
+            mvp_data[13] = -y
+            mvp_data[14] = -z
             view = setup_camera(dx, dy, dz)
-            mvp = model * view * self.proj
+            mul(mvp, view)
+            free(view)
+            mul(mvp, self.proj)
 
             if self.use_fixed_pipeline:
                 glMatrixMode(GL_MODELVIEW)
-                glLoadMatrixf(mvp.data)
+                glLoadMatrixf(mvp_data)
 
                 glEnable(GL_FOG)
                 glFogi(GL_FOG_MODE, GL_LINEAR)
@@ -158,6 +172,7 @@ cdef class GameRenderer(Renderer):
                 self.background_shader.uniform_1('fog_end', fog_end)
                 self.background_shader.uniform_4('fog_color', fog_r / 255., fog_g / 255., fog_b / 255., 1.)
 
+            free(mvp)
             self.background_renderer.render_background()
         else:
             glClear(GL_COLOR_BUFFER_BIT)
@@ -165,7 +180,7 @@ cdef class GameRenderer(Renderer):
         if game is not None:
             if self.use_fixed_pipeline:
                 glMatrixMode(GL_MODELVIEW)
-                glLoadMatrixf(self.game_mvp.data)
+                glLoadMatrixf(<GLfloat*>self.game_mvp)
                 glDisable(GL_FOG)
             else:
                 self.game_shader.bind()
@@ -220,7 +235,7 @@ cdef class GameRenderer(Renderer):
 
         if self.use_fixed_pipeline:
             glMatrixMode(GL_MODELVIEW)
-            glLoadMatrixf(self.interface_mvp.data)
+            glLoadMatrixf(<GLfloat*>self.interface_mvp)
             glDisable(GL_FOG)
         else:
             self.interface_shader.bind()
--- a/pytouhou/ui/opengl/shader.pxd
+++ b/pytouhou/ui/opengl/shader.pxd
@@ -12,4 +12,4 @@ cdef class Shader:
     cdef void bind(self) nogil
     cdef void uniform_1(self, name, GLfloat val) except *
     cdef void uniform_4(self, name, GLfloat a, GLfloat b, GLfloat c, GLfloat d) except *
-    cdef void uniform_matrix(self, name, Matrix mat) except *
+    cdef void uniform_matrix(self, name, Matrix *mat) except *
--- a/pytouhou/ui/opengl/shader.pyx
+++ b/pytouhou/ui/opengl/shader.pyx
@@ -135,8 +135,8 @@ cdef class Shader:
     # upload a uniform matrix
     # works with matrices stored as lists,
     # as well as euclid matrices
-    cdef void uniform_matrix(self, name, Matrix mat):
+    cdef void uniform_matrix(self, name, Matrix *mat):
         # obtain the uniform location
         loc = self.get_uniform_location(name)
         # uplaod the 4x4 floating point matrix
-        glUniformMatrix4fv(loc, 1, False, mat.data)
+        glUniformMatrix4fv(loc, 1, False, <GLfloat*>mat)
--- a/pytouhou/ui/opengl/sprite.pyx
+++ b/pytouhou/ui/opengl/sprite.pyx
@@ -15,29 +15,30 @@
 
 from libc.math cimport M_PI as pi
 
-from pytouhou.utils.matrix cimport Matrix
+from pytouhou.utils.matrix cimport Matrix, scale2d, flip, rotate_x, rotate_y, rotate_z, translate, translate2d
 from .renderer cimport Texture #XXX
 
 
 cpdef tuple get_sprite_rendering_data(Sprite sprite):
     cdef double tx, ty, tw, th, sx, sy, rx, ry, rz, tox, toy
+    cdef Matrix vertmat
 
     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
     width = sprite.width_override or (tw * sx)
     height = sprite.height_override or (th * sy)
 
-    vertmat.scale2d(width, height)
+    scale2d(&vertmat, width, height)
     if sprite.mirrored:
-        vertmat.flip()
+        flip(&vertmat)
 
     rx, ry, rz = sprite.rotations_3d
     if sprite.automatic_orientation:
@@ -46,15 +47,15 @@ cpdef tuple get_sprite_rendering_data(Sp
         rz += sprite.angle
 
     if rx:
-        vertmat.rotate_x(-rx)
+        rotate_x(&vertmat, -rx)
     if ry:
-        vertmat.rotate_y(ry)
+        rotate_y(&vertmat, ry)
     if rz:
-        vertmat.rotate_z(-rz) #TODO: minus, really?
+        rotate_z(&vertmat, -rz) #TODO: minus, really?
     if sprite.allow_dest_offset:
-        vertmat.translate(sprite.dest_offset[0], sprite.dest_offset[1], sprite.dest_offset[2])
+        translate(&vertmat, sprite.dest_offset[0], sprite.dest_offset[1], sprite.dest_offset[2])
     if sprite.corner_relative_placement: # Reposition
-        vertmat.translate(width / 2, height / 2, 0)
+        translate2d(&vertmat, width / 2, height / 2)
 
     size = sprite.anm.size
     x_1 = 1 / <double>size[0]
@@ -67,7 +68,7 @@ cpdef tuple get_sprite_rendering_data(Sp
 
     key = ((<Texture>sprite.anm.texture).key << 1) | sprite.blendfunc
     r, g, b = sprite.color
-    values = tuple([x for x in vertmat.data[:12]]), uvs, (r, g, b, sprite.alpha)
+    values = tuple([x for x in (<float*>&vertmat)[:12]]), uvs, (r, g, b, sprite.alpha)
     sprite._rendering_data = key, values
     sprite.changed = False
 
--- a/pytouhou/utils/maths.pxd
+++ b/pytouhou/utils/maths.pxd
@@ -1,5 +1,5 @@
 from .matrix cimport Matrix
 
-cdef Matrix ortho_2d(float left, float right, float bottom, float top)
-cdef Matrix perspective(float fovy, float aspect, float zNear, float zFar)
-cdef Matrix setup_camera(float dx, float dy, float dz)
+cdef Matrix *ortho_2d(float left, float right, float bottom, float top)
+cdef Matrix *perspective(float fovy, float aspect, float zNear, float zFar)
+cdef Matrix *setup_camera(float dx, float dy, float dz)
--- a/pytouhou/utils/maths.pyx
+++ b/pytouhou/utils/maths.pyx
@@ -14,6 +14,7 @@
 
 from libc.math cimport tan, M_PI as pi
 
+from .matrix cimport new_matrix, new_identity
 from .vector cimport Vector, normalize, cross, dot
 
 
@@ -21,11 +22,9 @@ cdef double radians(double degrees) nogi
     return degrees * pi / 180
 
 
-cdef Matrix ortho_2d(float left, float right, float bottom, float top):
-    cdef float *data
-
-    mat = Matrix()
-    data = mat.data
+cdef Matrix *ortho_2d(float left, float right, float bottom, float top):
+    mat = new_identity()
+    data = <float*>mat
     data[4*0+0] = 2 / (right - left)
     data[4*1+1] = 2 / (top - bottom)
     data[4*2+2] = -1
@@ -34,28 +33,30 @@ cdef Matrix ortho_2d(float left, float r
     return mat
 
 
-cdef Matrix look_at(Vector eye, Vector center, Vector up):
+cdef Matrix *look_at(Vector eye, Vector center, Vector up):
+    cdef Matrix mat
+
     f = normalize(center.sub(eye))
     u = normalize(up)
     s = normalize(cross(f, u))
     u = cross(s, f)
 
-    return Matrix([s.x, u.x, -f.x, 0,
-                   s.y, u.y, -f.y, 0,
-                   s.z, u.z, -f.z, 0,
-                   -dot(s, eye), -dot(u, eye), dot(f, eye), 1])
+    mat = Matrix(s.x, u.x, -f.x, 0,
+                 s.y, u.y, -f.y, 0,
+                 s.z, u.z, -f.z, 0,
+                 -dot(s, eye), -dot(u, eye), dot(f, eye), 1)
+
+    return new_matrix(&mat)
 
 
-cdef Matrix perspective(float fovy, float aspect, float z_near, float z_far):
-    cdef float *data
-
+cdef Matrix *perspective(float fovy, float aspect, float z_near, float z_far):
     top = tan(radians(fovy / 2)) * z_near
     bottom = -top
     left = -top * aspect
     right = top * aspect
 
-    mat = Matrix()
-    data = mat.data
+    mat = new_identity()
+    data = <float*>mat
     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)
@@ -65,7 +66,7 @@ cdef Matrix perspective(float fovy, floa
     return mat
 
 
-cdef Matrix setup_camera(float dx, float dy, float dz):
+cdef Matrix *setup_camera(float dx, float dy, float dz):
     # Some explanations on the magic constants:
     # 192. = 384. / 2. = width / 2.
     # 224. = 448. / 2. = height / 2.
--- a/pytouhou/utils/matrix.pxd
+++ b/pytouhou/utils/matrix.pxd
@@ -1,10 +1,18 @@
-cdef class Matrix:
-    cdef float data[16]
+ctypedef struct Matrix:
+    float a, b, c, d
+    float e, f, g, h
+    float i, j, k, l
+    float m, n, o, p
+
+cdef Matrix *new_matrix(Matrix *data) nogil
+cdef Matrix *new_identity() nogil
 
-    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
+cdef void mul(Matrix *mat1, Matrix *mat2) nogil
+cdef void flip(Matrix *mat) nogil
+cdef void scale(Matrix *mat, float x, float y, float z) nogil
+cdef void scale2d(Matrix *mat, float x, float y) nogil
+cdef void translate(Matrix *mat, float x, float y, float z) nogil
+cdef void translate2d(Matrix *mat, float x, float y) nogil
+cdef void rotate_x(Matrix *mat, float angle) nogil
+cdef void rotate_y(Matrix *mat, float angle) nogil
+cdef void rotate_z(Matrix *mat, float angle) nogil
--- a/pytouhou/utils/matrix.pyx
+++ b/pytouhou/utils/matrix.pyx
@@ -17,120 +17,123 @@ from libc.stdlib cimport malloc, free
 from libc.string cimport memcpy
 
 
-cdef float[16] identity
-identity[:] = [1, 0, 0, 0,
-               0, 1, 0, 0,
-               0, 0, 1, 0,
-               0, 0, 0, 1]
+cdef Matrix identity
+identity = Matrix(1, 0, 0, 0,
+                  0, 1, 0, 0,
+                  0, 0, 1, 0,
+                  0, 0, 0, 1)
 
 
-cdef class Matrix:
-    def __init__(self, data=None):
-        if data is not None:
-            for i in xrange(16):
-                self.data[i] = data[i]
-        else:
-            memcpy(self.data, identity, 16 * sizeof(float))
+cdef Matrix *new_matrix(Matrix *data) nogil:
+    mat = <Matrix*> malloc(sizeof(Matrix))
+    memcpy(mat, data, sizeof(Matrix))
+    return mat
+
+
+cdef Matrix *new_identity() nogil:
+    return new_matrix(&identity)
 
 
-    def __mul__(Matrix self, Matrix other):
-        cdef float *d1, *d2, *d3
+cdef void mul(Matrix *mat1, Matrix *mat2) nogil:
+    cdef float *d3
 
-        out = Matrix()
-        d1 = self.data
-        d2 = other.data
-        d3 = out.data
-        for i in xrange(4):
-            for j 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
+    out = <Matrix*> malloc(sizeof(Matrix))
+    d1 = <float*>mat1
+    d2 = <float*>mat2
+    d3 = <float*>out
+    for i in xrange(4):
+        for j 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]
+    memcpy(mat1, out, sizeof(Matrix))
+    free(out)
 
 
-    cdef void flip(self) nogil:
-        cdef float *data
-
-        data = self.data
-        for i in xrange(4):
-            data[i] = -data[i]
+cdef void flip(Matrix *mat) nogil:
+    data = <float*>mat
+    for i in xrange(4):
+        data[i] = -data[i]
 
 
-    cdef void scale(self, float x, float y, float z) nogil:
-        cdef float *data, coordinate[3]
+cdef void scale(Matrix *mat, float x, float y, float z) nogil:
+    cdef float coordinate[3]
+
+    data = <float*>mat
+    coordinate[0] = x
+    coordinate[1] = y
+    coordinate[2] = z
 
-        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]
+
 
-        for i in xrange(3):
-            for j in xrange(4):
-                data[4*i+j] *= coordinate[i]
+cdef void scale2d(Matrix *mat, float x, float y) nogil:
+    data = <float*>mat
+    for i in xrange(4):
+        data[  i] *= x
+        data[4+i] *= y
 
 
-    cdef void scale2d(self, float x, float y) nogil:
-        cdef float *data
+cdef void translate(Matrix *mat, float x, float y, float z) nogil:
+    cdef float offset[3], item[3]
+
+    offset[0] = x
+    offset[1] = y
+    offset[2] = z
 
-        data = self.data
-        for i in xrange(4):
-            data[  i] *= x
-            data[4+i] *= y
+    data = <float*>mat
+    for i in xrange(3):
+        item[i] = data[12+i] * offset[i]
+
+    for i in xrange(3):
+        for j in xrange(4):
+            data[4*i+j] += item[i]
 
 
-    cdef void translate(self, float x, float y, float z) nogil:
-        cdef float *data, coordinate[3], item[3]
-
-        data = self.data
-        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]
+cdef void translate2d(Matrix *mat, float x, float y) nogil:
+    translate(mat, x, y, 0)
 
 
-    cdef void rotate_x(self, float angle) nogil:
-        cdef float cos_a, sin_a
-        cdef float lines[8], *data
+cdef void rotate_x(Matrix *mat, float angle) nogil:
+    cdef float cos_a, sin_a
+    cdef float lines[8]
 
-        data = self.data
-        cos_a = cos(angle)
-        sin_a = sin(angle)
-        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]
+    data = <float*>mat
+    cos_a = cos(angle)
+    sin_a = sin(angle)
+    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]
 
 
-    cdef void rotate_y(self, float angle) nogil:
-        cdef float cos_a, sin_a
-        cdef float lines[8], *data
+cdef void rotate_y(Matrix *mat, float angle) nogil:
+    cdef float cos_a, sin_a
+    cdef float lines[8]
 
-        data = self.data
-        cos_a = cos(angle)
-        sin_a = sin(angle)
-        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]
+    data = <float*>mat
+    cos_a = cos(angle)
+    sin_a = sin(angle)
+    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]
 
 
-    cdef void rotate_z(self, float angle) nogil:
-        cdef float cos_a, sin_a
-        cdef float lines[8], *data
+cdef void rotate_z(Matrix *mat, float angle) nogil:
+    cdef float cos_a, sin_a
+    cdef float lines[8]
 
-        data = self.data
-        cos_a = cos(angle)
-        sin_a = sin(angle)
-        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]
+    data = <float*>mat
+    cos_a = cos(angle)
+    sin_a = sin(angle)
+    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]