changeset 473:1c891c71cf22

Cythonize pytouhou.game.text.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Mon, 16 Sep 2013 18:42:12 +0200
parents 8038f1957b71
children ca22df9e70bc
files pytouhou/game/game.pxd pytouhou/game/game.pyx pytouhou/game/item.pyx pytouhou/game/text.pxd pytouhou/game/text.py pytouhou/ui/gamerenderer.pyx pytouhou/ui/texture.pyx
diffstat 7 files changed, 127 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/pytouhou/game/game.pxd
+++ b/pytouhou/game/game.pxd
@@ -1,5 +1,6 @@
 from pytouhou.game.effect cimport Effect
 from pytouhou.game.player cimport Player
+from pytouhou.game.text cimport Text, NativeText
 
 cdef class Game:
     cdef public long width, height, nb_bullets_max, stage, rank, difficulty, difficulty_counter, difficulty_min, difficulty_max, frame, last_keystate
@@ -29,9 +30,9 @@ cdef class Game:
     cpdef new_particle(self, pos, long anim, long amp, long number=*, bint reverse=*, long duration=*)
     cpdef new_enemy(self, pos, life, instr_type, bonus_dropped, die_score)
     cpdef new_msg(self, sub)
-    cdef new_label(self, pos, str text)
-    cpdef new_native_text(self, pos, text, align=*)
-    cpdef new_hint(self, hint)
+    cdef Text new_label(self, tuple pos, bytes text)
+    cpdef NativeText new_native_text(self, tuple pos, unicode text, align=*)
+    cpdef Text new_hint(self, hint)
     cpdef new_face(self, side, effect)
     cpdef run_iter(self, long keystate)
     cdef void update_background(self) except *
--- a/pytouhou/game/game.pyx
+++ b/pytouhou/game/game.pyx
@@ -20,7 +20,6 @@ from pytouhou.game.enemy cimport Enemy
 from pytouhou.game.item cimport Item
 from pytouhou.game.effect cimport Particle
 from pytouhou.game.laser cimport Laser, PlayerLaser
-from pytouhou.game.text import Text, NativeText
 from pytouhou.game.face import Face
 
 
@@ -229,19 +228,19 @@ cdef class Game:
         self.msg_runner.run_iteration()
 
 
-    cdef new_label(self, pos, str text):
+    cdef Text new_label(self, tuple pos, bytes text):
         label = Text(pos, self.interface.ascii_anm, text=text, xspacing=8, shift=48)
         label.set_timeout(60, effect='move')
         self.labels.append(label)
         return label
 
 
-    cpdef new_native_text(self, pos, text, align='left'):
+    cpdef NativeText new_native_text(self, tuple pos, unicode text, align='left'):
         label = NativeText(pos, text, shadow=True, align=align)
         return label
 
 
-    cpdef new_hint(self, hint):
+    cpdef Text new_hint(self, hint):
         pos = hint['Pos']
         #TODO: Scale
 
@@ -249,7 +248,7 @@ cdef class Game:
         label = Text(pos, self.interface.ascii_anm, text=hint['Text'], align=hint['Align'])
         label.set_timeout(hint['Time'])
         label.set_alpha(hint['Alpha'])
-        label.set_color(hint['Color'], text=False)
+        label.set_color(None, hint['Color']) #XXX
         self.labels.append(label)
         return label
 
--- a/pytouhou/game/item.pyx
+++ b/pytouhou/game/item.pyx
@@ -94,7 +94,7 @@ cdef class Item(Element):
                     player_state.power = 128
                 for level in (8, 16, 32, 48, 64, 96):
                     if old_power < level and player_state.power >= level:
-                        label = self._game.new_label((self.x, self.y), ':') # Actually a “PowerUp” character.
+                        label = self._game.new_label((self.x, self.y), b':') # Actually a “PowerUp” character.
                         color = 'blue'
                         label.set_color(color)
                         labeled = True
