changeset 399:1c773544eaeb

Make the background use a single vbo and offsets, just like the 2D code.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Tue, 12 Feb 2013 19:19:31 +0100
parents 8d252cdb495f
children 7aa70f0def38
files pytouhou/ui/background.pxd pytouhou/ui/background.pyx pytouhou/ui/gamerenderer.py pytouhou/ui/gamerunner.py pytouhou/ui/renderer.pxd pytouhou/ui/renderer.pyx
diffstat 6 files changed, 85 insertions(+), 88 deletions(-) [+]
line wrap: on
line diff
deleted file mode 100644
--- a/pytouhou/ui/background.pxd
+++ /dev/null
@@ -1,1 +0,0 @@
-cpdef object get_background_rendering_data(object background)
deleted file mode 100644
--- a/pytouhou/ui/background.pyx
+++ /dev/null
@@ -1,53 +0,0 @@
-# -*- 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 .sprite cimport get_sprite_rendering_data
-
-cpdef object get_background_rendering_data(object background):
-    cdef float x, y, z, ox, oy, oz, ox2, oy2, oz2
-    cdef list vertices, uvs, colors
-
-    #TODO: do not cache the results, and use view frustum culling
-    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:
-            #TODO: view frustum culling
-            key, (vertices2, (left, right, bottom, top), 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((left, bottom, right, bottom, right, top, left, top))
-            colors.extend(colors2 * 4)
-
-    nb_vertices = len(vertices)
-    vertices_s = pack(str(3 * nb_vertices) + 'f', *chain(*vertices))
-    uvs_s = pack(str(2 * nb_vertices) + 'f', *uvs)
-    colors_s = pack(str(4 * nb_vertices) + 'B', *colors)
-
-    background._rendering_data = [(key, (nb_vertices, vertices_s, uvs_s, colors_s))]
-
-    return background._rendering_data
-
--- a/pytouhou/ui/gamerenderer.py
+++ b/pytouhou/ui/gamerenderer.py
@@ -43,6 +43,7 @@ class GameRenderer(Renderer):
         if game:
             # Preload textures
             self.texture_manager.preload(game.resource_loader.instanced_anms.values())
+            self.prerender_background(background)
 
 
     def render(self):
@@ -66,33 +67,33 @@ class GameRenderer(Renderer):
 
             self.render_elements([game.spellcard_effect])
         elif back is not None:
-            if self.use_fixed_pipeline:
-                glEnable(GL_FOG)
-            else:
-                self.background_shader.bind()
-            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
+            fog_b, fog_g, fog_r, fog_start, fog_end = back.fog_interpolator.values
+
+            model = Matrix()
+            model.data[3] = [-x, -y, -z, 1]
+            view = self.setup_camera(dx, dy, dz)
 
             glFogi(GL_FOG_MODE, GL_LINEAR)
             glFogf(GL_FOG_START, fog_start)
             glFogf(GL_FOG_END,  fog_end)
             glFogfv(GL_FOG_COLOR, (GLfloat * 4)(fog_r / 255., fog_g / 255., fog_b / 255., 1.))
 
-            model = Matrix()
-            model.data[3] = [-x, -y, -z, 1]
-            view = self.setup_camera(dx, dy, dz)
+            if self.use_fixed_pipeline:
+                glEnable(GL_FOG)
 
-            if self.use_fixed_pipeline:
                 model_view_projection = model * view * self.proj
                 glMatrixMode(GL_MODELVIEW)
                 glLoadMatrixf(model_view_projection.get_c_data())
             else:
+                self.background_shader.bind()
+
                 model_view = model * view
                 self.background_shader.uniform_matrixf('model_view', model_view.get_c_data())
                 self.background_shader.uniform_matrixf('projection', self.proj.get_c_data())
 
-            self.render_background(back)
+            self.render_background()
         else:
             glClear(GL_COLOR_BUFFER_BIT)
 
--- a/pytouhou/ui/gamerunner.py
+++ b/pytouhou/ui/gamerunner.py
@@ -57,7 +57,9 @@ class GameRunner(pyglet.window.Window, G
             self.background_shader = BackgroundShader()
             self.interface_shader = self.game_shader
 
-            self.vbo = c_uint(0)
+            vbo_array = (c_uint * 2)()
+            glGenBuffers(2, vbo_array)
+            self.vbo, self.back_vbo = vbo_array
 
         if game:
             self.load_game(game, background, replay)
@@ -106,8 +108,6 @@ class GameRunner(pyglet.window.Window, G
             glEnableClientState(GL_COLOR_ARRAY)
             glEnableClientState(GL_VERTEX_ARRAY)
             glEnableClientState(GL_TEXTURE_COORD_ARRAY)
-        else:
-            glGenBuffers(1, byref(self.vbo))
 
         self.proj = self.perspective(30, float(self.game.width) / float(self.game.height),
                                      101010101./2010101., 101010101./10101.)
@@ -129,7 +129,8 @@ class GameRunner(pyglet.window.Window, G
                 self.update()
 
         if not self.use_fixed_pipeline:
-            glDeleteBuffers(1, byref(self.vbo))
+            vbo_array = (c_uint * 2)(self.vbo, self.back_vbo)
+            glDeleteBuffers(2, vbo_array)
 
 
     def _event_text_symbol(self, ev):
--- a/pytouhou/ui/renderer.pxd
+++ b/pytouhou/ui/renderer.pxd
@@ -4,12 +4,22 @@ cdef struct Vertex:
     unsigned char r, g, b, a
 
 
+cdef struct VertexFloat:
+    float x, y, z
+    float u, v
+    unsigned char r, g, b, a
+
+
 cdef class Renderer:
     cdef public texture_manager
     cdef Vertex *vertex_buffer
+    cdef object texture_key
+    cdef unsigned short blendfunc, nb_vertices
+    cdef VertexFloat *background_vertex_buffer
 
     cpdef render_elements(self, elements)
-    cpdef render_background(self, back)
+    cpdef render_background(self)
+    cpdef prerender_background(self, background)
     cpdef ortho_2d(self, left, right, bottom, top)
     cpdef look_at(self, eye, center, up)
     cpdef perspective(self, fovy, aspect, zNear, zFar)
--- a/pytouhou/ui/renderer.pyx
+++ b/pytouhou/ui/renderer.pyx
@@ -12,7 +12,7 @@
 ## GNU General Public License for more details.
 ##
 
-from libc.stdlib cimport malloc, free
+from libc.stdlib cimport malloc, free, realloc
 from libc.math cimport tan
 from math import radians
 from itertools import chain
@@ -25,13 +25,12 @@ from pyglet.gl import (glVertexPointer, 
                        glVertexAttribPointer, glEnableVertexAttribArray,
                        glBlendFunc, glBindTexture, glDrawElements,
                        glBindBuffer, glBufferData, GL_ARRAY_BUFFER,
-                       GL_DYNAMIC_DRAW, GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT,
+                       GL_DYNAMIC_DRAW, GL_STATIC_DRAW, GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT,
                        GL_INT, GL_FLOAT, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
                        GL_ONE, GL_TEXTURE_2D, GL_TRIANGLES,
                        glEnable, glDisable, GL_DEPTH_TEST, glDrawArrays, GL_QUADS)
 
 from .sprite cimport get_sprite_rendering_data
-from .background import get_background_rendering_data
 from .texture cimport TextureManager
 from pytouhou.utils.matrix cimport Matrix
 from pytouhou.utils.vector import Vector, normalize, cross, dot
@@ -44,10 +43,12 @@ cdef class Renderer:
     def __cinit__(self):
         # Allocate buffers
         self.vertex_buffer = <Vertex*> malloc(MAX_ELEMENTS * sizeof(Vertex))
+        self.background_vertex_buffer = <VertexFloat*> malloc(65536 * sizeof(Vertex))
 
 
     def __dealloc__(self):
         free(self.vertex_buffer)
+        free(self.background_vertex_buffer)
 
 
     def __init__(self, resource_loader):
@@ -112,25 +113,63 @@ cdef class Renderer:
             glBindBuffer(GL_ARRAY_BUFFER, 0)
 
 
-    cpdef render_background(self, back):
+    cpdef render_background(self):
+        if self.use_fixed_pipeline:
+            glVertexPointer(3, GL_FLOAT, sizeof(VertexFloat), <long> &self.background_vertex_buffer[0].x)
+            glTexCoordPointer(2, GL_FLOAT, sizeof(VertexFloat), <long> &self.background_vertex_buffer[0].u)
+            glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexFloat), <long> &self.background_vertex_buffer[0].r)
+        else:
+            glBindBuffer(GL_ARRAY_BUFFER, self.back_vbo)
+
+            #TODO: find a way to use offsetof() instead of those ugly hardcoded values.
+            glVertexAttribPointer(0, 3, GL_FLOAT, False, sizeof(VertexFloat), 0)
+            glEnableVertexAttribArray(0)
+            glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(VertexFloat), 12)
+            glEnableVertexAttribArray(1)
+            glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, True, sizeof(VertexFloat), 20)
+            glEnableVertexAttribArray(2)
+
         glEnable(GL_DEPTH_TEST)
