1 |
using System; |
2 |
using System.Collections.Generic; |
3 |
|
4 |
namespace Oni.Totoro |
5 |
{ |
6 |
internal class AnimationDatReader |
7 |
{ |
8 |
private readonly Animation animation = new Animation(); |
9 |
private readonly InstanceDescriptor tram; |
10 |
private readonly BinaryReader dat; |
11 |
|
12 |
#region private class DatExtent |
13 |
|
14 |
private class DatExtent |
15 |
{ |
16 |
public int Frame; |
17 |
public readonly AttackExtent Extent = new AttackExtent(); |
18 |
} |
19 |
|
20 |
#endregion |
21 |
#region private class DatExtentInfo |
22 |
|
23 |
private class DatExtentInfo |
24 |
{ |
25 |
public float MaxHorizontal; |
26 |
public float MinY = 1e09f; |
27 |
public float MaxY = -1e09f; |
28 |
public readonly DatExtentInfoFrame FirstExtent = new DatExtentInfoFrame(); |
29 |
public readonly DatExtentInfoFrame MaxExtent = new DatExtentInfoFrame(); |
30 |
} |
31 |
|
32 |
#endregion |
33 |
#region private class DatExtentInfoFrame |
34 |
|
35 |
private class DatExtentInfoFrame |
36 |
{ |
37 |
public int Frame = -1; |
38 |
public int Attack; |
39 |
public int AttackOffset; |
40 |
public Vector2 Location; |
41 |
public float Height; |
42 |
public float Length; |
43 |
public float MinY; |
44 |
public float MaxY; |
45 |
public float Angle; |
46 |
} |
47 |
|
48 |
#endregion |
49 |
|
50 |
private AnimationDatReader(InstanceDescriptor tram, BinaryReader dat) |
51 |
{ |
52 |
this.tram = tram; |
53 |
this.dat = dat; |
54 |
} |
55 |
|
56 |
public static Animation Read(InstanceDescriptor tram) |
57 |
{ |
58 |
using (var dat = tram.OpenRead()) |
59 |
{ |
60 |
var reader = new AnimationDatReader(tram, dat); |
61 |
reader.ReadAnimation(); |
62 |
return reader.animation; |
63 |
} |
64 |
} |
65 |
|
66 |
private void ReadAnimation() |
67 |
{ |
68 |
dat.Skip(4); |
69 |
int heightOffset = dat.ReadInt32(); |
70 |
int velocityOffset = dat.ReadInt32(); |
71 |
int attackOffset = dat.ReadInt32(); |
72 |
int damageOffset = dat.ReadInt32(); |
73 |
int motionBlurOffset = dat.ReadInt32(); |
74 |
int shortcutOffset = dat.ReadInt32(); |
75 |
ReadOptionalThrowInfo(); |
76 |
int footstepOffset = dat.ReadInt32(); |
77 |
int particleOffset = dat.ReadInt32(); |
78 |
int positionOffset = dat.ReadInt32(); |
79 |
int rotationOffset = dat.ReadInt32(); |
80 |
int soundOffset = dat.ReadInt32(); |
81 |
animation.Flags = (AnimationFlags)dat.ReadInt32(); |
82 |
|
83 |
var directAnimations = dat.ReadLinkArray(2); |
84 |
for (int i = 0; i < directAnimations.Length; i++) |
85 |
animation.DirectAnimations[i] = (directAnimations[i] != null ? directAnimations[i].FullName : null); |
86 |
|
87 |
animation.OverlayUsedBones = (BoneMask)dat.ReadInt32(); |
88 |
animation.OverlayReplacedBones = (BoneMask)dat.ReadInt32(); |
89 |
animation.FinalRotation = dat.ReadSingle(); |
90 |
animation.Direction = (Direction)dat.ReadUInt16(); |
91 |
animation.Vocalization = dat.ReadUInt16(); |
92 |
var extents = ReadExtentInfo(); |
93 |
animation.Impact = dat.ReadString(16); |
94 |
animation.HardPause = dat.ReadUInt16(); |
95 |
animation.SoftPause = dat.ReadUInt16(); |
96 |
int soundCount = dat.ReadInt32(); |
97 |
dat.Skip(6); |
98 |
int fps = dat.ReadUInt16(); |
99 |
animation.FrameSize = dat.ReadUInt16(); |
100 |
animation.Type = (AnimationType)dat.ReadUInt16(); |
101 |
animation.AimingType = (AnimationType)dat.ReadUInt16(); |
102 |
animation.FromState = (AnimationState)dat.ReadUInt16(); |
103 |
animation.ToState = (AnimationState)dat.ReadUInt16(); |
104 |
int boneCount = dat.ReadUInt16(); |
105 |
int frameCount = dat.ReadUInt16(); |
106 |
int duration = dat.ReadInt16(); |
107 |
animation.Varient = (AnimationVarient)dat.ReadUInt16(); |
108 |
dat.Skip(2); |
109 |
animation.AtomicStart = dat.ReadUInt16(); |
110 |
animation.AtomicEnd = dat.ReadUInt16(); |
111 |
animation.InterpolationEnd = dat.ReadUInt16(); |
112 |
animation.InterpolationMax = dat.ReadUInt16(); |
113 |
animation.ActionFrame = dat.ReadUInt16(); |
114 |
animation.FirstLevelAvailable = dat.ReadUInt16(); |
115 |
animation.InvulnerableStart = dat.ReadByte(); |
116 |
animation.InvulnerableEnd = dat.ReadByte(); |
117 |
int attackCount = dat.ReadByte(); |
118 |
int damageCount = dat.ReadByte(); |
119 |
int motionBlurCount = dat.ReadByte(); |
120 |
int shortcutCount = dat.ReadByte(); |
121 |
int footstepCount = dat.ReadByte(); |
122 |
int particleCount = dat.ReadByte(); |
123 |
ReadRawArray(heightOffset, frameCount, animation.Heights, r => r.ReadSingle()); |
124 |
ReadRawArray(velocityOffset, frameCount, animation.Velocities, r => r.ReadVector2()); |
125 |
ReadRotations(rotationOffset, boneCount, frameCount); |
126 |
ReadRawArray(positionOffset, frameCount, animation.Positions, ReadPosition); |
127 |
ReadRawArray(shortcutOffset, shortcutCount, animation.Shortcuts, ReadShortcut); |
128 |
ReadRawArray(damageOffset, damageCount, animation.SelfDamage, ReadDamage); |
129 |
ReadRawArray(particleOffset, particleCount, animation.Particles, ReadParticle); |
130 |
ReadRawArray(footstepOffset, footstepCount, animation.Footsteps, ReadFootstep); |
131 |
ReadRawArray(soundOffset, soundCount, animation.Sounds, ReadSound); |
132 |
ReadRawArray(motionBlurOffset, motionBlurCount, animation.MotionBlur, ReadMotionBlur); |
133 |
ReadRawArray(attackOffset, attackCount, animation.Attacks, ReadAttack); |
134 |
|
135 |
foreach (var attack in animation.Attacks) |
136 |
{ |
137 |
for (int i = attack.Start; i <= attack.End; i++) |
138 |
{ |
139 |
var extent = extents.FirstOrDefault(e => e.Frame == i); |
140 |
|
141 |
if (extent != null) |
142 |
attack.Extents.Add(extent.Extent); |
143 |
} |
144 |
} |
145 |
} |
146 |
|
147 |
private void ReadRotations(int offset, int boneCount, int frameCount) |
148 |
{ |
149 |
using (var raw = tram.GetRawReader(offset)) |
150 |
{ |
151 |
int basePosition = raw.Position; |
152 |
var boneOffsets = raw.ReadUInt16Array(boneCount); |
153 |
|
154 |
foreach (int boneOffset in boneOffsets) |
155 |
{ |
156 |
raw.Position = basePosition + boneOffset; |
157 |
|
158 |
var keys = new List<KeyFrame>(); |
159 |
int time = 0; |
160 |
|
161 |
do |
162 |
{ |
163 |
var key = new KeyFrame(); |
164 |
|
165 |
if (animation.FrameSize == 6) |
166 |
{ |
167 |
key.Rotation.X = raw.ReadInt16() * 180.0f / 32767.5f; |
168 |
key.Rotation.Y = raw.ReadInt16() * 180.0f / 32767.5f; |
169 |
key.Rotation.Z = raw.ReadInt16() * 180.0f / 32767.5f; |
170 |
} |
171 |
else if (animation.FrameSize == 16) |
172 |
{ |
173 |
key.Rotation = raw.ReadQuaternion().ToVector4(); |
174 |
} |
175 |
|
176 |
if (time == frameCount - 1) |
177 |
key.Duration = 1; |
178 |
else |
179 |
key.Duration = raw.ReadByte(); |
180 |
|
181 |
time += key.Duration; |
182 |
keys.Add(key); |
183 |
|
184 |
} while (time < frameCount); |
185 |
|
186 |
animation.Rotations.Add(keys); |
187 |
} |
188 |
} |
189 |
} |
190 |
|
191 |
private List<DatExtent> ReadExtentInfo() |
192 |
{ |
193 |
var info = new DatExtentInfo |
194 |
{ |
195 |
MaxHorizontal = dat.ReadSingle(), |
196 |
MinY = dat.ReadSingle(), |
197 |
MaxY = dat.ReadSingle() |
198 |
}; |
199 |
|
200 |
for (int i = 0; i < animation.AttackRing.Length; i++) |
201 |
animation.AttackRing[i] = dat.ReadSingle(); |
202 |
|
203 |
info.FirstExtent.Frame = dat.ReadUInt16(); |
204 |
info.FirstExtent.Attack = dat.ReadByte(); |
205 |
info.FirstExtent.AttackOffset = dat.ReadByte(); |
206 |
info.FirstExtent.Location = dat.ReadVector2(); |
207 |
info.FirstExtent.Height = dat.ReadSingle(); |
208 |
info.FirstExtent.Length = dat.ReadSingle(); |
209 |
info.FirstExtent.MinY = dat.ReadSingle(); |
210 |
info.FirstExtent.MaxY = dat.ReadSingle(); |
211 |
info.FirstExtent.Angle = dat.ReadSingle(); |
212 |
|
213 |
info.MaxExtent.Frame = dat.ReadUInt16(); |
214 |
info.MaxExtent.Attack = dat.ReadByte(); |
215 |
info.MaxExtent.AttackOffset = dat.ReadByte(); |
216 |
info.MaxExtent.Location = dat.ReadVector2(); |
217 |
info.MaxExtent.Height = dat.ReadSingle(); |
218 |
info.MaxExtent.Length = dat.ReadSingle(); |
219 |
info.MaxExtent.MinY = dat.ReadSingle(); |
220 |
info.MaxExtent.MaxY = dat.ReadSingle(); |
221 |
info.MaxExtent.Angle = dat.ReadSingle(); |
222 |
|
223 |
dat.Skip(4); |
224 |
|
225 |
int extentCount = dat.ReadInt32(); |
226 |
int extentOffset = dat.ReadInt32(); |
227 |
|
228 |
var extents = new List<DatExtent>(); |
229 |
ReadRawArray(extentOffset, extentCount, extents, ReadExtent); |
230 |
|
231 |
foreach (var datExtent in extents) |
232 |
{ |
233 |
var attackExtent = datExtent.Extent; |
234 |
|
235 |
if (datExtent.Frame == info.FirstExtent.Frame) |
236 |
{ |
237 |
attackExtent.Angle = MathHelper.ToDegrees(info.FirstExtent.Angle); |
238 |
attackExtent.Length = info.FirstExtent.Length; |
239 |
attackExtent.MinY = info.FirstExtent.MinY; |
240 |
attackExtent.MaxY = info.FirstExtent.MaxY; |
241 |
} |
242 |
else if (datExtent.Frame == info.MaxExtent.Frame) |
243 |
{ |
244 |
attackExtent.Angle = MathHelper.ToDegrees(info.MaxExtent.Angle); |
245 |
attackExtent.Length = info.MaxExtent.Length; |
246 |
attackExtent.MinY = info.MaxExtent.MinY; |
247 |
attackExtent.MaxY = info.MaxExtent.MaxY; |
248 |
} |
249 |
|
250 |
if (Math.Abs(attackExtent.MinY - info.MinY) < 0.01f) |
251 |
attackExtent.MinY = info.MinY; |
252 |
|
253 |
if (Math.Abs(attackExtent.MaxY - info.MaxY) < 0.01f) |
254 |
attackExtent.MaxY = info.MaxY; |
255 |
} |
256 |
|
257 |
return extents; |
258 |
} |
259 |
|
260 |
private void ReadOptionalThrowInfo() |
261 |
{ |
262 |
int offset = dat.ReadInt32(); |
263 |
|
264 |
if (offset != 0) |
265 |
{ |
266 |
using (var raw = tram.GetRawReader(offset)) |
267 |
animation.ThrowSource = ReadThrowInfo(raw); |
268 |
} |
269 |
} |
270 |
|
271 |
private ThrowInfo ReadThrowInfo(BinaryReader raw) |
272 |
{ |
273 |
return new ThrowInfo |
274 |
{ |
275 |
Position = raw.ReadVector3(), |
276 |
Angle = raw.ReadSingle(), |
277 |
Distance = raw.ReadSingle(), |
278 |
Type = (AnimationType)raw.ReadUInt16() |
279 |
}; |
280 |
} |
281 |
|
282 |
private Shortcut ReadShortcut(BinaryReader raw) |
283 |
{ |
284 |
return new Shortcut |
285 |
{ |
286 |
FromState = (AnimationState)raw.ReadUInt16(), |
287 |
Length = raw.ReadUInt16(), |
288 |
ReplaceAtomic = (raw.ReadInt32() != 0) |
289 |
}; |
290 |
} |
291 |
|
292 |
private Footstep ReadFootstep(BinaryReader raw) |
293 |
{ |
294 |
return new Footstep |
295 |
{ |
296 |
Frame = raw.ReadUInt16(), |
297 |
Type = (FootstepType)raw.ReadUInt16() |
298 |
}; |
299 |
} |
300 |
|
301 |
private Sound ReadSound(BinaryReader raw) |
302 |
{ |
303 |
return new Sound |
304 |
{ |
305 |
Name = raw.ReadString(32), |
306 |
Start = raw.ReadUInt16() |
307 |
}; |
308 |
} |
309 |
|
310 |
private MotionBlur ReadMotionBlur(BinaryReader raw) |
311 |
{ |
312 |
var motionBlur = new MotionBlur |
313 |
{ |
314 |
Bones = (BoneMask)raw.ReadInt32(), |
315 |
Start = raw.ReadUInt16(), |
316 |
End = raw.ReadUInt16(), |
317 |
Lifetime = raw.ReadByte(), |
318 |
Alpha = raw.ReadByte(), |
319 |
Interval = raw.ReadByte() |
320 |
}; |
321 |
|
322 |
raw.Skip(1); |
323 |
|
324 |
return motionBlur; |
325 |
} |
326 |
|
327 |
private Particle ReadParticle(BinaryReader raw) |
328 |
{ |
329 |
return new Particle |
330 |
{ |
331 |
Start = raw.ReadUInt16(), |
332 |
End = raw.ReadUInt16(), |
333 |
Bone = (Bone)raw.ReadInt32(), |
334 |
Name = raw.ReadString(16) |
335 |
}; |
336 |
} |
337 |
|
338 |
private Damage ReadDamage(BinaryReader raw) |
339 |
{ |
340 |
return new Damage |
341 |
{ |
342 |
Points = raw.ReadUInt16(), |
343 |
Frame = raw.ReadUInt16() |
344 |
}; |
345 |
} |
346 |
|
347 |
private Position ReadPosition(BinaryReader raw) |
348 |
{ |
349 |
return new Position |
350 |
{ |
351 |
X = raw.ReadInt16() * 0.01f, |
352 |
Z = raw.ReadInt16() * 0.01f, |
353 |
Height = raw.ReadUInt16() * 0.01f, |
354 |
YOffset = raw.ReadInt16() * 0.01f |
355 |
}; |
356 |
} |
357 |
|
358 |
private Attack ReadAttack(BinaryReader raw) |
359 |
{ |
360 |
var attack = new Attack |
361 |
{ |
362 |
Bones = (BoneMask)raw.ReadInt32(), |
363 |
Knockback = raw.ReadSingle(), |
364 |
Flags = (AttackFlags)raw.ReadInt32(), |
365 |
HitPoints = raw.ReadInt16(), |
366 |
Start = raw.ReadUInt16(), |
367 |
End = raw.ReadUInt16(), |
368 |
HitType = (AnimationType)raw.ReadUInt16(), |
369 |
HitLength = raw.ReadUInt16(), |
370 |
StunLength = raw.ReadUInt16(), |
371 |
StaggerLength = raw.ReadUInt16() |
372 |
}; |
373 |
|
374 |
raw.Skip(6); |
375 |
|
376 |
return attack; |
377 |
} |
378 |
|
379 |
private DatExtent ReadExtent(BinaryReader raw) |
380 |
{ |
381 |
var extent = new DatExtent(); |
382 |
extent.Frame = raw.ReadInt16(); |
383 |
extent.Extent.Angle = raw.ReadUInt16() * 360.0f / 65535.0f; |
384 |
extent.Extent.Length = (raw.ReadUInt32() & 0xffffu) * 0.01f; |
385 |
extent.Extent.MinY = raw.ReadInt16() * 0.01f; |
386 |
extent.Extent.MaxY = raw.ReadInt16() * 0.01f; |
387 |
return extent; |
388 |
} |
389 |
|
390 |
private void ReadRawArray<T>(int offset, int count, List<T> list, Func<BinaryReader, T> readElement) |
391 |
{ |
392 |
if (offset == 0 || count == 0) |
393 |
return; |
394 |
|
395 |
using (var raw = tram.GetRawReader(offset)) |
396 |
{ |
397 |
for (int i = 0; i < count; i++) |
398 |
list.Add(readElement(raw)); |
399 |
} |
400 |
} |
401 |
} |
402 |
} |