1
0

BinBVHAnimation.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  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 = new byte[0];
  99. BinaryWriter iostream = new BinaryWriter(new MemoryStream());
  100. iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(unknown0)));
  101. iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(unknown1)));
  102. iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(Priority)));
  103. iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(Length)));
  104. iostream.Write(BinBVHUtil.WriteNullTerminatedString(ExpressionName));
  105. iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(InPoint)));
  106. iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(OutPoint)));
  107. iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(Loop ? 1 : 0)));
  108. iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(EaseInTime)));
  109. iostream.Write(BinBVHUtil.ES(Utils.FloatToBytes(EaseOutTime)));
  110. iostream.Write(BinBVHUtil.ES(Utils.UIntToBytes(HandPose)));
  111. iostream.Write(BinBVHUtil.ES(Utils.UIntToBytes((uint)(Joints.Length))));
  112. for (int i = 0; i < Joints.Length; i++)
  113. {
  114. Joints[i].WriteBytesToStream(iostream, InPoint, OutPoint);
  115. }
  116. iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(0)));
  117. MemoryStream ms = (MemoryStream)iostream.BaseStream;
  118. outputbytes = ms.ToArray();
  119. ms.Close();
  120. iostream.Close();
  121. return outputbytes;
  122. }
  123. public BinBVHAnimation()
  124. {
  125. rotationkeys = 0;
  126. positionkeys = 0;
  127. unknown0 = 1;
  128. unknown1 = 0;
  129. Priority = 1;
  130. Length = 0;
  131. ExpressionName = string.Empty;
  132. InPoint = 0;
  133. OutPoint = 0;
  134. Loop = false;
  135. EaseInTime = 0;
  136. EaseOutTime = 0;
  137. HandPose = 1;
  138. m_jointCount = 0;
  139. Joints = new binBVHJoint[1];
  140. Joints[0] = new binBVHJoint();
  141. Joints[0].Name = "mPelvis";
  142. Joints[0].Priority = 7;
  143. Joints[0].positionkeys = new binBVHJointKey[1];
  144. Joints[0].rotationkeys = new binBVHJointKey[1];
  145. Random rnd = new Random();
  146. Joints[0].rotationkeys[0] = new binBVHJointKey();
  147. Joints[0].rotationkeys[0].time = (0f);
  148. Joints[0].rotationkeys[0].key_element.X = ((float)rnd.NextDouble() * 2 - 1);
  149. Joints[0].rotationkeys[0].key_element.Y = ((float)rnd.NextDouble() * 2 - 1);
  150. Joints[0].rotationkeys[0].key_element.Z = ((float)rnd.NextDouble() * 2 - 1);
  151. Joints[0].positionkeys[0] = new binBVHJointKey();
  152. Joints[0].positionkeys[0].time = (0f);
  153. Joints[0].positionkeys[0].key_element.X = ((float)rnd.NextDouble() * 2 - 1);
  154. Joints[0].positionkeys[0].key_element.Y = ((float)rnd.NextDouble() * 2 - 1);
  155. Joints[0].positionkeys[0].key_element.Z = ((float)rnd.NextDouble() * 2 - 1);
  156. }
  157. public BinBVHAnimation(byte[] animationdata)
  158. {
  159. int i = 0;
  160. if (!BitConverter.IsLittleEndian)
  161. {
  162. unknown0 = Utils.BytesToUInt16(BinBVHUtil.EndianSwap(animationdata,i,2)); i += 2; // Always 1
  163. unknown1 = Utils.BytesToUInt16(BinBVHUtil.EndianSwap(animationdata, i, 2)); i += 2; // Always 0
  164. Priority = Utils.BytesToInt(BinBVHUtil.EndianSwap(animationdata, i, 4)); i += 4;
  165. Length = Utils.BytesToFloat(BinBVHUtil.EndianSwap(animationdata, i, 4), 0); i += 4;
  166. }
  167. else
  168. {
  169. unknown0 = Utils.BytesToUInt16(animationdata, i); i += 2; // Always 1
  170. unknown1 = Utils.BytesToUInt16(animationdata, i); i += 2; // Always 0
  171. Priority = Utils.BytesToInt(animationdata, i); i += 4;
  172. Length = Utils.BytesToFloat(animationdata, i); i += 4;
  173. }
  174. ExpressionName = ReadBytesUntilNull(animationdata, ref i);
  175. if (!BitConverter.IsLittleEndian)
  176. {
  177. InPoint = Utils.BytesToFloat(BinBVHUtil.EndianSwap(animationdata, i, 4), 0); i += 4;
  178. OutPoint = Utils.BytesToFloat(BinBVHUtil.EndianSwap(animationdata, i, 4), 0); i += 4;
  179. Loop = (Utils.BytesToInt(BinBVHUtil.EndianSwap(animationdata, i, 4)) != 0); i += 4;
  180. EaseInTime = Utils.BytesToFloat(BinBVHUtil.EndianSwap(animationdata, i, 4), 0); i += 4;
  181. EaseOutTime = Utils.BytesToFloat(BinBVHUtil.EndianSwap(animationdata, i, 4), 0); i += 4;
  182. HandPose = Utils.BytesToUInt(BinBVHUtil.EndianSwap(animationdata, i, 4)); i += 4; // Handpose?
  183. m_jointCount = Utils.BytesToUInt(animationdata, i); i += 4; // Get Joint count
  184. }
  185. else
  186. {
  187. InPoint = Utils.BytesToFloat(animationdata, i); i += 4;
  188. OutPoint = Utils.BytesToFloat(animationdata, i); i += 4;
  189. Loop = (Utils.BytesToInt(animationdata, i) != 0); i += 4;
  190. EaseInTime = Utils.BytesToFloat(animationdata, i); i += 4;
  191. EaseOutTime = Utils.BytesToFloat(animationdata, i); i += 4;
  192. HandPose = Utils.BytesToUInt(animationdata, i); i += 4; // Handpose?
  193. m_jointCount = Utils.BytesToUInt(animationdata, i); i += 4; // Get Joint count
  194. }
  195. Joints = new binBVHJoint[m_jointCount];
  196. // deserialize the number of joints in the animation.
  197. // Joints are variable length blocks of binary data consisting of joint data and keyframes
  198. for (int iter = 0; iter < m_jointCount; iter++)
  199. {
  200. binBVHJoint joint = readJoint(animationdata, ref i);
  201. Joints[iter] = joint;
  202. }
  203. }
  204. /// <summary>
  205. /// Variable length strings seem to be null terminated in the animation asset.. but..
  206. /// use with caution, home grown.
  207. /// advances the index.
  208. /// </summary>
  209. /// <param name="data">The animation asset byte array</param>
  210. /// <param name="i">The offset to start reading</param>
  211. /// <returns>a string</returns>
  212. private static string ReadBytesUntilNull(byte[] data, ref int i)
  213. {
  214. char nterm = '\0'; // Null terminator
  215. int endpos = i;
  216. int startpos = i;
  217. // Find the null character
  218. for (int j = i; j < data.Length; j++)
  219. {
  220. char spot = Convert.ToChar(data[j]);
  221. if (spot == nterm)
  222. {
  223. endpos = j;
  224. break;
  225. }
  226. }
  227. // if we got to the end, then it's a zero length string
  228. if (i == endpos)
  229. {
  230. // advance the 1 null character
  231. i++;
  232. return string.Empty;
  233. }
  234. else
  235. {
  236. // We found the end of the string
  237. // append the bytes from the beginning of the string to the end of the string
  238. // advance i
  239. byte[] interm = new byte[endpos-i];
  240. for (; i<endpos; i++)
  241. {
  242. interm[i-startpos] = data[i];
  243. }
  244. i++; // advance past the null character
  245. return Utils.BytesToString(interm);
  246. }
  247. }
  248. /// <summary>
  249. /// Read in a Joint from an animation asset byte array
  250. /// Variable length Joint fields, yay!
  251. /// Advances the index
  252. /// </summary>
  253. /// <param name="data">animation asset byte array</param>
  254. /// <param name="i">Byte Offset of the start of the joint</param>
  255. /// <returns>The Joint data serialized into the binBVHJoint structure</returns>
  256. private binBVHJoint readJoint(byte[] data, ref int i)
  257. {
  258. binBVHJointKey[] positions;
  259. binBVHJointKey[] rotations;
  260. binBVHJoint pJoint = new binBVHJoint();
  261. /*
  262. 109
  263. 84
  264. 111
  265. 114
  266. 114
  267. 111
  268. 0 <--- Null terminator
  269. */
  270. pJoint.Name = ReadBytesUntilNull(data, ref i); // Joint name
  271. /*
  272. 2 <- Priority Revisited
  273. 0
  274. 0
  275. 0
  276. */
  277. /*
  278. 5 <-- 5 keyframes
  279. 0
  280. 0
  281. 0
  282. ... 5 Keyframe data blocks
  283. */
  284. /*
  285. 2 <-- 2 keyframes
  286. 0
  287. 0
  288. 0
  289. .. 2 Keyframe data blocks
  290. */
  291. if (!BitConverter.IsLittleEndian)
  292. {
  293. pJoint.Priority = Utils.BytesToInt(BinBVHUtil.EndianSwap(data, i, 4)); i += 4; // Joint Priority override?
  294. rotationkeys = Utils.BytesToInt(BinBVHUtil.EndianSwap(data, i, 4)); i += 4; // How many rotation keyframes
  295. }
  296. else
  297. {
  298. pJoint.Priority = Utils.BytesToInt(data, i); i += 4; // Joint Priority override?
  299. rotationkeys = Utils.BytesToInt(data, i); i += 4; // How many rotation keyframes
  300. }
  301. // argh! floats into two bytes!.. bad bad bad bad
  302. // After fighting with it for a while.. -1, to 1 seems to give the best results
  303. rotations = readKeys(data, ref i, rotationkeys, -1f, 1f);
  304. for (int iter = 0; iter < rotations.Length; iter++)
  305. {
  306. rotations[iter].W = 1f -
  307. (rotations[iter].key_element.X + rotations[iter].key_element.Y +
  308. rotations[iter].key_element.Z);
  309. }
  310. if (!BitConverter.IsLittleEndian)
  311. {
  312. positionkeys = Utils.BytesToInt(BinBVHUtil.EndianSwap(data, i, 4)); i += 4; // How many position keyframes
  313. }
  314. else
  315. {
  316. positionkeys = Utils.BytesToInt(data, i); i += 4; // How many position keyframes
  317. }
  318. // Read in position keyframes
  319. // argh! more floats into two bytes!.. *head desk*
  320. // After fighting with it for a while.. -5, to 5 seems to give the best results
  321. positions = readKeys(data, ref i, positionkeys, -5f, 5f);
  322. pJoint.rotationkeys = rotations;
  323. pJoint.positionkeys = positions;
  324. return pJoint;
  325. }
  326. /// <summary>
  327. /// Read Keyframes of a certain type
  328. /// advance i
  329. /// </summary>
  330. /// <param name="data">Animation Byte array</param>
  331. /// <param name="i">Offset in the Byte Array. Will be advanced</param>
  332. /// <param name="keycount">Number of Keyframes</param>
  333. /// <param name="min">Scaling Min to pass to the Uint16ToFloat method</param>
  334. /// <param name="max">Scaling Max to pass to the Uint16ToFloat method</param>
  335. /// <returns></returns>
  336. private binBVHJointKey[] readKeys(byte[] data, ref int i, int keycount, float min, float max)
  337. {
  338. float x;
  339. float y;
  340. float z;
  341. /*
  342. 0.o, Float values in Two bytes.. this is just wrong >:(
  343. 17 255 <-- Time Code
  344. 17 255 <-- Time Code
  345. 255 255 <-- X
  346. 127 127 <-- X
  347. 255 255 <-- Y
  348. 127 127 <-- Y
  349. 213 213 <-- Z
  350. 142 142 <---Z
  351. */
  352. binBVHJointKey[] m_keys = new binBVHJointKey[keycount];
  353. for (int j = 0; j < keycount; j++)
  354. {
  355. binBVHJointKey pJKey = new binBVHJointKey();
  356. if (!BitConverter.IsLittleEndian)
  357. {
  358. pJKey.time = Utils.UInt16ToFloat(BinBVHUtil.EndianSwap(data, i, 2), 0, InPoint, OutPoint); i += 2;
  359. x = Utils.UInt16ToFloat(BinBVHUtil.EndianSwap(data, i, 2), 0, min, max); i += 2;
  360. y = Utils.UInt16ToFloat(BinBVHUtil.EndianSwap(data, i, 2), 0, min, max); i += 2;
  361. z = Utils.UInt16ToFloat(BinBVHUtil.EndianSwap(data, i, 2), 0, min, max); i += 2;
  362. }
  363. else
  364. {
  365. pJKey.time = Utils.UInt16ToFloat(data, i, InPoint, OutPoint); i += 2;
  366. x = Utils.UInt16ToFloat(data, i, min, max); i += 2;
  367. y = Utils.UInt16ToFloat(data, i, min, max); i += 2;
  368. z = Utils.UInt16ToFloat(data, i, min, max); i += 2;
  369. }
  370. pJKey.key_element = new Vector3(x, y, z);
  371. m_keys[j] = pJKey;
  372. }
  373. return m_keys;
  374. }
  375. }
  376. /// <summary>
  377. /// A Joint and it's associated meta data and keyframes
  378. /// </summary>
  379. public struct binBVHJoint
  380. {
  381. /// <summary>
  382. /// Name of the Joint. Matches the avatar_skeleton.xml in client distros
  383. /// </summary>
  384. public string Name;
  385. /// <summary>
  386. /// Joint Animation Override? Was the same as the Priority in testing..
  387. /// </summary>
  388. public int Priority;
  389. /// <summary>
  390. /// Array of Rotation Keyframes in order from earliest to latest
  391. /// </summary>
  392. public binBVHJointKey[] rotationkeys;
  393. /// <summary>
  394. /// Array of Position Keyframes in order from earliest to latest
  395. /// This seems to only be for the Pelvis?
  396. /// </summary>
  397. public binBVHJointKey[] positionkeys;
  398. public void WriteBytesToStream(BinaryWriter iostream, float InPoint, float OutPoint)
  399. {
  400. iostream.Write(BinBVHUtil.WriteNullTerminatedString(Name));
  401. iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(Priority)));
  402. iostream.Write(BinBVHUtil.ES(Utils.IntToBytes(rotationkeys.Length)));
  403. for (int i=0;i<rotationkeys.Length;i++)
  404. {
  405. rotationkeys[i].WriteBytesToStream(iostream, InPoint, OutPoint, -1f, 1f);
  406. }
  407. iostream.Write(BinBVHUtil.ES(Utils.IntToBytes((positionkeys.Length))));
  408. for (int i = 0; i < positionkeys.Length; i++)
  409. {
  410. positionkeys[i].WriteBytesToStream(iostream, InPoint, OutPoint, -256f, 256f);
  411. }
  412. }
  413. }
  414. /// <summary>
  415. /// A Joint Keyframe. This is either a position or a rotation.
  416. /// </summary>
  417. public struct binBVHJointKey
  418. {
  419. // Time in seconds for this keyframe.
  420. public float time;
  421. /// <summary>
  422. /// Either a Vector3 position or a Vector3 Euler rotation
  423. /// </summary>
  424. public Vector3 key_element;
  425. public float W;
  426. public void WriteBytesToStream(BinaryWriter iostream, float InPoint, float OutPoint, float min, float max)
  427. {
  428. iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(BinBVHUtil.FloatToUInt16(time, InPoint, OutPoint))));
  429. iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(BinBVHUtil.FloatToUInt16(key_element.X, min, max))));
  430. iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(BinBVHUtil.FloatToUInt16(key_element.Y, min, max))));
  431. iostream.Write(BinBVHUtil.ES(Utils.UInt16ToBytes(BinBVHUtil.FloatToUInt16(key_element.Z, min, max))));
  432. }
  433. }
  434. /// <summary>
  435. /// Poses set in the animation metadata for the hands.
  436. /// </summary>
  437. public enum HandPose : uint
  438. {
  439. Spread = 0,
  440. Relaxed = 1,
  441. Point_Both = 2,
  442. Fist = 3,
  443. Relaxed_Left = 4,
  444. Point_Left = 5,
  445. Fist_Left = 6,
  446. Relaxed_Right = 7,
  447. Point_Right = 8,
  448. Fist_Right = 9,
  449. Salute_Right = 10,
  450. Typing = 11,
  451. Peace_Right = 12
  452. }
  453. public static class BinBVHUtil
  454. {
  455. public const float ONE_OVER_U16_MAX = 1.0f / UInt16.MaxValue;
  456. public static UInt16 FloatToUInt16(float val, float lower, float upper)
  457. {
  458. UInt16 uival = 0;
  459. //m_parentGroup.GetTimeDilation() * (float)ushort.MaxValue
  460. //0-1
  461. // float difference = upper - lower;
  462. // we're trying to get a zero lower and modify all values equally so we get a percentage position
  463. if (lower > 0)
  464. {
  465. upper -= lower;
  466. val = val - lower;
  467. // start with 500 upper and 200 lower.. subtract 200 from the upper and the value
  468. }
  469. else //if (lower < 0 && upper > 0)
  470. {
  471. // double negative, 0 minus negative 5 is 5.
  472. upper += 0 - lower;
  473. lower += 0 - lower;
  474. val += 0 - lower;
  475. }
  476. if (upper == 0)
  477. val = 0;
  478. else
  479. {
  480. val /= upper;
  481. }
  482. uival = (UInt16)(val * UInt16.MaxValue);
  483. return uival;
  484. }
  485. /// <summary>
  486. /// Endian Swap
  487. /// Swaps endianness if necessary
  488. /// </summary>
  489. /// <param name="arr">Input array</param>
  490. /// <returns></returns>
  491. public static byte[] ES(byte[] arr)
  492. {
  493. if (!BitConverter.IsLittleEndian)
  494. Array.Reverse(arr);
  495. return arr;
  496. }
  497. public static byte[] EndianSwap(byte[] arr, int offset, int len)
  498. {
  499. byte[] bendian = new byte[offset + len];
  500. Buffer.BlockCopy(arr, offset, bendian, 0, len);
  501. Array.Reverse(bendian);
  502. return bendian;
  503. }
  504. public static byte[] WriteNullTerminatedString(string str)
  505. {
  506. byte[] output = new byte[str.Length + 1];
  507. Char[] chr = str.ToCharArray();
  508. int i = 0;
  509. for (i = 0; i < chr.Length; i++)
  510. {
  511. output[i] = Convert.ToByte(chr[i]);
  512. }
  513. output[i] = Convert.ToByte('\0');
  514. return output;
  515. }
  516. }
  517. }
  518. /*
  519. switch (jointname)
  520. {
  521. case "mPelvis":
  522. case "mTorso":
  523. case "mNeck":
  524. case "mHead":
  525. case "mChest":
  526. case "mHipLeft":
  527. case "mHipRight":
  528. case "mKneeLeft":
  529. case "mKneeRight":
  530. // XYZ->ZXY
  531. t = x;
  532. x = y;
  533. y = t;
  534. break;
  535. case "mCollarLeft":
  536. case "mCollarRight":
  537. case "mElbowLeft":
  538. case "mElbowRight":
  539. // YZX ->ZXY
  540. t = z;
  541. z = x;
  542. x = y;
  543. y = t;
  544. break;
  545. case "mWristLeft":
  546. case "mWristRight":
  547. case "mShoulderLeft":
  548. case "mShoulderRight":
  549. // ZYX->ZXY
  550. t = y;
  551. y = z;
  552. z = t;
  553. break;
  554. case "mAnkleLeft":
  555. case "mAnkleRight":
  556. // XYZ ->ZXY
  557. t = x;
  558. x = z;
  559. z = y;
  560. y = t;
  561. break;
  562. }
  563. */