changeset 455:6864a38b2413

Make pytouhou.lib.sdl cimportable, and convert pytouhou.ui.window.* to extension types.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Mon, 02 Sep 2013 22:16:38 +0200
parents a502887557ac
children cae1ae9de430
files pytouhou/lib/_sdl.pxd pytouhou/lib/sdl.pxd pytouhou/lib/sdl.pyx pytouhou/ui/anmrenderer.pyx pytouhou/ui/gamerunner.pyx pytouhou/ui/music.py pytouhou/ui/music.pyx pytouhou/ui/texture.pyx pytouhou/ui/window.pyx setup.py
diffstat 10 files changed, 408 insertions(+), 313 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pytouhou/lib/_sdl.pxd	Mon Sep 02 22:16:38 2013 +0200
@@ -0,0 +1,166 @@
+# -*- 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.
+##
+
+cdef extern from "SDL.h" nogil:
+    ctypedef unsigned int Uint32
+    ctypedef unsigned short Uint16
+    ctypedef unsigned char Uint8
+
+    int SDL_INIT_VIDEO
+
+    int SDL_Init(Uint32 flags)
+    void SDL_Quit()
+
+
+IF UNAME_SYSNAME == "Windows":
+    cdef extern from "SDL_main.h" nogil:
+        void SDL_SetMainReady()
+
+
+cdef extern from "SDL_error.h" nogil:
+    const char *SDL_GetError()
+
+
+cdef extern from "SDL_video.h" nogil:
+    ctypedef enum SDL_GLattr:
+        SDL_GL_CONTEXT_MAJOR_VERSION
+        SDL_GL_CONTEXT_MINOR_VERSION
+        SDL_GL_DOUBLEBUFFER
+        SDL_GL_DEPTH_SIZE
+
+    ctypedef enum SDL_WindowFlags:
+        SDL_WINDOWPOS_CENTERED
+        SDL_WINDOW_OPENGL
+        SDL_WINDOW_SHOWN
+
+    ctypedef struct SDL_Window:
+        pass
+
+    ctypedef void *SDL_GLContext
+
+    int SDL_GL_SetAttribute(SDL_GLattr attr, int value)
+    SDL_Window *SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
+    SDL_GLContext SDL_GL_CreateContext(SDL_Window *window)
+    void SDL_GL_SwapWindow(SDL_Window *window)
+    void SDL_GL_DeleteContext(SDL_GLContext context)
+    void SDL_DestroyWindow(SDL_Window *window)
+
+    void SDL_SetWindowSize(SDL_Window *window, int w, int h)
+
+
+cdef extern from "SDL_scancode.h" nogil:
+    ctypedef enum SDL_Scancode:
+        SDL_SCANCODE_Z
+        SDL_SCANCODE_X
+        SDL_SCANCODE_LSHIFT
+        SDL_SCANCODE_UP
+        SDL_SCANCODE_DOWN
+        SDL_SCANCODE_LEFT
+        SDL_SCANCODE_RIGHT
+        SDL_SCANCODE_LCTRL
+        SDL_SCANCODE_ESCAPE
+
+
+cdef extern from "SDL_events.h" nogil:
+    ctypedef enum SDL_EventType:
+        SDL_KEYDOWN
+        SDL_QUIT
+
+    ctypedef struct SDL_Keysym:
+        SDL_Scancode scancode
+
+    ctypedef struct SDL_KeyboardEvent:
+        Uint32 type
+        SDL_Keysym keysym
+
+    ctypedef union SDL_Event:
+        Uint32 type
+        SDL_KeyboardEvent key
+
+    int SDL_PollEvent(SDL_Event *event)
+
+
+cdef extern from "SDL_keyboard.h" nogil:
+    const Uint8 *SDL_GetKeyboardState(int *numkeys)
+
+
+cdef extern from "SDL_timer.h" nogil:
+    Uint32 SDL_GetTicks()
+    void SDL_Delay(Uint32 ms)
+
+
+cdef extern from "SDL_rect.h" nogil:
+    ctypedef struct SDL_Rect:
+        int x, y
+        int w, h
+
+
+cdef extern from "SDL_surface.h" nogil:
+    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" nogil:
+    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" nogil:
+    int IMG_INIT_PNG
+
+    int IMG_Init(int flags)
+    void IMG_Quit()
+    SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src)
+
+
+cdef extern from "SDL_mixer.h" nogil:
+    ctypedef enum:
+        MIX_DEFAULT_FORMAT
+
+    ctypedef struct Mix_Music:
+        pass
+
+    ctypedef struct Mix_Chunk:
+        pass
+
+    int Mix_Init(int flags)
+    void Mix_Quit()
+
+    int Mix_OpenAudio(int frequency, Uint16 format_, int channels, int chunksize)
+    void Mix_CloseAudio()
+
+    int Mix_AllocateChannels(int numchans)
+
+    Mix_Music *Mix_LoadMUS(const char *filename)
+    Mix_Chunk *Mix_LoadWAV_RW(SDL_RWops *src, int freesrc)
+
+    void Mix_FreeMusic(Mix_Music *music)
+    void Mix_FreeChunk(Mix_Chunk *chunk)
+
+    int Mix_PlayMusic(Mix_Music *music, int loops)
+    #int Mix_SetLoopPoints(Mix_Music *music, double start, double end)
+
+    int Mix_Volume(int channel, int volume)
+    int Mix_VolumeChunk(Mix_Chunk *chunk, int volume)
+    int Mix_VolumeMusic(int volume)
+
+    int Mix_PlayChannel(int channel, Mix_Chunk *chunk, int loops)
--- a/pytouhou/lib/sdl.pxd	Sat Aug 31 07:39:04 2013 +0200
+++ b/pytouhou/lib/sdl.pxd	Mon Sep 02 22:16:38 2013 +0200
@@ -12,155 +12,89 @@
 ## GNU General Public License for more details.
 ##
 
