# HG changeset patch # User Emmanuel Gil Peyrot # Date 1378502959 -7200 # Node ID ec327e58b477e80cfb5ce8d19f12d2a40d40eb73 # Parent 6e733ed817bd8ff9aeb423d84f027634248fbb82 Add a context manager to initialize and shut down SDL outside of Window. diff --git a/eosd b/eosd --- a/eosd +++ b/eosd @@ -53,6 +53,7 @@ args = parser.parse_args() import sys import logging +from pytouhou.lib.sdl import SDL from pytouhou.ui.window import Window from pytouhou.resource.loader import Loader from pytouhou.ui.gamerunner import GameRunner @@ -108,115 +109,116 @@ def main(path, data, stage_num, rank, ch sys.stderr.write('Some data files were not found, did you forget the -p option?\n') exit(1) - window = Window(double_buffer=(not single_buffer), fps_limit=fps_limit, fixed_pipeline=fixed_pipeline) + with SDL(): + window = Window(double_buffer=(not single_buffer), fps_limit=fps_limit, fixed_pipeline=fixed_pipeline) - if stage_num is None: - story = True - stage_num = 1 - continues = 3 - else: - story = False - continues = 0 + if stage_num is None: + story = True + stage_num = 1 + continues = 3 + else: + story = False + continues = 0 - if debug: - if not verbosity: - verbosity = 'DEBUG' - continues = float('inf') + if debug: + if not verbosity: + verbosity = 'DEBUG' + continues = float('inf') - if verbosity: - logging.basicConfig(level=logging.__getattribute__(verbosity)) + if verbosity: + logging.basicConfig(level=logging.__getattribute__(verbosity)) - if replay: - with open(replay, 'rb') as file: - replay = T6RP.read(file) - rank = replay.rank - character = replay.character + if replay: + with open(replay, 'rb') as file: + replay = T6RP.read(file) + rank = replay.rank + character = replay.character - save_keystates = None - if save_filename: - save_replay = T6RP() - save_replay.rank = rank - save_replay.character = character + save_keystates = None + if save_filename: + save_replay = T6RP() + save_replay.rank = rank + save_replay.character = character - if hints: - with open(hints, 'rb') as file: - hints = Hint.read(file) + if hints: + with open(hints, 'rb') as file: + hints = Hint.read(file) - difficulty = 16 - default_power = [0, 64, 128, 128, 128, 128, 0][stage_num - 1] - states = [PlayerState(character=character, power=default_power)] + difficulty = 16 + default_power = [0, 64, 128, 128, 128, 128, 0][stage_num - 1] + states = [PlayerState(character=character, power=default_power)] - game_class = GameBossRush if boss_rush else Game + game_class = GameBossRush if boss_rush else Game - common = Common(resource_loader) - runner = GameRunner(window, resource_loader, skip=skip_replay) - while True: - if replay: - level = replay.levels[stage_num - 1] - if not level: - raise Exception + common = Common(resource_loader) + runner = GameRunner(window, resource_loader, skip=skip_replay) + while True: + if replay: + level = replay.levels[stage_num - 1] + if not level: + raise Exception - prng = Random(level.random_seed) + prng = Random(level.random_seed) - #TODO: apply the replay to the other players. - #TODO: see if the stored score is used or if it’s the one from the previous stage. - if stage_num != 1 and stage_num - 2 in replay.levels: - previous_level = replay.levels[stage_num - 1] - states[0].score = previous_level.score - states[0].effective_score = previous_level.score - states[0].points = level.point_items - states[0].power = level.power - states[0].lives = level.lives - states[0].bombs = level.bombs - difficulty = level.difficulty - else: - prng = Random() + #TODO: apply the replay to the other players. + #TODO: see if the stored score is used or if it’s the one from the previous stage. + if stage_num != 1 and stage_num - 2 in replay.levels: + previous_level = replay.levels[stage_num - 1] + states[0].score = previous_level.score + states[0].effective_score = previous_level.score + states[0].points = level.point_items + states[0].power = level.power + states[0].lives = level.lives + states[0].bombs = level.bombs + difficulty = level.difficulty + else: + prng = Random() - if save_filename: - if not replay: - save_replay.levels[stage_num - 1] = level = Level() - level.score = states[0].score - level.random_seed = prng.seed - level.point_items = states[0].points - level.power = states[0].power - level.lives = states[0].lives - level.bombs = states[0].bombs - level.difficulty = difficulty - save_keystates = [] + if save_filename: + if not replay: + save_replay.levels[stage_num - 1] = level = Level() + level.score = states[0].score + level.random_seed = prng.seed + level.point_items = states[0].points + level.power = states[0].power + level.lives = states[0].lives + level.bombs = states[0].bombs + level.difficulty = difficulty + save_keystates = [] - hints_stage = hints.stages[stage_num - 1] if hints else None + hints_stage = hints.stages[stage_num - 1] if hints else None - game = game_class(resource_loader, states, stage_num, rank, difficulty, common, prng=prng, continues=continues, hints=hints_stage) + game = game_class(resource_loader, states, stage_num, rank, difficulty, common, prng=prng, continues=continues, hints=hints_stage) - if not enable_particles: - def new_particle(pos, anim, amp, number=1, reverse=False, duration=24): - pass - game.new_particle = new_particle + if not enable_particles: + def new_particle(pos, anim, amp, number=1, reverse=False, duration=24): + pass + game.new_particle = new_particle - background = game.background if enable_background else None - bgms = game.std.bgms if enable_music else None + background = game.background if enable_background else None + bgms = game.std.bgms if enable_music else None - # Main loop - runner.load_game(game, background, bgms, replay, save_keystates) - window.set_runner(runner) - try: - window.run() - break - except NextStage: - if not story or stage_num == (7 if boss_rush else 6 if rank > 0 else 5): + # Main loop + runner.load_game(game, background, bgms, replay, save_keystates) + window.set_runner(runner) + try: + window.run() break - stage_num += 1 - states = [player.state.copy() for player in game.players] # if player.state.lives >= 0] - except GameOver: - print('Game over') - break - finally: - if save_filename: - last_key = -1 - for time, key in enumerate(save_keystates): - if key != last_key: - level.keys.append((time, key, 0)) - last_key = key + except NextStage: + if not story or stage_num == (7 if boss_rush else 6 if rank > 0 else 5): + break + stage_num += 1 + states = [player.state.copy() for player in game.players] # if player.state.lives >= 0] + except GameOver: + print('Game over') + break + finally: + if save_filename: + last_key = -1 + for time, key in enumerate(save_keystates): + if key != last_key: + level.keys.append((time, key, 0)) + last_key = key if save_filename: with open(save_filename, 'wb+') as file: diff --git a/pytouhou/lib/sdl.pxd b/pytouhou/lib/sdl.pxd --- a/pytouhou/lib/sdl.pxd +++ b/pytouhou/lib/sdl.pxd @@ -15,9 +15,6 @@ from _sdl cimport * -cdef Uint32 INIT_VIDEO -cdef Uint32 INIT_PNG - cdef SDL_GLattr GL_CONTEXT_MAJOR_VERSION cdef SDL_GLattr GL_CONTEXT_MINOR_VERSION cdef SDL_GLattr GL_DOUBLEBUFFER @@ -41,8 +38,6 @@ cdef long SCANCODE_ESCAPE cdef SDL_EventType KEYDOWN cdef SDL_EventType QUIT -cdef Uint16 DEFAULT_FORMAT - cdef class Window: cdef SDL_Window *window @@ -84,21 +79,12 @@ cdef void init(Uint32 flags) except * cdef void img_init(Uint32 flags) except * cdef void mix_init(int flags) except * cdef void ttf_init() except * - -IF UNAME_SYSNAME == "Windows": - cdef void set_main_ready() - -cdef void quit() nogil -cdef void img_quit() nogil -cdef void mix_quit() nogil -cdef void ttf_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 diff --git a/pytouhou/lib/sdl.pyx b/pytouhou/lib/sdl.pyx --- a/pytouhou/lib/sdl.pyx +++ b/pytouhou/lib/sdl.pyx @@ -12,9 +12,6 @@ ## GNU General Public License for more details. ## -INIT_VIDEO = SDL_INIT_VIDEO -INIT_PNG = IMG_INIT_PNG - GL_CONTEXT_MAJOR_VERSION = SDL_GL_CONTEXT_MAJOR_VERSION GL_CONTEXT_MINOR_VERSION = SDL_GL_CONTEXT_MINOR_VERSION GL_DOUBLEBUFFER = SDL_GL_DOUBLEBUFFER @@ -37,13 +34,37 @@ SCANCODE_ESCAPE = SDL_SCANCODE_ESCAPE KEYDOWN = SDL_KEYDOWN QUIT = SDL_QUIT -DEFAULT_FORMAT = MIX_DEFAULT_FORMAT - class SDLError(Exception): pass +class SDL(object): + def __init__(self, sound=True): + self.sound = sound + + def __enter__(self): + IF UNAME_SYSNAME == "Windows": + SDL_SetMainReady() + init(SDL_INIT_VIDEO) + img_init(IMG_INIT_PNG) + ttf_init() + + if self.sound: + mix_init(0) + mix_open_audio(44100, MIX_DEFAULT_FORMAT, 2, 4096) + mix_allocate_channels(MAX_CHANNELS) #TODO: make it dependent on the SFX number. + + def __exit__(self, *args): + if self.sound: + Mix_CloseAudio() + Mix_Quit() + + TTF_Quit() + IMG_Quit() + SDL_Quit() + + cdef class Window: 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) @@ -157,11 +178,6 @@ cdef void ttf_init() except *: raise SDLError(SDL_GetError()) -IF UNAME_SYSNAME == "Windows": - cdef void set_main_ready(): - SDL_SetMainReady() - - cdef void quit() nogil: SDL_Quit() @@ -222,10 +238,6 @@ cdef void mix_open_audio(int frequency, raise SDLError(SDL_GetError()) -cdef void mix_close_audio() nogil: - Mix_CloseAudio() - - cdef void mix_allocate_channels(int numchans) except *: if Mix_AllocateChannels(numchans) != numchans: raise SDLError(SDL_GetError()) diff --git a/pytouhou/ui/window.pyx b/pytouhou/ui/window.pyx --- a/pytouhou/ui/window.pyx +++ b/pytouhou/ui/window.pyx @@ -81,14 +81,6 @@ cdef class Window: self.use_fixed_pipeline = fixed_pipeline self.runner = None - IF UNAME_SYSNAME == "Windows": - sdl.set_main_ready() - sdl.init(sdl.INIT_VIDEO) - sdl.img_init(sdl.INIT_PNG) - sdl.ttf_init() - 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)) @@ -116,11 +108,6 @@ cdef class Window: 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) @@ -153,11 +140,3 @@ cdef class Window: cpdef double get_fps(self): return self.clock.get_fps() - - - def __dealloc__(self): - sdl.mix_close_audio() - sdl.mix_quit() - sdl.ttf_quit() - sdl.img_quit() - sdl.quit() diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -79,6 +79,7 @@ setup(name='PyTouhou', compiler_directives={'infer_types': True, 'infer_types.verbose': True}, compile_time_env={'MAX_TEXTURES': 1024, + 'MAX_CHANNELS': 26, 'USE_GLEW': is_windows}), scripts=['eosd', 'anmviewer'], **extra)