BinBVHAnimation.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  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. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.IO;
  29. using OpenMetaverse;
  30. namespace OpenSim.Region.Framework.Scenes.Animation
  31. {
  32. /// <summary>
  33. /// Written to decode and encode a binary animation asset.
  34. /// The SecondLife Client reads in a BVH file and converts
  35. /// it to the format described here. This isn't
  36. /// </summary>
  37. public class BinBVHAnimation
  38. {
  39. /// <summary>
  40. /// Rotation Keyframe count (used internally)
  41. /// Don't use this, use the rotationkeys.Length on each joint
  42. /// </summary>
  43. private int rotationkeys;
  44. /// <summary>
  45. /// Position Keyframe count (used internally)
  46. /// Don't use this, use the positionkeys.Length on each joint
  47. /// </summary>
  48. private int positionkeys;
  49. public UInt16 unknown0; // Always 1
  50. public UInt16 unknown1; // Always 0
  51. /// <summary>
  52. /// Animation Priority
  53. /// </summary>
  54. public int Priority;
  55. /// <summary>
  56. /// The animation length in seconds.
  57. /// </summary>
  58. public Single Length;
  59. /// <summary>
  60. /// Expression set in the client. Null if [None] is selected
  61. /// </summary>
  62. public string ExpressionName; // "" (null)
  63. /// <summary>
  64. /// The time in seconds to start the animation
  65. /// </summary>
  66. public Single InPoint;
  67. /// <summary>
  68. /// The time in seconds to end the animation
  69. /// </summary>
  70. public Single OutPoint;
  71. /// <summary>
  72. /// Loop the animation
  73. /// </summary>
  74. public bool Loop;
  75. /// <summary>
  76. /// Meta data. Ease in Seconds.
  77. /// </summary>
  78. public Single EaseInTime;
  79. /// <summary>
  80. /// Meta data. Ease out seconds.
  81. /// </summary>
  82. public Single EaseOutTime;
  83. /// <summary>
  84. /// Meta Data for the Hand Pose
  85. /// </summary>
  86. public uint HandPose;
  87. /// <summary>
  88. /// Number of joints defined in the animation
  89. /// Don't use this.. use joints.Length
  90. /// </summary>
  91. private uint m_jointCount;
  92. /// <summary>
  93. /// Contains an array of joints
  94. /// </summary>
  95. public binBVHJoint[] Joints;
  96. public byte[] ToBytes()
  97. {
  98. byte[] outputbytes;
  99. using (MemoryStream ms = new MemoryStream())
  100. using (BinaryWriter iostream = new BinaryWriter(ms))
  101. {
  102. iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(unknown0)));
  103. iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(unknown1)));
  104. iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(Priority)));
  105. iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(Length)));
  106. iostream.Write(BinBVHUtil.WriteNullTerminatedString(ExpressionName));
  107. iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(InPoint)));
  108. iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(OutPoint)));
  109. iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(Loop ? 1 : 0)));
  110. iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(EaseInTime)));
  111. iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(EaseOutTime)));
  112. iostream.Write(BinBVHUtil.ES(Utils.UIntToBytes(HandPose)));
  113. iostream.Write(BinBVHUtil.ES(Utils.UIntToBytes((uint)(Joints.Length))));
  114. for (int i = 0; i < Joints.Length; i++)
  115. {
  116. Joints[i].WriteBytesToStream(iostream, InPoint, OutPoint);
  117. }
  118. iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(0)));
  119. using (MemoryStream ms2 = (MemoryStream)iostream.BaseStream)
  120. outputbytes = ms2.ToArray();
  121. }
  122. return outputbytes;
  123. }
  124. public BinBVHAnimation()
  125. {
  126. rotationkeys = 0;
  127. positionkeys = 0;
  128. unknown0 = 1;
  129. unknown1 = 0;
  130. Priority = 1;
  131. Length = 0;
  132. ExpressionName = string.Empty;
  133. InPoint = 0;
  134. OutPoint = 0;
  135. Loop = false;
  136. EaseInTime = 0;
  137. EaseOutTime = 0;
  138. HandPose = 1;
  139. m_jointCount = 0;
  140. Joints = new binBVHJoint[1];
  141. Joints[0] = new binBVHJoint();
  142. Joints[0].Name = "mPelvis";
  143. Joints[0].Priority = 7;
  144. Joints[0].positionkeys = new binBVHJointKey[1];
  145. Joints[0].rotationkeys = new binBVHJointKey[1];
  146. Random rnd = new Random();
  147. Joints[0].rotationkeys[0] = new binBVHJointKey();
  148. Joints[0].rotationkeys[0].time = (0f);
  149. Joints[0].rotationkeys[0].key_element.X = ((float)rnd.NextDouble() * 2 - 1);
  150. Joints[0].rotationkeys[0].key_element.Y = ((float)rnd.NextDouble() * 2 - 1);
  151. Joints[0].rotationkeys[0].key_element.Z = ((float)rnd.NextDouble() * 2 - 1);
  152. Joints[0].positionkeys[0] = new binBVHJointKey();
  153. Joints[0].positionkeys[0].time = (0f);
  154. Joints[0].positionkeys[0].key_element.X = ((float)rnd.NextDouble() * 2 - 1);
  155. Joints[0].positionkeys[0].key_element.Y = ((float)rnd.NextDouble() * 2 - 1);
  156. Joints[0].positionkeys[0].key_element.Z = ((float)rnd.NextDouble() * 2 - 1);
  157. }
  158. public BinBVHAnimation(byte[] animationdata)
  159. {
  160. int i = 0;
  161. if (!BitConverter.IsLittleEndian)
  162. {
  163. unknown0 = Utils.BytesToUInt16(BinBVHUtil.EndianSwap(animationdata,i,2)); i += 2; // Always 1
  164. unknown1 = Utils.BytesToUInt16(BinBVHUtil.EndianSwap(animationdata, i, 2)); i += 2; // Always 0
  165. Priority = Utils.BytesToInt(BinBVHUtil.EndianSwap(animationdata, i, 4)); i += 4;
  166. Length = Utils.BytesToFloat(BinBVHUtil.EndianSwap(animationdata, i, 4), 0); i += 4;
  167. }
  168. else
  169. {
  170. unknown0 = Utils.BytesToUInt16(animationdata, i); i += 2; // Always 1
  171. unknown1 = Utils.BytesToUInt16(animationdata, i); i += 2; // Always 0
  172. Priority = Utils.BytesToInt(animationdata, i); i += 4;
  173. Length = Utils.BytesToFloat(animationdata, i); i += 4;
  174. }
  175. ExpressionName = ReadBytesUntilNull(animationdata, ref i);
  176. if (!BitConverter.IsLittleEndian)
  177. {
  178. InPoint = Utils.BytesToFloat(BinBVHUtil.EndianSwap(animationdata, i, 4), 0); i += 4;
  179. OutPoint = Utils.BytesToFloat(BinBVHUtil.EndianSwap(animationdata, i, 4), 0); i += 4;
  180. Loop = (Utils.BytesToInt(BinBVHUtil.EndianSwap(animationdata, i, 4)) != 0); i += 4;
  181. EaseInTime = Utils.BytesToFloat(BinBVHUtil.EndianSwap(animationdata, i, 4), 0); i += 4;
  182. EaseOutTime = Utils.BytesToFloat(BinBVHUtil.EndianSwap(animationdata, i, 4), 0); i += 4;
  183. HandPose = Utils.BytesToUInt(BinBVHUtil.EndianSwap(animationdata, i, 4)); i += 4; // Handpose?
  184. m_jointCount = Utils.BytesToUInt(animationdata, i); i += 4; // Get Joint count
  185. }
  186. else
  187. {
  188. InPoint = Utils.BytesToFloat(animationdata, i); i += 4;
  189. OutPoint = Utils.BytesToFloat(animationdata, i); i += 4;
  190. Loop = (Utils.BytesToInt(animationdata, i) != 0); i += 4;
  191. EaseInTime = Utils.BytesToFloat(animationdata, i); i += 4;
  192. EaseOutTime = Utils.BytesToFloat(animationdata, i); i += 4;
  193. HandPose = Utils.BytesToUInt(animationdata, i); i += 4; // Handpose?
  194. m_jointCount = Utils.BytesToUInt(animationdata, i); i += 4; // Get Joint count
  195. }
  196. Joints = new binBVHJoint[m_jointCount];
  197. // deserialize the number of joints in the animation.
  198. // Joints are variable length blocks of binary data consisting of joint data and keyframes
  199. for (int iter = 0; iter < m_jointCount; iter++)
  200. {
  201. binBVHJoint joint = readJoint(animationdata, ref i);
  202. Joints[iter] = joint;
  203. }
  204. }
  205. /// <summary>
  206. /// Variable length strings seem to be null terminated in the animation asset.. but..
  207. /// use with caution, home grown.
  208. /// advances the index.
  209. /// </summary>
  210. /// <param name="data">The animation asset byte array</param>
  211. /// <param name="i">The offset to start reading</param>
  212. /// <returns>a string</returns>
  213. private static string ReadBytesUntilNull(byte[] data, ref int i)
  214. {
  215. char nterm = '\0'; // Null terminator
  216. int endpos = i;
  217. int startpos = i;
  218. // Find the null character
  219. for (int j = i; j < data.Length; j++)
  220. {
  221. char spot = Convert.ToChar(data[j]);
  222. if (spot == nterm)
  223. {
  224. endpos = j;
  225. break;
  226. }
  227. }
  228. // if we got to the end, then it's a zero length string
  229. if (i == endpos)
  230. {
  231. // advance the 1 null character
  232. i++;
  233. return string.Empty;
  234. }
  235. else
  236. {
  237. // We found the end of the string
  238. // append the bytes from the beginning of the string to the end of the string
  239. // advance i
  240. byte[] interm = new byte[endpos-i];
  241. for (; i<endpos; i++)
  242. {
  243. interm[i-startpos] = data[i];
  244. }
  245. i++; // advance past the null character
  246. return Utils.BytesToString(interm);
  247. }
  248. }
  249. /// <summary>
  250. /// Read in a Joint from an animation asset byte array
  251. /// Variable length Joint fields, yay!
  252. /// Advances the index
  253. /// </summary>
  254. /// <param name="data">animation asset byte array</param>
  255. /// <param name="i">Byte Offset of the start of the joint</param>
  256. /// <returns>The Joint data serialized into the binBVHJoint structure</returns>
  257. private binBVHJoint readJoint(byte[] data, ref int i)
  258. {
  259. binBVHJointKey[] positions;
  260. binBVHJointKey[] rotations;
  261. binBVHJoint pJoint = new binBVHJoint();
  262. /*
  263. 109
  264. 84
  265. 111
  266. 114
  267. 114
  268. 111
  269. 0 <--- Null terminator
  270. */
  271. pJoint.Name = ReadBytesUntilNull(data, ref i); // Joint name
  272. /*
  273. 2 <- Priority Revisited
  274. 0
  275. 0
  276. 0
  277. */
  278. /*
  279. 5 <-- 5 keyframes
  280. 0
  281. 0
  282. 0
  283. ... 5 Keyframe data blocks
  284. */
  285. /*
  286. 2 <-- 2 keyframes
  287. 0
  288. 0
  289. 0
  290. .. 2 Keyframe data blocks
  291. */
  292. if (!BitConverter.IsLittleEndian)
  293. {
  294. pJoint.Priority = Utils.BytesToInt(BinBVHUtil.EndianSwap(data, i, 4)); i += 4; // Joint Priority override?
  295. rotationkeys = Utils.BytesToInt(BinBVHUtil.EndianSwap(data, i, 4)); i += 4; // How many rotation keyframes
  296. }
  297. else
  298. {
  299. pJoint.Priority = Utils.BytesToInt(data, i); i += 4; // Joint Priority override?
  300. rotationkeys = Utils.BytesToInt(data, i); i += 4; // How many rotation keyframes
  301. }
  302. // argh! floats into two bytes!.. bad bad bad bad
  303. // After fighting with it for a while.. -1, to 1 seems to give the best results
  304. rotations = readKeys(data, ref i, rotationkeys, -1f, 1f);
  305. for (int iter = 0; iter < rotations.Length; iter++)
  306. {
  307. rotations[iter].W = 1f -
  308. (rotations[iter].key_element.X + rotations[iter].key_element.Y +
  309. rotations[iter].key_element.Z);
  310. }
  311. if (!BitConverter.IsLittleEndian)
  312. {
  313. positionkeys = Utils.BytesToInt(BinBVHUtil.EndianSwap(data, i, 4)); i += 4; // How many position keyframes
  314. }
  315. else
  316. {
  317. positionkeys = Utils.BytesToInt(data, i); i += 4; // How many position keyframes
  318. }
  319. // Read in position keyframes
  320. // argh! more floats into two bytes!.. *head desk*
  321. // After fighting with it for a while.. -5, to 5 seems to give the best results
  322. positions = readKeys(data, ref i, positionkeys, -5f, 5f);
  323. pJoint.rotationkeys = rotations;
  324. pJoint.positionkeys = positions;
  325. return pJoint;
  326. }
  327. /// <summary>
  328. /// Read Keyframes of a certain type
  329. /// advance i
  330. /// </summary>
  331. /// <param name="data">Animation Byte array</param>
  332. /// <param name="i">Offset in the Byte Array. Will be advanced</param>
  333. /// <param name="keycount">Number of Keyframes</param>
  334. /// <param name="min">Scaling Min to pass to the Uint16ToFloat method</param>
  335. /// <param name="max">Scaling Max to pass to the Uint16ToFloat method</param>
  336. /// <returns></returns>
  337. private binBVHJointKey[] readKeys(byte[] data, ref int i, int keycount, float min, float max)
  338. {
  339. float x;
  340. float y;
  341. float z;
  342. /*
  343. 0.o, Float values in Two bytes.. this is just wrong >:(
  344. 17 255 <-- Time Code
  345. 17 255 <-- Time Code
  346. 255 255 <-- X
  347. 127 127 <-- X
  348. 255 255 <-- Y
  349. 127 127 <-- Y
  350. 213 213 <-- Z
  351. 142 142 <---Z
  352. */
  353. binBVHJointKey[] m_keys = new binBVHJointKey[keycount];
  354. for (int j = 0; j < keycount; j++)
  355. {
  356. binBVHJointKey pJKey = new binBVHJointKey();
  357. pJKey.time = Utils.BytesUInt16ToFloat(data, i, InPoint, OutPoint); i += 2;
  358. x = Utils.BytesUInt16ToFloat(data, i, min, max); i += 2;
  359. y = Utils.BytesUInt16ToFloat(data, i, min, max); i += 2;
  360. z = Utils.BytesUInt16ToFloat(data, i, min, max); i += 2;
  361. pJKey.key_element = new Vector3(x, y, z);
  362. m_keys[j] = pJKey;
  363. }
  364. return m_keys;
  365. }
  366. }
  367. /// <summary>
  368. /// A Joint and it's associated meta data and keyframes
  369. /// </summary>
  370. public struct binBVHJoint
  371. {
  372. /// <summary>
  373. /// Name of the Joint. Matches the avatar_skeleton.xml in client distros
  374. /// </summary>
  375. public string Name;
  376. /// <summary>
  377. /// Joint Animation Override? Was the same as the Priority in testing..
  378. /// </summary>
  379. public int Priority;
  380. /// <summary>
  381. /// Array of Rotation Keyframes in order from earliest to latest
  382. /// </summary>
  383. public binBVHJointKey[] rotationkeys;
  384. /// <summary>
  385. /// Array of Position Keyframes in order from earliest to latest
  386. /// This seems to only be for the Pelvis?
  387. /// </summary>
  388. public binBVHJointKey[] positionkeys;
  389. public void WriteBytesToStream(BinaryWriter iostream, float InPoint, float OutPoint)
  390. {
  391. iostream.Write(BinBVHUtil.WriteNullTerminatedString(Name));
  392. iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(Priority)));
  393. iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(rotationkeys.Length)));
  394. for (int i=0;i<rotationkeys.Length;i++)
  395. {
  396. rotationkeys[i].WriteBytesToStream(iostream, InPoint, OutPoint, -1f, 1f);
  397. }
  398. iostream.Write(BinBVHUtil.ES(Utils.IntToBytes((positionkeys.Length))));
  399. for (int i = 0; i < positionkeys.Length; i++)
  400. {
  401. positionkeys[i].WriteBytesToStream(iostream, InPoint, OutPoint, -256f, 256f);
  402. }
  403. }
  404. }
  405. /// <summary>
  406. /// A Joint Keyframe. This is either a position or a rotation.
  407. /// </summary>
  408. public struct binBVHJointKey
  409. {
  410. // Time in seconds for this keyframe.
  411. public float time;
  412. /// <summary>
  413. /// Either a Vector3 position or a Vector3 Euler rotation
  414. /// </summary>
  415. public Vector3 key_element;
  416. public float W;
  417. public void WriteBytesToStream(BinaryWriter iostream, float InPoint, float OutPoint, float min, float max)
  418. {
  419. iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(BinBVHUtil.FloatToUInt16(time, InPoint, OutPoint))));
  420. iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(BinBVHUtil.FloatToUInt16(key_element.X, min, max))));
  421. iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(BinBVHUtil.FloatToUInt16(key_element.Y, min, max))));
  422. iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(BinBVHUtil.FloatToUInt16(key_element.Z, min, max))));
  423. }
  424. }
  425. /// <summary>
  426. /// Poses set in the animation metadata for the hands.
  427. /// </summary>
  428. public enum HandPose : uint
  429. {
  430. Spread = 0,
  431. Relaxed = 1,
  432. Point_Both = 2,
  433. Fist = 3,
  434. Relaxed_Left = 4,
  435. Point_Left = 5,
  436. Fist_Left = 6,
  437. Relaxed_Right = 7,
  438. Point_Right = 8,
  439. Fist_Right = 9,
  440. Salute_Right = 10,
  441. Typing = 11,
  442. Peace_Right = 12
  443. }
  444. public static class BinBVHUtil
  445. {
  446. public const float ONE_OVER_U16_MAX = 1.0f / UInt16.MaxValue;
  447. public static UInt16 FloatToUInt16(float val, float lower, float upper)
  448. {
  449. UInt16 uival = 0;
  450. //m_parentGroup.GetTimeDilation() * (float)ushort.MaxValue
  451. //0-1
  452. // float difference = upper - lower;
  453. // we're trying to get a zero lower and modify all values equally so we get a percentage position
  454. if (lower > 0)
  455. {
  456. upper -= lower;
  457. val = val - lower;
  458. // start with 500 upper and 200 lower.. subtract 200 from the upper and the value
  459. }
  460. else //if (lower < 0 && upper > 0)
  461. {
  462. // double negative, 0 minus negative 5 is 5.
  463. upper += 0 - lower;
  464. lower += 0 - lower;
  465. val += 0 - lower;
  466. }
  467. if (upper == 0)
  468. val = 0;
  469. else
  470. {
  471. val /= upper;
  472. }
  473. uival = (UInt16)(val * UInt16.MaxValue);
  474. return uival;
  475. }
  476. /// <summary>
  477. /// Endian Swap
  478. /// Swaps endianness if necessary
  479. /// </summary>
  480. /// <param name="arr">Input array</param>
  481. /// <returns></returns>
  482. public static byte[] ES(byte[] arr)
  483. {
  484. if (!BitConverter.IsLittleEndian)
  485. Array.Reverse(arr);
  486. return arr;
  487. }
  488. public static byte[] EndianSwap(byte[] arr, int offset, int len)
  489. {
  490. byte[] bendian = new byte[offset + len];
  491. Buffer.BlockCopy(arr, offset, bendian, 0, len);
  492. Array.Reverse(bendian);
  493. return bendian;
  494. }
  495. public static byte[] WriteNullTerminatedString(string str)
  496. {
  497. byte[] output = new byte[str.Length + 1];
  498. Char[] chr = str.ToCharArray();
  499. int i = 0;
  500. for (i = 0; i < chr.Length; i++)
  501. {
  502. output[i] = Convert.ToByte(chr[i]);
  503. }
  504. output[i] = Convert.ToByte('\0');
  505. return output;
  506. }
  507. }
  508. }
  509. /*
  510. switch (jointname)
  511. {
  512. case "mPelvis":
  513. case "mTorso":
  514. case "mNeck":
  515. case "mHead":
  516. case "mChest":
  517. case "mHipLeft":
  518. case "mHipRight":
  519. case "mKneeLeft":
  520. case "mKneeRight":
  521. // XYZ->ZXY
  522. t = x;
  523. x = y;
  524. y = t;
  525. break;
  526. case "mCollarLeft":
  527. case "mCollarRight":
  528. case "mElbowLeft":
  529. case "mElbowRight":
  530. // YZX ->ZXY
  531. t = z;
  532. z = x;
  533. x = y;
  534. y = t;
  535. break;
  536. case "mWristLeft":
  537. case "mWristRight":
  538. case "mShoulderLeft":
  539. case "mShoulderRight":
  540. // ZYX->ZXY
  541. t = y;
  542. y = z;
  543. z = t;
  544. break;
  545. case "mAnkleLeft":
  546. case "mAnkleRight":
  547. // XYZ ->ZXY
  548. t = x;
  549. x = z;
  550. z = y;
  551. y = t;
  552. break;
  553. }
  554. */