-cdef extern from "SDL.h":
-    ctypedef unsigned int Uint32
-    ctypedef unsigned short Uint16
-    ctypedef unsigned char Uint8
-
-    int SDL_INIT_VIDEO
-
-    int SDL_Init(Uint32 flags)
-    void SDL_Quit()
-
-
-IF UNAME_SYSNAME == "Windows":
-    cdef extern from "SDL_main.h":
-        void SDL_SetMainReady()
-
-
-cdef extern from "SDL_error.h":
-    const char *SDL_GetError()
+from _sdl cimport *
 
 
-cdef extern from "SDL_video.h":
-    ctypedef enum SDL_GLattr:
-        SDL_GL_CONTEXT_MAJOR_VERSION
-        SDL_GL_CONTEXT_MINOR_VERSION
-        SDL_GL_DOUBLEBUFFER
-        SDL_GL_DEPTH_SIZE
+cdef Uint32 INIT_VIDEO
+cdef Uint32 INIT_PNG
 
-    ctypedef enum SDL_WindowFlags:
-        SDL_WINDOWPOS_CENTERED
-        SDL_WINDOW_OPENGL
-        SDL_WINDOW_SHOWN
+cdef SDL_GLattr GL_CONTEXT_MAJOR_VERSION
+cdef SDL_GLattr GL_CONTEXT_MINOR_VERSION
+cdef SDL_GLattr GL_DOUBLEBUFFER
+cdef SDL_GLattr GL_DEPTH_SIZE
+
+cdef SDL_WindowFlags WINDOWPOS_CENTERED
+cdef SDL_WindowFlags WINDOW_OPENGL
+cdef SDL_WindowFlags WINDOW_SHOWN
 
-    ctypedef struct SDL_Window:
-        pass
-
-    ctypedef void *SDL_GLContext
+#TODO: should be SDL_Scancode, but Cython doesn’t allow enum for array indexing.
+cdef long SCANCODE_Z
+cdef long SCANCODE_X
+cdef long SCANCODE_LSHIFT
+cdef long SCANCODE_UP
+cdef long SCANCODE_DOWN
+cdef long SCANCODE_LEFT
+cdef long SCANCODE_RIGHT
+cdef long SCANCODE_LCTRL
+cdef long SCANCODE_ESCAPE
 
