source: OniSplit/Totoro/AnimationDaeReader.cs

Last change on this file 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: 5.3 KB
Line 
1using System;
2using System.Collections.Generic;
3
4namespace Oni.Totoro
5{
6 internal class AnimationDaeReader
7 {
8 private Animation animation;
9 private Dae.Scene scene;
10 private int startFrame;
11 private int endFrame;
12 private Body body;
13 private int frameCount;
14
15 public void Read(Animation targetAnimation)
16 {
17 animation = targetAnimation;
18
19 body = BodyDaeReader.Read(scene);
20
21 ComputeFrameCount();
22 ImportTranslation();
23 ImportRotations();
24 animation.ComputeExtents(body);
25 }
26
27 public Dae.Scene Scene
28 {
29 get { return scene; }
30 set { scene = value; }
31 }
32
33 public int StartFrame
34 {
35 get { return startFrame; }
36 set { startFrame = value; }
37 }
38
39 public int EndFrame
40 {
41 get { return endFrame; }
42 set { endFrame = value; }
43 }
44
45 private void ComputeFrameCount()
46 {
47 float maxTime = float.MinValue;
48
49 var inputs = body.Nodes
50 .SelectMany(n => n.DaeNode.Transforms).Where(t => t.HasAnimations)
51 .SelectMany(t => t.Animations).Where(a => a != null)
52 .SelectMany(a => a.Inputs).Where(i => i.Semantic == Dae.Semantic.Input);
53
54 foreach (var input in inputs)
55 maxTime = Math.Max(maxTime, input.Source.FloatData.Max());
56
57 float maxFrameF = maxTime * 60.0f;
58 int maxFrame;
59
60 if (maxFrameF - Math.Round(maxFrameF) < 0.0005)
61 maxFrame = FMath.RoundToInt32(maxFrameF);
62 else
63 maxFrame = FMath.TruncateToInt32(maxFrameF);
64
65 //Console.Error.WriteLine("Info: The last keyframe time is {0}s. The animation length is {1} (at 60fps).",
66 // maxTime, maxFrame + 1);
67
68 if (endFrame == 0)
69 {
70 endFrame = maxFrame;
71 }
72 else if (endFrame > maxFrame)
73 {
74 Console.Error.WriteLine("Warning: the specified animation end frame ({0}) is beyond the last key frame ({1}), using the last frame instead", endFrame, maxFrame);
75 endFrame = maxFrame;
76 }
77
78 if (startFrame >= maxFrame)
79 {
80 Console.Error.WriteLine("Warning: the specified animation start frame ({0}) is beyond the last key frame ({1}), using 0 instead", startFrame, maxFrame);
81 startFrame = 0;
82 }
83
84 frameCount = endFrame - startFrame;
85 }
86
87 private void ImportTranslation()
88 {
89 var rootNode = body.Nodes[0].DaeNode;
90 var translate = rootNode.Transforms[0] as Dae.TransformTranslate;
91
92 if (translate == null)
93 {
94 animation.Heights.AddRange(Enumerable.Repeat(0.0f, frameCount));
95 animation.Velocities.AddRange(Enumerable.Repeat(Vector2.Zero, frameCount));
96 }
97 else
98 {
99 animation.Heights.AddRange(Sample(translate, 1, endFrame - 1));
100
101 var x = Sample(translate, 0, endFrame);
102 var z = Sample(translate, 2, endFrame);
103
104 for (int i = 1; i < x.Length; i++)
105 animation.Velocities.Add(new Vector2(x[i] - x[i - 1], z[i] - z[i - 1]));
106 }
107 }
108
109 private void ImportRotations()
110 {
111 animation.FrameSize = 16;
112
113 foreach (var node in body.Nodes.Select(n => n.DaeNode))
114 {
115 var keys = new List<KeyFrame>();
116 animation.Rotations.Add(keys);
117
118 var rotations = new List<Dae.TransformRotate>();
119 var angles = new List<float[]>();
120
121 foreach (var transform in node.Transforms)
122 {
123 var rotate = transform as Dae.TransformRotate;
124
125 if (rotate != null)
126 {
127 rotations.Add(rotate);
128 angles.Add(Sample(rotate, 3, endFrame - 1));
129 }
130 }
131
132 for (int i = 0; i < frameCount; i++)
133 {
134 var q = Quaternion.Identity;
135
136 for (int j = 0; j < rotations.Count; j++)
137 q *= Quaternion.CreateFromAxisAngle(rotations[j].Axis, MathHelper.ToRadians(angles[j][i]));
138
139 keys.Add(new KeyFrame {
140 Duration = 1,
141 Rotation = q.ToVector4()
142 });
143 }
144 }
145 }
146
147 private float[] Sample(Dae.Transform transform, int index, int endFrame)
148 {
149 Dae.Sampler sampler = null;
150
151 if (transform.HasAnimations)
152 sampler = transform.Animations[index];
153
154 if (sampler == null)
155 {
156 var value = transform.Values[index];
157 var values = new float[endFrame - startFrame + 1];
158
159 for (int i = 0; i < values.Length; i++)
160 values[i] = value;
161
162 return values;
163 }
164
165 return sampler.Sample(startFrame, endFrame);
166 }
167 }
168}
Note: See TracBrowser for help on using the repository browser.