1 | using System;
|
---|
2 | using System.Collections.Generic;
|
---|
3 | using Oni.Physics;
|
---|
4 |
|
---|
5 | namespace 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 | }
|
---|