-    int SDL_GL_SetAttribute(SDL_GLattr attr, int value)
-    SDL_Window *SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags)
-    SDL_GLContext SDL_GL_CreateContext(SDL_Window *window)
-    void SDL_GL_SwapWindow(SDL_Window *window)
-    void SDL_GL_DeleteContext(SDL_GLContext context)
-    void SDL_DestroyWindow(SDL_Window *window)
+cdef SDL_EventType KEYDOWN
+cdef SDL_EventType QUIT
 
-    void SDL_SetWindowSize(SDL_Window *window, int w, int h)
+cdef Uint16 DEFAULT_FORMAT
 
 
-cdef extern from "SDL_scancode.h":
-    ctypedef enum SDL_Scancode:
-        SDL_SCANCODE_Z
-        SDL_SCANCODE_X
-        SDL_SCANCODE_LSHIFT
-        SDL_SCANCODE_UP
-        SDL_SCANCODE_DOWN
-        SDL_SCANCODE_LEFT
-        SDL_SCANCODE_RIGHT
-        SDL_SCANCODE_LCTRL
-        SDL_SCANCODE_ESCAPE
+cdef class Window:
+    cdef SDL_Window *window
+    cdef SDL_GLContext context
+
+    cdef void gl_create_context(self) except *
+    cdef void gl_swap_window(self) nogil
+    cdef void set_window_size(self, int width, int height) nogil
 
 
-cdef extern from "SDL_events.h":
-    ctypedef enum SDL_EventType:
-        SDL_KEYDOWN
-        SDL_QUIT
-
-    ctypedef struct SDL_Keysym:
-        SDL_Scancode scancode
+cdef class Surface:
+    cdef SDL_Surface *surface
 
-    ctypedef struct SDL_KeyboardEvent:
-        Uint32 type
-        SDL_Keysym keysym
-
-    ctypedef union SDL_Event:
-        Uint32 type
-        SDL_KeyboardEvent key
-
-    int SDL_PollEvent(SDL_Event *event)
+    cdef void blit(self, Surface other) except *
+    cdef void set_alpha(self, Surface alpha_surface) nogil
 
 
-cdef extern from "SDL_keyboard.h":
-    const Uint8 *SDL_GetKeyboardState(int *numkeys)
-
+cdef class Music:
+    cdef Mix_Music *music
 
-cdef extern from "SDL_timer.h":
-    Uint32 SDL_GetTicks()
-    void SDL_Delay(Uint32 ms)
+    cdef void play(self, int loops) nogil
+    cdef void set_loop_points(self, double start, double end) nogil
 
 
-cdef extern from "SDL_rect.h":
-    ctypedef struct SDL_Rect:
-        int x, y
-        int w, h
-
+cdef class Chunk:
+    cdef Mix_Chunk *chunk
 
-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 void play(self, int channel, int loops) nogil
+    cdef void set_volume(self, float volume) nogil
 
 
-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
+cdef void init(Uint32 flags) except *
+cdef void img_init(Uint32 flags) except *
+cdef void mix_init(int flags) except *
 
-    int IMG_Init(int flags)
-    void IMG_Quit()
-    SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src)
-
-
-cdef extern from "SDL_mixer.h":
-    ctypedef enum:
-        MIX_DEFAULT_FORMAT
-
-    ctypedef struct Mix_Music:
-        pass
+IF UNAME_SYSNAME == "Windows":
+    cdef void set_main_ready()
 
