changeset 393:9e2cbb2c2c64

Implement THTX, uncompressed textures stored inside ANM files, and use it instead of pyglet’s own wrapper.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Wed, 06 Feb 2013 19:55:54 +0100
parents 45e1a9a37e66
children 346614f788f1
files pytouhou/formats/thtx.py pytouhou/ui/gamerenderer.py pytouhou/ui/renderer.pyx pytouhou/ui/sprite.pyx pytouhou/ui/texture.pyx
diffstat 5 files changed, 86 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/pytouhou/formats/thtx.py
@@ -0,0 +1,21 @@
+# -*- encoding: utf-8 -*-
+##
+## Copyright (C) 2013 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
+##
+## 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.
+##
+
+
+class Texture(object):
+    def __init__(self, width, height, fmt, data):
+        self.width = width
+        self.height = height
+        self.fmt = fmt
+        self.data = data
--- a/pytouhou/ui/gamerenderer.py
+++ b/pytouhou/ui/gamerenderer.py
@@ -102,7 +102,7 @@ class GameRenderer(Renderer):
             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].id)
+                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)
--- a/pytouhou/ui/renderer.pyx
+++ b/pytouhou/ui/renderer.pyx
@@ -89,7 +89,7 @@ cdef class Renderer:
             nb_indices = len(indices)
             indices = pack(str(nb_indices) + 'H', *indices)
             glBlendFunc(GL_SRC_ALPHA, (GL_ONE_MINUS_SRC_ALPHA, GL_ONE)[blendfunc])
-            glBindTexture(GL_TEXTURE_2D, self.texture_manager[texture_key].id)
+            glBindTexture(GL_TEXTURE_2D, self.texture_manager[texture_key])
             glDrawElements(GL_TRIANGLES, nb_indices, GL_UNSIGNED_SHORT, indices)
 
 
--- a/pytouhou/ui/sprite.pyx
+++ b/pytouhou/ui/sprite.pyx
@@ -66,7 +66,7 @@ cpdef object get_sprite_rendering_data(o
 
     (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
+    key = sprite.anm.texture, sprite.blendfunc
     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
--- a/pytouhou/ui/texture.pyx
+++ b/pytouhou/ui/texture.pyx
@@ -15,10 +15,17 @@
 from libc.stdlib cimport malloc, free
 
 import pyglet
-from pyglet.gl import (glTexParameteri,
-                       GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
+from pyglet.gl import (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)
+from ctypes import c_uint, byref
 import os
 
+from pytouhou.formats.thtx import Texture #TODO: perhaps define that elsewhere?
+
 
 cdef class TextureManager:
     def __init__(self, loader=None):
@@ -33,32 +40,24 @@ cdef class TextureManager:
 
 
     def preload(self, anm_wrapper):
-        try:
-            anms = anm_wrapper.anm_files
-        except AttributeError:
-            anms = anm_wrapper
-
-        for anm in anms:
-            key = anm.first_name, anm.secondary_name
-            texture = self[key]
+        for anm in anm_wrapper:
+            anm.texture = self.load_png_texture(anm.first_name, anm.secondary_name)
 
 
-    def load_texture(self, key):
+    def load_png_texture(self, first_name, secondary_name):
         cdef char *image, *alpha, *new_data
         cdef unsigned int i, width, height, pixels
 
-        first_name, secondary_name = key
-
         image_file = pyglet.image.load(first_name, file=self.loader.get_file(os.path.basename(first_name)))
+        width, height = image_file.width, image_file.height
+        image_data = image_file.get_data('RGB', width * 3)
 
         if secondary_name:
             alpha_file = pyglet.image.load(secondary_name, file=self.loader.get_file(os.path.basename(secondary_name)))
             assert (image_file.width, image_file.height) == (alpha_file.width, image_file.height)
 
-            width, height = image_file.width, image_file.height
             pixels = width * height
 
-            image_data = image_file.get_data('RGB', width * 3)
             alpha_data = alpha_file.get_data('RGB', width * 3)
             image = <char *>image_data
             alpha = <char *>alpha_data
@@ -70,13 +69,56 @@ cdef class TextureManager:
                 new_data[i*4+1] = image[i*3+1]
                 new_data[i*4+2] = image[i*3+2]
                 new_data[i*4+3] = alpha[i*3]
-            image_file = pyglet.image.ImageData(width, height, 'RGBA', new_data[:(pixels * 4)])
+            data = new_data[:(pixels * 4)]
             free(new_data)
+            return Texture(width, height, -4, data)
 
-        texture = image_file.get_texture()
+        return Texture(width, height, -3, image_data)
+
+
+    def load_texture(self, key):
+        if not isinstance(key, Texture):
+            first_name, secondary_name = key
+            key = self.load_png_texture(first_name, secondary_name)
 
-        glTexParameteri(texture.target, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
-        glTexParameteri(texture.target, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
+        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 == -3: #XXX: non-standard, remove it!
+            format_ = GL_RGB
+            type_ = GL_UNSIGNED_BYTE
+            composants = GL_RGB
+        elif key.fmt == -4: #XXX: non-standard
+            format_ = GL_RGBA
+            type_ = GL_UNSIGNED_BYTE
+            composants = GL_RGBA
+        else:
+            raise Exception('Unknown texture type')
 
-        return texture
+        id_ = c_uint()
+        glGenTextures(1, byref(id_))
+        glBindTexture(GL_TEXTURE_2D, id_.value)
+        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)
+
+        return id_.value