changeset 15:07fba4e1da65

Refactor
author Thibaut Girka <thib@sitedethib.com>
date Fri, 05 Aug 2011 21:21:06 +0200
parents 07a7f28c8aaa
children 66ce9bb440ac
files pytouhou/formats/std.py pytouhou/game/background.py pytouhou/game/sprite.py pytouhou/opengl/texture.py stageviewer.py
diffstat 5 files changed, 120 insertions(+), 74 deletions(-) [+]
line wrap: on
line diff
--- a/pytouhou/formats/std.py
+++ b/pytouhou/formats/std.py
@@ -11,7 +11,8 @@ class Object(object):
 
 
 class Stage(object):
-    def __init__(self):
+    def __init__(self, num):
+        self.num = num
         self.name = ''
         self.bgms = (('', ''), ('', ''), ('', ''))
         self.objects = []
@@ -20,8 +21,8 @@ class Stage(object):
 
 
     @classmethod
-    def read(cls, file):
-        stage = Stage()
+    def read(cls, file, num):
+        stage = Stage(num)
 
         nb_objects, nb_faces = unpack('<HH', file.read(4))
         object_instances_offset, script_offset = unpack('<II', file.read(8))
--- a/pytouhou/game/background.py
+++ b/pytouhou/game/background.py
@@ -3,21 +3,20 @@ import os
 import struct
 from itertools import chain
 
-from pytouhou.utils.matrix import Matrix
 from pytouhou.utils.interpolator import Interpolator
-
-from pytouhou.formats.std import Stage
-from pytouhou.formats.anm0 import Animations
+from pytouhou.game.sprite import Sprite
 
 
 class Background(object):
-    def __init__(self, archive, stage_num):
-        self.stage = Stage.read(BytesIO(archive.extract('stage%d.std' % stage_num)))
-        self.anim = Animations.read(BytesIO(archive.extract('stg%dbg.anm' % stage_num)))
+    def __init__(self, stage, anim):
+        self.stage = stage
+        self.anim = anim
         self.objects = []
         self.object_instances = []
         self._uvs = b''
         self._vertices = b''
+        self.nb_vertices = 0
+
         self.build_objects()
         self.build_object_instances()
 
@@ -51,67 +50,10 @@ class Background(object):
         self.objects = []
         for i, obj in enumerate(self.stage.objects):
             faces = []
-            for script_index, x, y, z, width_override, height_override in obj.quads:
-                #TODO: refactor
-                vertices = []
-                uvs = []
-                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.
-
-                properties = {}
-                for time, instr_type, data in self.anim.scripts[script_index]:
-                    if instr_type == 15:
-                        properties[15] = b''
-                        break
-                    elif time == 0: #TODO
-                        properties[instr_type] = data
-                #if 15 not in properties: #TODO: Skip properties
-                #    continue
-
-                #TODO: properties 3 and 4
-                if 1 in properties:
-                    tx, ty, tw, th = self.anim.sprites[struct.unpack('<I', properties[1])[0]]
-                width, height = 1., 1.
-                if 2 in properties:
-                    width, height = struct.unpack('<ff', properties[2])
-                width = width_override or width * tw
-                height = height_override or height * th
-                transform = Matrix.get_scaling_matrix(width, height, 1.)
-                if 7 in properties:
-                    transform = Matrix.get_scaling_matrix(-1., 1., 1.).mult(transform)
-                if 9 in properties:
-                    rx, ry, rz = struct.unpack('<fff', properties[9])
-                    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 23 in properties: # Reposition
-                    transform = Matrix.get_translation_matrix(width / 2., height / 2., 0.).mult(transform)
-                vertmat = transform.mult(vertmat)
-
-                uvs = [(tx / self.anim.size[0],         1. - (ty / self.anim.size[1])),
-                       ((tx + tw) / self.anim.size[0],  1. - (ty / self.anim.size[1])),
-                       ((tx + tw) / self.anim.size[0],  1. - ((ty + th) / self.anim.size[1])),
-                       (tx / self.anim.size[0],         1. - ((ty + th) / self.anim.size[1]))]
-
-                for i in xrange(4):
-                    w = vertmat.data[3][i]
-                    vertices.append((vertmat.data[0][i] / w + x,
-                                     vertmat.data[1][i] / w + y,
-                                     vertmat.data[2][i] / w + z))
+            for script_index, ox, oy, oz, width_override, height_override in obj.quads:
+                sprite = Sprite(self.anim, script_index)
+                sprite.update(0, width_override, height_override)
+                uvs, vertices = sprite._uvs, tuple((x + ox, y + oy, z + oz) for x, y, z in sprite._vertices)
                 faces.append((vertices, uvs))
             self.objects.append(faces)
 
