Mercurial > touhou
comparison pytouhou/ui/gamerunner.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 | b1248bab2d0f |
children |
comparison
equal
deleted
inserted
replaced
421:b1248bab2d0f | 422:52829ebe2561 |
---|---|
12 ## GNU General Public License for more details. | 12 ## GNU General Public License for more details. |
13 ## | 13 ## |
14 | 14 |
15 from pytouhou.lib import sdl | 15 from pytouhou.lib import sdl |
16 | 16 |
17 from pyglet.gl import (glMatrixMode, glLoadIdentity, glEnable, glDisable, | 17 from pyglet.gl import (glMatrixMode, glEnable, glDisable, glViewport, |
18 glHint, glEnableClientState, glViewport, glScissor, | 18 glScissor, glLoadMatrixf, glGenBuffers, glDeleteBuffers, |
19 glLoadMatrixf, glGenBuffers, glDeleteBuffers, | 19 GL_MODELVIEW, GL_PROJECTION, GL_FOG, GL_SCISSOR_TEST) |
20 GL_MODELVIEW, GL_PROJECTION, | |
21 GL_TEXTURE_2D, GL_BLEND, GL_FOG, | |
22 GL_PERSPECTIVE_CORRECTION_HINT, GL_FOG_HINT, GL_NICEST, | |
23 GL_COLOR_ARRAY, GL_VERTEX_ARRAY, GL_TEXTURE_COORD_ARRAY, | |
24 GL_SCISSOR_TEST) | |
25 | 20 |
26 from pytouhou.utils.helpers import get_logger | 21 from pytouhou.utils.helpers import get_logger |
27 from pytouhou.utils.maths import perspective, setup_camera, ortho_2d | 22 from pytouhou.utils.maths import perspective, setup_camera, ortho_2d |
28 | 23 |
29 from .gamerenderer import GameRenderer | 24 from .gamerenderer import GameRenderer |
34 | 29 |
35 | 30 |
36 logger = get_logger(__name__) | 31 logger = get_logger(__name__) |
37 | 32 |
38 | 33 |
39 class Clock(object): | |
40 def __init__(self, fps=None): | |
41 self._target_fps = 0 | |
42 self._ref_tick = 0 | |
43 self._ref_frame = 0 | |
44 self._fps_tick = 0 | |
45 self._fps_frame = 0 | |
46 self._rate = 0 | |
47 self.set_target_fps(fps) | |
48 | |
49 | |
50 def set_target_fps(self, fps): | |
51 self._target_fps = fps | |
52 self._ref_tick = 0 | |
53 self._fps_tick = 0 | |
54 | |
55 | |
56 def get_fps(self): | |
57 return self._rate | |
58 | |
59 | |
60 def tick(self): | |
61 current = sdl.get_ticks() | |
62 | |
63 if not self._ref_tick: | |
64 self._ref_tick = current | |
65 self._ref_frame = 0 | |
66 | |
67 if self._fps_frame >= (self._target_fps or 60): | |
68 self._rate = self._fps_frame * 1000. / (current - self._fps_tick) | |
69 self._fps_tick = current | |
70 self._fps_frame = 0 | |
71 | |
72 self._ref_frame += 1 | |
73 self._fps_frame += 1 | |
74 | |
75 target_tick = self._ref_tick | |
76 if self._target_fps: | |
77 target_tick += int(self._ref_frame * 1000 / self._target_fps) | |
78 | |
79 if current <= target_tick: | |
80 sdl.delay(target_tick - current) | |
81 else: | |
82 self._ref_tick = current | |
83 self._ref_frame = 0 | |
84 | |
85 | |
86 class GameRunner(GameRenderer): | 34 class GameRunner(GameRenderer): |
87 def __init__(self, resource_loader, game=None, background=None, replay=None, double_buffer=True, fps_limit=60, fixed_pipeline=False, skip=False): | 35 def __init__(self, window, resource_loader, replay=None, skip=False): |
88 GameRenderer.__init__(self, resource_loader, game, background) | 36 GameRenderer.__init__(self, resource_loader) |
89 | 37 |
90 sdl.init(sdl.INIT_VIDEO) | 38 self.window = window |
91 sdl.img_init(sdl.INIT_PNG) | |
92 sdl.mix_init(0) | |
93 | |
94 sdl.gl_set_attribute(sdl.GL_CONTEXT_MAJOR_VERSION, 2) | |
95 sdl.gl_set_attribute(sdl.GL_CONTEXT_MINOR_VERSION, 1) | |
96 sdl.gl_set_attribute(sdl.GL_DOUBLEBUFFER, int(double_buffer)) | |
97 sdl.gl_set_attribute(sdl.GL_DEPTH_SIZE, 24) | |
98 | |
99 self.width, self.height = (game.interface.width, game.interface.height) if game else (640, 480) | |
100 self.win = sdl.Window('PyTouhou', | |
101 sdl.WINDOWPOS_CENTERED, sdl.WINDOWPOS_CENTERED, | |
102 self.width, self.height, | |
103 sdl.WINDOW_OPENGL | sdl.WINDOW_SHOWN) | |
104 self.win.gl_create_context() | |
105 | |
106 sdl.mix_open_audio(44100, sdl.DEFAULT_FORMAT, 2, 4096) | |
107 sdl.mix_allocate_channels(26) #TODO: make it dependent on the SFX number. | |
108 | |
109 self.fps_limit = fps_limit | |
110 self.use_fixed_pipeline = fixed_pipeline | |
111 self.replay_level = None | 39 self.replay_level = None |
112 self.skip = skip | 40 self.skip = skip |
113 self.has_exit = False | |
114 self.keystate = 0 | 41 self.keystate = 0 |
42 | |
43 self.use_fixed_pipeline = window.use_fixed_pipeline #XXX | |
44 self.width = window.width #XXX | |
45 self.height = window.height #XXX | |
115 | 46 |
116 if not self.use_fixed_pipeline: | 47 if not self.use_fixed_pipeline: |
117 self.game_shader = GameShader() | 48 self.game_shader = GameShader() |
118 self.background_shader = BackgroundShader() | 49 self.background_shader = BackgroundShader() |
119 self.interface_shader = self.game_shader | 50 self.interface_shader = self.game_shader |
120 | 51 |
121 vbo_array = (c_uint * 2)() | 52 vbo_array = (c_uint * 2)() |
122 glGenBuffers(2, vbo_array) | 53 glGenBuffers(2, vbo_array) |
123 self.vbo, self.back_vbo = vbo_array | 54 self.vbo, self.back_vbo = vbo_array |
124 | 55 |
125 if game: | |
126 self.load_game(game, background, replay) | |
127 | |
128 self.clock = Clock(self.fps_limit) | |
129 | |
130 | 56 |
131 def load_game(self, game=None, background=None, bgms=None, replay=None, save_keystates=None): | 57 def load_game(self, game=None, background=None, bgms=None, replay=None, save_keystates=None): |
132 GameRenderer.load_game(self, game, background) | 58 self.game = game |
59 self.background = background | |
60 | |
61 self.texture_manager.preload(game.resource_loader.instanced_anms.values()) | |
62 | |
63 if background: | |
64 self.prerender_background(background) | |
65 | |
133 self.set_input(replay) | 66 self.set_input(replay) |
134 if replay and replay.levels[game.stage - 1]: | 67 if replay and replay.levels[game.stage - 1]: |
135 game.players[0].state.lives = self.replay_level.lives | 68 game.players[0].state.lives = self.replay_level.lives |
136 game.players[0].state.power = self.replay_level.power | 69 game.players[0].state.power = self.replay_level.power |
137 game.players[0].state.bombs = self.replay_level.bombs | 70 game.players[0].state.bombs = self.replay_level.bombs |
150 else: | 83 else: |
151 self.replay_level = replay.levels[self.game.stage-1] | 84 self.replay_level = replay.levels[self.game.stage-1] |
152 self.keys = self.replay_level.iter_keystates() | 85 self.keys = self.replay_level.iter_keystates() |
153 | 86 |
154 | 87 |
155 def set_size(self, width, height): | 88 def start(self): |
156 self.win.set_window_size(width, height) | 89 width = self.game.interface.width if self.game else 640 |
157 | 90 height = self.game.interface.height if self.game else 480 |
158 | |
159 def start(self, width=None, height=None): | |
160 width = width or (self.game.interface.width if self.game else 640) | |
161 height = height or (self.game.interface.height if self.game else 480) | |
162 if (width, height) != (self.width, self.height): | 91 if (width, height) != (self.width, self.height): |
163 self.set_size(width, height) | 92 self.window.set_size(width, height) |
164 | |
165 # Initialize OpenGL | |
166 glEnable(GL_BLEND) | |
167 if self.use_fixed_pipeline: | |
168 glEnable(GL_TEXTURE_2D) | |
169 glHint(GL_FOG_HINT, GL_NICEST) | |
170 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) | |
171 glEnableClientState(GL_COLOR_ARRAY) | |
172 glEnableClientState(GL_VERTEX_ARRAY) | |
173 glEnableClientState(GL_TEXTURE_COORD_ARRAY) | |
174 | 93 |
175 self.proj = perspective(30, float(self.game.width) / float(self.game.height), | 94 self.proj = perspective(30, float(self.game.width) / float(self.game.height), |
176 101010101./2010101., 101010101./10101.) | 95 101010101./2010101., 101010101./10101.) |
177 game_view = setup_camera(0, 0, 1) | 96 game_view = setup_camera(0, 0, 1) |
178 self.game_mvp = game_view * self.proj | 97 self.game_mvp = game_view * self.proj |
179 self.interface_mvp = ortho_2d(0., float(self.width), float(self.height), 0.) | 98 self.interface_mvp = ortho_2d(0., float(self.width), float(self.height), 0.) |
180 | 99 |
181 while not self.has_exit: | 100 |
182 if not self.skip: | 101 def finish(self): |
183 self.update() | 102 #TODO: actually clean after buffers are not needed anymore. |
184 self.render_game() | 103 #if not self.use_fixed_pipeline: |
185 self.render_interface() | 104 # vbo_array = (c_uint * 2)(self.vbo, self.back_vbo) |
186 self.win.gl_swap_window() | 105 # glDeleteBuffers(2, vbo_array) |
187 self.clock.tick() | 106 pass |
188 else: | |
189 self.update() | |
190 | |
191 if not self.use_fixed_pipeline: | |
192 vbo_array = (c_uint * 2)(self.vbo, self.back_vbo) | |
193 glDeleteBuffers(2, vbo_array) | |
194 | |
195 self.win.gl_delete_context() | |
196 self.win.destroy_window() | |
197 sdl.mix_close_audio() | |
198 sdl.mix_quit() | |
199 sdl.img_quit() | |
200 sdl.quit() | |
201 | 107 |
202 | 108 |
203 def update(self): | 109 def update(self): |
204 if self.background: | 110 if self.background: |
205 self.background.update(self.game.frame) | 111 self.background.update(self.game.frame) |
206 for event in sdl.poll_events(): | 112 for event in sdl.poll_events(): |
207 type_ = event[0] | 113 type_ = event[0] |
208 if type_ == sdl.KEYDOWN: | 114 if type_ == sdl.KEYDOWN: |
209 scancode = event[1] | 115 scancode = event[1] |
210 if scancode == sdl.SCANCODE_ESCAPE: | 116 if scancode == sdl.SCANCODE_ESCAPE: |
211 self.has_exit = True #TODO: implement the pause. | 117 return False #TODO: implement the pause. |
212 elif type_ == sdl.QUIT: | 118 elif type_ == sdl.QUIT: |
213 self.has_exit = True | 119 return False |
214 if self.game: | 120 if self.game: |
215 if not self.replay_level: | 121 if not self.replay_level: |
216 #TODO: allow user settings | 122 #TODO: allow user settings |
217 keys = sdl.get_keyboard_state() | 123 keys = sdl.get_keyboard_state() |
218 keystate = 0 | 124 keystate = 0 |
244 | 150 |
245 if self.save_keystates is not None: | 151 if self.save_keystates is not None: |
246 self.save_keystates.append(keystate) | 152 self.save_keystates.append(keystate) |
247 | 153 |
248 self.game.run_iter(keystate) | 154 self.game.run_iter(keystate) |
155 if not self.skip: | |
156 self.render_game() | |
157 self.render_interface() | |
158 return True | |
249 | 159 |
250 | 160 |
251 def render_game(self): | 161 def render_game(self): |
252 # Switch to game projection | 162 # Switch to game projection |
253 #TODO: move that to GameRenderer? | 163 #TODO: move that to GameRenderer? |
261 glDisable(GL_SCISSOR_TEST) | 171 glDisable(GL_SCISSOR_TEST) |
262 | 172 |
263 | 173 |
264 def render_interface(self): | 174 def render_interface(self): |
265 interface = self.game.interface | 175 interface = self.game.interface |
266 interface.labels['framerate'].set_text('%.2ffps' % self.clock.get_fps()) | 176 interface.labels['framerate'].set_text('%.2ffps' % self.window.clock.get_fps()) |
267 | 177 |
268 if self.use_fixed_pipeline: | 178 if self.use_fixed_pipeline: |
269 glMatrixMode(GL_MODELVIEW) | 179 glMatrixMode(GL_MODELVIEW) |
270 glLoadMatrixf(self.interface_mvp.get_c_data()) | 180 glLoadMatrixf(self.interface_mvp.get_c_data()) |
271 glDisable(GL_FOG) | 181 glDisable(GL_FOG) |