changeset 16:66ce9bb440ac

Refactor in order to support multiple textures
author Thibaut Girka <thib@sitedethib.com>
date Sat, 06 Aug 2011 12:36:25 +0200
parents 07fba4e1da65
children d940d004b840
files pytouhou/formats/anm0.py pytouhou/game/background.py pytouhou/opengl/texture.py stageviewer.py
diffstat 4 files changed, 99 insertions(+), 81 deletions(-) [+]
line wrap: on
line diff
--- a/pytouhou/formats/anm0.py
+++ b/pytouhou/formats/anm0.py
@@ -62,5 +62,5 @@ class Animations(object):
                 anm.scripts[i].append((time, instr_type, data))
         #TODO
 
+        return anm
 
-        return anm
--- a/pytouhou/game/background.py
+++ b/pytouhou/game/background.py
@@ -13,9 +13,7 @@ class Background(object):
         self.anim = anim
         self.objects = []
         self.object_instances = []
-        self._uvs = b''
-        self._vertices = b''
-        self.nb_vertices = 0
+        self.objects_by_texture = {}
 
         self.build_objects()
         self.build_object_instances()
@@ -59,13 +57,14 @@ class Background(object):
 
 
     def update(self, frame):
-        if not self._uvs or not self._vertices:
+        if not self.objects_by_texture:
             vertices, uvs = self.object_instances_to_vertices_uvs()
-            self.nb_vertices = len(vertices)
-            vertices_format = 'f' * (3 * self.nb_vertices)
-            uvs_format = 'f' * (2 * self.nb_vertices)
-            self._vertices = struct.pack(vertices_format, *chain(*vertices))
-            self._uvs = struct.pack(uvs_format, *chain(*uvs))
+            nb_vertices = len(vertices)
+            vertices_format = 'f' * (3 * nb_vertices)
+            uvs_format = 'f' * (2 * nb_vertices)
+            vertices = struct.pack(vertices_format, *chain(*vertices))
+            uvs = struct.pack(uvs_format, *chain(*uvs))
+            self.objects_by_texture = {(self.anim.first_name, self.anim.secondary_name): (nb_vertices, vertices, uvs)}
 
             self.position_interpolator = Interpolator((0, 0, 0))
             self.fog_interpolator = Interpolator((0, 0, 0, 0, 0))
--- a/pytouhou/opengl/texture.py
+++ b/pytouhou/opengl/texture.py
@@ -8,33 +8,50 @@ from OpenGL.GL import *
 from OpenGL.GLU import *
 
 
-def load_texture(archive, anim):
-    image_file = BytesIO(archive.extract(os.path.basename(anim.first_name)))
-    textureSurface = pygame.image.load(image_file).convert_alpha()
+class TextureManager(object):
+    def __init__(self, archive):
+        self.archive = archive
+        self.textures = {}
+
+    def __getitem__(self, key):
+        if not key in self.textures:
+            self.textures[key] = self.load_texture(key)
+        return self.textures[key]
 
-    if anim.secondary_name:
-        alpha_image_file = BytesIO(archive.extract(os.path.basename(anim.secondary_name)))
-        alphaSurface = pygame.image.load(alpha_image_file)
-        assert textureSurface.get_size() == alphaSurface.get_size()
-        for x in range(alphaSurface.get_width()):
-            for y in range(alphaSurface.get_height()):
-                r, g, b, a = textureSurface.get_at((x, y))
-                color2 = alphaSurface.get_at((x, y))
-                textureSurface.set_at((x, y), (r, g, b, color2[0]))
+
+    def set_archive(self, archive):
+        self.archive = archive
+
+
+    def load_texture(self, key):
+        first_name, secondary_name = key
+
+        image_file = BytesIO(self.archive.extract(os.path.basename(first_name)))
+        textureSurface = pygame.image.load(image_file).convert_alpha()
 
-    textureData = pygame.image.tostring(textureSurface, 'RGBA', 1)
+        if secondary_name:
+            alpha_image_file = BytesIO(self.archive.extract(os.path.basename(secondary_name)))
+            alphaSurface = pygame.image.load(alpha_image_file)
+            assert textureSurface.get_size() == alphaSurface.get_size()
+            for x in range(alphaSurface.get_width()):
+                for y in range(alphaSurface.get_height()):
+                    r, g, b, a = textureSurface.get_at((x, y))
+                    color2 = alphaSurface.get_at((x, y))
+                    textureSurface.set_at((x, y), (r, g, b, color2[0]))
 
-    width = textureSurface.get_width()
-    height = textureSurface.get_height()
-
-    texture = glGenTextures(1)
-    glBindTexture(GL_TEXTURE_2D, texture)
+        textureData = pygame.image.tostring(textureSurface, 'RGBA', 1)
 
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
-        GL_UNSIGNED_BYTE, textureData)
+        width = textureSurface.get_width()
+        height = textureSurface.get_height()
+
+        texture = glGenTextures(1)
+        glBindTexture(GL_TEXTURE_2D, texture)
 
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
-    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
+            GL_UNSIGNED_BYTE, textureData)
 
-    return texture, width, height
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
 
+        return texture
+
--- a/stageviewer.py
+++ b/stageviewer.py
@@ -14,7 +14,7 @@ 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
+from pytouhou.opengl.texture import TextureManager
 
 import OpenGL
 OpenGL.FORWARD_COMPATIBLE_ONLY = True