new file mode 100644
--- /dev/null
+++ b/pytouhou/game/text.pxd
@@ -0,0 +1,81 @@
+from pytouhou.game.element cimport Element
+from pytouhou.game.sprite cimport Sprite
+from pytouhou.utils.interpolator cimport Interpolator
+
+cdef class Glyph(Element):
+    pass
+
+
+cdef class Widget(Element):
+    cdef public object update
+    cdef public bint changed
+
+    cdef unsigned long frame
+    cdef object back_anm
+
+    #def update(self)
+
+
+cdef class GlyphCollection(Widget):
+    cdef Sprite ref_sprite
+    cdef object anm
+    cdef list glyphes
+    cdef long xspacing
+
+    cpdef set_length(self, unsigned long length)
+    cpdef set_sprites(self, list sprite_indexes)
+    cpdef set_color(self, text=*, color=*)
+    cpdef set_alpha(self, unsigned char alpha)
+
+
+cdef class Text(GlyphCollection):
+    cdef bytes text
+    cdef long shift, timeout, duration, start
+    cdef Interpolator fade_interpolator
+    cdef unsigned char alpha
+
+    cpdef set_text(self, bytes text)
+    #def timeout_update(self)
+    #def move_timeout_update(self)
+    #def fadeout_timeout_update(self)
+    cdef void fade(self, unsigned long duration, unsigned char alpha, formula=*) except *
+    cpdef set_timeout(self, long timeout, str effect=*, long duration=*, long start=*)
+
+
+cdef class Counter(GlyphCollection):
+    cdef long value
+
+    cpdef set_value(self, long value)
+
+
+cdef class Gauge(Element):
+    cdef public long value, max_length, maximum
+
+    cpdef set_value(self, long value)
+    cpdef update(self)
+
+
+cdef class NativeText(Element):
+    cdef public object update
+
+    cdef unicode text
+    cdef long width, height
+    cdef unsigned char alpha
+    cdef bint shadow
+    cdef bytes align #TODO: use a proper enum.
+    cdef unsigned long frame, timeout, duration
+    cdef long start
+    cdef double to[2], end[2]
+    cdef list gradient
+    cdef Interpolator fade_interpolator, offset_interpolator
+    cdef object texture
+
+    #def normal_update(self)
+    #def timeout_update(self)
+    #def move_timeout_update(self)
+    #def move_ex_timeout_update(self)
+    #def fadeout_timeout_update(self)
+
+    cdef void fade(self, unsigned long duration, unsigned char alpha, formula=*) except *
+    cdef void move_in(self, unsigned long duration, double x, double y, formula=*) except *
+    cpdef set_timeout(self, long timeout, str effect=*, long duration=*, long start=*, to=*, end=*)
--- a/pytouhou/game/text.py
+++ b/pytouhou/game/text.py
@@ -36,12 +36,12 @@ class Widget(Element):
             self.sprite = Sprite()
             self.anmrunner = ANMRunner(back_anm, back_script, self.sprite)
 
-    def update(self):
-        self.frame += 1
+    def normal_update(self):
         if self.changed:
-            if self.anmrunner and not self.anmrunner.run_frame():
+            if self.anmrunner is not None and not self.anmrunner.run_frame():
                 self.anmrunner = None
             self.changed = False
+        self.frame += 1
 
 
 
@@ -60,19 +60,16 @@ class GlyphCollection(Widget):
         self.ref_sprite.corner_relative_placement = True #TODO: perhaps not right
 
 
-    @property
-    def objects(self):
-        return [self] + self.glyphes
-
-
     def set_length(self, length):
         current_length = len(self.glyphes)
         if length > current_length:
-            self.glyphes.extend(Glyph(self.ref_sprite.copy(),
-                                      (self.x + self.xspacing * i, self.y))
-                                for i in range(current_length, length))
+            self.glyphes.extend([Glyph(self.ref_sprite.copy(),
+                                       (self.x + self.xspacing * i, self.y))
+                                 for i in range(current_length, length)])
+            self.objects = [self] + self.glyphes
         elif length < current_length:
             self.glyphes[:] = self.glyphes[:length]
+            self.objects = [self] + self.glyphes
 
 
     def set_sprites(self, sprite_indexes):
@@ -83,12 +80,14 @@ class GlyphCollection(Widget):
             glyph.sprite.changed = True
 
 
-    def set_color(self, color, text=True):
-        if text:
+    def set_color(self, text=None, color=None):
+        if text is not None:
             colors = {'white': (255, 255, 255), 'yellow': (255, 255, 0),
                       'blue': (192, 192, 255), 'darkblue': (160, 128, 255),
                       'purple': (224, 128, 255), 'red': (255, 64, 0)}
-            color = colors[color]
+            color = colors[text]
+        else:
+            assert color is not None
         self.ref_sprite.color = color
         for glyph in self.glyphes:
             glyph.sprite.color = color
@@ -106,7 +105,7 @@ class Text(GlyphCollection):
                  xspacing=14, shift=21, back_script=22, align='left'):
         GlyphCollection.__init__(self, pos, ascii_anm, back_anm,
                                  xspacing=xspacing, back_script=back_script)
-        self.text = ''
+        self.text = b''
         self.shift = shift
 
         if align == 'center':
@@ -129,7 +128,7 @@ class Text(GlyphCollection):
 
 
     def timeout_update(self):
-        GlyphCollection.update(self)
+        GlyphCollection.normal_update(self)
         if self.frame == self.timeout:
             self.removed = True
 
@@ -144,9 +143,9 @@ class Text(GlyphCollection):
     def fadeout_timeout_update(self):
         if self.frame >= self.start:
             if self.frame == self.start:
-                self.fade(self.duration, 255, lambda x: x)
+                self.fade(self.duration, 255)
             elif self.frame == self.timeout - self.duration:
