Mercurial > touhou
comparison pytouhou/ui/renderer.pyx @ 449:d56536ef28e8
Improve render_elements’ speed a lot, and fix it in some corner cases. Thanks liori!
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Sat, 03 Aug 2013 15:49:11 +0200 |
parents | 878273a984c4 |
children | cae1ae9de430 |
comparison
equal
deleted
inserted
replaced
448:3bc37791f0a2 | 449:d56536ef28e8 |
---|---|
11 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 ## GNU General Public License for more details. | 12 ## GNU General Public License for more details. |
13 ## | 13 ## |
14 | 14 |
15 from libc.stdlib cimport malloc, free | 15 from libc.stdlib cimport malloc, free |
16 from itertools import chain | 16 from libc.string cimport memset |
17 | |
18 from struct import pack | |
19 | 17 |
20 from pytouhou.lib.opengl cimport \ | 18 from pytouhou.lib.opengl cimport \ |
21 (glVertexPointer, glTexCoordPointer, glColorPointer, | 19 (glVertexPointer, glTexCoordPointer, glColorPointer, |
22 glVertexAttribPointer, glEnableVertexAttribArray, glBlendFunc, | 20 glVertexAttribPointer, glEnableVertexAttribArray, glBlendFunc, |
23 glBindTexture, glDrawElements, glBindBuffer, glBufferData, | 21 glBindTexture, glDrawElements, glBindBuffer, glBufferData, |
24 GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, GL_UNSIGNED_BYTE, | 22 GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW, GL_UNSIGNED_BYTE, |
25 GL_UNSIGNED_SHORT, GL_INT, GL_FLOAT, GL_SRC_ALPHA, | 23 GL_UNSIGNED_SHORT, GL_INT, GL_FLOAT, GL_SRC_ALPHA, |
26 GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_TEXTURE_2D, GL_TRIANGLES, | 24 GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_TEXTURE_2D, GL_TRIANGLES, |
27 glGenBuffers) | 25 glGenBuffers) |
28 | 26 |
27 from pytouhou.game.element cimport Element | |
29 from .sprite cimport get_sprite_rendering_data | 28 from .sprite cimport get_sprite_rendering_data |
30 from .texture import TextureManager | 29 from .texture import TextureManager |
31 | 30 |
32 | 31 |
33 MAX_ELEMENTS = 640*4*3 | 32 DEF MAX_ELEMENTS = 640*4*3 |
33 | |
34 | |
35 cdef long find_objects(Renderer self, object elements): | |
36 # Don’t type element as Element, or else the overriding of objects won’t work. | |
37 cdef Element obj | |
38 cdef long i = 0 | |
39 for element in elements: | |
40 for obj in element.objects: | |
41 sprite = obj.sprite | |
42 if sprite and sprite.visible: | |
43 # warning: no reference is preserved on the object—assuming the object will not die accidentally | |
44 self.elements[i] = <PyObject*>obj | |
45 i += 1 | |
46 if i >= 640*3-4: | |
47 return i | |
48 return i | |
34 | 49 |
35 | 50 |
36 cdef class Renderer: | 51 cdef class Renderer: |
37 def __cinit__(self): | 52 def __cinit__(self): |
38 # Allocate buffers | |
39 self.vertex_buffer = <Vertex*> malloc(MAX_ELEMENTS * sizeof(Vertex)) | 53 self.vertex_buffer = <Vertex*> malloc(MAX_ELEMENTS * sizeof(Vertex)) |
40 | 54 |
41 | 55 |
42 def __dealloc__(self): | 56 def __dealloc__(self): |
43 free(self.vertex_buffer) | 57 free(self.vertex_buffer) |
44 | 58 |
45 | 59 |
46 def __init__(self, resource_loader): | 60 def __init__(self, resource_loader): |
47 self.texture_manager = TextureManager(resource_loader) | 61 self.texture_manager = TextureManager(resource_loader, self) |
48 | 62 |
49 if not self.use_fixed_pipeline: | 63 if not self.use_fixed_pipeline: |
50 glGenBuffers(1, &self.vbo) | 64 glGenBuffers(1, &self.vbo) |
51 | 65 |
52 | 66 |
67 def add_texture(self, int texture): | |
68 for i in xrange(2): | |
69 self.indices[i][texture] = <unsigned short*> malloc(65536 * sizeof(unsigned short)) | |
70 | |
71 | |
72 def remove_texture(self, int texture): | |
73 for i in xrange(2): | |
74 free(self.indices[i][texture]) | |
75 | |
76 | |
53 cpdef render_elements(self, elements): | 77 cpdef render_elements(self, elements): |
54 cdef unsigned short nb_vertices = 0, nb_indices, *new_indices | 78 cdef int key |
79 cdef int x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4, ox, oy | |
80 cdef float left, right, bottom, top | |
81 cdef unsigned char r, g, b, a | |
55 | 82 |
56 indices_by_texture = {} | 83 nb_vertices = 0 |
84 memset(self.last_indices, 0, sizeof(self.last_indices)) | |
57 | 85 |
58 objects = chain(*[element.objects for element in elements]) | 86 nb_elements = find_objects(self, elements) |
59 for element in objects: | 87 for element_idx in xrange(nb_elements): |
60 if nb_vertices >= MAX_ELEMENTS - 4: | 88 element = <object>self.elements[element_idx] |
61 break | 89 sprite = element.sprite |
90 ox, oy = element.x, element.y | |
91 key, (vertices, uvs, colors) = get_sprite_rendering_data(sprite) | |
62 | 92 |
63 sprite = element.sprite | 93 blendfunc = key // MAX_TEXTURES |
64 if sprite and sprite.visible: | 94 texture = key % MAX_TEXTURES |
65 ox, oy = element.x, element.y | |
66 key, (vertices, uvs, colors) = get_sprite_rendering_data(sprite) | |
67 rec = indices_by_texture.setdefault(key, []) | |
68 | 95 |
69 # Pack data in buffer | 96 rec = self.indices[blendfunc][texture] |
70 x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4 = vertices | 97 next_indice = self.last_indices[key] |
71 left, right, bottom, top = uvs | |
72 r, g, b, a = colors | |
73 self.vertex_buffer[nb_vertices] = Vertex(x1 + ox, y1 + oy, z1, left, bottom, r, g, b, a) | |
74 self.vertex_buffer[nb_vertices+1] = Vertex(x2 + ox, y2 + oy, z2, right, bottom, r, g, b, a) | |
75 self.vertex_buffer[nb_vertices+2] = Vertex(x3 + ox, y3 + oy, z3, right, top, r, g, b, a) | |
76 self.vertex_buffer[nb_vertices+3] = Vertex(x4 + ox, y4 + oy, z4, left, top, r, g, b, a) | |
77 | 98 |
78 # Add indices | 99 # Pack data in buffer |
79 index = nb_vertices | 100 x1, x2, x3, x4, y1, y2, y3, y4, z1, z2, z3, z4 = vertices |
80 rec.extend((index, index + 1, index + 2, index + 2, index + 3, index)) | 101 left, right, bottom, top = uvs |
102 r, g, b, a = colors | |
103 self.vertex_buffer[nb_vertices] = Vertex(x1 + ox, y1 + oy, z1, left, bottom, r, g, b, a) | |
104 self.vertex_buffer[nb_vertices+1] = Vertex(x2 + ox, y2 + oy, z2, right, bottom, r, g, b, a) | |
105 self.vertex_buffer[nb_vertices+2] = Vertex(x3 + ox, y3 + oy, z3, right, top, r, g, b, a) | |
106 self.vertex_buffer[nb_vertices+3] = Vertex(x4 + ox, y4 + oy, z4, left, top, r, g, b, a) | |
81 | 107 |
82 nb_vertices += 4 | 108 # Add indices |
109 rec[next_indice] = nb_vertices | |
110 rec[next_indice+1] = nb_vertices + 1 | |
111 rec[next_indice+2] = nb_vertices + 2 | |
112 rec[next_indice+3] = nb_vertices + 2 | |
113 rec[next_indice+4] = nb_vertices + 3 | |
114 rec[next_indice+5] = nb_vertices | |
115 self.last_indices[key] += 6 | |
116 | |
117 nb_vertices += 4 | |
83 | 118 |
84 if nb_vertices == 0: | 119 if nb_vertices == 0: |
85 return | 120 return |
86 | 121 |
87 if self.use_fixed_pipeline: | 122 if self.use_fixed_pipeline: |
98 glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(Vertex), <void*>12) | 133 glVertexAttribPointer(1, 2, GL_FLOAT, False, sizeof(Vertex), <void*>12) |
99 glEnableVertexAttribArray(1) | 134 glEnableVertexAttribArray(1) |
100 glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, True, sizeof(Vertex), <void*>20) | 135 glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, True, sizeof(Vertex), <void*>20) |
101 glEnableVertexAttribArray(2) | 136 glEnableVertexAttribArray(2) |
102 | 137 |
103 for (texture, blendfunc), indices in indices_by_texture.items(): | 138 for key in xrange(2 * MAX_TEXTURES): |
139 nb_indices = self.last_indices[key] | |
140 if not nb_indices: | |
141 continue | |
104 | 142 |
105 #TODO: find a more elegent way. | 143 blendfunc = key // MAX_TEXTURES |
106 nb_indices = len(indices) | 144 texture = key % MAX_TEXTURES |
107 new_indices = <unsigned short*> malloc(nb_indices * sizeof(unsigned short)) | |
108 for i in xrange(nb_indices): | |
109 new_indices[i] = indices[i] | |
110 | 145 |
111 glBlendFunc(GL_SRC_ALPHA, (GL_ONE_MINUS_SRC_ALPHA, GL_ONE)[blendfunc]) | 146 glBlendFunc(GL_SRC_ALPHA, (GL_ONE_MINUS_SRC_ALPHA, GL_ONE)[blendfunc]) |
112 glBindTexture(GL_TEXTURE_2D, texture) | 147 glBindTexture(GL_TEXTURE_2D, texture) |
113 glDrawElements(GL_TRIANGLES, nb_indices, GL_UNSIGNED_SHORT, new_indices) | 148 glDrawElements(GL_TRIANGLES, nb_indices, GL_UNSIGNED_SHORT, self.indices[blendfunc][texture]) |
114 free(new_indices) | |
115 | 149 |
116 if not self.use_fixed_pipeline: | 150 if not self.use_fixed_pipeline: |
117 glBindBuffer(GL_ARRAY_BUFFER, 0) | 151 glBindBuffer(GL_ARRAY_BUFFER, 0) |