+import mathutils
+
+class Curve:
+ def __init__(self, curve):
+ self._curve = curve
+ self.knots = []
+
+ for i in range(len(self.keyframe_points)-1):
+ kf1 = self.keyframe_points[i]
+ kf2 = self.keyframe_points[i+1]
+ dx = (kf2.co[0]-kf1.co[0])/3
+ slope1 = (kf1.handle_right[1]-kf1.co[1])/(kf1.handle_right[0]-kf1.co[0])
+ slope2 = (kf2.co[1]-kf2.handle_left[1])/(kf2.co[0]-kf2.handle_left[0])
+
+ if i==0:
+ self.knots.append(mathutils.Vector(kf1.co))
+ self.knots.append(kf1.co+mathutils.Vector((dx, slope1*dx)))
+ self.knots.append(kf2.co-mathutils.Vector((dx, slope2*dx)))
+ self.knots.append(mathutils.Vector(kf2.co))
+
+ def __getattr__(self, attr):
+ return getattr(self._curve, attr)
+
+
+class Keyframe:
+ def __init__(self, time):
+ self.time = time
+ self.control = False
+ self.curves = []
+
+
+class Animation:
+ def __init__(self, action):
+ self._action = action
+ self.curves = [Curve(c) for c in action.fcurves]
+ self.fps = 1
+
+ for c in self.curves:
+ for i in range(0, len(c.knots)-1, 3):
+ p0 = c.knots[i]
+ p1 = c.knots[i+1]
+ p2 = c.knots[i+2]
+ p3 = c.knots[i+3]
+ for j in range(50):
+ t = (p0[0]*(50-j)+p3[0]*j)/50
+ x = (t-p0[0])/(p3[0]-p0[0])
+ v1 = c._curve.evaluate(t)
+ v2 = p0[1]*(1-x)**3+3*p1[1]*x*(1-x)**2+3*p2[1]*x**2*(1-x)+p3[1]*x**3
+
+ keyframes_by_time = {}
+ controls_by_time = {}
+ self.keyframes = []
+ for c in self.curves:
+ for i, k in enumerate(c.knots):
+ x = k[0]
+ control = i%3!=0
+ kf_map = controls_by_time if control else keyframes_by_time
+ if x in kf_map:
+ kf = kf_map[x]
+ else:
+ kf = Keyframe(x)
+ kf.control = control
+ self.keyframes.append(kf)
+ kf_map[x] = kf
+ kf.curves.append((c, i))
+
+ self.keyframes.sort(key=lambda k: k.time)
+
+ def __getattr__(self, attr):
+ return getattr(self._curve, attr)
+
+ def change_fps(self, fps):
+ scale = self.fps/fps
+ self.fps = fps
+
+ for c in self.curves:
+ for k in c.knots:
+ k[0] *= scale
+
+ for k in self.keyframes:
+ k.time *= scale
+
+
+def create_animation_from_action(context, action):
+ anim = Animation(action)
+ render = context.scene.render
+ anim.change_fps(render.fps/render.fps_base)
+ return anim