-        for (texture_key, blendfunc), (nb_vertices, vertices, uvs, colors) in get_background_rendering_data(back):
-            if self.use_fixed_pipeline:
-                glVertexPointer(3, GL_FLOAT, 0, vertices)
-                glTexCoordPointer(2, GL_FLOAT, 0, uvs)
-                glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors)
-            else:
-                glVertexAttribPointer(0, 3, GL_FLOAT, False, 0, vertices)
-                glEnableVertexAttribArray(0)
-                glVertexAttribPointer(1, 2, GL_FLOAT, False, 0, uvs)
-                glEnableVertexAttribArray(1)
-                glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, True, 0, colors)
-                glEnableVertexAttribArray(2)
-            glBlendFunc(GL_SRC_ALPHA, (GL_ONE_MINUS_SRC_ALPHA, GL_ONE)[blendfunc])
-            glBindTexture(GL_TEXTURE_2D, self.texture_manager[texture_key])
-            glDrawArrays(GL_QUADS, 0, nb_vertices)
+        glBlendFunc(GL_SRC_ALPHA, (GL_ONE_MINUS_SRC_ALPHA, GL_ONE)[self.blendfunc])
+        glBindTexture(GL_TEXTURE_2D, self.texture_manager[self.texture_key])
+        glDrawArrays(GL_QUADS, 0, self.nb_vertices)
         glDisable(GL_DEPTH_TEST)
 
