]> git.tdb.fi Git - libs/gl.git/blob - blender/io_mspgl/animation.py
Revise export function parameter orders
[libs/gl.git] / blender / io_mspgl / animation.py
1 import math
2 import mathutils
3
4 class Curve:
5         def __init__(self, curve):
6                 self._curve = curve
7                 self.knots = []
8
9                 for i in range(len(self.keyframe_points)-1):
10                         kf1 = self.keyframe_points[i]
11                         kf2 = self.keyframe_points[i+1]
12                         dx = (kf2.co[0]-kf1.co[0])/3
13                         slope1 = (kf1.handle_right[1]-kf1.co[1])/(kf1.handle_right[0]-kf1.co[0])
14                         slope2 = (kf2.co[1]-kf2.handle_left[1])/(kf2.co[0]-kf2.handle_left[0])
15
16                         if i==0:
17                                 self.knots.append(mathutils.Vector(kf1.co))
18                         self.knots.append(kf1.co+mathutils.Vector((dx, slope1*dx)))
19                         self.knots.append(kf2.co-mathutils.Vector((dx, slope2*dx)))
20                         self.knots.append(mathutils.Vector(kf2.co))
21
22         def __getattr__(self, attr):
23                 return getattr(self._curve, attr)
24
25
26 class Keyframe:
27         def __init__(self, time):
28                 self.time = time
29                 self.control = False
30                 self.curves = []
31
32
33 class Animation:
34         def __init__(self, action):
35                 self._action = action
36                 self.curves = [Curve(c) for c in action.fcurves]
37                 self.fps = 1
38                 self.looping = False
39
40                 for c in self.curves:
41                         for i in range(0, len(c.knots)-1, 3):
42                                 p0 = c.knots[i]
43                                 p1 = c.knots[i+1]
44                                 p2 = c.knots[i+2]
45                                 p3 = c.knots[i+3]
46                                 for j in range(50):
47                                         t = (p0[0]*(50-j)+p3[0]*j)/50
48                                         x = (t-p0[0])/(p3[0]-p0[0])
49                                         v1 = c._curve.evaluate(t)
50                                         v2 = p0[1]*(1-x)**3+3*p1[1]*x*(1-x)**2+3*p2[1]*x**2*(1-x)+p3[1]*x**3
51
52                 keyframes_by_time = {}
53                 controls_by_time = {}
54                 self.keyframes = []
55                 for c in self.curves:
56                         for i, k in enumerate(c.knots):
57                                 x = k[0]
58                                 control = i%3!=0
59                                 kf_map = controls_by_time if control else keyframes_by_time
60                                 if x in kf_map:
61                                         kf = kf_map[x]
62                                 else:
63                                         kf = Keyframe(x)
64                                         kf.control = control
65                                         self.keyframes.append(kf)
66                                         kf_map[x] = kf
67                                 kf.curves.append((c, i))
68
69                 self.keyframes.sort(key=lambda k: k.time)
70                 self.start_time = self.keyframes[0].time
71
72                 for c in self.curves:
73                         for k in c.knots:
74                                 k[0] -= self.start_time
75
76                 for k in self.keyframes:
77                         k.time -= self.start_time
78
79         def __getattr__(self, attr):
80                 return getattr(self._curve, attr)
81
82         def check_looping(self, threshold):
83                 self.looping = True
84                 for c in self.curves:
85                         first_y = c.knots[0][1]
86                         last_y = c.knots[-1][1]
87                         d = abs(last_y-first_y)
88
89                         if c.data_path=="rotation_euler":
90                                 while d>math.pi/2:
91                                         d -= math.pi
92                                 while d<-math.pi/2:
93                                         d += math.pi
94
95                         if d>threshold:
96                                 self.looping = False
97                                 break
98
99         def change_fps(self, fps):
100                 scale = self.fps/fps
101                 self.fps = fps
102
103                 for c in self.curves:
104                         for k in c.knots:
105                                 k[0] *= scale
106
107                 for k in self.keyframes:
108                         k.time *= scale
109
110
111 def create_animation_from_action(context, action, *, looping_threshold=0.001):
112         anim = Animation(action)
113         render = context.scene.render
114         anim.check_looping(looping_threshold)
115         anim.change_fps(render.fps/render.fps_base)
116         return anim