-    ctypedef struct Mix_Chunk:
-        pass
-
-    int Mix_Init(int flags)
-    void Mix_Quit()
-
-    int Mix_OpenAudio(int frequency, Uint16 format_, int channels, int chunksize)
-    void Mix_CloseAudio()
-
-    int Mix_AllocateChannels(int numchans)
-
-    Mix_Music *Mix_LoadMUS(const char *filename)
-    Mix_Chunk *Mix_LoadWAV_RW(SDL_RWops *src, int freesrc)
-
-    void Mix_FreeMusic(Mix_Music *music)
-    void Mix_FreeChunk(Mix_Chunk *chunk)
-
-    int Mix_PlayMusic(Mix_Music *music, int loops)
-    #int Mix_SetLoopPoints(Mix_Music *music, double start, double end)
-
-    int Mix_Volume(int channel, int volume)
-    int Mix_VolumeChunk(Mix_Chunk *chunk, int volume)
-    int Mix_VolumeMusic(int volume)
-
-    int Mix_PlayChannel(int channel, Mix_Chunk *chunk, int loops)
+cdef void quit() nogil
+cdef void img_quit() nogil
+cdef void mix_quit() nogil
+cdef void gl_set_attribute(SDL_GLattr attr, int value) except *
+cdef list poll_events()
+cdef const Uint8* get_keyboard_state() nogil
+cdef Surface load_png(file_)
+cdef Surface create_rgb_surface(int width, int height, int depth, Uint32 rmask=*, Uint32 gmask=*, Uint32 bmask=*, Uint32 amask=*)
+cdef void mix_open_audio(int frequency, Uint16 format_, int channels, int chunksize) except *
+cdef void mix_close_audio() nogil
+cdef void mix_allocate_channels(int numchans) except *
+cdef int mix_volume(int channel, float volume) nogil
+cdef int mix_volume_music(float volume) nogil
+cdef Music load_music(const char *filename)
+cdef Chunk load_chunk(file_)
+cdef Uint32 get_ticks() nogil
+cdef void delay(Uint32 ms) nogil
--- a/pytouhou/lib/sdl.pyx	Sat Aug 31 07:39:04 2013 +0200
+++ b/pytouhou/lib/sdl.pyx	Mon Sep 02 22:16:38 2013 +0200
@@ -45,56 +45,43 @@
 
 
 cdef class Window:
-    cdef SDL_Window *window
-    cdef SDL_GLContext context
-
     def __init__(self, const char *title, int x, int y, int w, int h, Uint32 flags):
         self.window = SDL_CreateWindow(title, x, y, w, h, flags)
         if self.window == NULL:
             raise SDLError(SDL_GetError())
 
-    def destroy_window(self):
-        SDL_DestroyWindow(self.window)
+    def __dealloc__(self):
+        if self.context != NULL:
+            SDL_GL_DeleteContext(self.context)
+        if self.window != NULL:
+            SDL_DestroyWindow(self.window)
 
-    def gl_create_context(self):
+    cdef void gl_create_context(self) except *:
         self.context = SDL_GL_CreateContext(self.window)
         if self.context == NULL:
             raise SDLError(SDL_GetError())
 
-    def gl_swap_window(self):
+    cdef void gl_swap_window(self) nogil:
         SDL_GL_SwapWindow(self.window)
 
-    def gl_delete_context(self):
-        SDL_GL_DeleteContext(self.context)
-
-    def set_window_size(self, width, height):
+    cdef void set_window_size(self, int width, int height) nogil:
         SDL_SetWindowSize(self.window, width, height)
 
 
 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):
+    cdef void 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):
+    cdef void set_alpha(self, Surface alpha_surface) nogil:
         nb_pixels = self.surface.w * self.surface.h
         image = self.surface.pixels
         alpha = alpha_surface.surface.pixels
@@ -105,73 +92,68 @@
 
 
 cdef class Music:
-    cdef Mix_Music *music
-
     def __dealloc__(self):
         if self.music != NULL:
             Mix_FreeMusic(self.music)
 
-    def play(self, int loops):
+    cdef void play(self, int loops) nogil:
         Mix_PlayMusic(self.music, loops)
 
-    def set_loop_points(self, double start, double end):
+    cdef void set_loop_points(self, double start, double end) nogil:
         #Mix_SetLoopPoints(self.music, start, end)
         pass
 
 
 cdef class Chunk:
-    cdef Mix_Chunk *chunk
-
     def __dealloc__(self):
         if self.chunk != NULL:
             Mix_FreeChunk(self.chunk)
 
-    property volume:
-        def __set__(self, float volume):
-            Mix_VolumeChunk(self.chunk, int(volume * 128))
-
-    def play(self, int channel, int loops):
+    cdef void play(self, int channel, int loops) nogil:
         Mix_PlayChannel(channel, self.chunk, loops)
 
+    cdef void set_volume(self, float volume) nogil:
+        Mix_VolumeChunk(self.chunk, int(volume * 128))
 
-def init(Uint32 flags):
+
+cdef void init(Uint32 flags) except *:
     if SDL_Init(flags) < 0:
         raise SDLError(SDL_GetError())
 
 
