diff pytouhou/ui/window.py @ 422:52829ebe2561

Refactor window management in its own class.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Tue, 16 Jul 2013 21:07:15 +0200
parents
children
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/pytouhou/ui/window.py
@@ -0,0 +1,146 @@
+# -*- 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.
+##
+
+
+from pytouhou.lib import sdl
+
+from pyglet.gl import (glEnable, glHint, glEnableClientState, GL_TEXTURE_2D,
+                       GL_BLEND, GL_PERSPECTIVE_CORRECTION_HINT, GL_FOG_HINT,
+                       GL_NICEST, GL_COLOR_ARRAY, GL_VERTEX_ARRAY,
+                       GL_TEXTURE_COORD_ARRAY)
+
+
+class Clock(object):
+    def __init__(self, fps=None):
+        self._target_fps = 0
+        self._ref_tick = 0
+        self._ref_frame = 0
+        self._fps_tick = 0
+        self._fps_frame = 0
+        self._rate = 0
+        self.set_target_fps(fps)
+
+
+    def set_target_fps(self, fps):
+        self._target_fps = fps
+        self._ref_tick = 0
+        self._fps_tick = 0
+
+
+    def get_fps(self):
+        return self._rate
+
+
+    def tick(self):
+        current = sdl.get_ticks()
+
+        if not self._ref_tick:
+            self._ref_tick = current
+            self._ref_frame = 0
+
+        if self._fps_frame >= (self._target_fps or 60):
+            self._rate = self._fps_frame * 1000. / (current - self._fps_tick)
+            self._fps_tick = current
+            self._fps_frame = 0
+
+        self._ref_frame += 1
+        self._fps_frame += 1
+
+        target_tick = self._ref_tick
+        if self._target_fps:
+            target_tick += int(self._ref_frame * 1000 / self._target_fps)
+
+        if current <= target_tick:
+            sdl.delay(target_tick - current)
+        else:
+            self._ref_tick = current
+            self._ref_frame = 0
+
+
+
+class Window(object):
+    def __init__(self, size=None, double_buffer=True, fps_limit=60,
+                 fixed_pipeline=False, sound=True):
+        self.fps_limit = fps_limit
+        self.use_fixed_pipeline = fixed_pipeline
+        self.runner = None
+
+        sdl.init(sdl.INIT_VIDEO)
+        sdl.img_init(sdl.INIT_PNG)
+        if sound:
+            sdl.mix_init(0)
+
+        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))
+        sdl.gl_set_attribute(sdl.GL_DEPTH_SIZE, 24)
+
+        self.width, self.height = size if size else (640, 480)
+
+        self.win = sdl.Window('PyTouhou',
+                              sdl.WINDOWPOS_CENTERED, sdl.WINDOWPOS_CENTERED,
+                              self.width, self.height,
+                              sdl.WINDOW_OPENGL | sdl.WINDOW_SHOWN)
+        self.win.gl_create_context()
+
+        # Initialize OpenGL
+        glEnable(GL_BLEND)
+        if self.use_fixed_pipeline:
+            glEnable(GL_TEXTURE_2D)
+            glHint(GL_FOG_HINT, GL_NICEST)
+            glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
+            glEnableClientState(GL_COLOR_ARRAY)
+            glEnableClientState(GL_VERTEX_ARRAY)
+            glEnableClientState(GL_TEXTURE_COORD_ARRAY)
+
+        # Initialize sound
+        if sound:
+            sdl.mix_open_audio(44100, sdl.DEFAULT_FORMAT, 2, 4096)
+            sdl.mix_allocate_channels(26) #TODO: make it dependent on the SFX number.
+
+        self.clock = Clock(self.fps_limit)
+
+
+    def set_size(self, width, height):
+        self.win.set_window_size(width, height)
+
+
+    def set_runner(self, runner):
+        self.runner = runner
+        runner.start()
+
+
+    def run(self):
+        try:
+            while self.run_frame():
+                pass
+        finally:
+            self.runner.finish()
+
+
+    def run_frame(self):
+        if self.runner:
+            running = self.runner.update()
+        self.win.gl_swap_window()
+        self.clock.tick()
+        return running
+
+
+    def __dealloc__(self):
+        self.win.gl_delete_context()
+        self.win.destroy_window()
+        sdl.mix_close_audio()
+        sdl.mix_quit()
+        sdl.img_quit()
+        sdl.quit()