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)