-def img_init(Uint32 flags):
+cdef void img_init(Uint32 flags) except *:
     if IMG_Init(flags) != flags:
         raise SDLError(SDL_GetError())
 
 
-def mix_init(int flags):
+cdef void mix_init(int flags) except *:
     if Mix_Init(flags) != flags:
         raise SDLError(SDL_GetError())
 
 
 IF UNAME_SYSNAME == "Windows":
-    def set_main_ready():
+    cdef void set_main_ready():
         SDL_SetMainReady()
 
 
-def quit():
+cdef void quit() nogil:
     SDL_Quit()
 
 
-def img_quit():
+cdef void img_quit() nogil:
     IMG_Quit()
 
 
-def mix_quit():
+cdef void mix_quit() nogil:
     Mix_Quit()
 
 
-def gl_set_attribute(SDL_GLattr attr, int value):
+cdef void gl_set_attribute(SDL_GLattr attr, int value) except *:
     if SDL_GL_SetAttribute(attr, value) < 0:
         raise SDLError(SDL_GetError())
 
 
-def poll_events():
+cdef list poll_events():
     cdef SDL_Event event
     ret = []
     while SDL_PollEvent(&event):
@@ -182,15 +164,11 @@
     return ret
 
 
-def get_keyboard_state():
-    cdef int numkeys
-    cdef bint k
-    cdef const Uint8 *state
-    state = SDL_GetKeyboardState(&numkeys)
-    return tuple([k is not False for k in state[:numkeys]])
+cdef const Uint8* get_keyboard_state() nogil:
+    return SDL_GetKeyboardState(NULL)
 
 
-def load_png(file_):
+cdef Surface load_png(file_):
     data = file_.read()
     rwops = SDL_RWFromConstMem(<char*>data, len(data))
     surface = Surface()
@@ -201,7 +179,7 @@
     return surface
 
 
-def create_rgb_surface(int width, int height, int depth, Uint32 rmask=0, Uint32 gmask=0, Uint32 bmask=0, Uint32 amask=0):
+cdef Surface 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:
@@ -209,29 +187,29 @@
     return surface
 
 
-def mix_open_audio(int frequency, Uint16 format_, int channels, int chunksize):
+cdef void mix_open_audio(int frequency, Uint16 format_, int channels, int chunksize) except *:
     if Mix_OpenAudio(frequency, format_, channels, chunksize) < 0:
         raise SDLError(SDL_GetError())
 
 
-def mix_close_audio():
+cdef void mix_close_audio() nogil:
     Mix_CloseAudio()
 
 
-def mix_allocate_channels(int numchans):
+cdef void mix_allocate_channels(int numchans) except *:
     if Mix_AllocateChannels(numchans) != numchans:
         raise SDLError(SDL_GetError())
 
 
-def mix_volume(int channel, float volume):
+cdef int mix_volume(int channel, float volume) nogil:
     return Mix_Volume(channel, int(volume * 128))
 
 
-def mix_volume_music(float volume):
+cdef int mix_volume_music(float volume) nogil:
     return Mix_VolumeMusic(int(volume * 128))
 
 
-def load_music(const char *filename):
+cdef Music load_music(const char *filename):
     music = Music()
     music.music = Mix_LoadMUS(filename)
     if music.music == NULL:
@@ -239,7 +217,7 @@
     return music
 
 
-def load_chunk(file_):
+cdef Chunk load_chunk(file_):
     cdef SDL_RWops *rwops
     chunk = Chunk()
     data = file_.read()
@@ -250,9 +228,9 @@
     return chunk
 
 
-def get_ticks():
+cdef Uint32 get_ticks() nogil:
     return SDL_GetTicks()
 
 
-def delay(Uint32 ms):
+cdef void delay(Uint32 ms) nogil:
     SDL_Delay(ms)
--- a/pytouhou/ui/anmrenderer.pyx	Sat Aug 31 07:39:04 2013 +0200
+++ b/pytouhou/ui/anmrenderer.pyx	Mon Sep 02 22:16:38 2013 +0200
@@ -24,7 +24,7 @@
 from .renderer import Renderer
 from .shaders.eosd import GameShader
 
-from pytouhou.lib import sdl
+from pytouhou.lib cimport sdl
 
 
 logger = get_logger(__name__)