new file mode 100644
--- /dev/null
+++ b/pytouhou/game/sprite.py
@@ -0,0 +1,98 @@
+from struct import unpack
+
+from pytouhou.utils.matrix import Matrix
+
+class Sprite(object):
+    def __init__(self, anm, script_index):
+        self.anm = anm
+        self.script_index = script_index
+        self.texcoords = (0, 0, 0, 0) # x, y, width, height
+        self.mirrored = False
+        self.rescale = (1., 1.)
+        self.rotations_3d = (0., 0., 0.)
+        self.corner_relative_placement = False
+        self._uvs = []
+        self._vertices = []
+
+
+    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.
+
+        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.)
+        if self.mirrored:
+            transform = Matrix.get_scaling_matrix(-1., 1., 1.).mult(transform)
+        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 self.corner_relative_placement: # Reposition
+            transform = Matrix.get_translation_matrix(width / 2., height / 2., 0.).mult(transform)
+        vertmat = transform.mult(vertmat)
+
+        uvs = [(tx / self.anm.size[0],         1. - (ty / self.anm.size[1])),
+               ((tx + tw) / self.anm.size[0],  1. - (ty / self.anm.size[1])),
+               ((tx + tw) / self.anm.size[0],  1. - ((ty + th) / self.anm.size[1])),
+               (tx / self.anm.size[0],         1. - ((ty + th) / self.anm.size[1]))]
+
+        vertices = []
+        for i in xrange(4):
+            w = vertmat.data[3][i]
+            vertices.append((vertmat.data[0][i] / w,
+                             vertmat.data[1][i] / w,
+                             vertmat.data[2][i] / w))
+
+        self._uvs, self._vertices = uvs, vertices
+
+
+
+    def update(self, frame, override_width=0, override_height=0):
+        properties = {}
+        for time, instr_type, data in self.anm.scripts[self.script_index]:
+            if time == frame:
+                if instr_type == 15: #Return
+                    break
+                else:
+                    properties[instr_type] = data
+        if properties:
+            if 1 in properties:
+                self.texcoords = self.anm.sprites[unpack('<I', properties[1])[0]]
+                del properties[1]
+            if 2 in properties:
+                self.rescale = unpack('<ff', properties[2])
+                del properties[2]
+            if 7 in properties:
+                self.mirrored = True #TODO
+                del properties[7]
+            if 9 in properties:
+                self.rotations_3d = unpack('<fff', properties[9])
+                del properties[9]
+            if 23 in properties:
+                self.corner_relative_placement = True #TODO
+                del properties[23]
+            if properties:
+                print('Leftover properties: %r' % properties) #TODO
+            self.update_uvs_vertices(override_width, override_height)
+            return True
+        return False
+
--- a/pytouhou/opengl/texture.py
+++ b/pytouhou/opengl/texture.py
@@ -33,5 +33,8 @@ def load_texture(archive, anim):
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
         GL_UNSIGNED_BYTE, textureData)
 
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
+
     return texture, width, height
 
--- a/stageviewer.py
+++ b/stageviewer.py
@@ -11,6 +11,8 @@ from itertools import chain
 import pygame
 
 from pytouhou.formats.pbg3 import PBG3
+from pytouhou.formats.std import Stage
+from pytouhou.formats.anm0 import Animations
 from pytouhou.game.background import Background
 from pytouhou.opengl.texture import load_texture
 
@@ -36,8 +38,6 @@ def main(path, stage_num):
     glEnable(GL_FOG)
     glHint(GL_FOG_HINT, GL_NICEST)
     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
     glEnableClientState(GL_VERTEX_ARRAY)
     glEnableClientState(GL_TEXTURE_COORD_ARRAY)
@@ -45,7 +45,9 @@ def main(path, stage_num):
     # Load data
     with open(path, 'rb') as file:
         archive = PBG3.read(file)
-        background = Background(archive, stage_num)
+        stage = Stage.read(BytesIO(archive.extract('stage%d.std' % stage_num)), stage_num)
+        background_anim = Animations.read(BytesIO(archive.extract('stg%dbg.anm' % stage_num)))
+        background = Background(stage, background_anim)
         texture = load_texture(archive, background.anim)
 
     print(background.stage.name)