Adjust exported animation keyframes to start from zero time
[libs/gl.git] / blender / io_mspgl / animation.py
1 import mathutils
2
3 class Curve:
4         def __init__(self, curve):
5                 self._curve = curve
6                 self.knots = []
7
8                 for i in range(len(self.keyframe_points)-1):
9                         kf1 = self.keyframe_points[i]
10                         kf2 = self.keyframe_points[i+1]
11                         dx = (kf2.co[0]-kf1.co[0])/3
12                         slope1 = (kf1.handle_right[1]-kf1.co[1])/(kf1.handle_right[0]-kf1.co[0])
13                         slope2 = (kf2.co[1]-kf2.handle_left[1])/(kf2.co[0]-kf2.handle_left[0])
14
15                         if i==0:
16                                 self.knots.append(mathutils.Vector(kf1.co))
17                         self.knots.append(kf1.co+mathutils.Vector((dx, slope1*dx)))
18                         self.knots.append(kf2.co-mathutils.Vector((dx, slope2*dx)))
19                         self.knots.append(mathutils.Vector(kf2.co))
20
21         def __getattr__(self, attr):
22                 return getattr(self._curve, attr)
23
24
25 class Keyframe:
26         def __init__(self, time):
27                 self.time = time
28                 self.control = False
29                 self.curves = []
30
31
32 class Animation:
33         def __init__(self, action):
34                 self._action = action
35                 self.curves = [Curve(c) for c in action.fcurves]
36                 self.fps = 1
37
38                 for c in self.curves:
39                         for i in range(0, len(c.knots)-1, 3):
40                                 p0 = c.knots[i]
41                                 p1 = c.knots[i+1]
42                                 p2 = c.knots[i+2]
43                                 p3 = c.knots[i+3]
44                                 for j in range(50):
45                                         t = (p0[0]*(50-j)+p3[0]*j)/50
46                                         x = (t-p0[0])/(p3[0]-p0[0])
47                                         v1 = c._curve.evaluate(t)
48                                         v2 = p0[1]*(1-x)**3+3*p1[1]*x*(1-x)**2+3*p2[1]*x**2*(1-x)+p3[1]*x**3
49
50                 keyframes_by_time = {}
51                 controls_by_time = {}
52                 self.keyframes = []
53                 for c in self.curves:
54                         for i, k in enumerate(c.knots):
55                                 x = k[0]
56                                 control = i%3!=0
57                                 kf_map = controls_by_time if control else keyframes_by_time
58                                 if x in kf_map:
59                                         kf = kf_map[x]
60                                 else:
61                                         kf = Keyframe(x)
62                                         kf.control = control
63                                         self.keyframes.append(kf)
64                                         kf_map[x] = kf
65                                 kf.curves.append((c, i))
66
67                 self.keyframes.sort(key=lambda k: k.time)
68                 self.start_time = self.keyframes[0].time
69
70                 for c in self.curves:
71                         for k in c.knots:
72                                 k[0] -= self.start_time
73
74                 for k in self.keyframes:
75                         k.time -= self.start_time
76
77         def __getattr__(self, attr):
78                 return getattr(self._curve, attr)
79
80         def change_fps(self, fps):
81                 scale = self.fps/fps
82                 self.fps = fps
83
84                 for c in self.curves:
85                         for k in c.knots:
86                                 k[0] *= scale
87
88                 for k in self.keyframes:
89                         k.time *= scale
90
91
92 def create_animation_from_action(context, action):
93         anim = Animation(action)
94         render = context.scene.render
95         anim.change_fps(render.fps/render.fps_base)
96         return anim