Mercurial > touhou
changeset 108:2a03940deea3
Move everything graphical to pytouhou.opengl!
author | Thibaut Girka <thib@sitedethib.com> |
---|---|
date | Tue, 06 Sep 2011 00:26:13 +0200 |
parents | 5d9052b9a4e8 |
children | e93a7ed4f203 |
files | eclviewer.py pytouhou/game/background.py pytouhou/game/bullet.py pytouhou/game/enemy.py pytouhou/game/sprite.py pytouhou/opengl/background.py pytouhou/opengl/gamerenderer.py pytouhou/opengl/sprite.py |
diffstat | 8 files changed, 302 insertions(+), 255 deletions(-) [+] |
line wrap: on
line diff
--- a/eclviewer.py +++ b/eclviewer.py @@ -16,68 +16,30 @@ import sys import os -import struct -from math import degrees, radians -from itertools import chain - import pygame from pytouhou.resource.loader import Loader from pytouhou.game.background import Background -from pytouhou.opengl.texture import TextureManager +from pytouhou.opengl.gamerenderer import GameRenderer from pytouhou.game.game import Game from pytouhou.game.player import Player -import OpenGL -OpenGL.FORWARD_COMPATIBLE_ONLY = True -from OpenGL.GL import * -from OpenGL.GLU import * - def main(path, stage_num): - # Initialize pygame - pygame.init() - window = pygame.display.set_mode((384, 448), pygame.OPENGL | pygame.DOUBLEBUF) - - # Initialize OpenGL - glMatrixMode(GL_PROJECTION) - glLoadIdentity() - gluPerspective(30, float(window.get_width())/window.get_height(), 101010101./2010101., 101010101./10101.) - - glEnable(GL_BLEND) - glEnable(GL_TEXTURE_2D) - glEnable(GL_FOG) - glHint(GL_FOG_HINT, GL_NICEST) - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) - glEnableClientState(GL_COLOR_ARRAY) - glEnableClientState(GL_VERTEX_ARRAY) - glEnableClientState(GL_TEXTURE_COORD_ARRAY) - resource_loader = Loader() - texture_manager = TextureManager(resource_loader) resource_loader.scan_archives(os.path.join(path, name) for name in ('CM.DAT', 'ST.DAT')) game = Game(resource_loader, [Player()], stage_num, 3, 16) - # Load common data - etama_anm_wrappers = (resource_loader.get_anm_wrapper(('etama3.anm',)), - resource_loader.get_anm_wrapper(('etama4.anm',))) - effects_anm_wrapper = resource_loader.get_anm_wrapper(('eff00.anm',)) - # Load stage data stage = resource_loader.get_stage('stage%d.std' % stage_num) - enemies_anm_wrapper = resource_loader.get_anm_wrapper2(('stg%denm.anm' % stage_num, - 'stg%denm2.anm' % stage_num)) background_anm_wrapper = resource_loader.get_anm_wrapper(('stg%dbg.anm' % stage_num,)) background = Background(stage, background_anm_wrapper) - # Preload textures - for anm_wrapper in chain(etama_anm_wrappers, - (background_anm_wrapper, enemies_anm_wrapper, - effects_anm_wrapper)): - texture_manager.preload(anm_wrapper) + # Renderer + renderer = GameRenderer(resource_loader, game, background) + renderer.start() # Let's go! print(stage.name) @@ -99,78 +61,10 @@ def main(path, stage_num): game.run_iter(keystate) # Draw everything -# glClearColor(0.0, 0.0, 1.0, 0) - glClear(GL_DEPTH_BUFFER_BIT) - - fog_b, fog_g, fog_r, _, fog_start, fog_end = background.fog_interpolator.values - x, y, z = background.position_interpolator.values - dx, 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.)) - - #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. + dx, 224. - dy, 0., 0., -1., 0.) - glTranslatef(-x, -y, -z) - - glEnable(GL_DEPTH_TEST) - for (texture_key, blendfunc), (nb_vertices, vertices, uvs, colors) in background.objects_by_texture.items(): - glBlendFunc(GL_SRC_ALPHA, (GL_ONE_MINUS_SRC_ALPHA, GL_ONE)[blendfunc]) - glBindTexture(GL_TEXTURE_2D, texture_manager[texture_key]) - glVertexPointer(3, GL_FLOAT, 0, vertices) - glTexCoordPointer(2, GL_FLOAT, 0, uvs) - glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors) - glDrawArrays(GL_QUADS, 0, nb_vertices) - glDisable(GL_DEPTH_TEST) - - #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, - 192., 224., 0., 0., -1., 0.) - - glDisable(GL_FOG) - objects_by_texture = {} - for enemy in game.enemies: - enemy.get_objects_by_texture(objects_by_texture) - for (texture_key, blendfunc), (vertices, uvs, colors) in objects_by_texture.items(): - nb_vertices = len(vertices) - glBlendFunc(GL_SRC_ALPHA, (GL_ONE_MINUS_SRC_ALPHA, GL_ONE)[blendfunc]) - glBindTexture(GL_TEXTURE_2D, texture_manager[texture_key]) - glVertexPointer(3, GL_FLOAT, 0, struct.pack(str(3 * nb_vertices) + 'f', *chain(*vertices))) - glTexCoordPointer(2, GL_FLOAT, 0, struct.pack(str(2 * nb_vertices) + 'f', *chain(*uvs))) - glColorPointer(4, GL_UNSIGNED_BYTE, 0, struct.pack(str(4 * nb_vertices) + 'B', *chain(*colors))) - glDrawArrays(GL_QUADS, 0, nb_vertices) - - objects_by_texture = {} - for bullet in game.game_state.bullets: - bullet.get_objects_by_texture(objects_by_texture) - for (texture_key, blendfunc), (vertices, uvs, colors) in objects_by_texture.items(): - nb_vertices = len(vertices) - glBlendFunc(GL_SRC_ALPHA, (GL_ONE_MINUS_SRC_ALPHA, GL_ONE)[blendfunc]) - glBindTexture(GL_TEXTURE_2D, texture_manager[texture_key]) - glVertexPointer(3, GL_FLOAT, 0, struct.pack(str(3 * nb_vertices) + 'f', *chain(*vertices))) - glTexCoordPointer(2, GL_FLOAT, 0, struct.pack(str(2 * nb_vertices) + 'f', *chain(*uvs))) - glColorPointer(4, GL_UNSIGNED_BYTE, 0, struct.pack(str(4 * nb_vertices) + 'B', *chain(*colors))) - glDrawArrays(GL_QUADS, 0, nb_vertices) - glEnable(GL_FOG) + renderer.render() pygame.display.flip() + clock.tick(120)
--- a/pytouhou/game/background.py +++ b/pytouhou/game/background.py @@ -13,11 +13,6 @@ ## -from io import BytesIO -import os -import struct -from itertools import chain - from pytouhou.utils.interpolator import Interpolator from pytouhou.vm.anmrunner import ANMRunner from pytouhou.game.sprite import Sprite @@ -27,9 +22,10 @@ class Background(object): def __init__(self, stage, anm_wrapper): self.stage = stage self.anm_wrapper = anm_wrapper + self.models = [] self.object_instances = [] - self.objects_by_texture = {} + self.anm_runners = [] self.position_interpolator = Interpolator((0, 0, 0)) self.fog_interpolator = Interpolator((0, 0, 0, 0, 0)) @@ -41,63 +37,31 @@ class Background(object): def build_object_instances(self): self.object_instances = [] - for obj, ox, oy, oz in self.stage.object_instances: - - obj_instance = [] - for face_vertices, face_uvs, face_colors in self.models[obj]: - obj_instance.append((tuple((x + ox, y + oy, z + oz) - for x, y, z in face_vertices), - face_uvs, - face_colors)) - self.object_instances.append(obj_instance) + for model_id, ox, oy, oz in self.stage.object_instances: + self.object_instances.append((ox, oy, oz, model_id, self.models[model_id])) # Z-sorting def keyfunc(obj): - return min(z for face in obj for x, y, z in face[0]) + bounding_box = self.stage.models[obj[3]].bounding_box + return obj[2] + min(bounding_box[2], bounding_box[5]) self.object_instances.sort(key=keyfunc, reverse=True) - def object_instances_to_vertices_uvs_colors(self): - vertices = tuple(vertex for obj in self.object_instances - for face in obj for vertex in face[0]) - uvs = tuple(uv for obj in self.object_instances - for face in obj for uv in face[1]) - colors = tuple(color for obj in self.object_instances - for face in obj for color in face[2]) - return vertices, uvs, colors - - def build_models(self): self.models = [] - for i, obj in enumerate(self.stage.models): - faces = [] + for obj in self.stage.models: + quads = [] for script_index, ox, oy, oz, width_override, height_override in obj.quads: #TODO: per-texture rendering sprite = Sprite() anm_runner = ANMRunner(self.anm_wrapper, script_index, sprite) anm_runner.run_frame() sprite.update(width_override, height_override) - if sprite._changed: - sprite.update_vertices_uvs_colors() - uvs, vertices = sprite._uvs, tuple((x + ox, y + oy, z + oz) for x, y, z in sprite._vertices) - colors = sprite._colors - faces.append((vertices, uvs, colors)) - self.models.append(faces) + quads.append((ox, oy, oz, width_override, height_override, sprite)) + self.anm_runners.append(anm_runner) + self.models.append(quads) def update(self, frame): - if not self.objects_by_texture: - vertices, uvs, colors = self.object_instances_to_vertices_uvs_colors() - nb_vertices = len(vertices) - vertices_format = 'f' * (3 * nb_vertices) - uvs_format = 'f' * (2 * nb_vertices) - colors_format = 'B' * (4 * nb_vertices) - vertices = struct.pack(vertices_format, *chain(*vertices)) - uvs = struct.pack(uvs_format, *chain(*uvs)) - colors = struct.pack(colors_format, *chain(*colors)) - assert len(self.anm_wrapper.anm_files) == 1 #TODO - anm = self.anm_wrapper.anm_files[0] - self.objects_by_texture = {((anm.first_name, anm.secondary_name), 0): (nb_vertices, vertices, uvs, colors)} #TODO: blendfunc - for frame_num, message_type, args in self.stage.script: if frame_num == frame: if message_type == 0: @@ -116,6 +80,14 @@ class Background(object): self.position_interpolator.set_interpolation_end(frame_num, args) break + for anm_runner in tuple(self.anm_runners): + if not anm_runner.run_frame(): + self.anm_runners.remove(anm_runner) + + for model in self.models: + for ox, oy, oz, width_override, height_override, sprite in model: + sprite.update(width_override, height_override) + self.position2_interpolator.update(frame) self.fog_interpolator.update(frame) self.position_interpolator.update(frame)
--- a/pytouhou/game/bullet.py +++ b/pytouhou/game/bullet.py @@ -98,18 +98,6 @@ class Bullet(object): return True - def get_objects_by_texture(self, objects_by_texture): - sprite = self._sprite - sprite.update_vertices_uvs_colors() - key = sprite.anm.first_name, sprite.anm.secondary_name - key = (key, sprite.blendfunc) - rec = objects_by_texture.setdefault(key, ([], [], [])) - vertices = ((x + self.x, y + self.y, z) for x, y, z in sprite._vertices) - rec[0].extend(vertices) - rec[1].extend(sprite._uvs) - rec[2].extend(sprite._colors) - - def set_anim(self, anim_idx=None, sprite_idx_offset=None): if anim_idx is not None: self.anim_idx = anim_idx
--- a/pytouhou/game/enemy.py +++ b/pytouhou/game/enemy.py @@ -184,22 +184,6 @@ class Enemy(object): return True - def get_objects_by_texture(self, objects_by_texture): - if not self._sprite: - return - - sprite = self._sprite - sprite.update_vertices_uvs_colors() - - key = sprite.anm.first_name, sprite.anm.secondary_name - key = (key, sprite.blendfunc) - rec = objects_by_texture.setdefault(key, ([], [], [])) - vertices = ((x + self.x, y + self.y, z) for x, y, z in sprite._vertices) - rec[0].extend(vertices) - rec[1].extend(sprite._uvs) - rec[2].extend(sprite._colors) - - def update(self): x, y = self.x, self.y if self.interpolator:
--- a/pytouhou/game/sprite.py +++ b/pytouhou/game/sprite.py @@ -12,9 +12,7 @@ ## GNU General Public License for more details. ## -from math import pi -from pytouhou.utils.matrix import Matrix from pytouhou.utils.interpolator import Interpolator @@ -50,9 +48,8 @@ class Sprite(object): self.frame = 0 self.color = (255, 255, 255) self.alpha = 255 - self._uvs = [] - self._vertices = [] - self._colors = [] + + self._rendering_data = None def fade(self, duration, alpha, formula): @@ -76,69 +73,6 @@ class Sprite(object): self.offset_interpolator.set_interpolation_end(self.frame + duration - 1, (x, y, z)) - def update_vertices_uvs_colors(self): - if not self._changed: - return - - if self.fade_interpolator: - self.fade_interpolator.update(self.frame) - self.alpha = int(self.fade_interpolator.values[0]) - - if self.scale_interpolator: - self.scale_interpolator.update(self.frame) - self.rescale = self.scale_interpolator.values - - if self.offset_interpolator: - self.offset_interpolator.update(self.frame) - self.dest_offset = self.offset_interpolator.values - - vertmat = Matrix([[-.5, .5, .5, -.5], - [-.5, -.5, .5, .5], - [ .0, .0, .0, .0], - [ 1., 1., 1., 1.]]) - - tx, ty, tw, th = self.texcoords - sx, sy = self.rescale - width = self.width_override or (tw * sx) - height = self.height_override or (th * sy) - - vertmat.scale2d(width, height) - if self.mirrored: - vertmat.flip() - - rx, ry, rz = self.rotations_3d - if self.automatic_orientation: - rz += pi/2. - self.angle - elif self.force_rotation: - rz += self.angle - - if (rx, ry, rz) != (0., 0., 0.): - if rx: - vertmat.rotate_x(-rx) - if ry: - vertmat.rotate_y(ry) - if rz: - vertmat.rotate_z(-rz) #TODO: minus, really? - if self.corner_relative_placement: # Reposition - vertmat.translate(width / 2., height / 2., 0.) - if self.allow_dest_offset: - vertmat.translate(*self.dest_offset) - - x_1 = 1. / self.anm.size[0] - y_1 = 1. / self.anm.size[1] - tox, toy = self.texoffsets - uvs = [(tx * x_1 + tox, 1. - (ty * y_1) + toy), - ((tx + tw) * x_1 + tox, 1. - (ty * y_1) + toy), - ((tx + tw) * x_1 + tox, 1. - ((ty + th) * y_1 + toy)), - (tx * x_1 + tox, 1. - ((ty + th) * y_1 + toy))] - - d = vertmat.data - assert (d[3][0], d[3][1], d[3][2], d[3][3]) == (1., 1., 1., 1.) - self._colors = [(self.color[0], self.color[1], self.color[2], self.alpha)] * 4 - self._uvs, self._vertices = uvs, zip(d[0], d[1], d[2]) - self._changed = False - - def update(self, override_width=0, override_height=0, angle_base=0., force_rotation=False): if (override_width != self.width_override or override_height != self.height_override
new file mode 100644 --- /dev/null +++ b/pytouhou/opengl/background.py @@ -0,0 +1,46 @@ +# -*- encoding: utf-8 -*- +## +## Copyright (C) 2011 Thibaut Girka <thib@sitedethib.com> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published +## by the Free Software Foundation; version 3 only. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## + +#TODO: lots of things + +from struct import pack +from itertools import chain + +from pytouhou.opengl.sprite import get_sprite_rendering_data + +def get_background_rendering_data(background): + #TODO + try: + return background._rendering_data + except AttributeError: + pass + + vertices = [] + uvs = [] + colors = [] + for ox, oy, oz, model_id, model in background.object_instances: + for ox2, oy2, oz2, width_override, height_override, sprite in model: + key, (vertices2, uvs2, colors2) = get_sprite_rendering_data(sprite) + vertices.extend((x + ox + ox2, y + oy + oy2, z + oz + oz2) for x, y, z in vertices2) + uvs.extend(uvs2) + colors.extend(colors2) + + nb_vertices = len(vertices) + vertices = pack(str(3 * nb_vertices) + 'f', *chain(*vertices)) + uvs = pack(str(2 * nb_vertices) + 'f', *chain(*uvs)) + colors = pack(str(4 * nb_vertices) + 'B', *chain(*colors)) + + background._rendering_data = [(key, (nb_vertices, vertices, uvs, colors))] + + return background._rendering_data
new file mode 100644 --- /dev/null +++ b/pytouhou/opengl/gamerenderer.py @@ -0,0 +1,143 @@ +# -*- encoding: utf-8 -*- +## +## Copyright (C) 2011 Thibaut Girka <thib@sitedethib.com> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published +## by the Free Software Foundation; version 3 only. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## + +import struct +from itertools import chain + +import pygame + +import OpenGL +OpenGL.FORWARD_COMPATIBLE_ONLY = True +from OpenGL.GL import * +from OpenGL.GLU import * + + +from pytouhou.opengl.texture import TextureManager +from pytouhou.opengl.sprite import get_sprite_rendering_data +from pytouhou.opengl.background import get_background_rendering_data + + +class GameRenderer(object): + def __init__(self, resource_loader, game=None, background=None): + self.texture_manager = TextureManager(resource_loader) + + self.game = game + self.background = background + + self.window = None + + + def start(self, width=384, height=448): + # Initialize pygame + pygame.init() + self.window = pygame.display.set_mode((width, height), + pygame.OPENGL | pygame.DOUBLEBUF) + + # Initialize OpenGL + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + gluPerspective(30, float(width)/float(height), + 101010101./2010101., 101010101./10101.) + + glEnable(GL_BLEND) + glEnable(GL_TEXTURE_2D) + glEnable(GL_FOG) + glHint(GL_FOG_HINT, GL_NICEST) + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) + glEnableClientState(GL_COLOR_ARRAY) + glEnableClientState(GL_VERTEX_ARRAY) + glEnableClientState(GL_TEXTURE_COORD_ARRAY) + + + def render_elements(self, elements): + texture_manager = self.texture_manager + objects_by_texture = {} + for element in elements: + sprite = element._sprite + if sprite: + ox, oy = element.x, element.y + key, (vertices, uvs, colors) = get_sprite_rendering_data(sprite) + rec = objects_by_texture.setdefault(key, ([], [], [])) + vertices = ((x + ox, y + oy, z) for x, y, z in vertices) + rec[0].extend(vertices) + rec[1].extend(uvs) + rec[2].extend(colors) + + for (texture_key, blendfunc), (vertices, uvs, colors) in objects_by_texture.items(): + nb_vertices = len(vertices) + glBlendFunc(GL_SRC_ALPHA, (GL_ONE_MINUS_SRC_ALPHA, GL_ONE)[blendfunc]) + glBindTexture(GL_TEXTURE_2D, texture_manager[texture_key]) + glVertexPointer(3, GL_FLOAT, 0, struct.pack(str(3 * nb_vertices) + 'f', *chain(*vertices))) + glTexCoordPointer(2, GL_FLOAT, 0, struct.pack(str(2 * nb_vertices) + 'f', *chain(*uvs))) + glColorPointer(4, GL_UNSIGNED_BYTE, 0, struct.pack(str(4 * nb_vertices) + 'B', *chain(*colors))) + glDrawArrays(GL_QUADS, 0, nb_vertices) + + + def render(self): + glClear(GL_DEPTH_BUFFER_BIT) + + back = self.background + game = self.game + texture_manager = self.texture_manager + + if back is not None: + fog_b, fog_g, fog_r, _, fog_start, fog_end = back.fog_interpolator.values + x, y, z = back.position_interpolator.values + dx, dy, dz = back.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.)) + + 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. + dx, 224. - dy, 0., 0., -1., 0.) + glTranslatef(-x, -y, -z) + + glEnable(GL_DEPTH_TEST) + for (texture_key, blendfunc), (nb_vertices, vertices, uvs, colors) in get_background_rendering_data(back): + glBlendFunc(GL_SRC_ALPHA, (GL_ONE_MINUS_SRC_ALPHA, GL_ONE)[blendfunc]) + glBindTexture(GL_TEXTURE_2D, texture_manager[texture_key]) + glVertexPointer(3, GL_FLOAT, 0, vertices) + glTexCoordPointer(2, GL_FLOAT, 0, uvs) + glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors) + glDrawArrays(GL_QUADS, 0, nb_vertices) + glDisable(GL_DEPTH_TEST) + else: + glClear(GL_COLOR_BUFFER_BIT) + + + if game is not None: + 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, + 192., 224., 0., 0., -1., 0.) + + glDisable(GL_FOG) + self.render_elements(game.enemies) + self.render_elements(game.game_state.bullets) + glEnable(GL_FOG) +
new file mode 100644 --- /dev/null +++ b/pytouhou/opengl/sprite.py @@ -0,0 +1,86 @@ +# -*- encoding: utf-8 -*- +## +## Copyright (C) 2011 Thibaut Girka <thib@sitedethib.com> +## +## This program is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published +## by the Free Software Foundation; version 3 only. +## +## This program is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## + + +from math import pi + +from pytouhou.utils.matrix import Matrix + + +def get_sprite_rendering_data(sprite): + if not sprite._changed: + return sprite._rendering_data + + if sprite.fade_interpolator: + sprite.fade_interpolator.update(sprite.frame) + sprite.alpha = int(sprite.fade_interpolator.values[0]) + + if sprite.scale_interpolator: + sprite.scale_interpolator.update(sprite.frame) + sprite.rescale = sprite.scale_interpolator.values + + if sprite.offset_interpolator: + sprite.offset_interpolator.update(sprite.frame) + sprite.dest_offset = sprite.offset_interpolator.values + + 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) + if sprite.mirrored: + vertmat.flip() + + rx, ry, rz = sprite.rotations_3d + if sprite.automatic_orientation: + rz += pi/2. - sprite.angle + elif sprite.force_rotation: + rz += sprite.angle + + if (rx, ry, rz) != (0., 0., 0.): + if rx: + vertmat.rotate_x(-rx) + if ry: + vertmat.rotate_y(ry) + if rz: + vertmat.rotate_z(-rz) #TODO: minus, really? + if sprite.corner_relative_placement: # Reposition + vertmat.translate(width / 2., height / 2., 0.) + if sprite.allow_dest_offset: + vertmat.translate(*sprite.dest_offset) + + x_1 = 1. / sprite.anm.size[0] + y_1 = 1. / sprite.anm.size[1] + tox, toy = sprite.texoffsets + uvs = [(tx * x_1 + tox, 1. - (ty * y_1) + toy), + ((tx + tw) * x_1 + tox, 1. - (ty * y_1) + toy), + ((tx + tw) * x_1 + tox, 1. - ((ty + th) * y_1 + toy)), + (tx * x_1 + tox, 1. - ((ty + th) * y_1 + toy))] + + d = vertmat.data + assert (d[3][0], d[3][1], d[3][2], d[3][3]) == (1., 1., 1., 1.) + + key = (sprite.anm.first_name, sprite.anm.secondary_name), sprite.blendfunc + values = zip(d[0], d[1], d[2]), uvs, [(sprite.color[0], sprite.color[1], sprite.color[2], sprite.alpha)] * 4 + sprite._rendering_data = key, values + sprite._changed = False + + return sprite._rendering_data +