# HG changeset patch # User Thibaut Girka # Date 1315659887 -7200 # Node ID 0313ca2c50e945390897d74536b63d8343e905e6 # Parent f06e96dbed4e02241f39c31fde00a457645f65ca Small refactoring and massive performance improvements diff --git a/pytouhou/opengl/background.py b/pytouhou/opengl/background.py --- a/pytouhou/opengl/background.py +++ b/pytouhou/opengl/background.py @@ -38,8 +38,8 @@ def get_background_rendering_data(backgr 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)) + uvs = pack(str(2 * nb_vertices) + 'f', *uvs) + colors = pack(str(4 * nb_vertices) + 'B', *colors) background._rendering_data = [(key, (nb_vertices, vertices, uvs, colors))] diff --git a/pytouhou/opengl/gamerenderer.py b/pytouhou/opengl/gamerenderer.py --- a/pytouhou/opengl/gamerenderer.py +++ b/pytouhou/opengl/gamerenderer.py @@ -14,6 +14,7 @@ import struct from itertools import chain +import ctypes import pyglet from pyglet.gl import * @@ -23,6 +24,9 @@ from pytouhou.opengl.sprite import get_s from pytouhou.opengl.background import get_background_rendering_data +MAX_ELEMENTS = 10000 + + class GameRenderer(pyglet.window.Window): def __init__(self, resource_loader, game=None, background=None): pyglet.window.Window.__init__(self, caption='PyTouhou', resizable=False) @@ -55,7 +59,13 @@ class GameRenderer(pyglet.window.Window) glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_TEXTURE_COORD_ARRAY) - pyglet.clock.schedule_interval(self.update, 1./120) + # Allocate buffers + buff = ctypes.c_buffer(MAX_ELEMENTS * 4 * (3 * 4 + 2 * 4 + 4)) + self.buffers = (buff, + ctypes.byref(buff, 3 * 4), + ctypes.byref(buff, 3 * 4 + 2 * 4)) + + pyglet.clock.schedule_interval(self.update, 1./120.) pyglet.app.run() @@ -80,29 +90,57 @@ class GameRenderer(pyglet.window.Window) def render_elements(self, elements): texture_manager = self.texture_manager - objects_by_texture = {} + + pack_data = struct.Struct('fff ff BBBB' * 4).pack_into + _vertices, _uvs, _colors = self.buffers + + nb_vertices = 0 + indices_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) + rec = indices_by_texture.setdefault(key, [0, []]) + index = rec[0] + + # Pack data in buffer + (x1, y1, z1), (x2, y2, z2), (x3, y3, z3), (x4, y4, z4) = vertices + r1, g1, b1, a1, r2, g2, b2, a2, r3, g3, b3, a3, r4, g4, b4, a4 = colors + u1, v1, u2, v2, u3, v3, u4, v4 = uvs + pack_data(_vertices, nb_vertices * (3 * 4 + 2 * 4 + 4), + x1 + ox, y1 + oy, z1, + u1, v1, + r1, g1, b1, a1, + + x2 + ox, y2 + oy, z2, + u2, v2, + r2, g2, b2, a2, - for (texture_key, blendfunc), (vertices, uvs, colors) in objects_by_texture.items(): - nb_vertices = len(vertices) - vertices = struct.pack(str(3 * nb_vertices) + 'f', *chain(*vertices)) - uvs = struct.pack(str(2 * nb_vertices) + 'f', *chain(*uvs)) - colors = struct.pack(str(4 * nb_vertices) + 'B', *chain(*colors)) + x3 + ox, y3 + oy, z3, + u3, v3, + r3, g3, b3, a3, + + x4 + ox, y4 + oy, z4, + u4, v4, + r4, g4, b4, a4) + + # Add indices + rec[0] += 4 + rec[1].extend((index, index + 1, index + 2, index + 3)) + + nb_vertices += 4 + + glVertexPointer(3, GL_FLOAT, 24, _vertices) + glTexCoordPointer(2, GL_FLOAT, 24, _uvs) + glColorPointer(4, GL_UNSIGNED_BYTE, 24, _colors) + + for (texture_key, blendfunc), (nb_indices, indices) in indices_by_texture.items(): + indices = struct.pack(str(nb_indices) + 'H', *indices) glBlendFunc(GL_SRC_ALPHA, (GL_ONE_MINUS_SRC_ALPHA, GL_ONE)[blendfunc]) glBindTexture(GL_TEXTURE_2D, texture_manager[texture_key].id) - 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) + glDrawElements(GL_QUADS, nb_indices, GL_UNSIGNED_SHORT, indices) def on_draw(self): diff --git a/pytouhou/opengl/sprite.py b/pytouhou/opengl/sprite.py --- a/pytouhou/opengl/sprite.py +++ b/pytouhou/opengl/sprite.py @@ -57,16 +57,16 @@ def get_sprite_rendering_data(sprite): 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))] + 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.) + (x1, x2 , x3, x4), (y1, y2, y3, y4), (z1, z2, z3, z4), _ = vertmat.data 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 + r, g, b = sprite.color + values = ((x1, y1, z1), (x2, y2, z2), (x3, y3, z3), (x4, y4, z4)), uvs, [r, g, b, sprite.alpha] * 4 sprite._rendering_data = key, values sprite._changed = False