source: OniSplit/Totoro/Animation.cs@ 1152

Last change on this file since 1152 was 1114, checked in by iritscen, 5 years ago

Adding OniSplit source code (v0.9.99.0). Many thanks to Neo for all his work over the years.

File size: 10.3 KB
Line 
1using System;
2using System.Collections.Generic;
3using Oni.Physics;
4
5namespace Oni.Totoro
6{
7 internal class Animation
8 {
9 public string Name;
10 public AnimationFlags Flags;
11 public readonly string[] DirectAnimations = new string[2];
12 public float FinalRotation;
13 public Direction Direction = Direction.Forward;
14 public int Vocalization = 65535;
15 public string Impact;
16 public int HardPause;
17 public int SoftPause;
18 public AnimationType Type;
19 public AnimationType AimingType;
20 public AnimationState FromState;
21 public AnimationState ToState;
22 public AnimationVarient Varient;
23 public int ActionFrame = 65535;
24 public int FirstLevelAvailable;
25 public BoneMask OverlayUsedBones;
26 public BoneMask OverlayReplacedBones;
27 public int AtomicStart;
28 public int AtomicEnd;
29 public int InvulnerableStart;
30 public int InvulnerableEnd;
31 public int InterpolationMax;
32 public int InterpolationEnd;
33 public int FrameSize;
34
35 public readonly List<float> Heights = new List<float>();
36 public readonly List<Vector2> Velocities = new List<Vector2>();
37 public readonly List<List<KeyFrame>> Rotations = new List<List<KeyFrame>>();
38 public readonly List<Shortcut> Shortcuts = new List<Shortcut>();
39 public readonly List<Position> Positions = new List<Position>();
40 public readonly List<Damage> SelfDamage = new List<Damage>();
41 public ThrowInfo ThrowSource;
42 public readonly List<Sound> Sounds = new List<Sound>();
43 public readonly List<Footstep> Footsteps = new List<Footstep>();
44 public readonly List<Particle> Particles = new List<Particle>();
45 public readonly List<MotionBlur> MotionBlur = new List<MotionBlur>();
46 public readonly List<Attack> Attacks = new List<Attack>();
47 public readonly float[] AttackRing = new float[36];
48 public readonly List<List<Vector3>> AllPoints = new List<List<Vector3>>();
49
50 public void ValidateFrames()
51 {
52 var error = Console.Error;
53 int frameCount = Heights.Count;
54
55 foreach (var sound in Sounds.FindAll(s => s.Start >= frameCount))
56 {
57 error.WriteLine("Warning: sound start {0} is beyond the last animation frame", sound.Start);
58 Sounds.Remove(sound);
59 }
60
61 foreach (var footstep in Footsteps.FindAll(f => f.Frame >= frameCount))
62 {
63 error.WriteLine("Warning: footstep frame {0} is beyond the last animation frame", footstep.Frame);
64 Footsteps.Remove(footstep);
65 }
66
67 foreach (var damage in SelfDamage.FindAll(d => d.Frame > frameCount))
68 {
69 error.WriteLine("Warning: damage frame {0} is beyond the last animation frame", damage.Frame);
70 SelfDamage.Remove(damage);
71 }
72
73 foreach (var attack in Attacks.FindAll(a => a.Start >= frameCount))
74 {
75 error.WriteLine("Warning: attack start frame {0} is beyond the last animation frame", attack.Start);
76 Attacks.Remove(attack);
77 }
78
79 foreach (var particle in Particles.FindAll(p => p.Start >= frameCount))
80 {
81 error.WriteLine("Warning: particle start frame {0} is beyond the last animation frame", particle.Start);
82 Particles.Remove(particle);
83 }
84 }
85
86 public void ComputeExtents(Body body)
87 {
88 Positions.Clear();
89 AllPoints.Clear();
90
91 int frameCount = Heights.Count;
92 int boneCount = Rotations.Count;
93
94 var rotations = new Quaternion[frameCount, boneCount];
95
96 //
97 // Compute the quaternions for each bone and frame
98 //
99
100 for (int bone = 0; bone < boneCount; bone++)
101 {
102 var keys = Rotations[bone];
103
104 for (int frame = 0; frame < keys.Count; frame++)
105 rotations[frame, bone] = new Quaternion(keys[frame].Rotation);
106 }
107
108 var transforms = new Matrix[boneCount];
109 var offset = Vector2.Zero;
110
111 for (int frame = 0; frame < frameCount; frame++)
112 {
113 //
114 // Create transforms
115 //
116
117 for (int bone = 0; bone < boneCount; bone++)
118 {
119 transforms[bone] = Matrix.CreateFromQuaternion(rotations[frame, bone]);
120 transforms[bone].Translation = body.Nodes[bone].Translation;
121 }
122
123 //
124 // Propagate transforms through the hierarchy
125 //
126
127 PropagateTransforms(body.Root, transforms);
128
129 //
130 // Apply the root translation
131 //
132
133 for (int bone = 0; bone < boneCount; bone++)
134 {
135 transforms[bone] *= Matrix.CreateTranslation(offset.X, Heights[frame], offset.Y);
136 }
137
138 //
139 // Compute the vertical extent for this frame
140 //
141
142 var minY = 1e09f;
143 var maxY = -1e09f;
144 var allFramePoints = new List<Vector3>(8 * boneCount);
145
146 for (int bone = 0; bone < boneCount; bone++)
147 {
148 var points = body.Nodes[bone].Geometry.Points;
149 var box = BoundingBox.CreateFromPoints(points);
150 var sphere = BoundingSphere.CreateFromBoundingBox(box);
151 var worldCorners = Vector3.Transform(box.GetCorners(), ref transforms[bone]);
152 var worldCenter = Vector3.Transform(sphere.Center, ref transforms[bone]);
153
154 minY = Math.Min(minY, worldCenter.Y - sphere.Radius);
155 maxY = Math.Max(maxY, worldCenter.Y + sphere.Radius);
156 allFramePoints.AddRange(worldCorners);
157 }
158
159 Positions.Add(new Position {
160 Height = maxY - minY,
161 YOffset = minY,
162 X = offset.X,
163 Z = offset.Y
164 });
165
166 AllPoints.Add(allFramePoints);
167
168 offset += Velocities[frame];
169 }
170 }
171
172 private static void PropagateTransforms(BodyNode bodyNode, Matrix[] transforms)
173 {
174 foreach (var child in bodyNode.Nodes)
175 {
176 transforms[child.Index] *= transforms[bodyNode.Index];
177 PropagateTransforms(child, transforms);
178 }
179 }
180
181 public ObjectAnimation[] ToObjectAnimation(Body body)
182 {
183 var anims = new ObjectAnimation[body.Nodes.Count];
184
185 foreach (var node in body.Nodes)
186 {
187 anims[node.Index] = new ObjectAnimation {
188 Name = Name + "_" + node.Name,
189 Length = Heights.Count,
190 };
191 }
192
193 FillObjectAnimationFrames(anims, body.Root, null);
194
195 return anims;
196 }
197
198 private void FillObjectAnimationFrames(ObjectAnimation[] anims, BodyNode node, BodyNode parentNode)
199 {
200 var frames = new ObjectAnimationKey[Velocities.Count];
201
202 //
203 // Scale is always 1. Frame length is always 1 too.
204 //
205
206 for (int i = 0; i < frames.Length; i++)
207 {
208 frames[i] = new ObjectAnimationKey {
209 Time = i,
210 Scale = Vector3.One
211 };
212 }
213
214 //
215 // Transform key frames to quaternions.
216 //
217
218 var keys = Rotations[node.Index];
219 var quats = new Quaternion[keys.Count];
220 var isCompressed = FrameSize == 6;
221
222 for (int k = 0; k < keys.Count; k++)
223 {
224 var key = keys[k];
225
226 if (isCompressed)
227 {
228 quats[k] = Quaternion.CreateFromAxisAngle(Vector3.UnitX, MathHelper.ToRadians(key.Rotation.X))
229 * Quaternion.CreateFromAxisAngle(Vector3.UnitY, MathHelper.ToRadians(key.Rotation.Y))
230 * Quaternion.CreateFromAxisAngle(Vector3.UnitZ, MathHelper.ToRadians(key.Rotation.Z));
231 }
232 else
233 {
234 quats[k] = new Quaternion(key.Rotation);
235 }
236 }
237
238 //
239 // Interpolate the quaternions.
240 //
241
242 int frame = 0;
243
244 for (int k = 0; k < keys.Count; k++)
245 {
246 var duration = keys[k].Duration;
247
248 var q1 = quats[k];
249 var q2 = (k == keys.Count - 1) ? quats[k] : quats[k + 1];
250
251 for (int t = 0; t < duration; t++)
252 frames[frame++].Rotation = Quaternion.Lerp(q1, q2, (float)t / (float)duration);
253 }
254
255 //
256 // Build translation and merge with parent anim.
257 //
258
259 if (parentNode == null)
260 {
261 Vector2 offset = Vector2.Zero;
262
263 for (int i = 0; i < frames.Length; i++)
264 {
265 //frames[i].Translation = new Vector3(offset.X, 0.0f, offset.Y);
266 offset += Velocities[i];
267 }
268 }
269 else
270 {
271 for (int i = 0; i < frames.Length; i++)
272 {
273 frames[i].Translation = node.Translation;
274 }
275
276 var parentFrames = anims[parentNode.Index].Keys;
277
278 for (int i = 0; i < frames.Length; i++)
279 {
280 frames[i].Rotation = parentFrames[i].Rotation * frames[i].Rotation;
281 frames[i].Translation = parentFrames[i].Translation + Vector3.Transform(frames[i].Translation, parentFrames[i].Rotation);
282 }
283 }
284
285 anims[node.Index].Keys = frames;
286
287 foreach (var child in node.Nodes)
288 FillObjectAnimationFrames(anims, child, node);
289 }
290 }
291}
Note: See TracBrowser for help on using the repository browser.