corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.org
3 * All rights reserved.
4 *
5 * - Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26 using System;
27  
28 namespace OpenMetaverse
29 {
30 /// <summary>
31 /// Reads in a byte array of an Animation Asset created by the SecondLife(tm) client.
32 /// </summary>
33 public class BinBVHAnimationReader
34 {
35 /// <summary>
36 /// Rotation Keyframe count (used internally)
37 /// </summary>
38 private int rotationkeys;
39  
40 /// <summary>
41 /// Position Keyframe count (used internally)
42 /// </summary>
43 private int positionkeys;
44  
45 public UInt16 unknown0; // Always 1
46 public UInt16 unknown1; // Always 0
47  
48 /// <summary>
49 /// Animation Priority
50 /// </summary>
51 public int Priority;
52  
53 /// <summary>
54 /// The animation length in seconds.
55 /// </summary>
56 public Single Length;
57  
58 /// <summary>
59 /// Expression set in the client. Null if [None] is selected
60 /// </summary>
61 public string ExpressionName; // "" (null)
62  
63 /// <summary>
64 /// The time in seconds to start the animation
65 /// </summary>
66 public Single InPoint;
67  
68 /// <summary>
69 /// The time in seconds to end the animation
70 /// </summary>
71 public Single OutPoint;
72  
73 /// <summary>
74 /// Loop the animation
75 /// </summary>
76 public bool Loop;
77  
78 /// <summary>
79 /// Meta data. Ease in Seconds.
80 /// </summary>
81 public Single EaseInTime;
82  
83 /// <summary>
84 /// Meta data. Ease out seconds.
85 /// </summary>
86 public Single EaseOutTime;
87  
88 /// <summary>
89 /// Meta Data for the Hand Pose
90 /// </summary>
91 public uint HandPose;
92  
93 /// <summary>
94 /// Number of joints defined in the animation
95 /// </summary>
96 public uint JointCount;
97  
98  
99 /// <summary>
100 /// Contains an array of joints
101 /// </summary>
102 public binBVHJoint[] joints;
103  
104 /// <summary>
105 /// Searialize an animation asset into it's joints/keyframes/meta data
106 /// </summary>
107 /// <param name="animationdata"></param>
108 public BinBVHAnimationReader(byte[] animationdata)
109 {
110 int i = 0;
111 if (!BitConverter.IsLittleEndian)
112 {
113 unknown0 = Utils.BytesToUInt16(EndianSwap(animationdata, i, 2)); i += 2; // Always 1
114 unknown1 = Utils.BytesToUInt16(EndianSwap(animationdata, i, 2)); i += 2; // Always 0
115 Priority = Utils.BytesToInt(EndianSwap(animationdata, i, 4)); i += 4;
116 Length = Utils.BytesToFloat(EndianSwap(animationdata, i, 4), 0); i += 4;
117 }
118 else
119 {
120 unknown0 = Utils.BytesToUInt16(animationdata, i); i += 2; // Always 1
121 unknown1 = Utils.BytesToUInt16(animationdata, i); i += 2; // Always 0
122 Priority = Utils.BytesToInt(animationdata, i); i += 4;
123 Length = Utils.BytesToFloat(animationdata, i); i += 4;
124 }
125 ExpressionName = ReadBytesUntilNull(animationdata, ref i);
126 if (!BitConverter.IsLittleEndian)
127 {
128 InPoint = Utils.BytesToFloat(EndianSwap(animationdata, i, 4), 0); i += 4;
129 OutPoint = Utils.BytesToFloat(EndianSwap(animationdata, i, 4), 0); i += 4;
130 Loop = (Utils.BytesToInt(EndianSwap(animationdata, i, 4)) != 0); i += 4;
131 EaseInTime = Utils.BytesToFloat(EndianSwap(animationdata, i, 4), 0); i += 4;
132 EaseOutTime = Utils.BytesToFloat(EndianSwap(animationdata, i, 4), 0); i += 4;
133 HandPose = Utils.BytesToUInt(EndianSwap(animationdata, i, 4)); i += 4; // Handpose?
134  
135 JointCount = Utils.BytesToUInt(animationdata, i); i += 4; // Get Joint count
136 }
137 else
138 {
139 InPoint = Utils.BytesToFloat(animationdata, i); i += 4;
140 OutPoint = Utils.BytesToFloat(animationdata, i); i += 4;
141 Loop = (Utils.BytesToInt(animationdata, i) != 0); i += 4;
142 EaseInTime = Utils.BytesToFloat(animationdata, i); i += 4;
143 EaseOutTime = Utils.BytesToFloat(animationdata, i); i += 4;
144 HandPose = Utils.BytesToUInt(animationdata, i); i += 4; // Handpose?
145  
146 JointCount = Utils.BytesToUInt(animationdata, i); i += 4; // Get Joint count
147 }
148 joints = new binBVHJoint[JointCount];
149  
150 // deserialize the number of joints in the animation.
151 // Joints are variable length blocks of binary data consisting of joint data and keyframes
152 for (int iter = 0; iter < JointCount; iter++)
153 {
154 binBVHJoint joint = readJoint(animationdata, ref i);
155 joints[iter] = joint;
156 }
157 }
158  
159 private byte[] EndianSwap(byte[] arr, int offset, int len)
160 {
161 byte[] bendian = new byte[offset + len];
162 Buffer.BlockCopy(arr, offset, bendian, 0, len);
163 Array.Reverse(bendian);
164 return bendian;
165 }
166 /// <summary>
167 /// Variable length strings seem to be null terminated in the animation asset.. but..
168 /// use with caution, home grown.
169 /// advances the index.
170 /// </summary>
171 /// <param name="data">The animation asset byte array</param>
172 /// <param name="i">The offset to start reading</param>
173 /// <returns>a string</returns>
174 public string ReadBytesUntilNull(byte[] data, ref int i)
175 {
176 char nterm = '\0'; // Null terminator
177 int endpos = i;
178 int startpos = i;
179  
180 // Find the null character
181 for (int j = i; j < data.Length; j++)
182 {
183 char spot = Convert.ToChar(data[j]);
184 if (spot == nterm)
185 {
186 endpos = j;
187 break;
188 }
189 }
190  
191 // if we got to the end, then it's a zero length string
192 if (i == endpos)
193 {
194 // advance the 1 null character
195 i++;
196 return string.Empty;
197 }
198 else
199 {
200 // We found the end of the string
201 // append the bytes from the beginning of the string to the end of the string
202 // advance i
203 byte[] interm = new byte[endpos - i];
204 for (; i < endpos; i++)
205 {
206 interm[i - startpos] = data[i];
207 }
208 i++; // advance past the null character
209  
210 return Utils.BytesToString(interm);
211 }
212 }
213  
214 /// <summary>
215 /// Read in a Joint from an animation asset byte array
216 /// Variable length Joint fields, yay!
217 /// Advances the index
218 /// </summary>
219 /// <param name="data">animation asset byte array</param>
220 /// <param name="i">Byte Offset of the start of the joint</param>
221 /// <returns>The Joint data serialized into the binBVHJoint structure</returns>
222 public binBVHJoint readJoint(byte[] data, ref int i)
223 {
224  
225 binBVHJointKey[] positions;
226 binBVHJointKey[] rotations;
227  
228 binBVHJoint pJoint = new binBVHJoint();
229  
230 /*
231 109
232 84
233 111
234 114
235 114
236 111
237  
238 */
239  
240 pJoint.Name = ReadBytesUntilNull(data, ref i); // Joint name
241  
242 /*
243 2 <- Priority Revisited
244  
245  
246  
247 */
248  
249 /*
250 5 <-- 5 keyframes
251  
252  
253  
254 ... 5 Keyframe data blocks
255 */
256  
257 /*
258 2 <-- 2 keyframes
259  
260  
261  
262 .. 2 Keyframe data blocks
263 */
264 if (!BitConverter.IsLittleEndian)
265 {
266 pJoint.Priority = Utils.BytesToInt(EndianSwap(data, i, 4)); i += 4; // Joint Priority override?
267 rotationkeys = Utils.BytesToInt(EndianSwap(data, i, 4)); i += 4; // How many rotation keyframes
268 }
269 else
270 {
271 pJoint.Priority = Utils.BytesToInt(data, i); i += 4; // Joint Priority override?
272 rotationkeys = Utils.BytesToInt(data, i); i += 4; // How many rotation keyframes
273 }
274  
275 // Sanity check how many rotation keys there are
276 if (rotationkeys < 0 || rotationkeys > 10000)
277 {
278 rotationkeys = 0;
279 }
280  
281 rotations = readKeys(data, ref i, rotationkeys, -1.0f, 1.0f);
282  
283 if (!BitConverter.IsLittleEndian)
284 {
285 positionkeys = Utils.BytesToInt(EndianSwap(data, i, 4)); i += 4; // How many position keyframes
286 }
287 else
288 {
289 positionkeys = Utils.BytesToInt(data, i); i += 4; // How many position keyframes
290 }
291  
292 // Sanity check how many positions keys there are
293 if (positionkeys < 0 || positionkeys > 10000)
294 {
295 positionkeys = 0;
296 }
297  
298 // Read in position keyframes
299 positions = readKeys(data, ref i, positionkeys, -0.5f, 1.5f);
300  
301 pJoint.rotationkeys = rotations;
302 pJoint.positionkeys = positions;
303  
304 return pJoint;
305 }
306  
307 /// <summary>
308 /// Read Keyframes of a certain type
309 /// advance i
310 /// </summary>
311 /// <param name="data">Animation Byte array</param>
312 /// <param name="i">Offset in the Byte Array. Will be advanced</param>
313 /// <param name="keycount">Number of Keyframes</param>
314 /// <param name="min">Scaling Min to pass to the Uint16ToFloat method</param>
315 /// <param name="max">Scaling Max to pass to the Uint16ToFloat method</param>
316 /// <returns></returns>
317 public binBVHJointKey[] readKeys(byte[] data, ref int i, int keycount, float min, float max)
318 {
319 float x;
320 float y;
321 float z;
322  
323 /*
324 17 255 <-- Time Code
325 17 255 <-- Time Code
326 255 255 <-- X
327 127 127 <-- X
328 255 255 <-- Y
329 127 127 <-- Y
330 213 213 <-- Z
331 142 142 <---Z
332  
333 */
334  
335 binBVHJointKey[] m_keys = new binBVHJointKey[keycount];
336 for (int j = 0; j < keycount; j++)
337 {
338 binBVHJointKey pJKey = new binBVHJointKey();
339 if (!BitConverter.IsLittleEndian)
340 {
341 pJKey.time = Utils.UInt16ToFloat(EndianSwap(data, i, 2), 0, InPoint, OutPoint); i += 2;
342 x = Utils.UInt16ToFloat(EndianSwap(data, i, 2), 0, min, max); i += 2;
343 y = Utils.UInt16ToFloat(EndianSwap(data, i, 2), 0, min, max); i += 2;
344 z = Utils.UInt16ToFloat(EndianSwap(data, i, 2), 0, min, max); i += 2;
345 }
346 else
347 {
348 pJKey.time = Utils.UInt16ToFloat(data, i, InPoint, OutPoint); i += 2;
349 x = Utils.UInt16ToFloat(data, i, min, max); i += 2;
350 y = Utils.UInt16ToFloat(data, i, min, max); i += 2;
351 z = Utils.UInt16ToFloat(data, i, min, max); i += 2;
352 }
353 pJKey.key_element = new Vector3(x, y, z);
354 m_keys[j] = pJKey;
355 }
356 return m_keys;
357 }
358  
359 public bool Equals(BinBVHAnimationReader other)
360 {
361 if (ReferenceEquals(null, other)) return false;
362 if (ReferenceEquals(this, other)) return true;
363 return other.Loop.Equals(Loop) && other.OutPoint == OutPoint && other.InPoint == InPoint && other.Length == Length && other.HandPose == HandPose && other.JointCount == JointCount && Equals(other.joints, joints) && other.EaseInTime == EaseInTime && other.EaseOutTime == EaseOutTime && other.Priority == Priority && other.unknown1 == unknown1 && other.unknown0 == unknown0 && other.positionkeys == positionkeys && other.rotationkeys == rotationkeys;
364 }
365  
366 /// <summary>
367 /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
368 /// </summary>
369 /// <returns>
370 /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
371 /// </returns>
372 /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.
373 /// </param><exception cref="T:System.NullReferenceException">The <paramref name="obj"/> parameter is null.
374 /// </exception><filterpriority>2</filterpriority>
375 public override bool Equals(object obj)
376 {
377 if (ReferenceEquals(null, obj)) return false;
378 if (ReferenceEquals(this, obj)) return true;
379 if (obj.GetType() != typeof(BinBVHAnimationReader)) return false;
380 return Equals((BinBVHAnimationReader)obj);
381 }
382  
383 /// <summary>
384 /// Serves as a hash function for a particular type.
385 /// </summary>
386 /// <returns>
387 /// A hash code for the current <see cref="T:System.Object"/>.
388 /// </returns>
389 /// <filterpriority>2</filterpriority>
390 public override int GetHashCode()
391 {
392 unchecked
393 {
394 int result = Loop.GetHashCode();
395 result = (result * 397) ^ OutPoint.GetHashCode();
396 result = (result * 397) ^ InPoint.GetHashCode();
397 result = (result * 397) ^ Length.GetHashCode();
398 result = (result * 397) ^ HandPose.GetHashCode();
399 result = (result * 397) ^ JointCount.GetHashCode();
400 result = (result * 397) ^ (joints != null ? joints.GetHashCode() : 0);
401 result = (result * 397) ^ EaseInTime.GetHashCode();
402 result = (result * 397) ^ EaseOutTime.GetHashCode();
403 result = (result * 397) ^ Priority;
404 result = (result * 397) ^ unknown1.GetHashCode();
405 result = (result * 397) ^ unknown0.GetHashCode();
406 result = (result * 397) ^ positionkeys;
407 result = (result * 397) ^ rotationkeys;
408 return result;
409 }
410 }
411  
412 public static bool Equals(binBVHJoint[] arr1, binBVHJoint[] arr2)
413 {
414 if (arr1.Length == arr2.Length)
415 {
416 for (int i = 0; i < arr1.Length; i++)
417 if (!arr1[i].Equals(arr2[i]))
418 return false;
419 /* not same*/
420 return true;
421 }
422 return false;
423 }
424  
425 }
426  
427  
428 /// <summary>
429 /// A Joint and it's associated meta data and keyframes
430 /// </summary>
431 public struct binBVHJoint
432 {
433 public static bool Equals(binBVHJointKey[] arr1, binBVHJointKey[] arr2)
434 {
435 if (arr1.Length == arr2.Length)
436 {
437 for (int i = 0; i < arr1.Length; i++)
438 if (!Equals(arr1[i], arr2[i]))
439 return false;
440 /* not same*/
441 return true;
442 }
443 return false;
444 }
445 public static bool Equals(binBVHJointKey arr1, binBVHJointKey arr2)
446 {
447 return (arr1.time == arr2.time && arr1.key_element == arr2.key_element);
448 }
449  
450 public bool Equals(binBVHJoint other)
451 {
452 return other.Priority == Priority && Equals(other.rotationkeys, rotationkeys) && Equals(other.Name, Name) && Equals(other.positionkeys, positionkeys);
453 }
454  
455 /// <summary>
456 /// Indicates whether this instance and a specified object are equal.
457 /// </summary>
458 /// <returns>
459 /// true if <paramref name="obj"/> and this instance are the same type and represent the same value; otherwise, false.
460 /// </returns>
461 /// <param name="obj">Another object to compare to.
462 /// </param><filterpriority>2</filterpriority>
463 public override bool Equals(object obj)
464 {
465 if (ReferenceEquals(null, obj)) return false;
466 if (obj.GetType() != typeof(binBVHJoint)) return false;
467 return Equals((binBVHJoint)obj);
468 }
469  
470 /// <summary>
471 /// Returns the hash code for this instance.
472 /// </summary>
473 /// <returns>
474 /// A 32-bit signed integer that is the hash code for this instance.
475 /// </returns>
476 /// <filterpriority>2</filterpriority>
477 public override int GetHashCode()
478 {
479 unchecked
480 {
481 int result = Priority;
482 result = (result * 397) ^ (rotationkeys != null ? rotationkeys.GetHashCode() : 0);
483 result = (result * 397) ^ (Name != null ? Name.GetHashCode() : 0);
484 result = (result * 397) ^ (positionkeys != null ? positionkeys.GetHashCode() : 0);
485 return result;
486 }
487 }
488  
489 public static bool operator ==(binBVHJoint left, binBVHJoint right)
490 {
491 return left.Equals(right);
492 }
493  
494 public static bool operator !=(binBVHJoint left, binBVHJoint right)
495 {
496 return !left.Equals(right);
497 }
498  
499 /// <summary>
500 /// Name of the Joint. Matches the avatar_skeleton.xml in client distros
501 /// </summary>
502 public string Name;
503  
504 /// <summary>
505 /// Joint Animation Override? Was the same as the Priority in testing..
506 /// </summary>
507 public int Priority;
508  
509 /// <summary>
510 /// Array of Rotation Keyframes in order from earliest to latest
511 /// </summary>
512 public binBVHJointKey[] rotationkeys;
513  
514 /// <summary>
515 /// Array of Position Keyframes in order from earliest to latest
516 /// This seems to only be for the Pelvis?
517 /// </summary>
518 public binBVHJointKey[] positionkeys;
519  
520 /// <summary>
521 /// Custom application data that can be attached to a joint
522 /// </summary>
523 public object Tag;
524 }
525  
526 /// <summary>
527 /// A Joint Keyframe. This is either a position or a rotation.
528 /// </summary>
529 public struct binBVHJointKey
530 {
531 // Time in seconds for this keyframe.
532 public float time;
533  
534 /// <summary>
535 /// Either a Vector3 position or a Vector3 Euler rotation
536 /// </summary>
537 public Vector3 key_element;
538 }
539  
540 /// <summary>
541 /// Poses set in the animation metadata for the hands.
542 /// </summary>
543 public enum HandPose : uint
544 {
545 Spread = 0,
546 Relaxed = 1,
547 Point_Both = 2,
548 Fist = 3,
549 Relaxed_Left = 4,
550 Point_Left = 5,
551 Fist_Left = 6,
552 Relaxed_Right = 7,
553 Point_Right = 8,
554 Fist_Right = 9,
555 Salute_Right = 10,
556 Typing = 11,
557 Peace_Right = 12
558 }
559 }