# HG changeset patch # User Emmanuel Gil Peyrot # Date 1325443894 -3600 # Node ID cbe9dbd80dfb610f7ca127f80b15732541f9b5bf # Parent 741860192b56dc75b93575097a8d935d1270ead2 Add an anmviewer script. diff --git a/anmviewer b/anmviewer new file mode 100644 --- /dev/null +++ b/anmviewer @@ -0,0 +1,48 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +## +## Copyright (C) 2011 Emmanuel Gil Peyrot +## +## 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. +## + +import argparse +import os + +import pyximport +pyximport.install() + +from pytouhou.resource.loader import Loader +from pytouhou.game.sprite import Sprite +from pytouhou.vm.anmrunner import ANMRunner +from pytouhou.ui.anmrenderer import ANMRenderer + + +def main(path, data, name, script, sprites): + resource_loader = Loader() + resource_loader.scan_archives(os.path.join(path, name) for name in data) + + # Get out animation + anm_wrapper = resource_loader.get_anm_wrapper((name,)) + anm = ANMRenderer(resource_loader, anm_wrapper, script, sprites) + anm.start() + + +parser = argparse.ArgumentParser(description='Viewer of ANM files, archives containing animations used in Touhou games.') + +parser.add_argument('data', metavar='DAT', default=('CM.DAT', 'ST.DAT'), nargs='*', help='Game’s .DAT data files') +parser.add_argument('-p', '--path', metavar='DIRECTORY', default='.', help='Game directory path.') +parser.add_argument('--anm', metavar='ANM', required=True, help='Select an ANM') +parser.add_argument('--script', metavar='SCRIPT', type=int, default=0, help='First script to play') +parser.add_argument('--sprites', action='store_true', default=False, help='Display sprites instead of scripts.') + +args = parser.parse_args() + +main(args.path, tuple(args.data), args.anm, args.script, args.sprites) diff --git a/pytouhou/ui/anmrenderer.py b/pytouhou/ui/anmrenderer.py new file mode 100644 --- /dev/null +++ b/pytouhou/ui/anmrenderer.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +## +## Copyright (C) 2011 Emmanuel Gil Peyrot +## +## 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. +## + +import pyglet +import traceback + +from pyglet.gl import (glMatrixMode, glLoadIdentity, glEnable, + glHint, glEnableClientState, glViewport, + gluPerspective, GL_PROJECTION, + GL_TEXTURE_2D, GL_BLEND, + GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST, + GL_COLOR_ARRAY, GL_VERTEX_ARRAY, GL_TEXTURE_COORD_ARRAY, + glClear, GL_COLOR_BUFFER_BIT) + +from pytouhou.game.sprite import Sprite +from pytouhou.vm.anmrunner import ANMRunner + +from pytouhou.utils.helpers import get_logger + +from .renderer import Renderer + + +logger = get_logger(__name__) + + +class ANMRenderer(pyglet.window.Window, Renderer): + def __init__(self, resource_loader, anm_wrapper, index=0, sprites=False): + Renderer.__init__(self, resource_loader) + + width, height = 384, 448 + pyglet.window.Window.__init__(self, width=width, height=height, + caption='PyTouhou', resizable=False) + + self._anm_wrapper = anm_wrapper + self.anm = anm_wrapper.anm_files[0] + self.sprites = sprites + if sprites: + self.items = self.anm.sprites + else: + self.items = self.anm.scripts + self.load(index) + + self.x = width / 2 + self.y = height / 2 + + + def start(self, width=384, height=448): + if (width, height) != (self.width, self.height): + self.set_size(width, height) + + # Initialize OpenGL + glEnable(GL_BLEND) + glEnable(GL_TEXTURE_2D) + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST) + glEnableClientState(GL_COLOR_ARRAY) + glEnableClientState(GL_VERTEX_ARRAY) + glEnableClientState(GL_TEXTURE_COORD_ARRAY) + + # Switch to game projection + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + gluPerspective(30, float(self.width) / float(self.height), + 101010101./2010101., 101010101./10101.) + + self.setup_camera(0, 0, 1) + + # Use our own loop to ensure 60 fps + pyglet.clock.set_fps_limit(60) + while not self.has_exit: + pyglet.clock.tick() + self.dispatch_events() + self.update() + self.flip() + + + def on_resize(self, width, height): + glViewport(0, 0, width, height) + + + def _event_text_symbol(self, ev): + # XXX: Ugly workaround to a pyglet bug on X11 + #TODO: fix that bug in pyglet + try: + return pyglet.window.Window._event_text_symbol(self, ev) + except Exception as exc: + logger.warn('Pyglet error: %s', traceback.format_exc(exc)) + return None, None + + + def on_key_press(self, symbol, modifiers): + if symbol == pyglet.window.key.ESCAPE: + self.has_exit = True + # XXX: Fullscreen will be enabled the day pyglet stops sucking + elif symbol == pyglet.window.key.F11: + self.set_fullscreen(not self.fullscreen) + elif symbol == pyglet.window.key.W: + self.load() + elif symbol == pyglet.window.key.X: + self.x, self.y = (192, 224) if self.x == 0 else (0, 0) + elif symbol == pyglet.window.key.LEFT: + self.change(-1) + elif symbol == pyglet.window.key.RIGHT: + self.change(+1) + elif symbol == pyglet.window.key.TAB: + self.toggle_sprites() + elif symbol >= pyglet.window.key.F1 and symbol <= pyglet.window.key.F12: + print (symbol - pyglet.window.key.F1 + (12 if modifiers == pyglet.window.key.MOD_CTRL else 0) + 1) + #self._anmrunner.interrupt(symbol - pyglet.window.key.F1 + (12 if modifiers == pyglet.window.key.MOD_CTRL) + 1) + + + def load(self, index=None): + if index is None: + index = self.num + self._sprite = Sprite() + print index + if self.sprites: + self._sprite.anm, self._sprite.texcoords = self._anm_wrapper.get_sprite(index) + else: + self._anmrunner = ANMRunner(self._anm_wrapper, index, self._sprite) + self._anmrunner.run_frame() + self.num = index + + + def change(self, diff): + keys = self.items.keys() + keys.sort() + index = keys.index(self.num) + diff + if index < 0 or index >= len(keys): + return + item = keys[index] + self.load(item) + + + def toggle_sprites(self): + self.sprites = not(self.sprites) + if self.sprites: + self.items = self.anm.sprites + else: + self.items = self.anm.scripts + self.load() + + + def update(self): + if not self.sprites: + self._anmrunner.run_frame() + + glClear(GL_COLOR_BUFFER_BIT) + self.render_elements([self]) + diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -73,7 +73,7 @@ setup(name='PyTouhou', license='GPLv3', packages=packages, ext_modules=extensions, - scripts=['scripts/eosd'], + scripts=['scripts/eosd', 'scripts/anmviewer'], cmdclass={'build_ext': build_ext, 'build_scripts': BuildScripts}, **extra