changeset 464:36bc577b2392

Make the window resizable, and scale its content correctly.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Wed, 11 Sep 2013 15:55:19 +0200
parents 11708a1d0a1a
children 5f5955635d2c
files pytouhou/lib/_sdl.pxd pytouhou/lib/sdl.pxd pytouhou/lib/sdl.pyx pytouhou/ui/gamerenderer.pxd pytouhou/ui/gamerenderer.pyx pytouhou/ui/gamerunner.pyx pytouhou/ui/renderer.pxd pytouhou/ui/renderer.pyx pytouhou/ui/window.pxd pytouhou/ui/window.pyx
diffstat 10 files changed, 57 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/pytouhou/lib/_sdl.pxd
+++ b/pytouhou/lib/_sdl.pxd
@@ -43,6 +43,7 @@ cdef extern from "SDL_video.h" nogil:
         SDL_WINDOWPOS_CENTERED
         SDL_WINDOW_OPENGL
         SDL_WINDOW_SHOWN
+        SDL_WINDOW_RESIZABLE
 
     ctypedef struct SDL_Window:
         pass
@@ -76,6 +77,7 @@ cdef extern from "SDL_events.h" nogil:
     ctypedef enum SDL_EventType:
         SDL_KEYDOWN
         SDL_QUIT
+        SDL_WINDOWEVENT
 
     ctypedef struct SDL_Keysym:
         SDL_Scancode scancode
@@ -84,9 +86,19 @@ cdef extern from "SDL_events.h" nogil:
         Uint32 type
         SDL_Keysym keysym
 
+    ctypedef enum SDL_WindowEventID:
+        SDL_WINDOWEVENT_RESIZED
+
+    ctypedef struct SDL_WindowEvent:
+        Uint32 type
+        SDL_WindowEventID event
+        int data1
+        int data2
+
     ctypedef union SDL_Event:
         Uint32 type
         SDL_KeyboardEvent key
+        SDL_WindowEvent window
 
     int SDL_PollEvent(SDL_Event *event)
 
--- a/pytouhou/lib/sdl.pxd
+++ b/pytouhou/lib/sdl.pxd
@@ -23,6 +23,7 @@ cdef SDL_GLattr GL_DEPTH_SIZE
 cdef SDL_WindowFlags WINDOWPOS_CENTERED
 cdef SDL_WindowFlags WINDOW_OPENGL
 cdef SDL_WindowFlags WINDOW_SHOWN
+cdef SDL_WindowFlags WINDOW_RESIZABLE
 
 #TODO: should be SDL_Scancode, but Cython doesn’t allow enum for array indexing.
 cdef long SCANCODE_Z
@@ -35,8 +36,11 @@ cdef long SCANCODE_RIGHT
 cdef long SCANCODE_LCTRL
 cdef long SCANCODE_ESCAPE
 
+cdef SDL_WindowEventID WINDOWEVENT_RESIZED
+
 cdef SDL_EventType KEYDOWN
 cdef SDL_EventType QUIT
+cdef SDL_EventType WINDOWEVENT
 
 
 cdef class Window:
--- a/pytouhou/lib/sdl.pyx
+++ b/pytouhou/lib/sdl.pyx
@@ -20,6 +20,7 @@ GL_DEPTH_SIZE = SDL_GL_DEPTH_SIZE
 WINDOWPOS_CENTERED = SDL_WINDOWPOS_CENTERED
 WINDOW_OPENGL = SDL_WINDOW_OPENGL
 WINDOW_SHOWN = SDL_WINDOW_SHOWN
+WINDOW_RESIZABLE = SDL_WINDOW_RESIZABLE
 
 SCANCODE_Z = SDL_SCANCODE_Z
 SCANCODE_X = SDL_SCANCODE_X
@@ -31,8 +32,11 @@ SCANCODE_RIGHT = SDL_SCANCODE_RIGHT
 SCANCODE_LCTRL = SDL_SCANCODE_LCTRL
 SCANCODE_ESCAPE = SDL_SCANCODE_ESCAPE
 
+WINDOWEVENT_RESIZED = SDL_WINDOWEVENT_RESIZED
+
 KEYDOWN = SDL_KEYDOWN
 QUIT = SDL_QUIT
+WINDOWEVENT = SDL_WINDOWEVENT
 
 
 class SDLError(Exception):
@@ -207,6 +211,8 @@ cdef list poll_events():
             ret.append((event.type, event.key.keysym.scancode))
         elif event.type == SDL_QUIT:
             ret.append((event.type,))
+        elif event.type == SDL_WINDOWEVENT:
+            ret.append((event.type, event.window.event, event.window.data1, event.window.data2))
     return ret
 
 
--- a/pytouhou/ui/gamerenderer.pxd
+++ b/pytouhou/ui/gamerenderer.pxd
@@ -11,7 +11,7 @@ cdef class GameRenderer(Renderer):
 
     cdef void load_background(self, background)
     cdef void start(self, game)
-    cdef void render(self, game)
+    cdef void render(self, game, window)
     cdef void render_game(self, game)
     cdef void render_text(self, texts)
     cdef void render_interface(self, interface, game_boss)
--- a/pytouhou/ui/gamerenderer.pyx
+++ b/pytouhou/ui/gamerenderer.pyx
@@ -60,7 +60,7 @@ cdef class GameRenderer(Renderer):
         self.interface_mvp = ortho_2d(0., float(game.interface.width), float(game.interface.height), 0.)
 
 
-    cdef void render(self, game):
+    cdef void render(self, game, window):
         if not self.use_fixed_pipeline:
             self.framebuffer.bind()
 