-                self.fade(self.duration, 0, lambda x: x)
+                self.fade(self.duration, 0)
             self.fade_interpolator.update(self.frame)
             self.alpha = int(self.fade_interpolator.values[0])
             for glyph in self.glyphes:
@@ -155,7 +154,7 @@ class Text(GlyphCollection):
         self.timeout_update()
 
 
-    def fade(self, duration, alpha, formula):
+    def fade(self, duration, alpha, formula=None):
         self.fade_interpolator = Interpolator((self.alpha,), self.frame,
                                               (alpha,), self.frame + duration,
                                               formula)
@@ -225,12 +224,12 @@ class Gauge(Element):
             self.sprite.visible = False
         else:
             self.sprite.visible = True
-        if self.anmrunner and not self.anmrunner.run_frame():
+        if self.anmrunner is not None and not self.anmrunner.run_frame():
             self.anmrunner = None
 
 
 
-class NativeText(object):
+class NativeText(Element):
     def __init__(self, pos, text, gradient=None, alpha=255, shadow=False, align='left'):
         self.removed = False
         self.x, self.y = pos
@@ -265,9 +264,9 @@ class NativeText(object):
     def move_ex_timeout_update(self):
         if self.frame >= self.start:
             if self.frame == self.start:
-                self.move_in(self.duration, self.to[0], self.to[1], lambda x: x)
+                self.move_in(self.duration, self.to[0], self.to[1])
             elif self.frame == self.timeout - self.duration:
-                self.move_in(self.duration, self.end[0], self.end[1], lambda x: x)
+                self.move_in(self.duration, self.end[0], self.end[1])
             if self.offset_interpolator:
                 self.offset_interpolator.update(self.frame)
                 self.x, self.y = self.offset_interpolator.values
@@ -277,21 +276,21 @@ class NativeText(object):
     def fadeout_timeout_update(self):
         if self.frame >= self.start:
             if self.frame == self.start:
-                self.fade(self.duration, 255, lambda x: x)
+                self.fade(self.duration, 255)
             elif self.frame == self.timeout - self.duration:
-                self.fade(self.duration, 0, lambda x: x)
+                self.fade(self.duration, 0)
             self.fade_interpolator.update(self.frame)
             self.alpha = int(self.fade_interpolator.values[0])
         self.timeout_update()
 
 
-    def fade(self, duration, alpha, formula):
+    def fade(self, duration, alpha, formula=None):
         self.fade_interpolator = Interpolator((self.alpha,), self.frame,
                                               (alpha,), self.frame + duration,
                                               formula)
 
 
-    def move_in(self, duration, x, y, formula):
+    def move_in(self, duration, x, y, formula=None):
         self.offset_interpolator = Interpolator((self.x, self.y), self.frame,
                                                 (x, y), self.frame + duration,
                                                 formula)
@@ -305,8 +304,8 @@ class NativeText(object):
             self.update = self.move_ex_timeout_update
             self.duration = duration
             self.start = start
-            self.to = to
-            self.end = end
+            self.to[:] = [to[0], to[1]]
+            self.end[:] = [end[0], end[1]]
         elif effect == 'fadeout':
             self.alpha = 0
             self.update = self.fadeout_timeout_update
--- a/pytouhou/ui/gamerenderer.pyx
+++ b/pytouhou/ui/gamerenderer.pyx
@@ -22,6 +22,7 @@ from pytouhou.lib.opengl cimport \
           GL_SCISSOR_TEST, GL_DEPTH_BUFFER_BIT)
 
 from pytouhou.utils.maths cimport perspective, setup_camera, ortho_2d
+from pytouhou.game.text cimport NativeText, GlyphCollection
 from .shaders.eosd import GameShader, BackgroundShader, PassthroughShader
 
 from collections import namedtuple
@@ -177,6 +178,8 @@ cdef class GameRenderer(Renderer):
 
 
     cdef void render_text(self, texts):
+        cdef NativeText label
+
         if self.font_manager is None:
             return
 
@@ -201,6 +204,8 @@ cdef class GameRenderer(Renderer):
 
 
     cdef void render_interface(self, interface, game_boss):
+        cdef GlyphCollection label
+
         elements = []
 
         if self.use_fixed_pipeline:
--- a/pytouhou/ui/texture.pyx
+++ b/pytouhou/ui/texture.pyx
@@ -21,6 +21,7 @@ from pytouhou.lib.opengl cimport \
 
 from pytouhou.lib.sdl cimport load_png, create_rgb_surface, Font
 from pytouhou.formats.thtx import Texture #TODO: perhaps define that elsewhere?
+from pytouhou.game.text cimport NativeText
 
 import os
 
@@ -60,8 +61,10 @@ cdef class FontManager:
 
 
     def load(self, label_list):
+        cdef NativeText label
+
         for label in label_list:
-            if not hasattr(label, 'texture'):
+            if label.texture is None:
                 surface = self.font.render(label.text)
                 label.width, label.height = surface.surface.w, surface.surface.h