@@ -45,67 +45,69 @@ def main(path, stage_num):
     # Load data
     with open(path, 'rb') as file:
         archive = PBG3.read(file)
+        texture_manager = TextureManager(archive)
+
         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)
+        print(background.stage.name)
 
-    frame = 0
+        frame = 0
 
-    # Main loop
-    clock = pygame.time.Clock()
-    while True:
-        # Check events
-        for event in pygame.event.get():
-            if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key in (pygame.K_ESCAPE, pygame.K_q)):
-                sys.exit(0)
-            elif event.type == pygame.KEYDOWN:
-                if event.key == pygame.K_RETURN and event.mod & pygame.KMOD_ALT:
-                    pygame.display.toggle_fullscreen()
+        # Main loop
+        clock = pygame.time.Clock()
+        while True:
+            # Check events
+            for event in pygame.event.get():
+                if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key in (pygame.K_ESCAPE, pygame.K_q)):
+                    sys.exit(0)
+                elif event.type == pygame.KEYDOWN:
+                    if event.key == pygame.K_RETURN and event.mod & pygame.KMOD_ALT:
+                        pygame.display.toggle_fullscreen()
 
-        # Update game
-        background.update(frame)
+            # Update game
+            background.update(frame)
 
-        # Draw everything
-        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
+            # Draw everything
+            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
 
-        glVertexPointer(3, GL_FLOAT, 0, background._vertices)
-        glTexCoordPointer(2, GL_FLOAT, 0, background._uvs)
+            fog_b, fog_g, fog_r, _, fog_start, fog_end = background.fog_interpolator.values
+            x, y, z = background.position_interpolator.values
+            unknownx, dy, dz = background.position2_interpolator.values
 
-        fog_b, fog_g, fog_r, _, fog_start, fog_end = background.fog_interpolator.values
-        x, y, z = background.position_interpolator.values
-        unknownx, dy, dz = background.position2_interpolator.values
-
-        glFogi(GL_FOG_MODE, GL_LINEAR)
-        glFogf(GL_FOG_START, fog_start)
-        glFogf(GL_FOG_END,  fog_end)
-        glFogfv(GL_FOG_COLOR, (fog_r / 255., fog_g / 255., fog_b / 255., 1.))
+            glFogi(GL_FOG_MODE, GL_LINEAR)
+            glFogf(GL_FOG_START, fog_start)
+            glFogf(GL_FOG_END,  fog_end)
+            glFogfv(GL_FOG_COLOR, (fog_r / 255., fog_g / 255., fog_b / 255., 1.))
 
-        #TODO
-        glMatrixMode(GL_MODELVIEW)
-        glLoadIdentity()
-        # Some explanations on the magic constants:
-        # 192. = 384. / 2. = width / 2.
-        # 224. = 448. / 2. = height / 2.
-        # 835.979370 = 224./math.tan(math.radians(15)) = (height/2.)/math.tan(math.radians(fov/2))
-        # This is so that objects on the (O, x, y) plane use pixel coordinates
-        gluLookAt(192., 224., - 835.979370 * dz,
-                  192., 224. - dy, 750 - 835.979370 * dz, 0., -1., 0.) #TODO: 750 might not be accurate
-        #print(glGetFloat(GL_MODELVIEW_MATRIX))
-        glTranslatef(-x, -y, -z)
+            #TODO
+            glMatrixMode(GL_MODELVIEW)
+            glLoadIdentity()
+            # Some explanations on the magic constants:
+            # 192. = 384. / 2. = width / 2.
+            # 224. = 448. / 2. = height / 2.
+            # 835.979370 = 224./math.tan(math.radians(15)) = (height/2.)/math.tan(math.radians(fov/2))
+            # This is so that objects on the (O, x, y) plane use pixel coordinates
+            gluLookAt(192., 224., - 835.979370 * dz,
+                      192., 224. - dy, 750 - 835.979370 * dz, 0., -1., 0.) #TODO: 750 might not be accurate
+            #print(glGetFloat(GL_MODELVIEW_MATRIX))
+            glTranslatef(-x, -y, -z)
 
-        glDrawArrays(GL_QUADS, 0, background.nb_vertices)
+            for texture_key, (nb_vertices, vertices, uvs) in background.objects_by_texture.items():
+                glBindTexture(GL_TEXTURE_2D, texture_manager[texture_key])
+                glVertexPointer(3, GL_FLOAT, 0, vertices)
+                glTexCoordPointer(2, GL_FLOAT, 0, uvs)
+                glDrawArrays(GL_QUADS, 0, nb_vertices)
 
-        #TODO: show the game itself
-        # It is displayed on (0, 0, 0), (0, 448, 0), (388, 448, 0), (388, 0, 0)
-        # using a camera at (192, 224, -835.979370) looking right behind itself
-        # Depth test should be disabled when rendering the game
+            #TODO: show the game itself
+            # It is displayed on (0, 0, 0), (0, 448, 0), (388, 448, 0), (388, 0, 0)
+            # using a camera at (192, 224, -835.979370) looking right behind itself
+            # Depth test should be disabled when rendering the game
 
-        pygame.display.flip()
-        clock.tick(120)
-        frame += 1
+            pygame.display.flip()
+            clock.tick(120)
+            frame += 1