Tools.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Runtime.InteropServices;
  6. using System.Windows.Forms;
  7. using Autodesk.Max;
  8. using BabylonExport.Entities;
  9. using SharpDX;
  10. namespace Max2Babylon
  11. {
  12. public static class Tools
  13. {
  14. public const float Epsilon = 0.001f;
  15. public static IPoint3 XAxis { get { return Loader.Global.Point3.Create(1, 0, 0); } }
  16. public static IPoint3 YAxis { get { return Loader.Global.Point3.Create(0, 1, 0); } }
  17. public static IPoint3 ZAxis { get { return Loader.Global.Point3.Create(0, 0, 1); } }
  18. public static IPoint3 Origin { get { return Loader.Global.Point3.Create(0, 0, 0); } }
  19. public static IInterval Forever
  20. {
  21. get { return Loader.Global.Interval.Create(int.MinValue, int.MaxValue); }
  22. }
  23. public static IMatrix3 Identity { get { return Loader.Global.Matrix3.Create(XAxis, YAxis, ZAxis, Origin); } }
  24. #if !MAX2015
  25. unsafe public static int GetParamBlockIndex(IIParamBlock paramBlock, string name)
  26. {
  27. for (short index = 0; index < paramBlock.NumParams; index++)
  28. {
  29. IGetParamName gpn = Loader.Global.GetParamName.Create("", index);
  30. paramBlock.NotifyDependents(Tools.Forever, (UIntPtr)gpn.Handle.ToPointer(), RefMessage.GetParamName, (SClass_ID)0xfffffff0, false, null);
  31. if (gpn.Name == name)
  32. {
  33. return index;
  34. }
  35. }
  36. return -1;
  37. }
  38. public static int GetParamBlockValueInt(IIParamBlock paramBlock, string name)
  39. {
  40. var index = Tools.GetParamBlockIndex(paramBlock, name);
  41. if (index == -1)
  42. {
  43. return 0;
  44. }
  45. return paramBlock.GetInt(index, 0);
  46. }
  47. public static float GetParamBlockValueFloat(IIParamBlock paramBlock, string name)
  48. {
  49. var index = Tools.GetParamBlockIndex(paramBlock, name);
  50. if (index == -1)
  51. {
  52. return 0;
  53. }
  54. return paramBlock.GetFloat(index, 0);
  55. }
  56. public static float[] GetParamBlockValueColor(IIParamBlock paramBlock, string name)
  57. {
  58. var index = Tools.GetParamBlockIndex(paramBlock, name);
  59. if (index == -1)
  60. {
  61. return null;
  62. }
  63. return paramBlock.GetColor(index, 0).ToArray();
  64. }
  65. #endif
  66. public static Vector3 ToEulerAngles(this IQuat q)
  67. {
  68. // Store the Euler angles in radians
  69. var pitchYawRoll = new Vector3();
  70. double sqw = q.W * q.W;
  71. double sqx = q.X * q.X;
  72. double sqy = q.Y * q.Y;
  73. double sqz = q.Z * q.Z;
  74. // If quaternion is normalised the unit is one, otherwise it is the correction factor
  75. double unit = sqx + sqy + sqz + sqw;
  76. double test = q.X * q.Y + q.Z * q.W;
  77. if (test > 0.4999f * unit) // 0.4999f OR 0.5f - EPSILON
  78. {
  79. // Singularity at north pole
  80. pitchYawRoll.Y = 2f * (float)Math.Atan2(q.X, q.W); // Yaw
  81. pitchYawRoll.X = (float)Math.PI * 0.5f; // Pitch
  82. pitchYawRoll.Z = 0f; // Roll
  83. return pitchYawRoll;
  84. }
  85. if (test < -0.4999f * unit) // -0.4999f OR -0.5f + EPSILON
  86. {
  87. // Singularity at south pole
  88. pitchYawRoll.Y = -2f * (float)Math.Atan2(q.X, q.W); // Yaw
  89. pitchYawRoll.X = -(float)Math.PI * 0.5f; // Pitch
  90. pitchYawRoll.Z = 0f; // Roll
  91. return pitchYawRoll;
  92. }
  93. pitchYawRoll.Y = (float)Math.Atan2(2f * q.Y * q.W - 2f * q.X * q.Z, sqx - sqy - sqz + sqw); // Yaw
  94. pitchYawRoll.X = (float)Math.Asin(2f * test / unit); // Pitch
  95. pitchYawRoll.Z = (float)Math.Atan2(2f * q.X * q.W - 2f * q.Y * q.Z, -sqx + sqy - sqz + sqw); // Roll
  96. return pitchYawRoll;
  97. }
  98. public static void PreparePipeline(IINode node, bool deactivate)
  99. {
  100. var obj = node.ObjectRef;
  101. if (obj == null || obj.SuperClassID != SClass_ID.GenDerivob)
  102. {
  103. return;
  104. }
  105. var derivedObject = obj as IIDerivedObject;
  106. if (derivedObject == null)
  107. {
  108. return;
  109. }
  110. for (var index = 0; index < derivedObject.NumModifiers; index++)
  111. {
  112. var modifier = derivedObject.GetModifier(index);
  113. //if (modifier.ClassID.PartA == 9815843 && modifier.ClassID.PartB == 87654) // Skin
  114. //{
  115. // if (deactivate)
  116. // {
  117. // modifier.DisableMod();
  118. // }
  119. // else
  120. // {
  121. // modifier.EnableMod();
  122. // }
  123. //}
  124. }
  125. }
  126. public static VNormal[] ComputeNormals(IMesh mesh, bool optimize)
  127. {
  128. var vnorms = new VNormal[mesh.NumVerts];
  129. var fnorms = new Vector3[mesh.NumFaces];
  130. for (var index = 0; index < mesh.NumVerts; index++)
  131. {
  132. vnorms[index] = new VNormal();
  133. }
  134. for (var index = 0; index < mesh.NumFaces; index++)
  135. {
  136. var face = mesh.Faces[index];
  137. Vector3 v0 = mesh.Verts[(int)face.V[0]].ToVector3();
  138. Vector3 v1 = mesh.Verts[(int)face.V[1]].ToVector3();
  139. Vector3 v2 = mesh.Verts[(int)face.V[2]].ToVector3();
  140. fnorms[index] = Vector3.Cross((v1 - v0), (v2 - v1));
  141. for (var j = 0; j < 3; j++)
  142. {
  143. vnorms[(int)face.V[j]].AddNormal(fnorms[index], optimize ? 1 : face.SmGroup);
  144. }
  145. fnorms[index].Normalize();
  146. }
  147. for (var index = 0; index < mesh.NumVerts; index++)
  148. {
  149. vnorms[index].Normalize();
  150. }
  151. return vnorms;
  152. }
  153. public static bool IsEqualTo(this float[] value, float[] other)
  154. {
  155. if (value.Length != other.Length)
  156. {
  157. return false;
  158. }
  159. return !value.Where((t, i) => Math.Abs(t - other[i]) > Epsilon).Any();
  160. }
  161. public static float[] ToArray(this IMatrix3 value)
  162. {
  163. var row0 = value.GetRow(0).ToArraySwitched();
  164. var row1 = value.GetRow(1).ToArraySwitched();
  165. var row2 = value.GetRow(2).ToArraySwitched();
  166. var row3 = value.GetRow(3).ToArraySwitched();
  167. return new[]
  168. {
  169. row0[0], row0[1], row0[2], 0,
  170. row2[0], row2[1], row2[2], 0,
  171. row1[0], row1[1], row1[2], 0,
  172. row3[0], row3[1], row3[2], 1
  173. };
  174. }
  175. public static IPoint3 ToPoint3(this Vector3 value)
  176. {
  177. return Loader.Global.Point3.Create(value.X, value.Y, value.Z);
  178. }
  179. public static Vector3 ToVector3(this IPoint3 value)
  180. {
  181. return new Vector3(value.X, value.Y, value.Z);
  182. }
  183. public static Quaternion ToQuat(this IQuat value)
  184. {
  185. return new Quaternion(value.X, value.Z, value.Y, value.W);
  186. }
  187. public static float[] ToArray(this IQuat value)
  188. {
  189. return new[] { value.X, value.Z, value.Y, value.W };
  190. }
  191. public static float[] Scale(this IColor value, float scale)
  192. {
  193. return new[] { value.R * scale, value.G * scale, value.B * scale };
  194. }
  195. public static float[] ToArray(this IPoint4 value)
  196. {
  197. return new[] { value.X, value.Y, value.Z, value.W };
  198. }
  199. public static float[] ToArray(this IPoint3 value)
  200. {
  201. return new[] { value.X, value.Y, value.Z };
  202. }
  203. public static float[] ToArray(this IPoint2 value)
  204. {
  205. return new[] { value.X, value.Y };
  206. }
  207. public static float[] ToArraySwitched(this IPoint2 value)
  208. {
  209. return new[] { value.X, 1.0f - value.Y };
  210. }
  211. public static float[] ToArraySwitched(this IPoint3 value)
  212. {
  213. return new[] { value.X, value.Z, value.Y };
  214. }
  215. public static float[] ToArray(this IColor value)
  216. {
  217. return new[] { value.R, value.G, value.B };
  218. }
  219. public static IEnumerable<IINode> Nodes(this IINode node)
  220. {
  221. for (int i = 0; i < node.NumberOfChildren; ++i)
  222. if (node.GetChildNode(i) != null)
  223. yield return node.GetChildNode(i);
  224. }
  225. public static IEnumerable<IINode> NodeTree(this IINode node)
  226. {
  227. foreach (var x in node.Nodes())
  228. {
  229. yield return x;
  230. foreach (var y in x.NodeTree())
  231. yield return y;
  232. }
  233. }
  234. public static IEnumerable<IINode> NodesListBySuperClass(this IINode rootNode, SClass_ID sid)
  235. {
  236. return from n in rootNode.NodeTree() where n.ObjectRef != null && n.EvalWorldState(0, false).Obj.SuperClassID == sid select n;
  237. }
  238. public static IEnumerable<IINode> NodesListBySuperClasses(this IINode rootNode, SClass_ID[] sids)
  239. {
  240. return from n in rootNode.NodeTree() where n.ObjectRef != null && sids.Any(sid => n.EvalWorldState(0, false).Obj.SuperClassID == sid) select n;
  241. }
  242. public static float ConvertFov(float fov)
  243. {
  244. return (float)(2.0f * Math.Atan(Math.Tan(fov / 2.0f) / Loader.Core.ImageAspRatio));
  245. }
  246. public static bool HasParent(this IINode node)
  247. {
  248. return node.ParentNode != null && node.ParentNode.ObjectRef != null;
  249. }
  250. public static bool IsInstance(this IAnimatable node)
  251. {
  252. var data = node.GetAppDataChunk(Loader.Class_ID, SClass_ID.Basenode, 1);
  253. if (data != null)
  254. {
  255. return data.Data[0] != 0;
  256. }
  257. return false;
  258. }
  259. public static void MarkAsInstance(this IAnimatable node)
  260. {
  261. node.AddAppDataChunk(Loader.Class_ID, SClass_ID.Basenode, 1, new byte[] { 1 });
  262. }
  263. public static Guid GetGuid(this IAnimatable node)
  264. {
  265. var uidData = node.GetAppDataChunk(Loader.Class_ID, SClass_ID.Basenode, 0);
  266. Guid uid;
  267. if (uidData != null)
  268. {
  269. uid = new Guid(uidData.Data);
  270. }
  271. else
  272. {
  273. uid = Guid.NewGuid();
  274. node.AddAppDataChunk(Loader.Class_ID, SClass_ID.Basenode, 0, uid.ToByteArray());
  275. }
  276. return uid;
  277. }
  278. public static string GetLocalData(this IAnimatable node)
  279. {
  280. var uidData = node.GetAppDataChunk(Loader.Class_ID, SClass_ID.Basenode, 1);
  281. if (uidData != null)
  282. {
  283. return System.Text.Encoding.UTF8.GetString(uidData.Data);
  284. }
  285. return "";
  286. }
  287. public static void SetLocalData(this IAnimatable node, string value)
  288. {
  289. var uidData = node.GetAppDataChunk(Loader.Class_ID, SClass_ID.Basenode, 1);
  290. if (uidData != null)
  291. {
  292. node.RemoveAppDataChunk(Loader.Class_ID, SClass_ID.Basenode, 1);
  293. }
  294. node.AddAppDataChunk(Loader.Class_ID, SClass_ID.Basenode, 1, System.Text.Encoding.UTF8.GetBytes(value));
  295. }
  296. public static IMatrix3 GetWorldMatrix(this IINode node, int t, bool parent)
  297. {
  298. var tm = node.GetNodeTM(t, Forever);
  299. var ptm = node.ParentNode.GetNodeTM(t, Forever);
  300. if (!parent)
  301. return tm;
  302. if (node.ParentNode.SuperClassID == SClass_ID.Camera)
  303. {
  304. var r = ptm.GetRow(3);
  305. ptm.IdentityMatrix();
  306. ptm.SetRow(3, r);
  307. }
  308. ptm.Invert();
  309. return tm.Multiply(ptm);
  310. }
  311. public static IMatrix3 GetWorldMatrixComplete(this IINode node, int t, bool parent)
  312. {
  313. var tm = node.GetObjTMAfterWSM(t, Forever);
  314. var ptm = node.ParentNode.GetObjTMAfterWSM(t, Forever);
  315. if (!parent)
  316. return tm;
  317. if (node.ParentNode.SuperClassID == SClass_ID.Camera)
  318. {
  319. var r = ptm.GetRow(3);
  320. ptm.IdentityMatrix();
  321. ptm.SetRow(3, r);
  322. }
  323. ptm.Invert();
  324. return tm.Multiply(ptm);
  325. }
  326. public static ITriObject GetMesh(this IObject obj)
  327. {
  328. var triObjectClassId = Loader.Global.Class_ID.Create(0x0009, 0);
  329. if (obj.CanConvertToType(triObjectClassId) == 0)
  330. return null;
  331. return obj.ConvertToType(0, triObjectClassId) as ITriObject;
  332. }
  333. public static bool IsAlmostEqualTo(this IPoint4 current, IPoint4 other, float epsilon)
  334. {
  335. if (Math.Abs(current.X - other.X) > epsilon)
  336. {
  337. return false;
  338. }
  339. if (Math.Abs(current.Y - other.Y) > epsilon)
  340. {
  341. return false;
  342. }
  343. if (Math.Abs(current.Z - other.Z) > epsilon)
  344. {
  345. return false;
  346. }
  347. if (Math.Abs(current.W - other.W) > epsilon)
  348. {
  349. return false;
  350. }
  351. return true;
  352. }
  353. public static bool IsAlmostEqualTo(this IPoint3 current, IPoint3 other, float epsilon)
  354. {
  355. if (Math.Abs(current.X - other.X) > epsilon)
  356. {
  357. return false;
  358. }
  359. if (Math.Abs(current.Y - other.Y) > epsilon)
  360. {
  361. return false;
  362. }
  363. if (Math.Abs(current.Z - other.Z) > epsilon)
  364. {
  365. return false;
  366. }
  367. return true;
  368. }
  369. public static bool IsAlmostEqualTo(this IPoint2 current, IPoint2 other, float epsilon)
  370. {
  371. if (Math.Abs(current.X - other.X) > epsilon)
  372. {
  373. return false;
  374. }
  375. if (Math.Abs(current.Y - other.Y) > epsilon)
  376. {
  377. return false;
  378. }
  379. return true;
  380. }
  381. public static bool IsAlmostEqualTo(this float[] current, float[] other, float epsilon)
  382. {
  383. if (current.Length != other.Length)
  384. {
  385. return false;
  386. }
  387. for (var index = 0; index < current.Length; index++)
  388. {
  389. if (Math.Abs(current[index] - other[index]) > epsilon)
  390. {
  391. return false;
  392. }
  393. }
  394. return true;
  395. }
  396. public static bool GetBoolProperty(this IINode node, string propertyName, int defaultState = 0)
  397. {
  398. int state = defaultState;
  399. #if MAX2015
  400. node.GetUserPropBool(propertyName, ref state);
  401. #else
  402. node.GetUserPropBool(ref propertyName, ref state);
  403. #endif
  404. return state == 1;
  405. }
  406. public static float GetFloatProperty(this IINode node, string propertyName, float defaultState = 0)
  407. {
  408. float state = defaultState;
  409. #if MAX2015
  410. node.GetUserPropFloat(propertyName, ref state);
  411. #else
  412. node.GetUserPropFloat(ref propertyName, ref state);
  413. #endif
  414. return state;
  415. }
  416. public static float[] GetVector3Property(this IINode node, string propertyName)
  417. {
  418. float state0 = 0;
  419. string name = propertyName + "_x";
  420. #if MAX2015
  421. node.GetUserPropFloat(name, ref state0);
  422. #else
  423. node.GetUserPropFloat(ref name, ref state0);
  424. #endif
  425. float state1 = 0;
  426. name = propertyName + "_y";
  427. #if MAX2015
  428. node.GetUserPropFloat(name, ref state1);
  429. #else
  430. node.GetUserPropFloat(ref name, ref state1);
  431. #endif
  432. float state2 = 0;
  433. name = propertyName + "_z";
  434. #if MAX2015
  435. node.GetUserPropFloat(name, ref state2);
  436. #else
  437. node.GetUserPropFloat(ref name, ref state2);
  438. #endif
  439. return new[] { state0, state1, state2 };
  440. }
  441. public static bool PrepareCheckBox(CheckBox checkBox, IINode node, string propertyName, int defaultState = 0)
  442. {
  443. var state = node.GetBoolProperty(propertyName, defaultState);
  444. if (checkBox.CheckState == CheckState.Indeterminate)
  445. {
  446. checkBox.CheckState = state ? CheckState.Checked : CheckState.Unchecked;
  447. }
  448. else
  449. {
  450. if (checkBox.ThreeState)
  451. {
  452. if (!state && checkBox.CheckState == CheckState.Checked ||
  453. state && checkBox.CheckState == CheckState.Unchecked)
  454. {
  455. checkBox.CheckState = CheckState.Indeterminate;
  456. return true;
  457. }
  458. }
  459. else
  460. {
  461. checkBox.CheckState = state ? CheckState.Checked : CheckState.Unchecked;
  462. return true;
  463. }
  464. }
  465. return false;
  466. }
  467. public static void PrepareCheckBox(CheckBox checkBox, List<IINode> nodes, string propertyName, int defaultState = 0)
  468. {
  469. checkBox.CheckState = CheckState.Indeterminate;
  470. foreach (var node in nodes)
  471. {
  472. if (PrepareCheckBox(checkBox, node, propertyName, defaultState))
  473. {
  474. break;
  475. }
  476. }
  477. }
  478. public static void UpdateCheckBox(CheckBox checkBox, IINode node, string propertyName)
  479. {
  480. if (checkBox.CheckState != CheckState.Indeterminate)
  481. {
  482. #if MAX2015
  483. node.SetUserPropBool(propertyName, checkBox.CheckState == CheckState.Checked);
  484. #else
  485. node.SetUserPropBool(ref propertyName, checkBox.CheckState == CheckState.Checked);
  486. #endif
  487. }
  488. }
  489. public static void UpdateCheckBox(CheckBox checkBox, List<IINode> nodes, string propertyName)
  490. {
  491. foreach (var node in nodes)
  492. {
  493. UpdateCheckBox(checkBox, node, propertyName);
  494. }
  495. }
  496. public static void PrepareNumericUpDown(NumericUpDown nup, List<IINode> nodes, string propertyName, float defaultState = 0)
  497. {
  498. nup.Value = (decimal)nodes[0].GetFloatProperty(propertyName, defaultState);
  499. }
  500. public static void UpdateNumericUpDown(NumericUpDown nup, List<IINode> nodes, string propertyName)
  501. {
  502. foreach (var node in nodes)
  503. {
  504. #if MAX2015
  505. node.SetUserPropFloat(propertyName, (float)nup.Value);
  506. #else
  507. node.SetUserPropFloat(ref propertyName, (float)nup.Value);
  508. #endif
  509. }
  510. }
  511. public static void PrepareVector3Control(Vector3Control vector3Control, IINode node, string propertyName, float defaultX = 0, float defaultY = 0, float defaultZ = 0)
  512. {
  513. vector3Control.X = node.GetFloatProperty(propertyName + "_x", defaultX);
  514. vector3Control.Y = node.GetFloatProperty(propertyName + "_y", defaultY);
  515. vector3Control.Z = node.GetFloatProperty(propertyName + "_z", defaultZ);
  516. }
  517. public static void UpdateVector3Control(Vector3Control vector3Control, IINode node, string propertyName)
  518. {
  519. string name = propertyName + "_x";
  520. #if MAX2015
  521. node.SetUserPropFloat(name, vector3Control.X);
  522. #else
  523. node.SetUserPropFloat(ref name, vector3Control.X);
  524. #endif
  525. name = propertyName + "_y";
  526. #if MAX2015
  527. node.SetUserPropFloat(name, vector3Control.Y);
  528. #else
  529. node.SetUserPropFloat(ref name, vector3Control.Y);
  530. #endif
  531. name = propertyName + "_z";
  532. #if MAX2015
  533. node.SetUserPropFloat(name, vector3Control.Z);
  534. #else
  535. node.SetUserPropFloat(ref name, vector3Control.Z);
  536. #endif
  537. }
  538. public static void UpdateVector3Control(Vector3Control vector3Control, List<IINode> nodes, string propertyName)
  539. {
  540. foreach (var node in nodes)
  541. {
  542. UpdateVector3Control(vector3Control, node, propertyName);
  543. }
  544. }
  545. public static IMatrix3 ExtractCoordinates(IINode meshNode, BabylonAbstractMesh babylonMesh, bool exportQuaternionsInsteadOfEulers)
  546. {
  547. var wm = meshNode.GetWorldMatrix(0, meshNode.HasParent());
  548. babylonMesh.position = wm.Trans.ToArraySwitched();
  549. var parts = Loader.Global.AffineParts.Create();
  550. Loader.Global.DecompAffine(wm, parts);
  551. if (exportQuaternionsInsteadOfEulers)
  552. {
  553. babylonMesh.rotationQuaternion = parts.Q.ToArray();
  554. }
  555. else
  556. {
  557. var rotate = new float[3];
  558. IntPtr xPtr = Marshal.AllocHGlobal(sizeof(float));
  559. IntPtr yPtr = Marshal.AllocHGlobal(sizeof(float));
  560. IntPtr zPtr = Marshal.AllocHGlobal(sizeof(float));
  561. parts.Q.GetEuler(xPtr, yPtr, zPtr);
  562. Marshal.Copy(xPtr, rotate, 0, 1);
  563. Marshal.Copy(yPtr, rotate, 1, 1);
  564. Marshal.Copy(zPtr, rotate, 2, 1);
  565. var temp = rotate[1];
  566. rotate[0] = -rotate[0] * parts.F;
  567. rotate[1] = -rotate[2] * parts.F;
  568. rotate[2] = -temp * parts.F;
  569. babylonMesh.rotation = rotate;
  570. }
  571. babylonMesh.scaling = parts.K.ToArraySwitched();
  572. return wm;
  573. }
  574. }
  575. }