changeset 437:d778db08190f

Make Interpolator an extension type.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Wed, 07 Aug 2013 11:34:44 +0200
parents cb5c68598ab0
children 43a8fed9a8d8
files pytouhou/game/enemy.py pytouhou/utils/interpolator.pxd pytouhou/utils/interpolator.pyx
diffstat 3 files changed, 69 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/pytouhou/game/enemy.py
+++ b/pytouhou/game/enemy.py
@@ -249,17 +249,16 @@ class Enemy(object):
     def set_pos(self, x, y, z):
         self.x, self.y = x, y
         self.update_mode = 1
-        self.interpolator = Interpolator((x, y))
-        self.interpolator.set_interpolation_start(self._game.frame, (x, y))
+        self.interpolator = Interpolator((x, y), self._game.frame)
 
 
     def move_to(self, duration, x, y, z, formula):
         frame = self._game.frame
         self.speed_interpolator = None
         self.update_mode = 1
-        self.interpolator = Interpolator((self.x, self.y), formula)
-        self.interpolator.set_interpolation_start(frame, (self.x, self.y))
-        self.interpolator.set_interpolation_end(frame + duration - 1, (x, y))
+        self.interpolator = Interpolator((self.x, self.y), frame,
+                                         (x, y), frame + duration - 1,
+                                         formula)
 
         self.angle = atan2(y - self.y, x - self.x)
 
@@ -268,9 +267,9 @@ class Enemy(object):
         frame = self._game.frame
         self.interpolator = None
         self.update_mode = 1
-        self.speed_interpolator = Interpolator((self.speed,), formula)
-        self.speed_interpolator.set_interpolation_start(frame, (self.speed,))
-        self.speed_interpolator.set_interpolation_end(frame + duration - 1, (0.,))
+        self.speed_interpolator = Interpolator((self.speed,), frame,
+                                               (0.,), frame + duration - 1,
+                                               formula)
 
 
     def is_visible(self, screen_width, screen_height):
new file mode 100644
--- /dev/null
+++ b/pytouhou/utils/interpolator.pxd
@@ -0,0 +1,11 @@
+cdef class Interpolator:
+    cdef unsigned long start_frame, end_frame, _frame
+    cdef long _length
+    cdef double *_values, *start_values, *end_values
+    cdef object _formula
+
+    cpdef set_interpolation_start(self, unsigned long frame, tuple values)
+    cpdef set_interpolation_end(self, unsigned long frame, tuple values)
+    cpdef set_interpolation_end_frame(self, unsigned long end_frame)
+    cpdef set_interpolation_end_values(self, tuple values)
+    cpdef update(self, unsigned long frame)
--- a/pytouhou/utils/interpolator.pyx
+++ b/pytouhou/utils/interpolator.pyx
@@ -12,50 +12,79 @@
 ## GNU General Public License for more details.
 ##
 
+from libc.stdlib cimport malloc, free
 
-class Interpolator(object):
-    __slots__ = ('values', 'start_values', 'end_values', 'start_frame', 'end_frame', '_frame', '_formula')
-    def __init__(self, values=(), start_frame=0, end_values=(), end_frame=0, formula=None):
-        self.values = tuple(values)
-        self.start_values = tuple(values)
-        self.end_values = tuple(end_values)
+
+cdef class Interpolator:
+    def __init__(self, tuple values, unsigned long start_frame=0, tuple end_values=None,
+                 unsigned long end_frame=0, formula=None):
+        self._length = len(values)
+        self._values = <double*>malloc(self._length * sizeof(double))
+        self.start_values = <double*>malloc(self._length * sizeof(double))
+        self.end_values = <double*>malloc(self._length * sizeof(double))
+        for i in xrange(self._length):
+            self._values[i] = values[i]
+            self.start_values[i] = self._values[i]
+        if end_values is not None:
+            for i in xrange(self._length):
+                self.end_values[i] = end_values[i]
         self.start_frame = start_frame
         self.end_frame = end_frame
         self._frame = 0
-        self._formula = formula or (lambda x: x)
+        self._formula = formula
+
+
+    def __dealloc__(self):
+        free(self.end_values)
+        free(self.start_values)
+        free(self._values)
+
+
+    property values:
+        def __get__(self):
+            return tuple([self._values[i] for i in xrange(self._length)])
 
 
     def __nonzero__(self):
         return self._frame < self.end_frame
 
 
-    def set_interpolation_start(self, frame, values):
-        self.start_values = tuple(values)
+    cpdef set_interpolation_start(self, unsigned long frame, tuple values):
+        for i in xrange(self._length):
+            self.start_values[i] = values[i]
         self.start_frame = frame
 
 
-    def set_interpolation_end(self, frame, values):
-        self.end_values = tuple(values)
+    cpdef set_interpolation_end(self, unsigned long frame, tuple values):
+        for i in xrange(self._length):
+            self.end_values[i] = values[i]
         self.end_frame = frame
 
 
-    def set_interpolation_end_frame(self, end_frame):
+    cpdef set_interpolation_end_frame(self, unsigned long end_frame):
         self.end_frame = end_frame
 
 
-    def set_interpolation_end_values(self, values):
-        self.end_values = tuple(values)
+    cpdef set_interpolation_end_values(self, tuple values):
+        for i in xrange(self._length):
+            self.end_values[i] = values[i]
 
 
-    def update(self, frame):
+    cpdef update(self, unsigned long frame):
+        cdef double coeff
+
         self._frame = frame
-        if frame >= self.end_frame - 1: #XXX: skip the last interpolation step
+        if frame + 1 >= self.end_frame: #XXX: skip the last interpolation step
             # This bug is replicated from the original game
-            self.values = self.end_values
-            self.start_values = self.end_values
+            for i in xrange(self._length):
+                self._values[i] = self.end_values[i]
+                self.start_values[i] = self.end_values[i]
             self.start_frame = frame
         else:
-            coeff = self._formula(float(frame - self.start_frame) / float(self.end_frame - self.start_frame))
-            self.values = [start_value + coeff * (end_value - start_value)
-                           for (start_value, end_value) in zip(self.start_values, self.end_values)]
-
+            coeff = float(frame - self.start_frame) / float(self.end_frame - self.start_frame)
+            if self._formula is not None:
+                coeff = self._formula(coeff)
+            for i in xrange(self._length):
+                start_value = self.start_values[i]
+                end_value = self.end_values[i]
+                self._values[i] = start_value + coeff * (end_value - start_value)