# HG changeset patch # User Emmanuel Gil Peyrot # Date 1375868084 -7200 # Node ID d778db08190fb5692f3252e3b79e376c33b82d64 # Parent cb5c68598ab0d88ea606a09863cb907842363d86 Make Interpolator an extension type. diff --git a/pytouhou/game/enemy.py b/pytouhou/game/enemy.py --- 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): diff --git a/pytouhou/utils/interpolator.pxd b/pytouhou/utils/interpolator.pxd 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) diff --git a/pytouhou/utils/interpolator.pyx b/pytouhou/utils/interpolator.pyx --- 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 = malloc(self._length * sizeof(double)) + self.start_values = malloc(self._length * sizeof(double)) + self.end_values = 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)