--- a/pytouhou/ui/gamerunner.pyx	Sat Aug 31 07:39:04 2013 +0200
+++ b/pytouhou/ui/gamerunner.pyx	Mon Sep 02 22:16:38 2013 +0200
@@ -12,7 +12,7 @@
 ## GNU General Public License for more details.
 ##
 
-from pytouhou.lib import sdl
+from pytouhou.lib cimport sdl
 
 from pytouhou.lib.opengl cimport \
          (glMatrixMode, glEnable, glDisable, glViewport, glScissor,
@@ -179,7 +179,7 @@
     def render_interface(self):
         elements = []
         interface = self.game.interface
-        interface.labels['framerate'].set_text('%.2ffps' % self.window.clock.get_fps())
+        interface.labels['framerate'].set_text('%.2ffps' % self.window.get_fps())
 
         if self.use_fixed_pipeline:
             glMatrixMode(GL_MODELVIEW)
--- a/pytouhou/ui/music.py	Sat Aug 31 07:39:04 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-# -*- encoding: utf-8 -*-
-##
-## Copyright (C) 2012 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.
-##
-
-
-from os.path import join
-from glob import glob
-from pytouhou.lib import sdl
-from pytouhou.utils.helpers import get_logger
-
-logger = get_logger(__name__)
-
-
-class MusicPlayer(object):
-    def __init__(self, resource_loader, bgms):
-        self.bgms = []
-        for bgm in bgms:
-            if not bgm:
-                self.bgms.append(None)
-                continue
-            posname = bgm[1].replace('bgm/', '').replace('.mid', '.pos')
-            try:
-                track = resource_loader.get_track(posname)
-            except KeyError:
-                self.bgms.append(None)
-                logger.warn(u'Music description “%s” not found.', posname)
-                continue
-            globname = join(resource_loader.game_dir, bgm[1]).replace('.mid', '.*')
-            filenames = glob(globname)
-            for filename in reversed(filenames):
-                try:
-                    source = sdl.load_music(filename)
-                except sdl.SDLError as error:
-                    logger.debug(u'Music file “%s” unreadable: %s', filename, error)
-                    continue
-                else:
-                    source.set_loop_points(track.start / 44100., track.end / 44100.) #TODO: retrieve the sample rate from the actual track.
-                    self.bgms.append(source)
-                    logger.debug(u'Music file “%s” opened.', filename)
-                    break
-            else:
-                self.bgms.append(None)
-                logger.warn(u'No working music file for “%s”, disabling bgm.', globname)
-
-    def play(self, index):
-        bgm = self.bgms[index]
-        if bgm:
-            bgm.play(-1)
-
-
-class SFXPlayer(object):
-    def __init__(self, loader, volume=.42):
-        self.loader = loader
-        self.channels = {}
-        self.sounds = {}
-        self.volume = volume
-        self.next_channel = 0
-
-    def get_channel(self, name):
-        if name not in self.channels:
-            self.channels[name] = self.next_channel
-            self.next_channel += 1
-        return self.channels[name]
-
-    def get_sound(self, name):
-        if name not in self.sounds:
-            wave_file = self.loader.get_file(name)
-            self.sounds[name] = sdl.load_chunk(wave_file)
-            self.sounds[name].volume = self.volume
-        return self.sounds[name]
-
-    def play(self, name, volume=None):
-        sound = self.get_sound(name)
-        channel = self.get_channel(name)
-        if volume:
-            sdl.mix_volume(channel, volume)
-        sound.play(channel, 0)
-
-
-class NullPlayer(object):
-    def __init__(self, loader=None, bgms=None):
-        pass
-
-    def play(self, name, volume=None):
-        pass
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pytouhou/ui/music.pyx	Mon Sep 02 22:16:38 2013 +0200
@@ -0,0 +1,98 @@
+# -*- encoding: utf-8 -*-
+##
+## Copyright (C) 2012 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.
+##
+
+
+from os.path import join
+from glob import glob
+from pytouhou.lib cimport sdl
+from pytouhou.utils.helpers import get_logger
+
+logger = get_logger(__name__)
+
+
+class MusicPlayer(object):
+    def __init__(self, resource_loader, bgms):
+        self.bgms = []
+        for bgm in bgms:
+            if not bgm:
+                self.bgms.append(None)
+                continue
+            posname = bgm[1].replace('bgm/', '').replace('.mid', '.pos')
+            try:
+                track = resource_loader.get_track(posname)
+            except KeyError:
+                self.bgms.append(None)
+                logger.warn(u'Music description “%s” not found.', posname)
+                continue
+            globname = join(resource_loader.game_dir, bgm[1]).replace('.mid', '.*')
+            filenames = glob(globname)
+            for filename in reversed(filenames):
+                try:
+                    source = sdl.load_music(filename)
+                except sdl.SDLError as error:
+                    logger.debug(u'Music file “%s” unreadable: %s', filename, error)
+                    continue
+                else:
+                    source.set_loop_points(track.start / 44100., track.end / 44100.) #TODO: retrieve the sample rate from the actual track.
+                    self.bgms.append(source)
+                    logger.debug(u'Music file “%s” opened.', filename)
+                    break
+            else:
+                self.bgms.append(None)
+                logger.warn(u'No working music file for “%s”, disabling bgm.', globname)
+
+    def play(self, index):
+        cdef sdl.Music bgm
+        bgm = self.bgms[index]
+        if bgm:
+            bgm.play(-1)
+
+
+class SFXPlayer(object):
+    def __init__(self, loader, volume=.42):
+        self.loader = loader
+        self.channels = {}
+        self.sounds = {}
+        self.volume = volume
+        self.next_channel = 0
+
+    def get_channel(self, name):
+        if name not in self.channels:
+            self.channels[name] = self.next_channel
+            self.next_channel += 1
+        return self.channels[name]
+
+    def get_sound(self, name):
+        if name not in self.sounds:
+            wave_file = self.loader.get_file(name)
+            chunk = sdl.load_chunk(wave_file)
+            chunk.set_volume(self.volume)
+            self.sounds[name] = chunk
+        return self.sounds[name]
+
+    def play(self, name, volume=None):
+        cdef sdl.Chunk sound
+        sound = self.get_sound(name)
+        channel = self.get_channel(name)
+        if volume:
+            sdl.mix_volume(channel, volume)
+        sound.play(channel, 0)
+
+
+class NullPlayer(object):
+    def __init__(self, loader=None, bgms=None):
+        pass
+
+    def play(self, name, volume=None):
+        pass
--- a/pytouhou/ui/texture.pyx	Sat Aug 31 07:39:04 2013 +0200
+++ b/pytouhou/ui/texture.pyx	Mon Sep 02 22:16:38 2013 +0200
@@ -19,7 +19,7 @@
           glGenTextures, glBindTexture, glTexImage2D, GL_TEXTURE_2D, GLuint,
           glDeleteTextures)
 
