# HG changeset patch # User Emmanuel Gil Peyrot # Date 1374001635 -7200 # Node ID 3a7b36324611020e0bc3ed5fae42f7d69c9e9cf4 # Parent 1c92721f8e49a06d1864a530eabe94aa47049098 Replace Pyglet’s image loader with our SDL2_image-based one. diff --git a/README b/README --- a/README +++ b/README @@ -16,6 +16,7 @@ Running: * Cython * Pyglet * SDL2 + * SDL2_image Building sample data: diff --git a/pytouhou/lib/sdl.pxd b/pytouhou/lib/sdl.pxd --- a/pytouhou/lib/sdl.pxd +++ b/pytouhou/lib/sdl.pxd @@ -91,3 +91,35 @@ cdef extern from "SDL_keyboard.h": cdef extern from "SDL_timer.h": Uint32 SDL_GetTicks() void SDL_Delay(Uint32 ms) + + +cdef extern from "SDL_rect.h": + ctypedef struct SDL_Rect: + int x, y + int w, h + + +cdef extern from "SDL_surface.h": + ctypedef struct SDL_Surface: + int w, h + unsigned char *pixels + + void SDL_FreeSurface(SDL_Surface *surface) + int SDL_BlitSurface(SDL_Surface *src, const SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect) + SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) + + +cdef extern from "SDL_rwops.h": + ctypedef struct SDL_RWops: + pass + + SDL_RWops *SDL_RWFromConstMem(const void *mem, int size) + int SDL_RWclose(SDL_RWops *context) + + +cdef extern from "SDL_image.h": + int IMG_INIT_PNG + + int IMG_Init(int flags) + void IMG_Quit() + SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src) diff --git a/pytouhou/lib/sdl.pyx b/pytouhou/lib/sdl.pyx --- a/pytouhou/lib/sdl.pyx +++ b/pytouhou/lib/sdl.pyx @@ -13,6 +13,7 @@ ## INIT_VIDEO = SDL_INIT_VIDEO +INIT_PNG = IMG_INIT_PNG GL_CONTEXT_MAJOR_VERSION = SDL_GL_CONTEXT_MAJOR_VERSION GL_CONTEXT_MINOR_VERSION = SDL_GL_CONTEXT_MINOR_VERSION @@ -63,15 +64,57 @@ cdef class Window: SDL_GL_DeleteContext(self.context) +cdef class Surface: + cdef SDL_Surface *surface + + def __dealloc__(self): + if self.surface != NULL: + SDL_FreeSurface(self.surface) + + property width: + def __get__(self): + return self.surface.w + + property height: + def __get__(self): + return self.surface.h + + property pixels: + def __get__(self): + return bytes(self.surface.pixels[:self.surface.w * self.surface.h * 4]) + + def blit(self, Surface other): + if SDL_BlitSurface(other.surface, NULL, self.surface, NULL) < 0: + raise SDLError(SDL_GetError()) + + def set_alpha(self, Surface alpha_surface): + nb_pixels = self.surface.w * self.surface.h + image = self.surface.pixels + alpha = alpha_surface.surface.pixels + + for i in xrange(nb_pixels): + # Only use the red value, assume the others are equal. + image[3+4*i] = alpha[3*i] + + def init(Uint32 flags): if SDL_Init(flags) < 0: raise SDLError(SDL_GetError()) +def img_init(Uint32 flags): + if IMG_Init(flags) != flags: + raise SDLError(SDL_GetError()) + + def quit(): SDL_Quit() +def img_quit(): + IMG_Quit() + + def gl_set_attribute(SDL_GLattr attr, int value): if SDL_GL_SetAttribute(attr, value) < 0: raise SDLError(SDL_GetError()) @@ -96,6 +139,25 @@ def get_keyboard_state(): return tuple([k is not False for k in state[:numkeys]]) +def load_png(file_): + data = file_.read() + rwops = SDL_RWFromConstMem(data, len(data)) + surface = Surface() + surface.surface = IMG_LoadPNG_RW(rwops) + SDL_RWclose(rwops) + if surface.surface == NULL: + raise SDLError(SDL_GetError()) + return surface + + +def create_rgb_surface(int width, int height, int depth, Uint32 rmask=0, Uint32 gmask=0, Uint32 bmask=0, Uint32 amask=0): + surface = Surface() + surface.surface = SDL_CreateRGBSurface(0, width, height, depth, rmask, gmask, bmask, amask) + if surface.surface == NULL: + raise SDLError(SDL_GetError()) + return surface + + def get_ticks(): return SDL_GetTicks() diff --git a/pytouhou/lib/sdl.pyxbld b/pytouhou/lib/sdl.pyxbld --- a/pytouhou/lib/sdl.pyxbld +++ b/pytouhou/lib/sdl.pyxbld @@ -18,7 +18,7 @@ from distutils.extension import Extensio from subprocess import check_output COMMAND = 'pkg-config' -LIBRARIES = ['sdl2'] +LIBRARIES = ['sdl2', 'SDL2_image'] def make_ext(modname, pyxfilename): """ Compile and link with the corrects options. """ diff --git a/pytouhou/ui/gamerunner.py b/pytouhou/ui/gamerunner.py --- a/pytouhou/ui/gamerunner.py +++ b/pytouhou/ui/gamerunner.py @@ -88,6 +88,7 @@ class GameRunner(GameRenderer): GameRenderer.__init__(self, resource_loader, game, background) sdl.init(sdl.INIT_VIDEO) + sdl.img_init(sdl.INIT_PNG) sdl.gl_set_attribute(sdl.GL_CONTEXT_MAJOR_VERSION, 2) sdl.gl_set_attribute(sdl.GL_CONTEXT_MINOR_VERSION, 1) sdl.gl_set_attribute(sdl.GL_DOUBLEBUFFER, int(double_buffer)) @@ -188,6 +189,7 @@ class GameRunner(GameRenderer): self.win.gl_delete_context() self.win.destroy_window() + sdl.img_quit() sdl.quit() diff --git a/pytouhou/ui/sprite.pyx b/pytouhou/ui/sprite.pyx --- a/pytouhou/ui/sprite.pyx +++ b/pytouhou/ui/sprite.pyx @@ -61,8 +61,8 @@ cpdef object get_sprite_rendering_data(o tox, toy = sprite.texoffsets uvs = (tx * x_1 + tox, (tx + tw) * x_1 + tox, - 1. - (ty * y_1 + toy), - 1. - ((ty + th) * y_1 + toy)) + ty * y_1 + toy, + (ty + th) * y_1 + toy) (x1, x2 , x3, x4), (y1, y2, y3, y4), (z1, z2, z3, z4), _ = vertmat.data diff --git a/pytouhou/ui/texture.pyx b/pytouhou/ui/texture.pyx --- a/pytouhou/ui/texture.pyx +++ b/pytouhou/ui/texture.pyx @@ -12,9 +12,6 @@ ## GNU General Public License for more details. ## -from libc.stdlib cimport malloc, free - -import pyglet 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, @@ -22,6 +19,7 @@ from pyglet.gl import (glTexParameteri, glGenTextures, glBindTexture, glTexImage2D, GL_TEXTURE_2D) from ctypes import c_uint, byref +from pytouhou.lib.sdl import load_png, create_rgb_surface import os from pytouhou.formats.thtx import Texture #TODO: perhaps define that elsewhere? @@ -45,35 +43,25 @@ cdef class TextureManager: def load_png_texture(self, first_name, secondary_name): - cdef char *image, *alpha, *new_data - cdef unsigned int i, width, height, pixels + image_file = load_png(self.loader.get_file(os.path.basename(first_name))) + width, height = image_file.width, image_file.height - 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) + # 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 = 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) - - pixels = width * height - - alpha_data = alpha_file.get_data('RGB', width * 3) - image = image_data - alpha = alpha_data + alpha_file = load_png(self.loader.get_file(os.path.basename(secondary_name))) + assert (width == alpha_file.width and + height == alpha_file.height) - # TODO: further optimizations - new_data = malloc(pixels * 4) - for i in range(pixels): - new_data[i*4] = image[i*3] - 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] - data = new_data[:(pixels * 4)] - free(new_data) - return Texture(width, height, -4, data) + new_alpha_file = create_rgb_surface(width, height, 24) + new_alpha_file.blit(alpha_file) - return Texture(width, height, -3, image_data) + new_image.set_alpha(new_alpha_file) + + return Texture(width, height, -4, new_image.pixels) def load_texture(self, key): @@ -97,10 +85,6 @@ cdef class TextureManager: 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 diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ except ImportError: COMMAND = 'pkg-config' -LIBRARIES = ['sdl2'] +LIBRARIES = ['sdl2', 'SDL2_image'] packages = [] extension_names = []