# HG changeset patch # User Emmanuel Gil Peyrot # Date 1374001895 -7200 # Node ID 5d7bb2fd74f7d604c4b510c9acbd646e8efc1795 # Parent 1104dc2553ee430fb832c5205e4fd4f11cfd13ab Never keep texture on the host when it has been uploaded, and prevent them from being decoded again. diff --git a/pytouhou/lib/opengl.pxd b/pytouhou/lib/opengl.pxd --- a/pytouhou/lib/opengl.pxd +++ b/pytouhou/lib/opengl.pxd @@ -94,6 +94,7 @@ cdef extern from 'GL/gl.h': void glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage) void glGenTextures(GLsizei n, GLuint *textures) + void glDeleteTextures(GLsizei n, const GLuint *textures) void glBindTexture(GLenum target, GLuint texture) void glTexParameteri(GLenum target, GLenum pname, GLint param) void glTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format_, GLenum type_, const GLvoid *data) diff --git a/pytouhou/ui/anmrenderer.pyx b/pytouhou/ui/anmrenderer.pyx --- a/pytouhou/ui/anmrenderer.pyx +++ b/pytouhou/ui/anmrenderer.pyx @@ -37,7 +37,7 @@ class ANMRenderer(Renderer): Renderer.__init__(self, resource_loader) self.window = window - self.texture_manager.preload(resource_loader.instanced_anms.values()) + self.texture_manager.load(resource_loader.instanced_anms.values()) self._anm_wrapper = anm_wrapper self.sprites = sprites diff --git a/pytouhou/ui/background.pxd b/pytouhou/ui/background.pxd --- a/pytouhou/ui/background.pxd +++ b/pytouhou/ui/background.pxd @@ -1,3 +1,5 @@ +from pytouhou.lib.opengl cimport GLuint + cdef struct Vertex: float x, y, z float u, v @@ -5,8 +7,7 @@ cdef struct Vertex: cdef class BackgroundRenderer: - cdef public texture_manager - cdef object texture_key + cdef GLuint texture cdef unsigned short blendfunc, nb_vertices cdef Vertex *vertex_buffer cdef unsigned int use_fixed_pipeline, vbo diff --git a/pytouhou/ui/background.pyx b/pytouhou/ui/background.pyx --- a/pytouhou/ui/background.pyx +++ b/pytouhou/ui/background.pyx @@ -35,8 +35,7 @@ cdef class BackgroundRenderer: free(self.vertex_buffer) - def __init__(self, texture_manager, use_fixed_pipeline): - self.texture_manager = texture_manager + def __init__(self, use_fixed_pipeline): self.use_fixed_pipeline = use_fixed_pipeline if not use_fixed_pipeline: @@ -61,7 +60,7 @@ cdef class BackgroundRenderer: glEnable(GL_DEPTH_TEST) glBlendFunc(GL_SRC_ALPHA, (GL_ONE_MINUS_SRC_ALPHA, GL_ONE)[self.blendfunc]) - glBindTexture(GL_TEXTURE_2D, self.texture_manager[self.texture_key]) + glBindTexture(GL_TEXTURE_2D, self.texture) glDrawArrays(GL_QUADS, 0, self.nb_vertices) glDisable(GL_DEPTH_TEST) @@ -91,7 +90,7 @@ cdef class BackgroundRenderer: nb_vertices += 4 - self.texture_key, self.blendfunc = key + self.texture, self.blendfunc = key self.nb_vertices = nb_vertices self.vertex_buffer = realloc(vertex_buffer, nb_vertices * sizeof(Vertex)) diff --git a/pytouhou/ui/gamerunner.pyx b/pytouhou/ui/gamerunner.pyx --- a/pytouhou/ui/gamerunner.pyx +++ b/pytouhou/ui/gamerunner.pyx @@ -56,10 +56,10 @@ class GameRunner(GameRenderer): self.game = game self.background = background - self.texture_manager.preload(game.resource_loader.instanced_anms.values()) + self.texture_manager.load(game.resource_loader.instanced_anms.values()) if background: - self.background_renderer = BackgroundRenderer(self.texture_manager, self.use_fixed_pipeline) + self.background_renderer = BackgroundRenderer(self.use_fixed_pipeline) self.background_renderer.prerender(background) self.set_input(replay) diff --git a/pytouhou/ui/renderer.pyx b/pytouhou/ui/renderer.pyx --- a/pytouhou/ui/renderer.pyx +++ b/pytouhou/ui/renderer.pyx @@ -27,7 +27,7 @@ from pytouhou.lib.opengl cimport \ glGenBuffers) from .sprite cimport get_sprite_rendering_data -from .texture cimport TextureManager +from .texture import TextureManager MAX_ELEMENTS = 640*4*3 @@ -100,7 +100,7 @@ cdef class Renderer: glVertexAttribPointer(2, 4, GL_UNSIGNED_BYTE, True, sizeof(Vertex), 20) glEnableVertexAttribArray(2) - for (texture_key, blendfunc), indices in indices_by_texture.items(): + for (texture, blendfunc), indices in indices_by_texture.items(): #TODO: find a more elegent way. nb_indices = len(indices) @@ -109,7 +109,7 @@ cdef class Renderer: new_indices[i] = indices[i] glBlendFunc(GL_SRC_ALPHA, (GL_ONE_MINUS_SRC_ALPHA, GL_ONE)[blendfunc]) - glBindTexture(GL_TEXTURE_2D, self.texture_manager[texture_key]) + glBindTexture(GL_TEXTURE_2D, texture) glDrawElements(GL_TRIANGLES, nb_indices, GL_UNSIGNED_SHORT, new_indices) free(new_indices) diff --git a/pytouhou/ui/texture.pxd b/pytouhou/ui/texture.pxd deleted file mode 100644 --- a/pytouhou/ui/texture.pxd +++ /dev/null @@ -1,3 +0,0 @@ -cdef class TextureManager: - cdef public object loader - cdef public dict textures diff --git a/pytouhou/ui/texture.pyx b/pytouhou/ui/texture.pyx --- a/pytouhou/ui/texture.pyx +++ b/pytouhou/ui/texture.pyx @@ -16,7 +16,8 @@ from pytouhou.lib.opengl cimport \ (glTexParameteri, GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER, GL_LINEAR, GL_BGRA, GL_RGBA, GL_RGB, GL_LUMINANCE, GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4_REV, - glGenTextures, glBindTexture, glTexImage2D, GL_TEXTURE_2D, GLuint) + glGenTextures, glBindTexture, glTexImage2D, GL_TEXTURE_2D, GLuint, + glDeleteTextures) from pytouhou.lib.sdl import load_png, create_rgb_surface from pytouhou.formats.thtx import Texture #TODO: perhaps define that elsewhere? @@ -24,85 +25,81 @@ from pytouhou.formats.thtx import Textur import os -cdef class TextureManager: - def __init__(self, loader=None): - self.loader = loader - self.textures = {} +class TextureId(int): + def __del__(self): + cdef GLuint texture = self + glDeleteTextures(1, &texture) - def __getitem__(self, key): - if not key in self.textures: - self.textures[key] = self.load_texture(key) - return self.textures[key] +class TextureManager(object): + def __init__(self, loader=None): + self.loader = loader - def preload(self, anm_wrapper): - for anm in anm_wrapper: - anm.texture = self.load_png_texture(anm.first_name, anm.secondary_name) + def load(self, anm_list): + for anm in anm_list: + if not hasattr(anm, 'texture'): + texture = decode_png(self.loader, anm.first_name, anm.secondary_name) + anm.texture = load_texture(texture) - def load_png_texture(self, first_name, secondary_name): - image_file = load_png(self.loader.get_file(os.path.basename(first_name))) - width, height = image_file.width, image_file.height +cdef decode_png(loader, first_name, secondary_name): + image_file = load_png(loader.get_file(os.path.basename(first_name))) + width, height = image_file.width, image_file.height - # Support only 32 bits RGBA. Paletted surfaces are awful to work with. - #TODO: verify it doesn’t blow up on big-endian systems. - new_image = create_rgb_surface(width, height, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000) - new_image.blit(image_file) + # Support only 32 bits RGBA. Paletted surfaces are awful to work with. + #TODO: verify it doesn’t blow up on big-endian systems. + new_image = create_rgb_surface(width, height, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000) + new_image.blit(image_file) - if secondary_name: - alpha_file = load_png(self.loader.get_file(os.path.basename(secondary_name))) - assert (width == alpha_file.width and - height == alpha_file.height) + if secondary_name: + alpha_file = load_png(loader.get_file(os.path.basename(secondary_name))) + assert (width == alpha_file.width and height == alpha_file.height) - new_alpha_file = create_rgb_surface(width, height, 24) - new_alpha_file.blit(alpha_file) + new_alpha_file = create_rgb_surface(width, height, 24) + new_alpha_file.blit(alpha_file) - new_image.set_alpha(new_alpha_file) + new_image.set_alpha(new_alpha_file) - return Texture(width, height, -4, new_image.pixels) + return Texture(width, height, -4, new_image.pixels) - def load_texture(self, key): - cdef GLuint id_ - - if not isinstance(key, Texture): - first_name, secondary_name = key - key = self.load_png_texture(first_name, secondary_name) +cdef load_texture(thtx): + cdef GLuint texture - if key.fmt == 1: - format_ = GL_BGRA - type_ = GL_UNSIGNED_BYTE - composants = GL_RGBA - elif key.fmt == 3: - format_ = GL_RGB - type_ = GL_UNSIGNED_SHORT_5_6_5 - composants = GL_RGB - elif key.fmt == 5: - format_ = GL_BGRA - type_ = GL_UNSIGNED_SHORT_4_4_4_4_REV - composants = GL_RGBA - elif key.fmt == 7: - format_ = GL_LUMINANCE - type_ = GL_UNSIGNED_BYTE - composants = GL_LUMINANCE - elif key.fmt == -4: #XXX: non-standard - format_ = GL_RGBA - type_ = GL_UNSIGNED_BYTE - composants = GL_RGBA - else: - raise Exception('Unknown texture type') + if thtx.fmt == 1: + format_ = GL_BGRA + type_ = GL_UNSIGNED_BYTE + composants = GL_RGBA + elif thtx.fmt == 3: + format_ = GL_RGB + type_ = GL_UNSIGNED_SHORT_5_6_5 + composants = GL_RGB + elif thtx.fmt == 5: + format_ = GL_BGRA + type_ = GL_UNSIGNED_SHORT_4_4_4_4_REV + composants = GL_RGBA + elif thtx.fmt == 7: + format_ = GL_LUMINANCE + type_ = GL_UNSIGNED_BYTE + composants = GL_LUMINANCE + elif thtx.fmt == -4: #XXX: non-standard + format_ = GL_RGBA + type_ = GL_UNSIGNED_BYTE + composants = GL_RGBA + else: + raise Exception('Unknown texture type') - glGenTextures(1, &id_) - glBindTexture(GL_TEXTURE_2D, id_) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + glGenTextures(1, &texture) + glBindTexture(GL_TEXTURE_2D, texture) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - glTexImage2D(GL_TEXTURE_2D, 0, - composants, - key.width, key.height, - 0, - format_, type_, - key.data) + glTexImage2D(GL_TEXTURE_2D, 0, + composants, + thtx.width, thtx.height, + 0, + format_, type_, + thtx.data) - return id_ + return TextureId(texture)