agg_def.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. /*
  2. ** Command & Conquer Generals(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 : WW3D *
  23. * *
  24. * $Archive:: /Commando/Code/ww3d2/agg_def.cpp $*
  25. * *
  26. * Author:: Patrick Smith
  27. * *
  28. * $Modtime:: 4/05/01 10:21a $*
  29. * *
  30. * $Revision:: 5 $*
  31. * *
  32. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  33. #include "agg_def.h"
  34. #include "htree.h"
  35. #include "w3derr.h"
  36. #include "chunkio.h"
  37. #include "wwdebug.h"
  38. #include "assetmgr.h"
  39. #include "matinfo.h"
  40. #include "texture.h"
  41. #include "wwstring.h"
  42. #include <windows.h>
  43. ///////////////////////////////////////////////////////////////////////////////////
  44. //
  45. // Local constants
  46. //
  47. const char * const EMPTY_STRING = "";
  48. ///////////////////////////////////////////////////////////////////////////////////
  49. //
  50. // Global variable initialization
  51. //
  52. AggregateLoaderClass _AggregateLoader;
  53. ///////////////////////////////////////////////////////////////////////////////////
  54. //
  55. // AggregateDefClass
  56. //
  57. AggregateDefClass::AggregateDefClass (void)
  58. : m_pName (NULL)
  59. {
  60. // Set our member data to default settings
  61. ::memset (&m_Info, 0, sizeof (m_Info));
  62. ::memset (&m_MiscInfo, 0, sizeof (m_MiscInfo));
  63. m_MiscInfo.OriginalClassID = RenderObjClass::CLASSID_HLOD;
  64. return ;
  65. }
  66. ///////////////////////////////////////////////////////////////////////////////////
  67. //
  68. // AggregateDefClass
  69. //
  70. AggregateDefClass::AggregateDefClass (const AggregateDefClass &src)
  71. : m_pName (NULL)
  72. {
  73. // Set our member data to default settings
  74. ::memset (&m_Info, 0, sizeof (m_Info));
  75. ::memset (&m_MiscInfo, 0, sizeof (m_MiscInfo));
  76. m_MiscInfo.OriginalClassID = RenderObjClass::CLASSID_HLOD;
  77. // Invoke the assignment operator
  78. (*this) = src;
  79. return ;
  80. }
  81. ///////////////////////////////////////////////////////////////////////////////////
  82. //
  83. // AggregateDefClass
  84. //
  85. AggregateDefClass::AggregateDefClass (RenderObjClass &base_model)
  86. : m_pName (NULL)
  87. {
  88. // Set our member data to default settings
  89. ::memset (&m_Info, 0, sizeof (m_Info));
  90. ::memset (&m_MiscInfo, 0, sizeof (m_MiscInfo));
  91. m_MiscInfo.OriginalClassID = RenderObjClass::CLASSID_HLOD;
  92. Initialize (base_model);
  93. return ;
  94. }
  95. ///////////////////////////////////////////////////////////////////////////////////
  96. //
  97. // ~AggregateDefClass
  98. //
  99. AggregateDefClass::~AggregateDefClass (void)
  100. {
  101. // Free the name buffer if necessary
  102. if (m_pName != NULL) {
  103. // free() is used because the buffer was allocated with ::_strdup().
  104. ::free (m_pName);
  105. m_pName = NULL;
  106. }
  107. Free_Subobject_List ();
  108. return ;
  109. }
  110. ///////////////////////////////////////////////////////////////////////////////////
  111. //
  112. // operator=
  113. //
  114. const AggregateDefClass &
  115. AggregateDefClass::operator= (const AggregateDefClass &src)
  116. {
  117. int index;
  118. // Free the name buffer if necessary
  119. if (m_pName != NULL) {
  120. ::free (m_pName);
  121. m_pName = NULL;
  122. }
  123. // Start with a fresh set of data
  124. Free_Subobject_List ();
  125. // Copy the src object's name and info struct
  126. Set_Name (src.Get_Name ());
  127. ::memcpy (&m_Info, &src.m_Info, sizeof (m_Info));
  128. ::memcpy (&m_MiscInfo, &src.m_MiscInfo, sizeof (m_MiscInfo));
  129. m_Version = src.m_Version;
  130. // Loop through all the entries in the src object's subobj list
  131. for (index = 0; index < src.m_SubobjectList.Count (); index ++) {
  132. W3dAggregateSubobjectStruct *pinfo = src.m_SubobjectList[index];
  133. if (pinfo != NULL) {
  134. // Copy the src object's info for this subobj
  135. W3dAggregateSubobjectStruct *new_info = W3DNEW W3dAggregateSubobjectStruct;
  136. ::memcpy (new_info, pinfo, sizeof (W3dAggregateSubobjectStruct));
  137. // Add this subobj to our list
  138. m_SubobjectList.Add (new_info);
  139. }
  140. }
  141. // Return a reference to ourselves
  142. return *this;
  143. }
  144. ///////////////////////////////////////////////////////////////////////////////////
  145. //
  146. // Free_Subobject_List
  147. //
  148. void
  149. AggregateDefClass::Free_Subobject_List (void)
  150. {
  151. // Delete all the stucture pointers contained in the subobject list
  152. for (int index = 0; index < m_SubobjectList.Count (); index ++) {
  153. W3dAggregateSubobjectStruct *pinfo = m_SubobjectList[index];
  154. if (pinfo) {
  155. delete pinfo;
  156. }
  157. }
  158. // Reset the lists contents
  159. m_SubobjectList.Delete_All ();
  160. return ;
  161. }
  162. ///////////////////////////////////////////////////////////////////////////////////
  163. //
  164. // Create
  165. //
  166. RenderObjClass *
  167. AggregateDefClass::Create (void)
  168. {
  169. // Attempt to create an instance of the hierarchy
  170. RenderObjClass *pmodel = Create_Render_Object (m_Info.BaseModelName);
  171. if (pmodel != NULL) {
  172. // Perform the aggregation
  173. Attach_Subobjects (*pmodel);
  174. // Let the new object know what its new name and base name are.
  175. pmodel->Set_Name (m_pName);
  176. pmodel->Set_Base_Model_Name (m_Info.BaseModelName);
  177. pmodel->Set_Sub_Objects_Match_LOD ((m_MiscInfo.Flags & W3D_AGGREGATE_FORCE_SUB_OBJ_LOD) == W3D_AGGREGATE_FORCE_SUB_OBJ_LOD);
  178. } else {
  179. WWDEBUG_SAY (("Unable to load aggregate %s.\r\n", m_Info.BaseModelName));
  180. }
  181. // Return a pointer to the new aggregate
  182. return pmodel;
  183. }
  184. ///////////////////////////////////////////////////////////////////////////////////
  185. //
  186. // Find_Subobject
  187. //
  188. RenderObjClass *
  189. AggregateDefClass::Find_Subobject
  190. (
  191. RenderObjClass &model,
  192. const char mesh_path[MESH_PATH_ENTRIES][MESH_PATH_ENTRY_LEN],
  193. const char bone_path[MESH_PATH_ENTRIES][MESH_PATH_ENTRY_LEN]
  194. )
  195. {
  196. RenderObjClass *parent_model = &model;
  197. parent_model->Add_Ref ();
  198. // Loop through all the models in our "path" until we've either failed
  199. // or found the exact mesh we were looking for...
  200. for (int index = 1;
  201. (mesh_path[index][0] != 0) && (parent_model != NULL);
  202. index ++) {
  203. // Look one level deeper into the subobject chain...
  204. RenderObjClass *sub_obj = NULL;
  205. if (bone_path[index][0] == 0) {
  206. sub_obj = parent_model->Get_Sub_Object_By_Name (mesh_path[index]);
  207. } else {
  208. int bone_index = parent_model->Get_Bone_Index (bone_path[index]);
  209. int subobj_count = parent_model->Get_Num_Sub_Objects_On_Bone (bone_index);
  210. // Loop through all the subobjects on this bone
  211. for (int subobj_index = 0; (subobj_index < subobj_count) && (sub_obj == NULL); subobj_index ++) {
  212. // Is this the subobject we were looking for?
  213. RenderObjClass *ptemp_obj = parent_model->Get_Sub_Object_On_Bone (subobj_index, bone_index);
  214. if (::lstrcmpi (ptemp_obj->Get_Name (), mesh_path[index]) == 0) {
  215. sub_obj = ptemp_obj;
  216. } else {
  217. REF_PTR_RELEASE (ptemp_obj);
  218. }
  219. }
  220. }
  221. REF_PTR_RELEASE (parent_model);
  222. // The parent for the next iteration is the subobject on this one.
  223. parent_model = sub_obj;
  224. }
  225. // Return a pointer to the subobject
  226. return parent_model;
  227. }
  228. ///////////////////////////////////////////////////////////////////////////////////
  229. //
  230. // Attach_Subobjects
  231. //
  232. void
  233. AggregateDefClass::Attach_Subobjects (RenderObjClass &base_model)
  234. {
  235. // Now loop through all the subobjects and attach them to the appropriate bone
  236. for (int index = 0; index < m_SubobjectList.Count (); index ++) {
  237. W3dAggregateSubobjectStruct *psubobj_info = m_SubobjectList[index];
  238. if (psubobj_info != NULL) {
  239. // Now create this subobject and attach it to its bone.
  240. RenderObjClass *prender_obj = Create_Render_Object (psubobj_info->SubobjectName);
  241. if (prender_obj != NULL) {
  242. // Attach this object to the requested bone
  243. if (base_model.Add_Sub_Object_To_Bone (prender_obj, psubobj_info->BoneName) == false) {
  244. WWDEBUG_SAY (("Unable to attach %s to %s.\r\n", psubobj_info->SubobjectName, psubobj_info->BoneName));
  245. }
  246. // Release our hold on this pointer
  247. prender_obj->Release_Ref ();
  248. } else {
  249. WWDEBUG_SAY (("Unable to load aggregate subobject %s.\r\n", psubobj_info->SubobjectName));
  250. }
  251. }
  252. }
  253. return ;
  254. }
  255. ///////////////////////////////////////////////////////////////////////////////////
  256. //
  257. // Create_Render_Object
  258. //
  259. RenderObjClass *
  260. AggregateDefClass::Create_Render_Object (const char *passet_name)
  261. {
  262. // Assume failure
  263. RenderObjClass *prender_obj = NULL;
  264. // Attempt to get an instance of the render object from the asset manager
  265. prender_obj = WW3DAssetManager::Get_Instance()->Create_Render_Obj (passet_name);
  266. // If we couldn't find the render object in the asset manager, then attempt to
  267. // load it from file
  268. if ((prender_obj == NULL) &&
  269. Load_Assets (passet_name)) {
  270. // It should be in the asset manager now, so attempt to get it again.
  271. prender_obj = WW3DAssetManager::Get_Instance()->Create_Render_Obj (passet_name);
  272. }
  273. // Return a pointer to the render object
  274. return prender_obj;
  275. }
  276. ///////////////////////////////////////////////////////////////////////////////////
  277. //
  278. // Load_Assets
  279. //
  280. bool
  281. AggregateDefClass::Load_Assets (const char *passet_name)
  282. {
  283. // Assume failure
  284. bool retval = false;
  285. // Param OK?
  286. if (passet_name != NULL) {
  287. // Determine what the current working directory is
  288. char path[MAX_PATH];
  289. ::GetCurrentDirectory (sizeof (path), path);
  290. // Ensure the path is directory delimited
  291. if (path[::lstrlen(path)-1] != '\\') {
  292. ::lstrcat (path, "\\");
  293. }
  294. // Assume the filename is simply the "asset name" + the w3d extension
  295. ::lstrcat (path, passet_name);
  296. ::lstrcat (path, ".w3d");
  297. // If the file exists, then load it into the asset manager.
  298. if (::GetFileAttributes (path) != 0xFFFFFFFF) {
  299. retval = WW3DAssetManager::Get_Instance()->Load_3D_Assets (path);
  300. }
  301. }
  302. // Return the true/false result code
  303. return retval;
  304. }
  305. ///////////////////////////////////////////////////////////////////////////////////
  306. //
  307. // Initialize
  308. //
  309. void
  310. AggregateDefClass::Initialize (RenderObjClass &base_model)
  311. {
  312. // Start with fresh lists
  313. Free_Subobject_List ();
  314. // Determine what the render objects original name was.
  315. const char *orig_model_name = base_model.Get_Base_Model_Name ();
  316. orig_model_name = (orig_model_name == NULL) ? base_model.Get_Name () : orig_model_name;
  317. // Record information about this base model
  318. ::lstrcpy (m_Info.BaseModelName, orig_model_name);
  319. m_Info.SubobjectCount = 0;
  320. m_MiscInfo.OriginalClassID = base_model.Class_ID ();
  321. m_MiscInfo.Flags = 0;
  322. m_MiscInfo.Flags |= base_model.Is_Sub_Objects_Match_LOD_Enabled () ? W3D_AGGREGATE_FORCE_SUB_OBJ_LOD : 0;
  323. // Pass the aggregate name along
  324. Set_Name (base_model.Get_Name ());
  325. // Create a new instance of the model which we can use
  326. // to compare with the supplied model and determine
  327. // which 'bones-models' and textures are new.
  328. RenderObjClass *pvanilla_model = (RenderObjClass *)Create_Render_Object (orig_model_name);
  329. // Build lists of changes from the delta between the original model and the provided one
  330. Build_Subobject_List (*pvanilla_model, base_model);
  331. // Release the model if necessary
  332. REF_PTR_RELEASE (pvanilla_model);
  333. return ;
  334. }
  335. ///////////////////////////////////////////////////////////////////////////////////
  336. //
  337. // Build_Subobject_List
  338. //
  339. void
  340. AggregateDefClass::Build_Subobject_List
  341. (
  342. RenderObjClass &original_model,
  343. RenderObjClass &model
  344. )
  345. {
  346. int index;
  347. // Loop through all the bones in this render obj
  348. int bone_count = model.Get_Num_Bones ();
  349. for (int bone_index = 0; bone_index < bone_count; bone_index ++) {
  350. const char *pbone_name = model.Get_Bone_Name (bone_index);
  351. // Build a list of nodes that are contained in the vanilla model
  352. DynamicVectorClass <RenderObjClass *> orig_node_list;
  353. for (index = 0;
  354. index < original_model.Get_Num_Sub_Objects_On_Bone (bone_index);
  355. index ++) {
  356. RenderObjClass *psubobj = original_model.Get_Sub_Object_On_Bone (index, bone_index);
  357. if (psubobj != NULL) {
  358. orig_node_list.Add (psubobj);
  359. }
  360. }
  361. // Build a list of nodes that are contained in this bone
  362. DynamicVectorClass <RenderObjClass *> node_list;
  363. for (index = 0;
  364. index < model.Get_Num_Sub_Objects_On_Bone (bone_index);
  365. index ++) {
  366. RenderObjClass *psubobj = model.Get_Sub_Object_On_Bone (index, bone_index);
  367. if (psubobj != NULL) {
  368. node_list.Add (psubobj);
  369. }
  370. }
  371. int node_count = node_list.Count ();
  372. if (node_count > 0) {
  373. // Loop through the subobjects and add each one to our internal list
  374. W3dAggregateSubobjectStruct subobj_info = { 0 };
  375. for (int node_index = 0; node_index < node_count; node_index ++) {
  376. RenderObjClass *psubobject = node_list[node_index];
  377. WWASSERT (psubobject != NULL);
  378. // Is this subobject new? (i.e. not in a 'vanilla' instance?)
  379. const char *prototype_name = psubobject->Get_Name ();
  380. if (psubobject != NULL &&
  381. (Is_Object_In_List (prototype_name, orig_node_list) == false)) {
  382. // Add this subobject to our list
  383. ::lstrcpy (subobj_info.SubobjectName, prototype_name);
  384. ::lstrcpy (subobj_info.BoneName, pbone_name);
  385. Add_Subobject (subobj_info);
  386. m_Info.SubobjectCount ++;
  387. // Attach this render object to the 'original' model (this is done
  388. // so we can do texture compares later)
  389. RenderObjClass *prender_obj = WW3DAssetManager::Get_Instance ()->Create_Render_Obj (prototype_name);
  390. ((RenderObjClass &)original_model).Add_Sub_Object_To_Bone (prender_obj, pbone_name);
  391. REF_PTR_RELEASE (prender_obj);
  392. }
  393. }
  394. }
  395. // Free our hold on the render objs in the original node list
  396. for (index = 0; index < orig_node_list.Count (); index ++) {
  397. REF_PTR_RELEASE (orig_node_list[index]);
  398. }
  399. orig_node_list.Delete_All ();
  400. // Free our hold on the render objs in the node list
  401. for (index = 0; index < node_list.Count (); index ++) {
  402. REF_PTR_RELEASE (node_list[index]);
  403. }
  404. node_list.Delete_All ();
  405. }
  406. return ;
  407. }
  408. ///////////////////////////////////////////////////////////////////////////////////
  409. //
  410. // Is_Object_In_List
  411. //
  412. bool
  413. AggregateDefClass::Is_Object_In_List
  414. (
  415. const char *passet_name,
  416. DynamicVectorClass <RenderObjClass *> &node_list
  417. )
  418. {
  419. // Assume failure
  420. bool retval = false;
  421. // Loop through the nodes in the list until we've found the one
  422. // were are looking for.
  423. for (int node_index = 0; (node_index < node_list.Count ()) && (retval == false); node_index ++) {
  424. RenderObjClass *prender_obj = node_list[node_index];
  425. // Is this the render object we were looking for?
  426. if (prender_obj != NULL &&
  427. ::lstrcmpi (prender_obj->Get_Name (), passet_name) == 0) {
  428. retval = true;
  429. }
  430. }
  431. // Return the true/false result code
  432. return retval;
  433. }
  434. ///////////////////////////////////////////////////////////////////////////////////
  435. //
  436. // Load
  437. //
  438. WW3DErrorType
  439. AggregateDefClass::Load_W3D (ChunkLoadClass &chunk_load)
  440. {
  441. W3dTextureReplacerHeaderStruct header = { 0 };
  442. while (chunk_load.Open_Chunk()) {
  443. WW3DErrorType error = WW3D_ERROR_OK;
  444. switch (chunk_load.Cur_Chunk_ID()) {
  445. case W3D_CHUNK_AGGREGATE_HEADER:
  446. error = Read_Header(chunk_load);
  447. break;
  448. case W3D_CHUNK_AGGREGATE_INFO:
  449. error = Read_Info(chunk_load);
  450. break;
  451. case W3D_CHUNK_TEXTURE_REPLACER_INFO:
  452. if (chunk_load.Read (&header, sizeof (header)) == sizeof (header)) {
  453. if (header.ReplacedTexturesCount > 0) {
  454. WWDEBUG_SAY(("Obsolete texture replacement chunk encountered in aggregate: %s\r\n",m_pName));
  455. }
  456. }
  457. break;
  458. case W3D_CHUNK_AGGREGATE_CLASS_INFO:
  459. error = Read_Class_Info(chunk_load);
  460. break;
  461. default:
  462. // Unknown chunk.
  463. break;
  464. }
  465. chunk_load.Close_Chunk();
  466. if (error != WW3D_ERROR_OK) return (error);
  467. }
  468. return WW3D_ERROR_OK;
  469. }
  470. ///////////////////////////////////////////////////////////////////////////////////
  471. //
  472. // Read_Header
  473. //
  474. WW3DErrorType
  475. AggregateDefClass::Read_Header (ChunkLoadClass &chunk_load)
  476. {
  477. // Assume error
  478. WW3DErrorType ret_val = WW3D_ERROR_LOAD_FAILED;
  479. // Is this the header chunk?
  480. W3dAggregateHeaderStruct header = { 0 };
  481. if (chunk_load.Read (&header, sizeof (header)) == sizeof (header)) {
  482. // Copy the name from the header structure
  483. m_pName = ::_strdup (header.Name);
  484. m_Version = header.Version;
  485. // Success!
  486. ret_val = WW3D_ERROR_OK;
  487. }
  488. // Return the WW3D_ERROR_TYPE return code
  489. return ret_val;
  490. }
  491. ///////////////////////////////////////////////////////////////////////////////////
  492. //
  493. // Read_Info
  494. //
  495. WW3DErrorType
  496. AggregateDefClass::Read_Info (ChunkLoadClass &chunk_load)
  497. {
  498. // Assume error
  499. WW3DErrorType ret_val = WW3D_ERROR_LOAD_FAILED;
  500. // Read the chunk straight into our member structure
  501. ::memset (&m_Info, 0, sizeof (m_Info));
  502. if (chunk_load.Read (&m_Info, sizeof (m_Info)) == sizeof (m_Info)) {
  503. // Success!
  504. ret_val = WW3D_ERROR_OK;
  505. // Read all the subobjects from the file
  506. for (UINT isubobject = 0;
  507. (isubobject < m_Info.SubobjectCount) && (ret_val == WW3D_ERROR_OK);
  508. isubobject ++) {
  509. // Read this subobject's definition from the file
  510. ret_val = Read_Subobject (chunk_load);
  511. }
  512. }
  513. // Return the WW3D_ERROR_TYPE return code
  514. return ret_val;
  515. }
  516. ///////////////////////////////////////////////////////////////////////////////////
  517. //
  518. // Read_Subobject
  519. //
  520. WW3DErrorType
  521. AggregateDefClass::Read_Subobject (ChunkLoadClass &chunk_load)
  522. {
  523. // Assume error
  524. WW3DErrorType ret_val = WW3D_ERROR_LOAD_FAILED;
  525. // Read the subobject information from the file
  526. W3dAggregateSubobjectStruct subobj_info = { 0 };
  527. if (chunk_load.Read (&subobj_info, sizeof (subobj_info)) == sizeof (subobj_info)) {
  528. // Add this subobject to our list
  529. Add_Subobject (subobj_info);
  530. // Success!
  531. ret_val = WW3D_ERROR_OK;
  532. }
  533. // Return the WW3D_ERROR_TYPE return code
  534. return ret_val;
  535. }
  536. ///////////////////////////////////////////////////////////////////////////////////
  537. //
  538. // Add_Subobject
  539. //
  540. void
  541. AggregateDefClass::Add_Subobject (const W3dAggregateSubobjectStruct &subobj_info)
  542. {
  543. // Create a new structure and copy the contents of the src
  544. W3dAggregateSubobjectStruct *pnew_entry = W3DNEW W3dAggregateSubobjectStruct;
  545. ::lstrcpy (pnew_entry->SubobjectName, subobj_info.SubobjectName);
  546. ::lstrcpy (pnew_entry->BoneName, subobj_info.BoneName);
  547. // Add this new entry to the list
  548. m_SubobjectList.Add (pnew_entry);
  549. return ;
  550. }
  551. ///////////////////////////////////////////////////////////////////////////////////
  552. //
  553. // Read_Class_Info
  554. //
  555. WW3DErrorType
  556. AggregateDefClass::Read_Class_Info (ChunkLoadClass &chunk_load)
  557. {
  558. // Assume error
  559. WW3DErrorType ret_val = WW3D_ERROR_LOAD_FAILED;
  560. // Read the chunk straight into our header structure
  561. ::memset (&m_MiscInfo, 0, sizeof (m_MiscInfo));
  562. if (chunk_load.Read (&m_MiscInfo, sizeof (m_MiscInfo)) == sizeof (m_MiscInfo)) {
  563. // Success!
  564. ret_val = WW3D_ERROR_OK;
  565. }
  566. // Return the WW3D_ERROR_TYPE return code
  567. return ret_val;
  568. }
  569. //////////////////////////////////////////////////////////////////////////////////
  570. //
  571. // Save
  572. //
  573. WW3DErrorType
  574. AggregateDefClass::Save_W3D (ChunkSaveClass &chunk_save)
  575. {
  576. // Assume error
  577. WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
  578. // Begin a chunk that identifies an aggregate
  579. if (chunk_save.Begin_Chunk (W3D_CHUNK_AGGREGATE) == TRUE) {
  580. // Attempt to save the different sections of the aggregate definition
  581. if ((Save_Header (chunk_save) == WW3D_ERROR_OK) &&
  582. (Save_Info (chunk_save) == WW3D_ERROR_OK) &&
  583. (Save_Class_Info (chunk_save) == WW3D_ERROR_OK)) {
  584. // Success!
  585. ret_val = WW3D_ERROR_OK;
  586. }
  587. // Close the aggregate chunk
  588. chunk_save.End_Chunk ();
  589. }
  590. // Return the WW3D_ERROR_TYPE return code
  591. return ret_val;
  592. }
  593. ///////////////////////////////////////////////////////////////////////////////////
  594. //
  595. // Save_Header
  596. //
  597. WW3DErrorType
  598. AggregateDefClass::Save_Header (ChunkSaveClass &chunk_save)
  599. {
  600. // Assume error
  601. WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
  602. // Begin a chunk that identifies the aggregate
  603. if (chunk_save.Begin_Chunk (W3D_CHUNK_AGGREGATE_HEADER) == TRUE) {
  604. // Fill the header structure
  605. W3dAggregateHeaderStruct header = { 0 };
  606. header.Version = W3D_CURRENT_AGGREGATE_VERSION;
  607. ::lstrcpyn (header.Name, m_pName, sizeof (header.Name));
  608. header.Name[sizeof (header.Name) - 1] = 0;
  609. // Write the header out to the chunk
  610. if (chunk_save.Write (&header, sizeof (header)) == sizeof (header)) {
  611. // Success!
  612. ret_val = WW3D_ERROR_OK;
  613. }
  614. // End the header chunk
  615. chunk_save.End_Chunk ();
  616. }
  617. // Return the WW3D_ERROR_TYPE return code
  618. return ret_val;
  619. }
  620. ///////////////////////////////////////////////////////////////////////////////////
  621. //
  622. // Save_Info
  623. //
  624. WW3DErrorType
  625. AggregateDefClass::Save_Info (ChunkSaveClass &chunk_save)
  626. {
  627. // Assume error
  628. WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
  629. // Begin a chunk that identifies the aggregate settings
  630. if (chunk_save.Begin_Chunk (W3D_CHUNK_AGGREGATE_INFO) == TRUE) {
  631. // Write the settings structure out to the chunk
  632. if (chunk_save.Write (&m_Info, sizeof (m_Info)) == sizeof (m_Info)) {
  633. // Success!
  634. ret_val = WW3D_ERROR_OK;
  635. // Write all the subobjects to the file
  636. for (int isubobject = 0;
  637. (isubobject < m_SubobjectList.Count ()) && (ret_val == WW3D_ERROR_OK);
  638. isubobject ++) {
  639. // Write this object to the file
  640. ret_val = Save_Subobject (chunk_save, m_SubobjectList[isubobject]);
  641. }
  642. }
  643. // End the settings chunk
  644. chunk_save.End_Chunk ();
  645. }
  646. // Return the WW3D_ERROR_TYPE return code
  647. return ret_val;
  648. }
  649. ///////////////////////////////////////////////////////////////////////////////////
  650. //
  651. // Save_Subobject
  652. //
  653. WW3DErrorType
  654. AggregateDefClass::Save_Subobject
  655. (
  656. ChunkSaveClass &chunk_save,
  657. W3dAggregateSubobjectStruct *psubobject
  658. )
  659. {
  660. // Assume error
  661. WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
  662. // Write the subobj structure out to the chunk
  663. if (chunk_save.Write (psubobject, sizeof (W3dAggregateSubobjectStruct)) == sizeof (W3dAggregateSubobjectStruct)) {
  664. // Success!
  665. ret_val = WW3D_ERROR_OK;
  666. }
  667. // Return the WW3D_ERROR_TYPE return code
  668. return ret_val;
  669. }
  670. /////////////////////////////////////////////////////////////////////////////////
  671. //
  672. // Save_Class_Info
  673. //
  674. WW3DErrorType
  675. AggregateDefClass::Save_Class_Info (ChunkSaveClass &chunk_save)
  676. {
  677. // Assume error
  678. WW3DErrorType ret_val = WW3D_ERROR_SAVE_FAILED;
  679. // Begin a chunk that identifies the texture replacer header
  680. if (chunk_save.Begin_Chunk (W3D_CHUNK_AGGREGATE_CLASS_INFO) == TRUE) {
  681. // Write the class information structure out to the chunk
  682. if (chunk_save.Write (&m_MiscInfo, sizeof (m_MiscInfo)) == sizeof (m_MiscInfo)) {
  683. // Success!
  684. ret_val = WW3D_ERROR_OK;
  685. }
  686. // End the class info chunk
  687. chunk_save.End_Chunk ();
  688. }
  689. // Return the WW3D_ERROR_TYPE return code
  690. return ret_val;
  691. }
  692. ///////////////////////////////////////////////////////////////////////////////////
  693. //
  694. // Load
  695. //
  696. PrototypeClass *
  697. AggregateLoaderClass::Load_W3D (ChunkLoadClass &chunk_load)
  698. {
  699. // Assume failure
  700. AggregatePrototypeClass *pprototype = NULL;
  701. // Create a definition object
  702. AggregateDefClass *pdefinition = W3DNEW AggregateDefClass;
  703. if (pdefinition != NULL) {
  704. // Ask the definition object to load the aggregate data
  705. if (pdefinition->Load_W3D (chunk_load) != WW3D_ERROR_OK) {
  706. // Error! Free the definition
  707. delete pdefinition;
  708. pdefinition = NULL;
  709. } else {
  710. // Success! Create a prototype from the definition
  711. pprototype = W3DNEW AggregatePrototypeClass (pdefinition);
  712. }
  713. }
  714. // Return a pointer to the prototype
  715. return pprototype;
  716. }