TerrainNode.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992
  1. /*
  2. ** Command & Conquer Renegade(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. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : LevelEdit *
  23. * *
  24. * $Archive:: /Commando/Code/Tools/LevelEdit/TerrainNode.cpp $*
  25. * *
  26. * Author:: Patrick Smith *
  27. * *
  28. * $Modtime:: 2/12/02 4:07p $*
  29. * *
  30. * $Revision:: 36 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. #include "stdafx.h"
  36. #include "terrainnode.h"
  37. #include "staticphys.h"
  38. #include "sceneeditor.h"
  39. #include "terraindefinition.h"
  40. #include "filemgr.h"
  41. #include "_assetmgr.h"
  42. #include "editorassetmgr.h"
  43. #include "w3d_file.h"
  44. #include "hlod.h"
  45. #include "cameramgr.h"
  46. #include "collisiongroups.h"
  47. #include "persistfactory.h"
  48. #include "editorchunkids.h"
  49. #include "preset.h"
  50. #include "collect.h"
  51. #include "presetmgr.h"
  52. #include "nodemgr.h"
  53. #include "editorsaveload.h"
  54. #include "terrainsectionpersist.h"
  55. #include "lightphys.h"
  56. #include "lightnode.h"
  57. #include "leveleditview.h"
  58. #include "hlod.h"
  59. //////////////////////////////////////////////////////////////////////////////
  60. // Persist factory
  61. //////////////////////////////////////////////////////////////////////////////
  62. SimplePersistFactoryClass<TerrainNodeClass, CHUNKID_NODE_TERRAIN> _TerrainNodePersistFactory;
  63. SimplePersistFactoryClass<TerrainNodeClass, CHUNKID_NODE_TERRAIN_SECTION> _TerrainSectionNodePersistFactory;
  64. enum
  65. {
  66. CHUNKID_VARIABLES = 0x10251130,
  67. CHUNKID_BASE_CLASS,
  68. CHUNKID_SECTION_PERSISTDATA,
  69. CHUNKID_SECTION_PERSIST_LIST
  70. };
  71. enum
  72. {
  73. XXX_VARID_VISID = 0x01,
  74. VARID_SECTIONID_OLD,
  75. VARID_SECTIONID,
  76. VARID_TM
  77. };
  78. //////////////////////////////////////////////////////////////////////////////
  79. //
  80. // TerrainNodeClass
  81. //
  82. //////////////////////////////////////////////////////////////////////////////
  83. TerrainNodeClass::TerrainNodeClass (PresetClass *preset) :
  84. Transform (1),
  85. LoadedTransform (1),
  86. NodeClass (preset)
  87. {
  88. return ;
  89. }
  90. //////////////////////////////////////////////////////////////////////////////
  91. //
  92. // ~TerrainNodeClass
  93. //
  94. //////////////////////////////////////////////////////////////////////////////
  95. TerrainNodeClass::~TerrainNodeClass (void)
  96. {
  97. Remove_From_Scene ();
  98. Free_Sections ();
  99. return ;
  100. }
  101. //////////////////////////////////////////////////////////////////////////////
  102. //
  103. // Free_Section_Data
  104. //
  105. //////////////////////////////////////////////////////////////////////////////
  106. void
  107. TerrainNodeClass::Free_Section_Data (void)
  108. {
  109. m_TerrainSectionInfo.Free_List ();
  110. return ;
  111. }
  112. //////////////////////////////////////////////////////////////////////////////
  113. //
  114. // Free_Sections
  115. //
  116. //////////////////////////////////////////////////////////////////////////////
  117. void
  118. TerrainNodeClass::Free_Sections (void)
  119. {
  120. //
  121. // Release our hold on all the physics pointers
  122. //
  123. for (int index = 0; index < m_Sections.Count (); index ++) {
  124. NodeClass *sub_node = m_Sections[index];
  125. MEMBER_RELEASE (sub_node);
  126. //
  127. // Remove the file dependencies for this tile from the file manager.
  128. //
  129. if (sub_node != NULL && sub_node->Get_Type () != NODE_TYPE_TERRAIN_SECTION) {
  130. ::Get_File_Mgr ()->Update (sub_node, false);
  131. }
  132. }
  133. m_Sections.Delete_All ();
  134. return ;
  135. }
  136. //////////////////////////////////////////////////////////////////////////////
  137. //
  138. // Add_To_Scene
  139. //
  140. //////////////////////////////////////////////////////////////////////////////
  141. void
  142. TerrainNodeClass::Add_To_Scene (void)
  143. {
  144. SceneEditorClass *scene = ::Get_Scene_Editor ();
  145. //
  146. // Add all the sections to the scene
  147. //
  148. for (int index = 0; index < m_Sections.Count (); index ++) {
  149. NodeClass *sub_node = m_Sections[index];
  150. sub_node->Add_To_Scene ();
  151. }
  152. m_IsInScene = true;
  153. return ;
  154. }
  155. //////////////////////////////////////////////////////////////////////////////
  156. //
  157. // Remove_From_Scene
  158. //
  159. //////////////////////////////////////////////////////////////////////////////
  160. void
  161. TerrainNodeClass::Remove_From_Scene (void)
  162. {
  163. SceneEditorClass *scene = ::Get_Scene_Editor ();
  164. if (scene != NULL && m_IsInScene) {
  165. Build_Section_ID_List ();
  166. //
  167. // Remove all the sections from the scene
  168. //
  169. for (int index = 0; index < m_Sections.Count (); index ++) {
  170. NodeClass *sub_node = m_Sections[index];
  171. sub_node->Remove_From_Scene ();
  172. }
  173. m_IsInScene = false;
  174. }
  175. return ;
  176. }
  177. //////////////////////////////////////////////////////////////////////////////
  178. //
  179. // Set_Transform
  180. //
  181. //////////////////////////////////////////////////////////////////////////////
  182. void
  183. TerrainNodeClass::Set_Transform (const Matrix3D &tm)
  184. {
  185. Special_Set_Transform (tm);
  186. Transform = tm;
  187. return ;
  188. }
  189. //////////////////////////////////////////////////////////////////////////////
  190. //
  191. // Special_Set_Transform
  192. //
  193. //////////////////////////////////////////////////////////////////////////////
  194. void
  195. TerrainNodeClass::Special_Set_Transform (const Matrix3D &tm)
  196. {
  197. Matrix3D curr_tm = Get_Transform ();
  198. Matrix3D inv_tm (1);
  199. curr_tm.Get_Orthogonal_Inverse (inv_tm);
  200. //
  201. // Move all the sub-sections
  202. //
  203. for (int index = 0; index < m_Sections.Count (); index ++) {
  204. NodeClass *sub_node = (TerrainSectionNodeClass *)m_Sections[index];
  205. if (sub_node->Get_Type () == NODE_TYPE_TERRAIN_SECTION) {
  206. //
  207. // Check to see if this sub-object is a dazzle. If it is, then
  208. // transform it relative to the terrain...
  209. //
  210. RenderObjClass *model = sub_node->Peek_Render_Obj ();
  211. if (model != NULL && model->Class_ID () == RenderObjClass::CLASSID_DAZZLE) {
  212. Matrix3D sub_obj_tm = sub_node->Get_Transform ();
  213. Matrix3D rel_sub_obj_tm = inv_tm * sub_obj_tm;
  214. Matrix3D new_tm = tm * rel_sub_obj_tm;
  215. ((TerrainSectionNodeClass *)sub_node)->Special_Set_Transform (new_tm);
  216. } else {
  217. ((TerrainSectionNodeClass *)sub_node)->Special_Set_Transform (tm);
  218. }
  219. } else if (sub_node->Get_Type () == NODE_TYPE_TERRAIN) {
  220. ((TerrainNodeClass *)sub_node)->Special_Set_Transform (tm);
  221. } else {
  222. //
  223. // Transform this object relative to the terrain
  224. //
  225. Matrix3D sub_obj_tm = sub_node->Get_Transform ();
  226. Matrix3D rel_sub_obj_tm = inv_tm * sub_obj_tm;
  227. Matrix3D new_tm = tm * rel_sub_obj_tm;
  228. sub_node->Set_Transform (new_tm);
  229. }
  230. }
  231. NodeClass::Set_Transform (tm);
  232. return ;
  233. }
  234. //////////////////////////////////////////////////////////////////////////////
  235. //
  236. // Initialize
  237. //
  238. // Note: This may be called more than once. It is used as an 'initialize'
  239. // and a 're-initialize'.
  240. //
  241. //////////////////////////////////////////////////////////////////////////////
  242. void
  243. TerrainNodeClass::Initialize (void)
  244. {
  245. Build_Section_ID_List ();
  246. Free_Sections ();
  247. TerrainDefinitionClass *definition = static_cast<TerrainDefinitionClass *> (m_Preset->Get_Definition ());
  248. if (definition != NULL) {
  249. //
  250. // Make sure all assets are loaded into memory before this tile is created...
  251. //
  252. m_Preset->Load_All_Assets ();
  253. CString filename = definition->Get_Model_Name ();
  254. CString asset_name = ::Asset_Name_From_Filename (filename);
  255. //
  256. // Filename valid?
  257. //
  258. if (filename.GetLength () > 0) {
  259. filename = ::Get_File_Mgr ()->Make_Full_Path (filename);
  260. _pThe3DAssetManager->Set_Current_Directory (::Strip_Filename_From_Path (filename));
  261. //
  262. // Create the terrain
  263. //
  264. RenderObjClass *terrain = ::Create_Render_Obj (asset_name);
  265. if (terrain != NULL) {
  266. //
  267. // Loop through all the sections inside the mesh collection and
  268. // create static phys objects for each one.
  269. //
  270. int section_count = terrain->Get_Num_Sub_Objects ();
  271. if (section_count > 0) {
  272. for (int index = 0; index < section_count; index ++) {
  273. RenderObjClass *sub_obj = terrain->Get_Sub_Object (index);
  274. if (sub_obj != NULL) {
  275. //
  276. // Create a new terrain section and add it to our list
  277. //
  278. TerrainSectionNodeClass *sub_node = new TerrainSectionNodeClass;
  279. sub_node->Create (sub_obj);
  280. sub_node->Set_Terrain (this);
  281. m_Sections.Add (sub_node);
  282. MEMBER_RELEASE (sub_obj);
  283. }
  284. }
  285. }
  286. //
  287. // Build a list of proxy objects
  288. //
  289. DynamicVectorClass<ProxyClass> proxy_list;
  290. if (terrain->Class_ID () == RenderObjClass::CLASSID_COLLECTION) {
  291. //
  292. // Add all the proxies from the collection to our list
  293. //
  294. CollectionClass *collection = (CollectionClass *)terrain;
  295. for (int index = 0; index < collection->Get_Proxy_Count (); index ++) {
  296. ProxyClass proxy;
  297. if (collection->Get_Proxy (index, proxy)) {
  298. proxy_list.Add (proxy);
  299. }
  300. }
  301. } else if (terrain->Class_ID () == RenderObjClass::CLASSID_HLOD) {
  302. //
  303. // Add all the proxies from the HLOD to our list
  304. //
  305. HLodClass *hlod = reinterpret_cast<HLodClass *>(terrain);
  306. for (int index = 0; index < hlod->Get_Proxy_Count (); index ++) {
  307. ProxyClass proxy;
  308. if (hlod->Get_Proxy (index, proxy)) {
  309. proxy_list.Add (proxy);
  310. }
  311. }
  312. }
  313. //
  314. // Create the proxy objects
  315. //
  316. Create_Proxies (proxy_list);
  317. //
  318. // Create all the lights that are associated with this terrain
  319. //
  320. Create_Lights ();
  321. MEMBER_RELEASE (terrain);
  322. }
  323. }
  324. //
  325. // Make sure we restore all the VIS ids (if necessary)
  326. //
  327. Assign_Section_IDs ();
  328. }
  329. return ;
  330. }
  331. ////////////////////////////////////////////////////////////////
  332. //
  333. // Assign_Section_IDs
  334. //
  335. ////////////////////////////////////////////////////////////////
  336. void
  337. TerrainNodeClass::Assign_Section_IDs (void)
  338. {
  339. m_TerrainSectionInfo.Assign_Section_IDs (this);
  340. return ;
  341. }
  342. ////////////////////////////////////////////////////////////////
  343. //
  344. // Build_Section_ID_List
  345. //
  346. ////////////////////////////////////////////////////////////////
  347. void
  348. TerrainNodeClass::Build_Section_ID_List (void)
  349. {
  350. //
  351. // Rebuild the list from scratch (if there is anything to do)
  352. //
  353. if (In_Scene () && m_Sections.Count () > 0) {
  354. Free_Section_Data ();
  355. m_TerrainSectionInfo.Build_List (m_Sections);
  356. }
  357. return ;
  358. }
  359. ////////////////////////////////////////////////////////////////
  360. //
  361. // Get_Factory
  362. //
  363. ////////////////////////////////////////////////////////////////
  364. const PersistFactoryClass &
  365. TerrainNodeClass::Get_Factory (void) const
  366. {
  367. return _TerrainNodePersistFactory;
  368. }
  369. /////////////////////////////////////////////////////////////////
  370. //
  371. // Add_Vis_Points
  372. //
  373. /////////////////////////////////////////////////////////////////
  374. void
  375. TerrainNodeClass::Add_Vis_Points
  376. (
  377. VisPointGeneratorClass & generator,
  378. RenderObjClass * render_obj
  379. )
  380. {
  381. /*for (int index = 0; index < m_Sections.Count (); index ++) {
  382. StaticPhysClass *phys_obj = m_Sections[index];
  383. //
  384. // Pass all the sections onto the generator
  385. //
  386. RenderObjClass *render_obj = phys_obj->Peek_Model ();
  387. if (render_obj != NULL) {
  388. NodeClass::Add_Vis_Points (generator, render_obj);
  389. }
  390. }*/
  391. return ;
  392. }
  393. /////////////////////////////////////////////////////////////////
  394. //
  395. // Hide
  396. //
  397. /////////////////////////////////////////////////////////////////
  398. void
  399. TerrainNodeClass::Hide (bool hide)
  400. {
  401. for (int index = 0; index < m_Sections.Count (); index ++) {
  402. NodeClass *node = m_Sections[index];
  403. node->Hide (hide);
  404. }
  405. return ;
  406. }
  407. /////////////////////////////////////////////////////////////////
  408. //
  409. // Is_Hidden
  410. //
  411. /////////////////////////////////////////////////////////////////
  412. bool
  413. TerrainNodeClass::Is_Hidden (void) const
  414. {
  415. bool retval = false;
  416. if (m_Sections.Count () > 0) {
  417. NodeClass *node = m_Sections[0];
  418. retval = node->Is_Hidden ();
  419. }
  420. return retval;
  421. }
  422. /////////////////////////////////////////////////////////////////
  423. //
  424. // Save
  425. //
  426. /////////////////////////////////////////////////////////////////
  427. bool
  428. TerrainNodeClass::Save (ChunkSaveClass &csave)
  429. {
  430. csave.Begin_Chunk (CHUNKID_BASE_CLASS);
  431. NodeClass::Save (csave);
  432. csave.End_Chunk ();
  433. //
  434. // Write a chunk for each section so we can store instance
  435. // specific data.
  436. //
  437. Build_Section_ID_List ();
  438. csave.Begin_Chunk (CHUNKID_SECTION_PERSIST_LIST);
  439. m_TerrainSectionInfo.Save (csave);
  440. csave.End_Chunk ();
  441. csave.Begin_Chunk (CHUNKID_VARIABLES);
  442. WRITE_MICRO_CHUNK (csave, VARID_TM, Transform)
  443. csave.End_Chunk ();
  444. return true;
  445. }
  446. /////////////////////////////////////////////////////////////////
  447. //
  448. // Load
  449. //
  450. /////////////////////////////////////////////////////////////////
  451. bool
  452. TerrainNodeClass::Load (ChunkLoadClass &cload)
  453. {
  454. while (cload.Open_Chunk ()) {
  455. switch (cload.Cur_Chunk_ID ()) {
  456. case CHUNKID_BASE_CLASS:
  457. NodeClass::Load (cload);
  458. break;
  459. case CHUNKID_VARIABLES:
  460. Load_Variables (cload);
  461. break;
  462. case CHUNKID_SECTION_PERSIST_LIST:
  463. m_TerrainSectionInfo.Load (cload);
  464. break;
  465. }
  466. cload.Close_Chunk ();
  467. }
  468. SaveLoadSystemClass::Register_Post_Load_Callback (this);
  469. return true;
  470. }
  471. /////////////////////////////////////////////////////////////////
  472. //
  473. // Load_Variables
  474. //
  475. /////////////////////////////////////////////////////////////////
  476. bool
  477. TerrainNodeClass::Load_Variables (ChunkLoadClass &cload)
  478. {
  479. while (cload.Open_Micro_Chunk ()) {
  480. switch (cload.Cur_Micro_Chunk_ID ()) {
  481. READ_MICRO_CHUNK (cload, VARID_TM, LoadedTransform)
  482. case VARID_SECTIONID_OLD:
  483. case VARID_SECTIONID:
  484. {
  485. //
  486. // Force vis to be reset
  487. //
  488. PhysicsSceneClass::Get_Instance ()->Reset_Vis ();
  489. EditorSaveLoadClass::Set_Loaded_Vis_Valid (false);
  490. ::Output_Message ("Old-style terrain section ID found, resetting VIS data.\r\n");
  491. }
  492. break;
  493. }
  494. cload.Close_Micro_Chunk ();
  495. }
  496. return true;
  497. }
  498. ////////////////////////////////////////////////////////////////
  499. //
  500. // Create_Lights
  501. //
  502. ////////////////////////////////////////////////////////////////
  503. void
  504. TerrainNodeClass::Create_Lights (void)
  505. {
  506. if (::Get_Scene_Editor ()->Is_Proxy_Creation_Enabled () == false) {
  507. return ;
  508. }
  509. //
  510. // Get the terrain's definition
  511. //
  512. TerrainDefinitionClass *definition = static_cast<TerrainDefinitionClass *> (m_Preset->Get_Definition ());
  513. if (definition == NULL) {
  514. return ;
  515. }
  516. ::Get_Main_View ()->Allow_Repaint (false);
  517. //
  518. // Get the filename for the light database
  519. //
  520. CString full_path = ::Get_File_Mgr ()->Make_Full_Path (definition->Get_Light_Filename ());
  521. DynamicVectorClass<StringClass> filename_list;
  522. filename_list.Add ((LPCTSTR)full_path);
  523. //
  524. // Import the lights into the level
  525. //
  526. DynamicVectorClass<LightNodeClass *> node_list;
  527. ::Get_Scene_Editor ()->Import_Lights (filename_list, &node_list);
  528. //
  529. // Add all these lights to our section list
  530. //
  531. for (int index = 0; index < node_list.Count (); index ++) {
  532. LightNodeClass *node = node_list[index];
  533. if (node != NULL) {
  534. //
  535. // Transform this light from world-relative to terrain relative
  536. //
  537. node->Set_Transform (Get_Transform () * node->Get_Transform ());
  538. //
  539. // Add the light to our section list and 'remove' it from the node manager
  540. //
  541. node->Lock (true);
  542. m_Sections.Add (node);
  543. NodeMgrClass::Remove_Node (node);
  544. }
  545. }
  546. ::Get_Main_View ()->Allow_Repaint (true);
  547. return ;
  548. }
  549. ////////////////////////////////////////////////////////////////
  550. //
  551. // Find_Proxy_Preset
  552. //
  553. ////////////////////////////////////////////////////////////////
  554. PresetClass *
  555. TerrainNodeClass::Find_Proxy_Preset (const char *preset_name)
  556. {
  557. bool is_restricted_user = ::Get_File_Mgr ()->Is_Special_User ();
  558. PresetClass *retval = NULL;
  559. //
  560. // Loop over all the presets, until we've found one that matches the
  561. // requirements
  562. //
  563. bool keep_going = true;
  564. bool is_preferred = false;
  565. for ( PresetClass *preset = PresetMgrClass::Get_First ();
  566. preset != NULL && keep_going;
  567. preset = PresetMgrClass::Get_Next (preset))
  568. {
  569. //
  570. // Is this the preset we are looking for?
  571. //
  572. if (::lstrcmpi (preset->Get_Name (), preset_name) == 0) {
  573. if (is_preferred == false) {
  574. retval = preset;
  575. }
  576. if (preset->Is_A_Parent (PROXY_TESTS_FOLDER)) {
  577. retval = preset;
  578. keep_going = false;
  579. } else if (is_restricted_user == preset->Is_A_Parent (SPECIAL_USER_FOLDER)) {
  580. //
  581. // Restricted users prefer presets under their folder, other's prefer
  582. // presets not under the restricted presets folder.
  583. //
  584. is_preferred = true;
  585. }
  586. }
  587. }
  588. return retval;
  589. }
  590. ////////////////////////////////////////////////////////////////
  591. //
  592. // Create_Proxies
  593. //
  594. ////////////////////////////////////////////////////////////////
  595. void
  596. TerrainNodeClass::Create_Proxies (DynamicVectorClass<ProxyClass> &proxy_list)
  597. {
  598. if (::Get_Scene_Editor ()->Is_Proxy_Creation_Enabled () == false) {
  599. return ;
  600. }
  601. //
  602. // Loop over all the proxy objects in the list
  603. //
  604. int count = proxy_list.Count ();
  605. for (int index = 0; index < count; index ++) {
  606. //
  607. // Get information about this proxy
  608. //
  609. Matrix3D rel_transform = proxy_list[index].Get_Transform ();
  610. CString preset_name = proxy_list[index].Get_Name ();
  611. //
  612. // Find the preset this placeholder references
  613. //
  614. PresetClass *preset = Find_Proxy_Preset (preset_name);
  615. if (preset != NULL) {
  616. //
  617. // Create the node from the base
  618. //
  619. NodeClass *node = ::Get_Scene_Editor ()->Create_Node (preset, &rel_transform, 0, false);
  620. ASSERT (node != NULL);
  621. if (node != NULL) {
  622. //
  623. // Change some flags on the object
  624. //
  625. node->Restrict_Rotation (false);
  626. node->Set_Is_Proxied (true);
  627. //
  628. // Is the node configured correctly?
  629. //
  630. if (node->Peek_Physics_Obj () != NULL || node->Get_Type () == NODE_TYPE_TERRAIN) {
  631. //
  632. // Normalize the rotation of this node
  633. //
  634. node->Rotate (Matrix3D (1), Matrix3D (1));
  635. node->Lock (true);
  636. //
  637. // We have to tell the terrain it can really be moved...
  638. //
  639. if (node->Get_Type () == NODE_TYPE_TERRAIN) {
  640. ((TerrainNodeClass *)node)->Special_Set_Transform (rel_transform);
  641. }
  642. //
  643. // Remove this node from the system, and add it to our
  644. // local sub-node list.
  645. //
  646. node->Add_Ref ();
  647. m_Sections.Add (node);
  648. NodeMgrClass::Remove_Node (node);
  649. ::Get_File_Mgr ()->Update (node, true);
  650. } else {
  651. ::Get_Scene_Editor ()->Delete_Node (node, false);
  652. CString message;
  653. message.Format ("Unable to create physics object for placeholder %s.\r\n", (LPCTSTR)preset_name);
  654. ::Output_Message (message);
  655. }
  656. }
  657. } else {
  658. CString message;
  659. message.Format ("Unable to find preset for placeholder %s.\r\n", (LPCTSTR)preset_name);
  660. ::Output_Message (message);
  661. }
  662. }
  663. return ;
  664. }
  665. /////////////////////////////////////////////////////////////////
  666. //
  667. // Update_Cached_Vis_IDs
  668. //
  669. /////////////////////////////////////////////////////////////////
  670. void
  671. TerrainNodeClass::Update_Cached_Vis_IDs (void)
  672. {
  673. //
  674. // Pass this call onto all subobjects
  675. //
  676. for (int index = 0; index < m_Sections.Count (); index ++) {
  677. NodeClass *node = m_Sections[index];
  678. if (node != NULL) {
  679. node->Update_Cached_Vis_IDs ();
  680. }
  681. }
  682. Build_Section_ID_List ();
  683. return ;
  684. }
  685. /////////////////////////////////////////////////////////////////
  686. //
  687. // Reload
  688. //
  689. /////////////////////////////////////////////////////////////////
  690. void
  691. TerrainNodeClass::Reload (void)
  692. {
  693. NodeClass::Reload ();
  694. return ;
  695. }
  696. //////////////////////////////////////////////////////////////////////
  697. //
  698. // Pre_Export
  699. //
  700. //////////////////////////////////////////////////////////////////////
  701. void
  702. TerrainNodeClass::Pre_Export (void)
  703. {
  704. NodeClass::Pre_Export ();
  705. return ;
  706. }
  707. //////////////////////////////////////////////////////////////////////
  708. //
  709. // Post_Export
  710. //
  711. //////////////////////////////////////////////////////////////////////
  712. void
  713. TerrainNodeClass::Post_Export (void)
  714. {
  715. NodeClass::Post_Export ();
  716. return ;
  717. }
  718. //////////////////////////////////////////////////////////////////////
  719. //
  720. // Is_A_Child_Node
  721. //
  722. //////////////////////////////////////////////////////////////////////
  723. bool
  724. TerrainNodeClass::Is_A_Child_Node (NodeClass *node) const
  725. {
  726. bool retval = false;
  727. //
  728. // Test each sub object
  729. //
  730. for (int index = 0; retval == false && index < m_Sections.Count (); index ++) {
  731. NodeClass *curr_node = m_Sections[index];
  732. if (curr_node != NULL) {
  733. //
  734. // Is this the node we are looking for?
  735. //
  736. if (curr_node == node) {
  737. retval = true;
  738. } else {
  739. //
  740. // Pass this call onto the child
  741. //
  742. retval = curr_node->Is_A_Child_Node (node);
  743. }
  744. }
  745. }
  746. return retval;
  747. }
  748. ///////////////////////////////////////////////////////////////////////
  749. //
  750. // On_Post_Load
  751. //
  752. ///////////////////////////////////////////////////////////////////////
  753. void
  754. TerrainNodeClass::On_Post_Load (void)
  755. {
  756. m_TerrainSectionInfo.Initialize_Virgin_Sections ();
  757. //
  758. // Transform the terrain to its new position
  759. //
  760. if (m_IsProxied == false && LoadedTransform != Matrix3D::Identity) {
  761. Set_Transform (LoadedTransform);
  762. }
  763. return ;
  764. }
  765. //******************************************************************************//
  766. //*
  767. //* Start of TerrainSectionNodeClass
  768. //*
  769. //******************************************************************************//
  770. ////////////////////////////////////////////////////////////////
  771. //
  772. // Get_Factory
  773. //
  774. ////////////////////////////////////////////////////////////////
  775. const PersistFactoryClass &
  776. TerrainSectionNodeClass::Get_Factory (void) const
  777. {
  778. return _TerrainSectionNodePersistFactory;
  779. }
  780. ////////////////////////////////////////////////////////////////
  781. //
  782. // Create
  783. //
  784. ////////////////////////////////////////////////////////////////
  785. void
  786. TerrainSectionNodeClass::Create (RenderObjClass *render_obj)
  787. {
  788. MEMBER_RELEASE (m_PhysObj);
  789. //
  790. // Create the new terrain section from the render object
  791. //
  792. m_PhysObj = new StaticPhysClass;
  793. m_PhysObj->Set_Model (render_obj);
  794. m_PhysObj->Set_Transform (render_obj->Get_Transform ());
  795. //
  796. // Give this section an ID (and pass it along to its physics obj)
  797. //
  798. m_PhysObj->Set_ID (Get_ID ());
  799. Set_ID (NodeMgrClass::Get_Node_ID (Get_Type ()));
  800. m_PhysObj->Peek_Model ()->Set_User_Data ((PVOID)&m_HitTestInfo, FALSE);
  801. //
  802. // Give the new node a name
  803. //
  804. Set_Name (render_obj->Get_Name ());
  805. return ;
  806. }
  807. ////////////////////////////////////////////////////////////////
  808. //
  809. // Set_Transform
  810. //
  811. ////////////////////////////////////////////////////////////////
  812. void
  813. TerrainSectionNodeClass::Set_Transform (const Matrix3D &tm)
  814. {
  815. if (Terrain == NULL) {
  816. return ;
  817. }
  818. //
  819. // Get the inverse tranform of the terrain section
  820. //
  821. Matrix3D curr_tm = Get_Transform ();
  822. Matrix3D inv_tm;
  823. curr_tm.Get_Orthogonal_Inverse (inv_tm);
  824. Matrix3D delta_tm = inv_tm * tm;
  825. //
  826. // Transform the terrain object relative to this section
  827. //
  828. Matrix3D terrain_obj_tm = Terrain->Get_Transform ();
  829. //Matrix3D rel_terrain_obj_tm = inv_tm * terrain_obj_tm;
  830. Matrix3D new_tm = terrain_obj_tm * delta_tm;
  831. Terrain->Set_Transform (new_tm);
  832. return ;
  833. }