# HG changeset patch # User Thibaut Girka # Date 1312626985 -7200 # Node ID 66ce9bb440acf81fbcd1173c4f89a6b3cbd93246 # Parent 07fba4e1da65406d56bc97107fce626afc26791f Refactor in order to support multiple textures diff --git a/pytouhou/formats/anm0.py b/pytouhou/formats/anm0.py --- 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 diff --git a/pytouhou/game/background.py b/pytouhou/game/background.py --- 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)) diff --git a/pytouhou/opengl/texture.py b/pytouhou/opengl/texture.py --- 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 + diff --git a/stageviewer.py b/stageviewer.py --- 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