hlodsave.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  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. /***********************************************************************************************
  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 : Renegade / G *
  23. * *
  24. * $Archive:: /Commando/Code/Tools/max2w3d/hlodsave.cpp $*
  25. * *
  26. * $Author:: Greg_h $*
  27. * *
  28. * $Modtime:: 11/07/00 5:24p $*
  29. * *
  30. * $Revision:: 9 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * -- The constructor builds the whole HLOD tree in a *
  35. * -- Destructor blows away the dynamic memory we used. *
  36. * -- Method called when saving to a W3D file. Saves the chunks *
  37. * -- Write the header *
  38. * -- Writes each LOD *
  39. * -- Writes the mesh to bone connectivity info for each mesh in an LOD. *
  40. * HLodSaveClass::save_aggregate_array -- save the aggregates (if any) *
  41. * HLodSaveClass::save_proxy_array -- save the array of proxies (if any) *
  42. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  43. #include "hlodsave.h"
  44. #include "meshcon.h"
  45. #include "errclass.h"
  46. #include "util.h"
  47. #include "w3dappdata.h"
  48. #include "wwmath.h" // NO_MAX_SCREEN_SIZE
  49. #include "exportlog.h"
  50. /* Behold, the applicable snippets of code from w3d_file.h that are applicable to this module!
  51. W3D_CHUNK_HLOD =0x00000700, // description of an HLod object (see HLodClass)
  52. W3D_CHUNK_HLOD_HEADER, // general information such as name and version
  53. W3D_CHUNK_HLOD_LOD_ARRAY, // wrapper around the array of objects for each level of detail
  54. W3D_CHUNK_HLOD_LOD_ARRAY_HEADER, // info on the objects in this level of detail array
  55. W3D_CHUNK_HLOD_SUB_OBJECT, // an object in this level of detail array
  56. struct W3dHLodHeaderStruct
  57. {
  58. uint32 Version;
  59. uint32 LodCount;
  60. char Name[W3D_NAME_LEN];
  61. char HierarchyName[W3D_NAME_LEN]; // name of the hierarchy tree to use (\0 if none)
  62. };
  63. struct W3dHLodArrayHeaderStruct
  64. {
  65. uint32 ModelCount;
  66. float32 MaxScreenSize; // if model is bigger than this, switch to higher lod.
  67. };
  68. struct W3dHLodSubObjectStruct
  69. {
  70. uint32 BoneIndex;
  71. char Name[W3D_NAME_LEN*2];
  72. };
  73. */
  74. /***********************************************************************************************
  75. * HLodSaveClass -- The constructor builds the whole HLOD tree in a form suitable for saving *
  76. * to a W3D file. *
  77. * *
  78. * INPUT: *
  79. * *
  80. * OUTPUT: *
  81. * *
  82. * WARNINGS: *
  83. * *
  84. * HISTORY: *
  85. * 9/14/1999 AJA : Created. *
  86. *=============================================================================================*/
  87. HLodSaveClass::HLodSaveClass (MeshConnectionsClass **connections, int lod_count, TimeValue CurTime,
  88. char *name, const char *htree_name, Progress_Meter_Class &meter,
  89. INodeListClass *origin_list)
  90. : lod_array(NULL)
  91. {
  92. /*
  93. ** Fill in the W3dHLodHeaderStruct
  94. */
  95. header.Version = W3D_CURRENT_HLOD_VERSION;
  96. header.LodCount = lod_count;
  97. Set_W3D_Name(header.Name, name);
  98. Set_W3D_Name(header.HierarchyName, htree_name);
  99. ExportLog::printf("\nExporting HLOD object: %s\n",header.Name);
  100. ExportLog::printf(" lod count: %d\n",header.LodCount);
  101. /*
  102. ** Create the array of stuff for each LOD.
  103. */
  104. lod_array = new HLodArrayEntry[lod_count];
  105. if (!lod_array)
  106. throw ErrorClass("Out Of Memory!");
  107. int i;
  108. for (i = 0; i < lod_count; i++)
  109. {
  110. ExportLog::printf(" Exporting LOD Array %d\n",i);
  111. INode *origin = connections[i]->Get_Origin();
  112. int sub_obj_count = connections[i]->Get_Sub_Object_Count();
  113. lod_array[i].Allocate_Sub_Objects(sub_obj_count);
  114. lod_array[i].header.ModelCount = sub_obj_count;
  115. float screen_size = NO_MAX_SCREEN_SIZE;
  116. if (origin)
  117. origin->GetUserPropFloat("MaxScreenSize", screen_size);
  118. lod_array[i].header.MaxScreenSize = screen_size;
  119. /*
  120. ** Create the info per mesh in this LOD.
  121. */
  122. int j;
  123. W3dHLodSubObjectStruct *sub_obj = lod_array[i].sub_obj;
  124. ExportLog::printf(" sub-object count: %d\n",sub_obj_count);
  125. for (j = 0; j < sub_obj_count; j++)
  126. {
  127. char *mesh_name;
  128. int bone_index;
  129. INode *mesh_node;
  130. if (!connections[i]->Get_Sub_Object_Data(j, &mesh_name, &bone_index, &mesh_node))
  131. throw ErrorClass("Model %s is missing connection data!", name);
  132. strcpy(sub_obj[j].Name, mesh_name);
  133. sub_obj[j].BoneIndex = bone_index;
  134. ExportLog::printf(" Sub Object: %s Bone: %d\n",mesh_name,bone_index);
  135. }
  136. }
  137. /*
  138. ** Copy aggregates from the Top-Level LOD
  139. */
  140. int agg_count = connections[lod_count-1]->Get_Aggregate_Count();
  141. aggregate_array.Allocate_Sub_Objects(agg_count);
  142. aggregate_array.header.ModelCount = agg_count;
  143. aggregate_array.header.MaxScreenSize = 0.0f;
  144. ExportLog::printf(" Exporting Aggregates:\n");
  145. ExportLog::printf(" aggregate count: %d\n",agg_count);
  146. for (i=0; i<agg_count; i++) {
  147. char *mesh_name;
  148. int bone_index;
  149. INode *mesh_node;
  150. connections[lod_count-1]->Get_Aggregate_Data(i, &mesh_name, &bone_index, &mesh_node);
  151. W3dHLodSubObjectStruct & sub_obj = aggregate_array.sub_obj[i];
  152. strcpy(sub_obj.Name, mesh_name);
  153. sub_obj.BoneIndex = bone_index;
  154. ExportLog::printf(" Aggregate object: %s Bone: %d\n",mesh_name,bone_index);
  155. }
  156. /*
  157. ** Copy the proxy objects from the Top-Level LOD
  158. */
  159. int proxy_count = connections[lod_count-1]->Get_Proxy_Count();
  160. proxy_array.Allocate_Sub_Objects(proxy_count);
  161. proxy_array.header.ModelCount = proxy_count;
  162. proxy_array.header.MaxScreenSize = 0.0f;
  163. ExportLog::printf(" Exporting Proxies\n");
  164. ExportLog::printf(" proxy count: %d\n",proxy_count);
  165. for (i=0; i<proxy_count; i++) {
  166. char *mesh_name;
  167. int bone_index;
  168. INode *mesh_node;
  169. connections[lod_count-1]->Get_Proxy_Data(i, &mesh_name, &bone_index, &mesh_node);
  170. W3dHLodSubObjectStruct & sub_obj = proxy_array.sub_obj[i];
  171. strcpy(sub_obj.Name, mesh_name);
  172. sub_obj.BoneIndex = bone_index;
  173. ExportLog::printf(" Proxy object: %s Bone: %d\n",mesh_name,bone_index);
  174. }
  175. }
  176. /***********************************************************************************************
  177. * ~HLodSaveClass -- Destructor blows away the dynamic memory we used. *
  178. * *
  179. * INPUT: *
  180. * *
  181. * OUTPUT: *
  182. * *
  183. * WARNINGS: *
  184. * *
  185. * HISTORY: *
  186. * 9/14/1999 AJA : Created. *
  187. *=============================================================================================*/
  188. HLodSaveClass::~HLodSaveClass (void)
  189. {
  190. if (lod_array)
  191. {
  192. delete []lod_array;
  193. lod_array = NULL;
  194. }
  195. }
  196. /***********************************************************************************************
  197. * HLodSaveClass::Save -- Method called when saving to a W3D file. Saves the chunks that *
  198. * define a HLOD. *
  199. * *
  200. * INPUT: *
  201. * *
  202. * OUTPUT: *
  203. * *
  204. * WARNINGS: *
  205. * *
  206. * HISTORY: *
  207. * 9/14/1999 AJA : Created. *
  208. *=============================================================================================*/
  209. bool HLodSaveClass::Save(ChunkSaveClass &csave)
  210. {
  211. if (!lod_array)
  212. return false;
  213. if (!csave.Begin_Chunk(W3D_CHUNK_HLOD))
  214. return false;
  215. if (!save_header(csave))
  216. return false;
  217. if (!save_lod_arrays(csave))
  218. return false;
  219. if (!save_aggregate_array(csave))
  220. return false;
  221. if (!save_proxy_array(csave))
  222. return false;
  223. if (!csave.End_Chunk())
  224. return false;
  225. return true;
  226. }
  227. /***********************************************************************************************
  228. * HLodSaveClass::save_header -- Write the header *
  229. * *
  230. * INPUT: *
  231. * *
  232. * OUTPUT: *
  233. * *
  234. * WARNINGS: *
  235. * *
  236. * HISTORY: *
  237. * 9/14/1999 AJA : Created. *
  238. *=============================================================================================*/
  239. bool HLodSaveClass::save_header (ChunkSaveClass &csave)
  240. {
  241. if (!csave.Begin_Chunk(W3D_CHUNK_HLOD_HEADER))
  242. return false;
  243. if (csave.Write(&header, sizeof(header)) != sizeof(header))
  244. return false;
  245. if (!csave.End_Chunk())
  246. return false;
  247. return true;
  248. }
  249. /***********************************************************************************************
  250. * HLodSaveClass::save_lod_arrays -- Writes each LOD *
  251. * *
  252. * INPUT: *
  253. * *
  254. * OUTPUT: *
  255. * *
  256. * WARNINGS: *
  257. * *
  258. * HISTORY: *
  259. * 9/14/1999 AJA : Created. *
  260. *=============================================================================================*/
  261. bool HLodSaveClass::save_lod_arrays(ChunkSaveClass &csave)
  262. {
  263. for (int i = 0; i < header.LodCount; i++)
  264. {
  265. if (!csave.Begin_Chunk(W3D_CHUNK_HLOD_LOD_ARRAY))
  266. return false;
  267. if (!save_sub_object_array(csave, lod_array[i]))
  268. return false;
  269. if (!csave.End_Chunk())
  270. return false;
  271. }
  272. return true;
  273. }
  274. /***********************************************************************************************
  275. * HLodSaveClass::save_aggregate_array -- save the aggregates (if any) *
  276. * *
  277. * INPUT: *
  278. * *
  279. * OUTPUT: *
  280. * *
  281. * WARNINGS: *
  282. * *
  283. * HISTORY: *
  284. * 10/25/2000 gth : Created. *
  285. *=============================================================================================*/
  286. bool HLodSaveClass::save_aggregate_array(ChunkSaveClass & csave)
  287. {
  288. if (aggregate_array.num_sub_objects > 0) {
  289. if (!csave.Begin_Chunk(W3D_CHUNK_HLOD_AGGREGATE_ARRAY))
  290. return false;
  291. if (!save_sub_object_array(csave, aggregate_array))
  292. return false;
  293. if (!csave.End_Chunk())
  294. return false;
  295. }
  296. return true;
  297. }
  298. /***********************************************************************************************
  299. * HLodSaveClass::save_proxy_array -- save the array of proxies (if any) *
  300. * *
  301. * INPUT: *
  302. * *
  303. * OUTPUT: *
  304. * *
  305. * WARNINGS: *
  306. * *
  307. * HISTORY: *
  308. * 10/27/2000 gth : Created. *
  309. *=============================================================================================*/
  310. bool HLodSaveClass::save_proxy_array(ChunkSaveClass & csave)
  311. {
  312. if (proxy_array.num_sub_objects > 0) {
  313. if (!csave.Begin_Chunk(W3D_CHUNK_HLOD_PROXY_ARRAY))
  314. return false;
  315. if (!save_sub_object_array(csave, proxy_array))
  316. return false;
  317. if (!csave.End_Chunk())
  318. return false;
  319. }
  320. return true;
  321. }
  322. /***********************************************************************************************
  323. * HLodSaveClass::save_sub_object_array -- Writes the mesh to bone connectivity info for each *
  324. * mesh in an LOD. *
  325. * *
  326. * INPUT: *
  327. * *
  328. * OUTPUT: *
  329. * *
  330. * WARNINGS: *
  331. * *
  332. * HISTORY: *
  333. * 9/14/1999 AJA : Created. *
  334. *=============================================================================================*/
  335. bool HLodSaveClass::save_sub_object_array(ChunkSaveClass &csave, const HLodArrayEntry & array)
  336. {
  337. if (!csave.Begin_Chunk(W3D_CHUNK_HLOD_SUB_OBJECT_ARRAY_HEADER))
  338. return false;
  339. if (csave.Write(&(array.header), sizeof(array.header)) != sizeof(array.header))
  340. return false;
  341. if (!csave.End_Chunk())
  342. return false;
  343. for (int j = 0; j < array.num_sub_objects; j++)
  344. {
  345. if (!csave.Begin_Chunk(W3D_CHUNK_HLOD_SUB_OBJECT))
  346. return false;
  347. if (csave.Write(&(array.sub_obj[j]), sizeof(array.sub_obj[j])) != sizeof(array.sub_obj[j]))
  348. return false;
  349. if (!csave.End_Chunk())
  350. return false;
  351. }
  352. return true;
  353. }