+        if not self.use_fixed_pipeline:
+            glBindBuffer(GL_ARRAY_BUFFER, 0)
+
+
+    cpdef prerender_background(self, background):
+        cdef float ox, oy, oz, ox2, oy2, oz2
+        cdef unsigned short nb_vertices = 0
+        cdef VertexFloat* vertex_buffer
+
+        vertex_buffer = self.background_vertex_buffer
+
+        for ox, oy, oz, model_id, model in background.object_instances:
+            for ox2, oy2, oz2, width_override, height_override, sprite in model:
+                #TODO: view frustum culling
+                key, (vertices, uvs, colors) = get_sprite_rendering_data(sprite)
+                (x1, y1, z1), (x2, y2, z2), (x3, y3, z3), (x4, y4, z4) = vertices
+                left, right, bottom, top = uvs
+                r, g, b, a = colors
+
+                vertex_buffer[nb_vertices] = VertexFloat(x1 + ox + ox2, y1 + oy + oy2, z1 + oz + oz2, left, bottom, r, g, b, a)
+                vertex_buffer[nb_vertices+1] = VertexFloat(x2 + ox + ox2, y2 + oy + oy2, z2 + oz + oz2, right, bottom, r, g, b, a)
+                vertex_buffer[nb_vertices+2] = VertexFloat(x3 + ox + ox2, y3 + oy + oy2, z3 + oz + oz2, right, top, r, g, b, a)
+                vertex_buffer[nb_vertices+3] = VertexFloat(x4 + ox + ox2, y4 + oy + oy2, z4 + oz + oz2, left, top, r, g, b, a)
+
+                nb_vertices += 4
+
+        self.texture_key, self.blendfunc = key
+        self.nb_vertices = nb_vertices
+        self.background_vertex_buffer = <VertexFloat*> realloc(vertex_buffer, nb_vertices * sizeof(VertexFloat))
+
+        if not self.use_fixed_pipeline:
+            glBindBuffer(GL_ARRAY_BUFFER, self.back_vbo)
+            glBufferData(GL_ARRAY_BUFFER, nb_vertices * sizeof(VertexFloat), <long> &self.background_vertex_buffer[0], GL_STATIC_DRAW)
+            glBindBuffer(GL_ARRAY_BUFFER, 0)
+
 
     cpdef ortho_2d(self, left, right, bottom, top):
         mat = Matrix()