hiersave.cpp 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /* $Header: /Commando/Code/Tools/max2w3d/hiersave.cpp 56 10/30/00 6:58p Greg_h $ */
  19. /***********************************************************************************************
  20. *** Confidential - Westwood Studios ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Commando / G 3D Engine *
  24. * *
  25. * $Archive:: /Commando/Code/Tools/max2w3d/hiersave.cpp $*
  26. * *
  27. * $Author:: Greg_h $*
  28. * *
  29. * $Modtime:: 10/30/00 6:14p $*
  30. * *
  31. * $Revision:: 56 $*
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * HierarchySaveClass::HierarchySaveClass -- constructor *
  36. * HierarchySaveClass::HierarchySaveClass -- constructor *
  37. * HierarchySaveClass::HierarchySaveClass -- constructor *
  38. * HierarchySaveClass::~HierarchySaveClass -- destructor *
  39. * HierarchySaveClass::Free -- releases all allocated memory *
  40. * HierarchySaveClass::Get_Node_Transform -- returns the transformation matrix of specified n*
  41. * HierarchySaveClass::get_relative_transform -- retruns tm between this node and its parent *
  42. * HierarchySaveClass::Get_Name -- returns the name of this hierarchy *
  43. * HierarchySaveClass::Get_Node -- Get the Max INode *
  44. * HierarchySaveClass::Get_Node_Name -- returns name of this hierarchy node *
  45. * HierarchySaveClass::Find_Named_Node -- returns index of a named node *
  46. * HierarchySaveClass::Get_Export_Coordinate_System - find the bone and coordinate system *
  47. * HierarchySaveClass::Save -- write the hierarchy into a W3D file *
  48. * HierarchySaveClass::Load -- read the hierarchy from a W3D file *
  49. * HierarchySaveClass::add_tree -- adds a node and all of its children *
  50. * HierarchySaveClass::add_node -- adds a single node to the tree *
  51. * HierarchySaveClass::Get_Fixup_Transform -- gets the "fixup" transform for a node *
  52. * HierarchySaveClass::fixup_matrix -- conditions a matrix *
  53. * HierarchySaveClass::save_header -- writes the header into a W3D file *
  54. * HierarchySaveClass::save_pivots -- writes the pivots into a W3D file *
  55. * HierarchySaveClass::save_fixups -- writes the fixup transforms into a W3D file *
  56. * HierarchySaveClass::load_header -- reads the header from a W3D file *
  57. * HierarchySaveClass::load_pivots -- reads the pivots from a W3D file *
  58. * HierarchySaveClass::load_fixups -- reads the fixup transforms from a W3D file *
  59. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  60. #include "hiersave.h"
  61. #include "w3d_file.h"
  62. #include "nodefilt.h"
  63. #include "euler.h"
  64. #include "util.h"
  65. #include "w3dappdata.h"
  66. #include "errclass.h"
  67. #include "exportlog.h"
  68. bool HierarchySaveClass::TerrainModeEnabled = false;
  69. /***********************************************************************************************
  70. * HierarchySaveClass::HierarchySaveClass -- constructor *
  71. * *
  72. * INPUT: *
  73. * root - root INode to construct the HTree from *
  74. * time - current time in Max, transforms at this time will be used *
  75. * treemeter - progress meter *
  76. * hname - name for the hierarchy tree *
  77. * fixup_type - can be used to force all transforms to be translation only *
  78. * fixuptree - htree loaded from a previous export *
  79. * *
  80. * OUTPUT: *
  81. * *
  82. * WARNINGS: *
  83. * *
  84. * HISTORY: *
  85. * 10/26/1997 GH : Created. *
  86. *=============================================================================================*/
  87. HierarchySaveClass::HierarchySaveClass
  88. (
  89. INode * root,
  90. TimeValue time,
  91. Progress_Meter_Class & treemeter,
  92. char * hname,
  93. int fixuptype,
  94. HierarchySaveClass * fixuptree
  95. ) :
  96. Node(DEFAULT_NODE_ARRAY_SIZE),
  97. CurNode(0),
  98. FixupType(fixuptype),
  99. FixupTree(fixuptree)
  100. {
  101. CurNode = 0;
  102. CurTime = time;
  103. /*
  104. ** This code-path is activated when the user has created a custom origin. In this case, we
  105. ** need to compute the transform which will make all bones relative to this origin.
  106. */
  107. OriginOffsetTransform = Inverse(root->GetNodeTM(CurTime));
  108. /*
  109. ** Build our tree from the given tree of nodes
  110. */
  111. int rootidx = add_node(NULL,-1);
  112. assert(rootidx == 0);
  113. add_tree(root,rootidx);
  114. HierarchyHeader.Version = W3D_CURRENT_HTREE_VERSION;
  115. Set_W3D_Name(HierarchyHeader.Name,hname);
  116. HierarchyHeader.NumPivots = CurNode;
  117. HierarchyHeader.Center.X = 0.0f;
  118. HierarchyHeader.Center.Y = 0.0f;
  119. HierarchyHeader.Center.Z = 0.0f;
  120. }
  121. /***********************************************************************************************
  122. * HierarchySaveClass::HierarchySaveClass -- constructor *
  123. * *
  124. * INPUT: *
  125. * *
  126. * rootlist - list of root nodes to add to the htree *
  127. * time - current time in Max, transforms at this time will be used *
  128. * treemeter - progress meter *
  129. * hname - name for the hierarchy tree *
  130. * fixup_type - can be used to force all transforms to be translation only *
  131. * fixuptree - htree loaded from a previous export *
  132. * origin_offset - origin offset transform *
  133. * *
  134. * OUTPUT: *
  135. * *
  136. * WARNINGS: *
  137. * *
  138. * HISTORY: *
  139. * 10/26/1997 GH : Created. *
  140. *=============================================================================================*/
  141. HierarchySaveClass::HierarchySaveClass
  142. (
  143. INodeListClass * rootlist,
  144. TimeValue time,
  145. Progress_Meter_Class & treemeter,
  146. char * hname,
  147. int fixuptype,
  148. HierarchySaveClass * fixuptree,
  149. const Matrix3 & origin_offset
  150. ) :
  151. Node(DEFAULT_NODE_ARRAY_SIZE),
  152. CurNode(0),
  153. FixupType(fixuptype),
  154. FixupTree(fixuptree),
  155. OriginOffsetTransform(origin_offset)
  156. {
  157. CurNode = 0;
  158. CurTime = time;
  159. /*
  160. ** Build the tree with all leaves of all of the nodes given
  161. */
  162. int rootidx = add_node(NULL,-1);
  163. assert(rootidx == 0);
  164. for (unsigned int i = 0; i < rootlist->Num_Nodes(); i++) {
  165. add_tree((*rootlist)[i],rootidx);
  166. }
  167. HierarchyHeader.Version = W3D_CURRENT_HTREE_VERSION;
  168. Set_W3D_Name(HierarchyHeader.Name,hname);
  169. HierarchyHeader.NumPivots = CurNode;
  170. HierarchyHeader.Center.X = 0.0f;
  171. HierarchyHeader.Center.Y = 0.0f;
  172. HierarchyHeader.Center.Z = 0.0f;
  173. }
  174. /***********************************************************************************************
  175. * HierarchySaveClass::HierarchySaveClass -- constructor *
  176. * *
  177. * INPUT: *
  178. * *
  179. * OUTPUT: *
  180. * *
  181. * WARNINGS: *
  182. * *
  183. * HISTORY: *
  184. * 10/26/1997 GH : Created. *
  185. *=============================================================================================*/
  186. HierarchySaveClass::HierarchySaveClass():
  187. Node(NULL),
  188. CurNode(0),
  189. CurTime(0)
  190. {
  191. }
  192. /***********************************************************************************************
  193. * HierarchySaveClass::~HierarchySaveClass -- destructor *
  194. * *
  195. * INPUT: *
  196. * *
  197. * OUTPUT: *
  198. * *
  199. * WARNINGS: *
  200. * *
  201. * HISTORY: *
  202. * 10/26/1997 GH : Created. *
  203. *=============================================================================================*/
  204. HierarchySaveClass::~HierarchySaveClass(void)
  205. {
  206. Free();
  207. }
  208. /***********************************************************************************************
  209. * HierarchySaveClass::Free -- releases all allocated memory *
  210. * *
  211. * INPUT: *
  212. * *
  213. * OUTPUT: *
  214. * *
  215. * WARNINGS: *
  216. * *
  217. * HISTORY: *
  218. * 10/26/1997 GH : Created. *
  219. *=============================================================================================*/
  220. void HierarchySaveClass::Free(void)
  221. {
  222. Node.Clear();
  223. }
  224. /***********************************************************************************************
  225. * HierarchySaveClass::Get_Node_Transform -- returns the transformation matrix of specified no *
  226. * *
  227. * INPUT: *
  228. * *
  229. * OUTPUT: *
  230. * *
  231. * WARNINGS: *
  232. * *
  233. * HISTORY: *
  234. * 10/26/1997 GH : Created. *
  235. *=============================================================================================*/
  236. Matrix3 HierarchySaveClass::Get_Node_Transform(int nodeidx) const
  237. {
  238. Matrix3 tm(1);
  239. int idx = nodeidx;
  240. while (idx != -1) {
  241. tm = tm * get_relative_transform(idx);
  242. idx = Node[idx].Pivot.ParentIdx;
  243. }
  244. return tm;
  245. }
  246. /***********************************************************************************************
  247. * HierarchySaveClass::get_relative_transform -- retruns tm between this node and its parent *
  248. * *
  249. * INPUT: *
  250. * *
  251. * OUTPUT: *
  252. * *
  253. * WARNINGS: *
  254. * *
  255. * HISTORY: *
  256. * 10/26/1997 GH : Created. *
  257. *=============================================================================================*/
  258. Matrix3 HierarchySaveClass::get_relative_transform(int nodeidx) const
  259. {
  260. assert(nodeidx >= 0);
  261. assert(nodeidx < CurNode);
  262. Point3 trans;
  263. Quat rot;
  264. Matrix3 tm(true);
  265. Matrix3 rtm(true);
  266. trans.x = Node[nodeidx].Pivot.Translation.X;
  267. trans.y = Node[nodeidx].Pivot.Translation.Y;
  268. trans.z = Node[nodeidx].Pivot.Translation.Z;
  269. // WARNING! I had to fudge the orientation
  270. // quaternion (Max's representation seems to
  271. // rotate in the opposite sense as mine...)
  272. rot[0] = -Node[nodeidx].Pivot.Rotation.Q[0];
  273. rot[1] = -Node[nodeidx].Pivot.Rotation.Q[1];
  274. rot[2] = -Node[nodeidx].Pivot.Rotation.Q[2];
  275. rot[3] = Node[nodeidx].Pivot.Rotation.Q[3];
  276. tm.Translate(trans);
  277. rot.MakeMatrix(rtm);
  278. tm = rtm * tm;
  279. return tm;
  280. }
  281. /***********************************************************************************************
  282. * HierarchySaveClass::Get_Name -- returns the name of this hierarchy *
  283. * *
  284. * INPUT: *
  285. * *
  286. * OUTPUT: *
  287. * *
  288. * WARNINGS: *
  289. * *
  290. * HISTORY: *
  291. * 10/26/1997 GH : Created. *
  292. *=============================================================================================*/
  293. const char * HierarchySaveClass::Get_Name(void) const
  294. {
  295. return HierarchyHeader.Name;
  296. }
  297. /***********************************************************************************************
  298. * HierarchySaveClass::Get_Node -- Get the Max INode *
  299. * *
  300. * INPUT: *
  301. * *
  302. * OUTPUT: *
  303. * *
  304. * WARNINGS: *
  305. * *
  306. * HISTORY: *
  307. * 1/15/98 GTH : Created. *
  308. *=============================================================================================*/
  309. INode * HierarchySaveClass::Get_Node(int node) const
  310. {
  311. assert(node >= 0);
  312. assert(node < CurNode);
  313. return Node[node].MaxNode;
  314. }
  315. /***********************************************************************************************
  316. * HierarchySaveClass::Get_Node_Name -- returns name of this hierarchy node *
  317. * *
  318. * INPUT: *
  319. * *
  320. * OUTPUT: *
  321. * *
  322. * WARNINGS: *
  323. * *
  324. * HISTORY: *
  325. * 10/26/1997 GH : Created. *
  326. *=============================================================================================*/
  327. const char * HierarchySaveClass::Get_Node_Name(int node) const
  328. {
  329. assert(node >= 0);
  330. assert(node < CurNode);
  331. return Node[node].Pivot.Name;
  332. }
  333. /***********************************************************************************************
  334. * HierarchySaveClass::Find_Named_Node -- returns index of a named node *
  335. * *
  336. * INPUT: *
  337. * *
  338. * OUTPUT: *
  339. * *
  340. * WARNINGS: *
  341. * *
  342. * HISTORY: *
  343. * 10/26/1997 GH : Created. *
  344. *=============================================================================================*/
  345. int HierarchySaveClass::Find_Named_Node(const char * name) const
  346. {
  347. int match = -1;
  348. for (int index=0; index<CurNode; index++) {
  349. if (strcmp(Node[index].Pivot.Name,name) == 0) {
  350. match = index;
  351. }
  352. }
  353. return match;
  354. }
  355. /***********************************************************************************************
  356. * HierarchySaveClass::Get_Export_Coordinate_System - find the bone and coordinate system *
  357. * for the given object *
  358. * *
  359. * INPUT: *
  360. * *
  361. * OUTPUT: *
  362. * *
  363. * WARNINGS: *
  364. * *
  365. * HISTORY: *
  366. * 10/17/2000 gth : Created. *
  367. *=============================================================================================*/
  368. void HierarchySaveClass::Get_Export_Coordinate_System
  369. (
  370. INode * node,
  371. int * set_bone_index,
  372. INode ** set_bone_node,
  373. Matrix3 * set_transform
  374. )
  375. {
  376. /*
  377. ** find the first parent of this node which
  378. ** is in the base pose. Note, we're finding the parent bone
  379. ** in our hierarchy with the same name as a bone in the "main"
  380. ** hierarchy. When we're exporting LOD models, there are multiple
  381. ** hierarchies...
  382. */
  383. bool done = false;
  384. int boneidx = -1;
  385. INode * pbone = node;
  386. while (!done) {
  387. char name[W3D_NAME_LEN];
  388. Set_W3D_Name(name,pbone->GetName());
  389. boneidx = Find_Named_Node(name);
  390. if (boneidx != -1) {
  391. /*
  392. ** We found the parent bone!
  393. */
  394. done = true;
  395. } else if (Is_Origin(pbone)) {
  396. /*
  397. ** Don't go up past our origin, use this as our bone.
  398. */
  399. boneidx = 0;
  400. done = true;
  401. } else {
  402. /*
  403. ** Nope, try the next parent
  404. */
  405. pbone = pbone->GetParentNode();
  406. assert(pbone != NULL);
  407. #if 0
  408. if (pbone == NULL) {
  409. /*
  410. ** mesh isn't connected to a bone, use the root
  411. */
  412. boneidx = 0;
  413. pbone = node;
  414. done = true;
  415. }
  416. #endif
  417. }
  418. }
  419. if (set_bone_index != NULL) {
  420. *set_bone_index = boneidx;
  421. }
  422. if (set_bone_node != NULL) {
  423. *set_bone_node = pbone;
  424. }
  425. if (set_transform != NULL) {
  426. *set_transform = Get_Fixup_Transform(boneidx) * pbone->GetNodeTM(CurTime);
  427. }
  428. }
  429. /***********************************************************************************************
  430. * HierarchySaveClass::Save -- write the hierarchy into a W3D file *
  431. * *
  432. * INPUT: *
  433. * *
  434. * OUTPUT: *
  435. * *
  436. * WARNINGS: *
  437. * *
  438. * HISTORY: *
  439. * 10/26/1997 GH : Created. *
  440. *=============================================================================================*/
  441. bool HierarchySaveClass::Save(ChunkSaveClass & csave)
  442. {
  443. ExportLog::printf("\nSaving Hierarchy Tree %s.\n",HierarchyHeader.Name);
  444. ExportLog::printf("Node Count: %d\n",CurNode);
  445. ExportLog::printf("Nodes: \n");
  446. for (int inode = 0; inode < CurNode; inode++) {
  447. ExportLog::printf(" %s\n",Node[inode].Pivot.Name);
  448. }
  449. if (!csave.Begin_Chunk(W3D_CHUNK_HIERARCHY)) {
  450. return false;
  451. }
  452. if (!save_header(csave)) {
  453. return false;
  454. }
  455. if (!save_pivots(csave)) {
  456. return false;
  457. }
  458. if (!save_fixups(csave)) {
  459. return false;
  460. }
  461. if (!csave.End_Chunk()) {
  462. return false;
  463. }
  464. return true;
  465. }
  466. /***********************************************************************************************
  467. * HierarchySaveClass::Load -- read the hierarchy from a W3D file *
  468. * *
  469. * INPUT: *
  470. * *
  471. * OUTPUT: *
  472. * *
  473. * WARNINGS: *
  474. * *
  475. * HISTORY: *
  476. * 10/26/1997 GH : Created. *
  477. *=============================================================================================*/
  478. bool HierarchySaveClass::Load(ChunkLoadClass & cload)
  479. {
  480. Free();
  481. bool error = false;
  482. while (cload.Open_Chunk()) {
  483. switch (cload.Cur_Chunk_ID()) {
  484. case W3D_CHUNK_HIERARCHY_HEADER:
  485. if (!load_header(cload)) error = true;
  486. break;
  487. case W3D_CHUNK_PIVOTS:
  488. if (!load_pivots(cload)) error = true;
  489. break;
  490. case W3D_CHUNK_PIVOT_FIXUPS:
  491. if (!load_fixups(cload)) error = true;
  492. break;
  493. default:
  494. break;
  495. }
  496. if (!cload.Close_Chunk() || error) {
  497. return false;
  498. }
  499. }
  500. CurNode = HierarchyHeader.NumPivots;
  501. return true;
  502. }
  503. /***********************************************************************************************
  504. * HierarchySaveClass::add_tree -- adds a node and all of its children *
  505. * *
  506. * INPUT: *
  507. * *
  508. * OUTPUT: *
  509. * *
  510. * WARNINGS: *
  511. * *
  512. * HISTORY: *
  513. * 10/26/1997 GH : Created. *
  514. *=============================================================================================*/
  515. void HierarchySaveClass::add_tree(INode * node,int pidx)
  516. {
  517. int nextparent;
  518. if (node->IsHidden ()) {
  519. // if the node is hidden, do not add it but add its children to the current parent.
  520. nextparent = pidx;
  521. } else if (TerrainModeEnabled && (Is_Normal_Mesh(node) || Is_Null_Object(node))) {
  522. // terrain optimization, normal meshes are not allowed to have transforms
  523. nextparent = pidx;
  524. } else if (!Is_Bone(node)) {
  525. // This node isn't a bone, don't add it
  526. nextparent = pidx;
  527. } else {
  528. // Add new pivot! it will be parent of all below it.
  529. nextparent = add_node(node,pidx);
  530. }
  531. // Add all of this nodes children
  532. for (int i=0; i < node->NumberOfChildren(); i++) {
  533. add_tree(node->GetChildNode(i),nextparent);
  534. }
  535. }
  536. /***********************************************************************************************
  537. * HierarchySaveClass::add_node -- adds a single node to the tree *
  538. * *
  539. * INPUT: *
  540. * *
  541. * OUTPUT: *
  542. * *
  543. * WARNINGS: *
  544. * *
  545. * HISTORY: *
  546. * 10/26/1997 GH : Created. *
  547. *=============================================================================================*/
  548. int HierarchySaveClass::add_node(INode * node,int pidx)
  549. {
  550. /*
  551. ** 'grow' the node array if necessary
  552. */
  553. if (CurNode >= Node.Length ()) {
  554. Node.Resize (Node.Length () + NODE_ARRAY_GROWTH_SIZE);
  555. }
  556. /*
  557. ** setup the pivot
  558. */
  559. Node[CurNode].MaxNode = node;
  560. Node[CurNode].Pivot.ParentIdx = pidx;
  561. if (node) {
  562. Set_W3D_Name(Node[CurNode].Pivot.Name,node->GetName());
  563. } else {
  564. Set_W3D_Name(Node[CurNode].Pivot.Name,"RootTransform");
  565. }
  566. /*
  567. ** Now, check if there is a bone with this W3D name already
  568. ** if there is, scold the user and bail out
  569. */
  570. if (Find_Named_Node(Node[CurNode].Pivot.Name) != -1) {
  571. char buf[128];
  572. sprintf(buf,"Bones with duplicate names found!\nDuplicated Name: %s\n",Node[CurNode].Pivot.Name);
  573. throw ErrorClass(buf);
  574. }
  575. /*
  576. ** Compute the transformation for this node
  577. */
  578. Matrix3 maxnodeTM(1);
  579. Matrix3 ournodeTM(1);
  580. Matrix3 fixupTM(1);
  581. Point3 trans(0,0,0);
  582. Quat rot(1);
  583. Point3 scale(1,1,1);
  584. if (node) {
  585. maxnodeTM = node->GetNodeTM(CurTime) * OriginOffsetTransform;
  586. } else {
  587. maxnodeTM = Matrix3(1);
  588. }
  589. /*
  590. ** If this tree is being "fixed up" the first thing we do
  591. ** is to transform Max's nodeTM by the fixup transform.
  592. ** This is done when a base pose was created using our own
  593. ** types of transforms and we want to apply the same
  594. ** changes to this tree.
  595. **
  596. ** Note that if FixupType is not "NONE", FixupTree must be NULL,
  597. */
  598. assert(!((FixupTree != NULL) && (FixupType != MATRIX_FIXUP_NONE)));
  599. if (FixupTree != NULL) {
  600. int fi = FixupTree->Find_Named_Node(Node[CurNode].Pivot.Name);
  601. if (fi == -1) {
  602. char buf[128];
  603. sprintf(buf,"Incompatible Base Pose!\nMissing Bone: %s\n",Node[CurNode].Pivot.Name);
  604. throw ErrorClass(buf);
  605. }
  606. Matrix3 fixup = FixupTree->Get_Fixup_Transform(fi);
  607. maxnodeTM = fixup * maxnodeTM;
  608. }
  609. ournodeTM = fixup_matrix(maxnodeTM);
  610. fixupTM = ournodeTM * Inverse(maxnodeTM);
  611. /*
  612. ** Now, make ournodeTM relative to its parent transform. We
  613. ** will always store relative transformations. (Also, note
  614. ** that it is relative to our version of the parent transform
  615. ** which is not necessarily the same as the MAX version...)
  616. */
  617. if (pidx != -1) {
  618. Matrix3 parentTM = Get_Node_Transform(pidx);
  619. Matrix3 pinv = Inverse(parentTM);
  620. ournodeTM = ournodeTM * pinv;
  621. }
  622. /*
  623. ** Break the matrix down into a rotation and translation.
  624. */
  625. DecomposeMatrix(ournodeTM,trans,rot,scale);
  626. /*
  627. ** Save the "fixup" matrix
  628. */
  629. for (int j=0;j<4;j++) {
  630. Point3 row = fixupTM.GetRow(j);
  631. Node[CurNode].Fixup.TM[j][0] = row.x;
  632. Node[CurNode].Fixup.TM[j][1] = row.y;
  633. Node[CurNode].Fixup.TM[j][2] = row.z;
  634. }
  635. /*
  636. ** Set the translation and rotation for this pivot.
  637. */
  638. Node[CurNode].Pivot.Translation.X = trans.x;
  639. Node[CurNode].Pivot.Translation.Y = trans.y;
  640. Node[CurNode].Pivot.Translation.Z = trans.z;
  641. Node[CurNode].Pivot.Rotation.Q[0] = -rot[0];
  642. Node[CurNode].Pivot.Rotation.Q[1] = -rot[1];
  643. Node[CurNode].Pivot.Rotation.Q[2] = -rot[2];
  644. Node[CurNode].Pivot.Rotation.Q[3] = rot[3];
  645. /*
  646. ** Compute the Euler angles and set them.
  647. */
  648. Matrix3 rotmat;
  649. rot.MakeMatrix(rotmat);
  650. EulerAnglesClass eangs(rotmat,EulerOrderXYZr);
  651. Node[CurNode].Pivot.EulerAngles.X = eangs.Get_Angle(0);
  652. Node[CurNode].Pivot.EulerAngles.Y = eangs.Get_Angle(1);
  653. Node[CurNode].Pivot.EulerAngles.Z = eangs.Get_Angle(2);
  654. return CurNode++;
  655. }
  656. /***********************************************************************************************
  657. * HierarchySaveClass::Get_Fixup_Transform -- gets the "fixup" transform for a node *
  658. * *
  659. * INPUT: *
  660. * *
  661. * OUTPUT: *
  662. * *
  663. * WARNINGS: *
  664. * *
  665. * HISTORY: *
  666. * 10/26/1997 GH : Created. *
  667. *=============================================================================================*/
  668. Matrix3 HierarchySaveClass::Get_Fixup_Transform(int node) const
  669. {
  670. assert(node >= 0);
  671. assert(node < CurNode);
  672. Matrix3 m;
  673. for (int j=0;j<4;j++) {
  674. m.SetRow(j,Point3(Node[node].Fixup.TM[j][0],Node[node].Fixup.TM[j][1],Node[node].Fixup.TM[j][2]));
  675. }
  676. return m;
  677. }
  678. /***********************************************************************************************
  679. * HierarchySaveClass::fixup_matrix -- conditions a matrix *
  680. * *
  681. * INPUT: *
  682. * *
  683. * OUTPUT: *
  684. * *
  685. * WARNINGS: *
  686. * *
  687. * HISTORY: *
  688. * 10/26/1997 GH : Created. *
  689. *=============================================================================================*/
  690. Matrix3 HierarchySaveClass::fixup_matrix(const Matrix3 & csrc) const
  691. {
  692. Matrix3 src = csrc; // the GetTrans function is not const correct...
  693. Matrix3 newtm(1);
  694. Point3 trans;
  695. Quat rot;
  696. Point3 scale;
  697. switch (FixupType) {
  698. case MATRIX_FIXUP_NONE:
  699. newtm = src;
  700. break;
  701. case MATRIX_FIXUP_TRANS:
  702. newtm.SetTrans(src.GetTrans());
  703. newtm = Cleanup_Orthogonal_Matrix(newtm);
  704. break;
  705. case MATRIX_FIXUP_TRANS_ROT:
  706. DecomposeMatrix(src,trans,rot,scale);
  707. rot.MakeMatrix(newtm);
  708. newtm.SetTrans(trans);
  709. newtm = Cleanup_Orthogonal_Matrix(newtm);
  710. break;
  711. };
  712. return newtm;
  713. }
  714. /***********************************************************************************************
  715. * HierarchySaveClass::save_header -- writes the header into a W3D file *
  716. * *
  717. * INPUT: *
  718. * *
  719. * OUTPUT: *
  720. * *
  721. * WARNINGS: *
  722. * *
  723. * HISTORY: *
  724. * 10/26/1997 GH : Created. *
  725. *=============================================================================================*/
  726. bool HierarchySaveClass::save_header(ChunkSaveClass & csave)
  727. {
  728. if (!csave.Begin_Chunk(W3D_CHUNK_HIERARCHY_HEADER)) {
  729. return false;
  730. }
  731. if (csave.Write(&HierarchyHeader,sizeof(HierarchyHeader)) != sizeof(HierarchyHeader)) {
  732. return false;
  733. }
  734. if (!csave.End_Chunk()) {
  735. return false;
  736. }
  737. return true;
  738. }
  739. /***********************************************************************************************
  740. * HierarchySaveClass::save_pivots -- writes the pivots into a W3D file *
  741. * *
  742. * INPUT: *
  743. * *
  744. * OUTPUT: *
  745. * *
  746. * WARNINGS: *
  747. * *
  748. * HISTORY: *
  749. * 10/26/1997 GH : Created. *
  750. *=============================================================================================*/
  751. bool HierarchySaveClass::save_pivots(ChunkSaveClass & csave)
  752. {
  753. if (!csave.Begin_Chunk(W3D_CHUNK_PIVOTS)) {
  754. return false;
  755. }
  756. for (uint32 i=0; i<HierarchyHeader.NumPivots; i++) {
  757. if (csave.Write(&Node[i].Pivot,sizeof(W3dPivotStruct)) != sizeof(W3dPivotStruct)) {
  758. return false;
  759. }
  760. }
  761. if (!csave.End_Chunk()) {
  762. return false;
  763. }
  764. return true;
  765. }
  766. /***********************************************************************************************
  767. * HierarchySaveClass::save_fixups -- writes the fixup transforms into a W3D file *
  768. * *
  769. * INPUT: *
  770. * *
  771. * OUTPUT: *
  772. * *
  773. * WARNINGS: *
  774. * *
  775. * HISTORY: *
  776. * 10/26/1997 GH : Created. *
  777. *=============================================================================================*/
  778. bool HierarchySaveClass::save_fixups(ChunkSaveClass & csave)
  779. {
  780. if (!csave.Begin_Chunk(W3D_CHUNK_PIVOT_FIXUPS)) {
  781. return false;
  782. }
  783. for (uint32 i=0; i<HierarchyHeader.NumPivots; i++) {
  784. if (csave.Write(&Node[i].Fixup,sizeof(W3dPivotFixupStruct)) != sizeof(W3dPivotFixupStruct)) {
  785. return false;
  786. }
  787. }
  788. if (!csave.End_Chunk()) {
  789. return false;
  790. }
  791. return true;
  792. }
  793. /***********************************************************************************************
  794. * HierarchySaveClass::load_header -- reads the header from a W3D file *
  795. * *
  796. * INPUT: *
  797. * *
  798. * OUTPUT: *
  799. * *
  800. * WARNINGS: *
  801. * *
  802. * HISTORY: *
  803. * 10/26/1997 GH : Created. *
  804. *=============================================================================================*/
  805. bool HierarchySaveClass::load_header(ChunkLoadClass & cload)
  806. {
  807. /*
  808. ** Load the header
  809. */
  810. if (cload.Read(&HierarchyHeader,sizeof(HierarchyHeader)) != sizeof(HierarchyHeader)) {
  811. return false;
  812. }
  813. /*
  814. ** Reset the current node count
  815. */
  816. CurNode = 0;
  817. Node.Resize(HierarchyHeader.NumPivots);
  818. /*
  819. ** Initialize everything to a default state (particularly the
  820. ** fixup matrices to identity...)
  821. */
  822. for (unsigned i=0; i < HierarchyHeader.NumPivots; i++) {
  823. memset(&(Node[i]),0,sizeof(HierarchyNodeStruct));
  824. Matrix3 ident(1);
  825. for (int j=0; j<3; j++) {
  826. Point3 row = ident.GetRow(j);
  827. Node[i].Fixup.TM[j][0] = row.x;
  828. Node[i].Fixup.TM[j][1] = row.y;
  829. Node[i].Fixup.TM[j][2] = row.z;
  830. }
  831. }
  832. return true;
  833. }
  834. /***********************************************************************************************
  835. * HierarchySaveClass::load_pivots -- reads the pivots from a W3D file *
  836. * *
  837. * INPUT: *
  838. * *
  839. * OUTPUT: *
  840. * *
  841. * WARNINGS: *
  842. * *
  843. * HISTORY: *
  844. * 10/26/1997 GH : Created. *
  845. *=============================================================================================*/
  846. bool HierarchySaveClass::load_pivots(ChunkLoadClass & cload)
  847. {
  848. for (uint32 i=0; i<HierarchyHeader.NumPivots; i++) {
  849. Node[i].MaxNode = NULL;
  850. if (cload.Read(&Node[i].Pivot,sizeof(W3dPivotStruct)) != sizeof(W3dPivotStruct)) {
  851. return false;
  852. }
  853. }
  854. return true;
  855. }
  856. /***********************************************************************************************
  857. * HierarchySaveClass::load_fixups -- reads the fixup transforms from a W3D file *
  858. * *
  859. * INPUT: *
  860. * *
  861. * OUTPUT: *
  862. * *
  863. * WARNINGS: *
  864. * *
  865. * HISTORY: *
  866. * 10/26/1997 GH : Created. *
  867. *=============================================================================================*/
  868. bool HierarchySaveClass::load_fixups(ChunkLoadClass & cload)
  869. {
  870. for (uint32 i=0; i<HierarchyHeader.NumPivots; i++) {
  871. if (cload.Read(&Node[i].Fixup,sizeof(W3dPivotFixupStruct)) != sizeof(W3dPivotFixupStruct)) {
  872. return false;
  873. }
  874. }
  875. return true;
  876. }