@@ -71,7 +71,7 @@ cdef class GameRenderer(Renderer):
         if not self.use_fixed_pipeline:
             self.passthrough_shader.bind()
             self.passthrough_shader.uniform_matrix('mvp', self.interface_mvp)
-            self.render_framebuffer(self.framebuffer)
+            self.render_framebuffer(self.framebuffer, window)
 
 
     cdef void render_game(self, game):
--- a/pytouhou/ui/gamerunner.pyx
+++ b/pytouhou/ui/gamerunner.pyx
@@ -25,12 +25,10 @@ cdef class GameRunner(Runner):
     cdef Window window
     cdef object replay_level, save_keystates
     cdef long keystate
-    cdef bint skip, use_fixed_pipeline
+    cdef bint skip
 
-    def __init__(self, window, resource_loader, bint skip=False):
-        self.use_fixed_pipeline = window.use_fixed_pipeline #XXX
-
-        self.renderer = GameRenderer(resource_loader, self.use_fixed_pipeline)
+    def __init__(self, Window window, resource_loader, bint skip=False):
+        self.renderer = GameRenderer(resource_loader, window.use_fixed_pipeline)
 
         self.window = window
         self.replay_level = None
@@ -98,6 +96,10 @@ cdef class GameRunner(Runner):
                     return False #TODO: implement the pause.
             elif type_ == sdl.QUIT:
                 return False
+            elif type_ == sdl.WINDOWEVENT:
+                event_ = event[1]
+                if event_ == sdl.WINDOWEVENT_RESIZED:
+                    self.window.set_size(event[2], event[3])
         if self.game:
             if self.replay_level is None:
                 #TODO: allow user settings
@@ -135,5 +137,5 @@ cdef class GameRunner(Runner):
             self.game.run_iter(keystate)
             self.game.interface.labels['framerate'].set_text('%.2ffps' % self.window.get_fps())
         if not self.skip:
-            self.renderer.render(self.game)
+            self.renderer.render(self.game, self.window)
         return True
--- a/pytouhou/ui/renderer.pxd
+++ b/pytouhou/ui/renderer.pxd
@@ -1,4 +1,5 @@
 from cpython cimport PyObject
+from .window cimport Window
 from pytouhou.lib.opengl cimport GLuint
 
 cdef struct Vertex:
@@ -25,7 +26,7 @@ cdef class Renderer:
 
     cpdef render_elements(self, elements)
     cpdef render_quads(self, rects, colors, texture)
-    cpdef render_framebuffer(self, Framebuffer fb)
+    cpdef render_framebuffer(self, Framebuffer fb, Window window)
 
 
 cdef class Framebuffer:
--- a/pytouhou/ui/renderer.pyx
+++ b/pytouhou/ui/renderer.pyx
@@ -217,7 +217,7 @@ cdef class Renderer:
             glBindBuffer(GL_ARRAY_BUFFER, 0)
 
 
-    cpdef render_framebuffer(self, Framebuffer fb):
+    cpdef render_framebuffer(self, Framebuffer fb, Window window):
         cdef PassthroughVertex[4] buf
         cdef unsigned short indices[6]
         indices[:] = [0, 1, 2, 2, 3, 0]
@@ -225,7 +225,7 @@ cdef class Renderer:
         assert not self.use_fixed_pipeline
 
         glBindFramebuffer(GL_FRAMEBUFFER, 0)
-        glViewport(0, 0, 640, 480)
+        glViewport(window.x, window.y, window.width, window.height)
         glBlendFunc(GL_ONE, GL_ZERO)
         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
 
--- a/pytouhou/ui/window.pxd
+++ b/pytouhou/ui/window.pxd
@@ -21,7 +21,7 @@ cdef class Runner:
 cdef class Window:
     cdef sdl.Window win
     cdef long fps_limit
-    cdef public long width, height
+    cdef public long x, y, width, height
     cdef public bint use_fixed_pipeline
     cdef Runner runner
     cdef Clock clock
--- a/pytouhou/ui/window.pyx
+++ b/pytouhou/ui/window.pyx
@@ -12,6 +12,7 @@
 ## GNU General Public License for more details.
 ##
 
+cimport cython
 
 from pytouhou.lib.opengl cimport \
          (glEnable, glHint, glEnableClientState, GL_TEXTURE_2D, GL_BLEND,
@@ -100,10 +101,14 @@ cdef class Window:
 
         self.width, self.height = size if size is not None else (640, 480)
 
+        flags = sdl.WINDOW_OPENGL | sdl.WINDOW_SHOWN
+        if not self.use_fixed_pipeline:
+            flags |= sdl.WINDOW_RESIZABLE
+
         self.win = sdl.Window('PyTouhou',
                               sdl.WINDOWPOS_CENTERED, sdl.WINDOWPOS_CENTERED,
                               self.width, self.height,
-                              sdl.WINDOW_OPENGL | sdl.WINDOW_SHOWN)
+                              flags)
         self.win.gl_create_context()
 
         IF USE_GLEW:
@@ -123,9 +128,22 @@ cdef class Window:
         self.clock = Clock(self.fps_limit)
 
 
+    @cython.cdivision(True)
     cdef void set_size(self, int width, int height) nogil:
         self.win.set_window_size(width, height)
 
+        runner_width = float(self.runner.width)
+        runner_height = float(self.runner.height)
+
+        scale = min(width / runner_width,
+                    height / runner_height)
+
+        self.width = int(runner_width * scale)
+        self.height = int(runner_height * scale)
+
+        self.x = (width - self.width) // 2
+        self.y = (height - self.height) // 2
+
 
     cpdef set_runner(self, Runner runner=None):
         self.runner = runner