-from pytouhou.lib.sdl import load_png, create_rgb_surface
+from pytouhou.lib.sdl cimport load_png, create_rgb_surface
 from pytouhou.formats.thtx import Texture #TODO: perhaps define that elsewhere?
 
 import os
@@ -52,7 +52,7 @@
 
 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
+    width, height = image_file.surface.w, image_file.surface.h
 
     # Support only 32 bits RGBA. Paletted surfaces are awful to work with.
     #TODO: verify it doesn’t blow up on big-endian systems.
@@ -61,7 +61,7 @@
 
     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)
+        assert (width == alpha_file.surface.w and height == alpha_file.surface.h)
 
         new_alpha_file = create_rgb_surface(width, height, 24)
         new_alpha_file.blit(alpha_file)
--- a/pytouhou/ui/window.pyx	Sat Aug 31 07:39:04 2013 +0200
+++ b/pytouhou/ui/window.pyx	Mon Sep 02 22:16:38 2013 +0200
@@ -13,7 +13,7 @@
 ##
 
 
-from pytouhou.lib import sdl
+from pytouhou.lib cimport sdl
 
 from pytouhou.lib.opengl cimport \
          (glEnable, glHint, glEnableClientState, GL_TEXTURE_2D, GL_BLEND,
@@ -24,8 +24,11 @@
     from pytouhou.lib.opengl cimport glewInit
 
 
-class Clock:
-    def __init__(self, fps=None):
+cdef class Clock:
+    cdef long _target_fps, _ref_tick, _ref_frame, _fps_tick, _fps_frame
+    cdef double _rate
+
+    def __init__(self, long fps=-1):
         self._target_fps = 0
         self._ref_tick = 0
         self._ref_frame = 0
@@ -35,17 +38,17 @@
         self.set_target_fps(fps)
 
 
-    def set_target_fps(self, fps):
+    cdef void set_target_fps(self, long fps) nogil:
         self._target_fps = fps
         self._ref_tick = 0
         self._fps_tick = 0
 
 
-    def get_fps(self):
+    cdef double get_fps(self) nogil:
         return self._rate
 
 
-    def tick(self):
+    cdef void tick(self) nogil except *:
         current = sdl.get_ticks()
 
         if not self._ref_tick:
@@ -66,7 +69,7 @@
 
         target_tick = self._ref_tick
         if self._target_fps:
-            target_tick += int(self._ref_frame * 1000 / self._target_fps)
+            target_tick += <long>(self._ref_frame * 1000 / self._target_fps)
 
         if current <= target_tick:
             sdl.delay(target_tick - current)
@@ -76,9 +79,16 @@
 
 
 
-class Window(object):
-    def __init__(self, size=None, double_buffer=True, fps_limit=60,
-                 fixed_pipeline=False, sound=True):
+cdef class Window:
+    cdef sdl.Window win
+    cdef long fps_limit
+    cdef public long width, height
+    cdef public bint use_fixed_pipeline
+    cdef object runner
+    cdef Clock clock
+
+    def __init__(self, size=None, bint double_buffer=True, long fps_limit=-1,
+                 bint fixed_pipeline=False, bint sound=True):
         self.fps_limit = fps_limit
         self.use_fixed_pipeline = fixed_pipeline
         self.runner = None
@@ -95,7 +105,7 @@
         sdl.gl_set_attribute(sdl.GL_DOUBLEBUFFER, int(double_buffer))
         sdl.gl_set_attribute(sdl.GL_DEPTH_SIZE, 24)
 
-        self.width, self.height = size if size else (640, 480)
+        self.width, self.height = size if size is not None else (640, 480)
 
         self.win = sdl.Window('PyTouhou',
                               sdl.WINDOWPOS_CENTERED, sdl.WINDOWPOS_CENTERED,
@@ -125,16 +135,17 @@
         self.clock = Clock(self.fps_limit)
 
 
-    def set_size(self, width, height):
+    cdef void set_size(self, int width, int height) nogil:
         self.win.set_window_size(width, height)
 
 
-    def set_runner(self, runner):
+    cpdef set_runner(self, runner=None):
         self.runner = runner
-        runner.start()
+        if runner is not None:
+            runner.start()
 
 
-    def run(self):
+    cpdef run(self):
         try:
             while self.run_frame():
                 pass
@@ -142,17 +153,20 @@
             self.runner.finish()
 
 
-    def run_frame(self):
-        if self.runner:
+    cdef bint run_frame(self) except? False:
+        cdef bint running = False
+        if self.runner is not None:
             running = self.runner.update()
         self.win.gl_swap_window()
         self.clock.tick()
         return running
 
 
+    cpdef double get_fps(self):
+        return self.clock.get_fps()
+
+
     def __dealloc__(self):
-        self.win.gl_delete_context()
-        self.win.destroy_window()
         sdl.mix_close_audio()
         sdl.mix_quit()
         sdl.img_quit()
--- a/setup.py	Sat Aug 31 07:39:04 2013 +0200
+++ b/setup.py	Mon Sep 02 22:16:38 2013 +0200
@@ -45,8 +45,8 @@
                 compile_args = get_arguments('--cflags', SDL_LIBRARIES)
                 link_args = get_arguments('--libs', SDL_LIBRARIES)
             elif extension_name.startswith('pytouhou.ui.'): #XXX
-                compile_args = get_arguments('--cflags', ['gl'])
-                link_args = get_arguments('--libs', ['gl'])
+                compile_args = get_arguments('--cflags', ['gl'] + SDL_LIBRARIES)
+                link_args = get_arguments('--libs', ['gl'] + SDL_LIBRARIES)
             else:
                 compile_args = None
                 link_args = None