meshsave.cpp 72 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039
  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. /* $Header: /Commando/Code/Tools/max2w3d/meshsave.cpp 109 3/14/02 4:19p Greg_h $ */
  19. /***********************************************************************************************
  20. *** Confidential - Westwood Studios ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Commando / G *
  24. * *
  25. * File Name : MESHSAVE.CPP *
  26. * *
  27. * Programmer : Greg Hjelstrom *
  28. * *
  29. * Start Date : 06/10/97 *
  30. * *
  31. * Last Update : 10/20/1999997 [GH] *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * MeshSaveClass::MeshSaveClass -- constructor, processes a Max mesh *
  36. * MeshSaveClass::~MeshSaveClass -- destructor, frees all allocated memory *
  37. * MeshSaveClass::write_verts -- write the vertex chunk into a wtm file *
  38. * MeshSaveClass::write_header -- write a mesh header chunk into a wtm file *
  39. * MeshSaveClass::Write_To_File -- Append the mesh to an open wtm file *
  40. * MeshSaveClass::write_normals -- writes the vertex normals chunk into a wtm file *
  41. * MeshSaveClass::write_vert_normals -- Writes the surrender normal chunk into a wtm file *
  42. * MeshSaveClass::write_triangles -- Write the triangles chunk into a wtm file. *
  43. * MeshSaveClass::write_sr_triangles -- writes the triangles in surrender friendly format *
  44. * MeshSaveClass::write_triangles -- write the triangles chunk *
  45. * MeshSaveClass::compute_surrender_vertex -- Compute the surrender vertex normals *
  46. * MeshSaveClass::setup_material -- Gets the texture names and base colors for a material *
  47. * MeshSaveClass::compute_bounding_volumes -- computes a bounding box and bounding sphere for*
  48. * MeshSaveClass::set_transform -- set the default transformation matrix for the mesh *
  49. * MeshSaveClass::compute_physical_properties -- computes the volume and moment of inertia *
  50. * MeshSaveClass::prep_mesh -- pre-transform the MAX mesh by a specified matrix *
  51. * MeshSaveClass::write_user_text -- write the user text chunk *
  52. * MeshSaveClass::get_htree_bone_index_for_inode -- searches the htree for the given INode *
  53. * MeshSaveClass::get_skin_modifier_objects -- Searches for the WWSkin modifier for this mes *
  54. * MeshSaveClass::inv_deform_mesh -- preprocess the mesh for skinning *
  55. * MeshSaveClass::create_materials -- create the materials for this mesh *
  56. * MeshSaveClass::write_ps2_shaders -- Write shaders specific to the PS2 in their own chunk. *
  57. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  58. #include "meshsave.h"
  59. #include <Max.h>
  60. #include <stdmat.h>
  61. #include <modstack.h>
  62. #include "gamemtl.h"
  63. #include "errclass.h"
  64. #include "vxl.h"
  65. #include "vxldbg.h"
  66. #include "nodelist.h"
  67. #include "hiersave.h"
  68. #include "util.h"
  69. #include "w3dappdata.h"
  70. #include "skin.h"
  71. #include "skindata.h"
  72. #include "meshbuild.h"
  73. #include "alphamodifier.h"
  74. #include "aabtreebuilder.h"
  75. #include "exportlog.h"
  76. static char _string1[512];
  77. const int VOXEL_RESOLUTION = 64; // resolution to use when computing I, V and CM
  78. #define DEBUG_VOXELS 0
  79. #define MIN_AABTREE_POLYGONS 8
  80. /************************************************************************************
  81. **
  82. ** check if this is a mesh which should use a simple rendering method. I don't
  83. ** compute vertex normals or store u-v's in that case (prevents vertex splitting)
  84. **
  85. ************************************************************************************/
  86. bool use_simple_rendering(int geo_type)
  87. {
  88. geo_type &= W3D_MESH_FLAG_GEOMETRY_TYPE_MASK;
  89. if ( (geo_type == OBSOLETE_W3D_MESH_FLAG_GEOMETRY_TYPE_SHADOW) ||
  90. (geo_type == W3D_MESH_FLAG_GEOMETRY_TYPE_AABOX) ||
  91. (geo_type == W3D_MESH_FLAG_GEOMETRY_TYPE_OBBOX) )
  92. {
  93. return true;
  94. } else {
  95. return false;
  96. }
  97. }
  98. /************************************************************************************
  99. **
  100. ** build the bitfield of W3D mesh attributes for the given node
  101. **
  102. ************************************************************************************/
  103. uint32 setup_mesh_attributes(INode * node)
  104. {
  105. uint32 attributes = W3D_MESH_FLAG_NONE;
  106. /*
  107. ** Mesh will be one of:
  108. ** W3D_MESH_FLAG_NONE,
  109. ** W3D_MESH_FLAG_COLLISION_BOX,
  110. ** W3D_MESH_FLAG_SKIN,
  111. ** W3D_MESH_FLAG_ALIGNED
  112. ** W3D_MESH_FLAG_ORIENTED
  113. */
  114. if (Is_Collision_AABox(node)) {
  115. attributes = W3D_MESH_FLAG_GEOMETRY_TYPE_AABOX;
  116. } else if (Is_Collision_OBBox(node)) {
  117. attributes = W3D_MESH_FLAG_GEOMETRY_TYPE_OBBOX;
  118. } else if (Is_Skin(node)) {
  119. attributes = W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN;
  120. } else if (Is_Camera_Aligned_Mesh(node)) {
  121. attributes = W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ALIGNED;
  122. } else if (Is_Camera_Oriented_Mesh(node)) {
  123. attributes = W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ORIENTED;
  124. }
  125. /*
  126. ** And, a mesh may have one or more types of collision detection enabled.
  127. ** W3D_MESH_FLAG_COLLISION_TYPE_PHYSICAL
  128. ** W3D_MESH_FLAG_COLLISION_TYPE_PROJECTILE
  129. ** However, if the mesh is SKIN, SHADOW, ALIGNED, ORIENTED or NULL, don't let
  130. ** the collision bits get set...
  131. */
  132. if ( attributes != W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN &&
  133. attributes != W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ALIGNED &&
  134. attributes != W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ORIENTED )
  135. {
  136. if (Is_Physical_Collision(node)) {
  137. attributes |= W3D_MESH_FLAG_COLLISION_TYPE_PHYSICAL;
  138. }
  139. if (Is_Projectile_Collision(node)) {
  140. attributes |= W3D_MESH_FLAG_COLLISION_TYPE_PROJECTILE;
  141. }
  142. if (Is_Vis_Collision(node)) {
  143. attributes |= W3D_MESH_FLAG_COLLISION_TYPE_VIS;
  144. }
  145. if (Is_Camera_Collision(node)) {
  146. attributes |= W3D_MESH_FLAG_COLLISION_TYPE_CAMERA;
  147. }
  148. if (Is_Vehicle_Collision(node)) {
  149. attributes |= W3D_MESH_FLAG_COLLISION_TYPE_VEHICLE;
  150. }
  151. }
  152. /*
  153. ** A mesh may have one of the following bits set as well
  154. */
  155. if (Is_Hidden(node)) {
  156. attributes |= W3D_MESH_FLAG_HIDDEN;
  157. }
  158. if (Is_Two_Sided(node)) {
  159. attributes |= W3D_MESH_FLAG_TWO_SIDED;
  160. }
  161. if (Is_Shadow(node)) {
  162. attributes |= W3D_MESH_FLAG_CAST_SHADOW;
  163. }
  164. if (Is_Shatterable(node)) {
  165. attributes |= W3D_MESH_FLAG_SHATTERABLE;
  166. }
  167. if (Is_NPatchable(node)) {
  168. attributes |= W3D_MESH_FLAG_NPATCHABLE;
  169. }
  170. return attributes;
  171. }
  172. /***********************************************************************************************
  173. * MeshSaveClass::MeshSaveClass -- constructor, processes a Max mesh *
  174. * *
  175. * This class takes a MAX mesh and computes the information for a W3D mesh or skin. *
  176. * *
  177. * INPUT: *
  178. * *
  179. * inode - the max INode containing the mesh/skin to export *
  180. * exportspace - matrix defining the desired coordinate system for the mesh *
  181. * htree - hierarchy tree that this mesh is being connected to *
  182. * curtime - current time in Max. *
  183. * meter - progress meter *
  184. * mesh_name - name to use for the mesh *
  185. * container_name - name of the container *
  186. * *
  187. * OUTPUT: *
  188. * *
  189. * WARNINGS: *
  190. * *
  191. * HISTORY: *
  192. * 06/10/1997 GH : Created. *
  193. *=============================================================================================*/
  194. MeshSaveClass::MeshSaveClass
  195. (
  196. char * mesh_name,
  197. char * container_name,
  198. INode * inode,
  199. const Mesh * input_mesh,
  200. Matrix3 & exportspace,
  201. W3DAppData2Struct & exportoptions,
  202. HierarchySaveClass * htree,
  203. TimeValue curtime,
  204. Progress_Meter_Class & meter,
  205. WorldInfoClass * world_info
  206. ) :
  207. MaxINode(inode),
  208. ExportOptions(exportoptions),
  209. CurTime(curtime),
  210. ExportSpace(exportspace),
  211. HTree(htree),
  212. UserText(NULL),
  213. VertInfluences(NULL),
  214. MaterialRemapTable(NULL)
  215. {
  216. Mesh mesh = *input_mesh; // copy the mesh so we can modify it
  217. Mtl * nodemtl = inode->GetMtl();
  218. DWORD wirecolor = inode->GetWireColor();
  219. PS2Material = FALSE;
  220. // Check to see if the mesh uses PS2 game materials. If so, set a flag so
  221. // that write_shaders will know to make a PS2 shader chunk.
  222. if (nodemtl) {
  223. if (nodemtl->ClassID() == PS2GameMaterialClassID) {
  224. PS2Material = TRUE;
  225. } else if (nodemtl->IsMultiMtl()) {
  226. for (int i = 0; i < nodemtl->NumSubMtls(); i++) {
  227. Mtl *sub = nodemtl->GetSubMtl(i);
  228. if (sub->ClassID() == PS2GameMaterialClassID) {
  229. PS2Material = TRUE;
  230. }
  231. }
  232. }
  233. }
  234. //////////////////////////////////////////////////////////////////////
  235. // Check if the mesh is being inverted by its transform. If this
  236. // is the case, then we will need to reverse the winding of all
  237. // polygons later.
  238. //////////////////////////////////////////////////////////////////////
  239. Matrix3 objtm = MaxINode->GetObjectTM(curtime);
  240. MeshInverted = (Compute_3x3_Determinant(objtm) < 0.0f);
  241. //////////////////////////////////////////////////////////////////////
  242. // Prep the mesh by transforming it by the delta between exportspace
  243. // and this INodes current space
  244. // (this is the delta between the bone and the mesh if one exists...)
  245. //////////////////////////////////////////////////////////////////////
  246. MeshToExportSpace = objtm * Inverse(ExportSpace);
  247. prep_mesh(mesh,MeshToExportSpace);
  248. //////////////////////////////////////////////////////////////////////
  249. // Prepare the mesh header.
  250. //////////////////////////////////////////////////////////////////////
  251. assert(mesh_name != NULL);
  252. assert(container_name != NULL);
  253. memset(&Header,0,sizeof(Header));
  254. Set_W3D_Name(Header.MeshName,mesh_name);
  255. Set_W3D_Name(Header.ContainerName,container_name);
  256. Header.Version = W3D_CURRENT_MESH_VERSION;
  257. Header.Attributes = setup_mesh_attributes(MaxINode);
  258. meter.Finish_In_Steps(
  259. 3*Header.NumTris + // normals
  260. Header.NumVertices + // surrender normals
  261. 64 // voxelization
  262. );
  263. ExportLog::printf("\nProcessing Mesh: %s\n",Header.MeshName);
  264. //////////////////////////////////////////////////////////////////////
  265. // Enforce that we have enough data to actually make a mesh
  266. //////////////////////////////////////////////////////////////////////
  267. if (mesh.getNumFaces() <= 0) {
  268. throw ErrorClass("No Triangles in Mesh: %s",Header.MeshName);
  269. }
  270. if (mesh.getNumVerts() <= 0) {
  271. throw ErrorClass("No Vertices in Mesh: %s",Header.MeshName);
  272. }
  273. //////////////////////////////////////////////////////////////////////
  274. // process the materials
  275. //////////////////////////////////////////////////////////////////////
  276. DebugPrint("processing materials\n");
  277. scan_used_materials(mesh,nodemtl);
  278. create_materials(nodemtl,wirecolor);
  279. //////////////////////////////////////////////////////////////////////
  280. // what face and vertex attributes are we going to export?
  281. //////////////////////////////////////////////////////////////////////
  282. Header.FaceChannels = W3D_FACE_CHANNEL_FACE;
  283. Header.VertexChannels = W3D_VERTEX_CHANNEL_LOCATION;
  284. if (!use_simple_rendering(Header.Attributes)) {
  285. Header.VertexChannels |= W3D_VERTEX_CHANNEL_NORMAL;
  286. }
  287. if (((Header.Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK) == W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN) && (HTree != NULL)) {
  288. Header.VertexChannels |= W3D_VERTEX_CHANNEL_BONEID;
  289. }
  290. //////////////////////////////////////////////////////////////////////
  291. // Process the mesh
  292. //////////////////////////////////////////////////////////////////////
  293. Builder.Set_World_Info (world_info);
  294. Build_Mesh(mesh, nodemtl);
  295. //////////////////////////////////////////////////////////////////////
  296. // Determine if the deformer should use alpha or v-color info
  297. //////////////////////////////////////////////////////////////////////
  298. if (ExportOptions.Is_Vertex_Alpha_Enabled()) {
  299. unsigned int alpha_passes = 0;
  300. for (int pass=0; pass < MaterialDesc.Pass_Count(); pass++) {
  301. if (MaterialDesc.Pass_Uses_Vertex_Alpha(pass)) {
  302. alpha_passes |= (1 << pass);
  303. }
  304. }
  305. }
  306. //////////////////////////////////////////////////////////////////////
  307. // Set the counts in the mesh header
  308. //////////////////////////////////////////////////////////////////////
  309. Header.NumTris = Builder.Get_Face_Count();
  310. Header.NumVertices = Builder.Get_Vertex_Count();
  311. //////////////////////////////////////////////////////////////////////
  312. // Compute the mesh's bounding box and sphere. This must be done
  313. // before we pre-deform the mesh (if its a skin).
  314. //////////////////////////////////////////////////////////////////////
  315. compute_bounding_volumes();
  316. //////////////////////////////////////////////////////////////////////
  317. // Voxelize the mesh and compute the Moment of Inertia and
  318. // Center of Mass. This must come after we compute the bounding
  319. // volumes and before we pre-deform the mesh.
  320. //////////////////////////////////////////////////////////////////////
  321. Progress_Meter_Class voxelmeter(meter, 64.0f * meter.Increment);
  322. compute_physical_constants(MaxINode,voxelmeter,false /*usevoxelizer*/);
  323. //////////////////////////////////////////////////////////////////////
  324. // If this is a skin, pre-deform the mesh.
  325. //////////////////////////////////////////////////////////////////////
  326. if (((Header.Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK) == W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN) && (HTree != NULL)) {
  327. inv_deform_mesh();
  328. }
  329. //////////////////////////////////////////////////////////////////////
  330. // Get the user text from MAX's properties window.
  331. //////////////////////////////////////////////////////////////////////
  332. TSTR usertext;
  333. MaxINode->GetUserPropBuffer(usertext);
  334. CStr usertext8 = usertext;
  335. if (usertext8.Length() > 0) {
  336. UserText = new char[usertext8.Length() + 1];
  337. memset(UserText,0,usertext8.Length() + 1);
  338. memcpy(UserText,usertext8.data(),usertext8.Length());
  339. }
  340. }
  341. /***********************************************************************************************
  342. * MeshSaveClass::~MeshSaveClass -- destructor, frees all allocated memory *
  343. * *
  344. * INPUT: *
  345. * *
  346. * OUTPUT: *
  347. * *
  348. * WARNINGS: *
  349. * *
  350. * HISTORY: *
  351. * 06/10/1997 GH : Created. *
  352. *=============================================================================================*/
  353. MeshSaveClass::~MeshSaveClass(void)
  354. {
  355. if (UserText) {
  356. delete[] UserText;
  357. UserText = NULL;
  358. }
  359. if (VertInfluences) {
  360. delete[] VertInfluences;
  361. VertInfluences = NULL;
  362. }
  363. if (MaterialRemapTable) {
  364. delete[] MaterialRemapTable;
  365. MaterialRemapTable = NULL;
  366. }
  367. }
  368. void MeshSaveClass::Build_Mesh(Mesh & mesh, Mtl *node_mtl)
  369. {
  370. int vert_counter;
  371. int face_index;
  372. int pass;
  373. int stage;
  374. float *vdata = NULL;
  375. Builder.Reset(true,mesh.getNumFaces(),mesh.getNumFaces()/3);
  376. // Get a pointer to the channel that has alpha values entered by the artist.
  377. // This pointer will be NULL if they didn't use the channel.
  378. vdata = mesh.vertexFloat(ALPHA_VERTEX_CHANNEL);
  379. /*
  380. ** Get the skin info
  381. */
  382. bool is_skin = false;
  383. SkinDataClass * skindata = NULL;
  384. SkinWSMObjectClass * skinobj = NULL;
  385. get_skin_modifier_objects(&skindata,&skinobj);
  386. if ( ((Header.Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK) == W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN) &&
  387. (HTree != NULL) )
  388. {
  389. is_skin = ((skindata != NULL) && (skinobj != NULL));
  390. }
  391. /*
  392. ** Submit all of the faces
  393. */
  394. MeshBuilderClass::FaceClass face;
  395. for (face_index = 0; face_index < mesh.getNumFaces(); face_index++) {
  396. Face maxface = mesh.faces[face_index];
  397. int mat_index = 0;
  398. if (Header.NumMaterials > 0) {
  399. mat_index = MaterialRemapTable[(maxface.getMatID() % Header.NumMaterials)];
  400. }
  401. assert(mat_index != -1);
  402. for (pass=0; pass<MaterialDesc.Pass_Count(); pass++) {
  403. face.ShaderIndex[pass] = MaterialDesc.Get_Shader_Index(mat_index,pass);
  404. for (stage=0; stage<W3dMaterialClass::MAX_STAGES; stage++) {
  405. face.TextureIndex[pass][stage] = MaterialDesc.Get_Texture_Index(mat_index,pass,stage);
  406. }
  407. }
  408. int geo_type = Header.Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK;
  409. if ( use_simple_rendering(geo_type) ) {
  410. face.SmGroup = 0xFFFFFFFF;
  411. } else {
  412. face.SmGroup = maxface.getSmGroup();
  413. }
  414. face.Index = face_index;
  415. face.Attributes = 0;
  416. face.SurfaceType = 0;
  417. /*
  418. ** Lookup this face's surface type
  419. */
  420. Mtl *mtl_to_use = node_mtl;
  421. if ((node_mtl != NULL) && (node_mtl->NumSubMtls() > 1)) {
  422. mtl_to_use = node_mtl->GetSubMtl (maxface.getMatID() % node_mtl->NumSubMtls());
  423. }
  424. if ((mtl_to_use != NULL) && ((mtl_to_use->ClassID() == GameMaterialClassID) ||
  425. (mtl_to_use->ClassID() == PS2GameMaterialClassID))) {
  426. face.SurfaceType = ((GameMtl *)mtl_to_use)->Get_Surface_Type ();
  427. }
  428. for (vert_counter = 0; vert_counter < 3; vert_counter++) {
  429. /*
  430. ** if this mesh is being inverted, we need to insert the verts in
  431. ** the opposite order. max_vert_counter will count backwards
  432. ** in this case; causing all vertex data to be entered in the
  433. ** reverse winding.
  434. */
  435. int max_vert_counter;
  436. if (MeshInverted) {
  437. max_vert_counter = 2 - vert_counter;
  438. } else {
  439. max_vert_counter = vert_counter;
  440. }
  441. int max_vert_index = maxface.v[max_vert_counter];
  442. /*
  443. ** Vertex Id, to prevent unwanted welding!
  444. */
  445. face.Verts[vert_counter].Id = max_vert_index;
  446. /*
  447. ** Vertex Position
  448. */
  449. face.Verts[vert_counter].Position.X = mesh.verts[max_vert_index].x;
  450. face.Verts[vert_counter].Position.Y = mesh.verts[max_vert_index].y;
  451. face.Verts[vert_counter].Position.Z = mesh.verts[max_vert_index].z;
  452. if (vdata) {
  453. // If an alpha channel has been created, use its value.
  454. for (int pass=0; pass < MaterialDesc.Pass_Count(); pass++) {
  455. if (MaterialDesc.Pass_Uses_Vertex_Alpha(pass)) {
  456. // Mulitiply by .01 to change from percentage.
  457. face.Verts[vert_counter].Alpha[pass] = vdata[max_vert_index] * .01;
  458. }
  459. }
  460. }
  461. /*
  462. ** Texture coordinate. Apply uv coords if the mesh has them and is not being
  463. ** instructed to ignore them.
  464. ** - check if the mesh needs them (uses_simple_rendering() == false)
  465. ** - for each pass and stage, look up what map channel this face's material is using
  466. ** - ask Max for the tfaces and tverts for that map channel
  467. ** - copy the values into each vertex
  468. */
  469. for (pass=0; pass<MaterialDesc.Pass_Count(); pass++) {
  470. for (stage=0; stage<W3dMaterialClass::MAX_STAGES; stage++) {
  471. /*
  472. ** Start with a 0,0 uv coordinate
  473. */
  474. UVVert tvert(0.0,0.0,0.0);
  475. /*
  476. ** If the mesh needs uv coords and they are present, copy the uv into tvert
  477. */
  478. if (!use_simple_rendering(Header.Attributes)) {
  479. int channel = MaterialDesc.Get_Map_Channel(mat_index,pass,stage);
  480. UVVert * uvarray = mesh.mapVerts(channel);
  481. TVFace * tvfacearray = mesh.mapFaces(channel);
  482. if ((uvarray != NULL) && (tvfacearray != NULL)) {
  483. int tvert_index = tvfacearray[face_index].t[max_vert_counter];
  484. tvert = uvarray[tvert_index];
  485. }
  486. }
  487. /*
  488. ** Copy the texture coordinate into the vertex structure
  489. */
  490. face.Verts[vert_counter].TexCoord[pass][stage].X = tvert.x;
  491. face.Verts[vert_counter].TexCoord[pass][stage].Y = tvert.y;
  492. }
  493. }
  494. /*
  495. ** Vertex Color
  496. */
  497. if (mesh.vcFace) {
  498. /*
  499. ** If the mesh is being mirrored, remap the index
  500. */
  501. int max_cvert_index = mesh.vcFace[face_index].t[max_vert_counter];
  502. VertColor vc;
  503. vc = mesh.vertCol[max_cvert_index];
  504. /*
  505. ** If Vertex Alpha is specified, the vertex color is converted
  506. ** to alpha. If the (obsolete) Node-flag for vertex alpha is enabled,
  507. ** the alpha is put into each pass which has alpha enabled. Otherwise,
  508. ** we check the material settings for which passes should get the alpha
  509. ** values. If neither alpha options are enabled, we put the color
  510. ** value into the first pass.
  511. */
  512. if (ExportOptions.Is_Vertex_Alpha_Enabled()) {
  513. float alpha = (vc.x + vc.y + vc.z) / 3.0f;
  514. for (int pass=0; pass < MaterialDesc.Pass_Count(); pass++) {
  515. if (MaterialDesc.Pass_Uses_Vertex_Alpha(pass)) {
  516. face.Verts[vert_counter].Alpha[pass] = alpha;
  517. }
  518. }
  519. } else {
  520. face.Verts[vert_counter].DiffuseColor[0].X = vc.x;
  521. face.Verts[vert_counter].DiffuseColor[0].Y = vc.y;
  522. face.Verts[vert_counter].DiffuseColor[0].Z = vc.z;
  523. }
  524. face.Verts[vert_counter].MaxVertColIndex = max_cvert_index;
  525. } else {
  526. face.Verts[vert_counter].MaxVertColIndex = 0;
  527. }
  528. /*
  529. ** Vertex materials
  530. */
  531. for (pass = 0; pass<MaterialDesc.Pass_Count(); pass++) {
  532. face.Verts[vert_counter].VertexMaterialIndex[pass] = MaterialDesc.Get_Vertex_Material_Index(mat_index,pass);
  533. }
  534. face.Verts[vert_counter].Attribute0 = max_vert_index;
  535. face.Verts[vert_counter].Attribute1 = face_index;
  536. /*
  537. ** Skin attachment
  538. */
  539. face.Verts[vert_counter].BoneIndex = 0;
  540. if (is_skin) {
  541. int skin_bone_index = skindata->VertData[max_vert_index].BoneIdx[0];
  542. // If this is a valid bone, try to find the corresponding bone index in the HTree
  543. if ( (skin_bone_index != -1) &&
  544. (skin_bone_index < skinobj->Num_Bones()) &&
  545. (skinobj->BoneTab[skin_bone_index] != NULL) )
  546. {
  547. face.Verts[vert_counter].BoneIndex = get_htree_bone_index_for_inode(skinobj->BoneTab[skin_bone_index]);
  548. }
  549. }
  550. }
  551. Builder.Add_Face(face);
  552. }
  553. /*
  554. ** Process the mesh
  555. */
  556. Builder.Build_Mesh(true);
  557. const MeshBuilderClass::MeshStatsStruct & stats = Builder.Get_Mesh_Stats();
  558. int vcount = Builder.Get_Vertex_Count();
  559. int pcount = mesh.numFaces;
  560. float vert_poly_ratio = (float)vcount / (float)pcount;
  561. ExportLog::printf(" triangle count: %d\n",pcount);
  562. ExportLog::printf(" final vertex count: %d\n",vcount);
  563. ExportLog::printf(" vertex/triangle ratio: %f\n",vert_poly_ratio);
  564. ExportLog::printf(" strip count: %d\n",stats.StripCount);
  565. ExportLog::printf(" average strip length: %f\n",stats.AvgStripLength);
  566. ExportLog::printf(" longest strip: %d\n",stats.MaxStripLength);
  567. }
  568. /***********************************************************************************************
  569. * MeshSaveClass::get_skin_modifier_objects -- Searches for the WWSkin modifier for this mesh *
  570. * *
  571. * INPUT: *
  572. * *
  573. * OUTPUT: *
  574. * *
  575. * WARNINGS: *
  576. * *
  577. * HISTORY: *
  578. *=============================================================================================*/
  579. void MeshSaveClass::get_skin_modifier_objects(SkinDataClass ** skin_data_ptr,SkinWSMObjectClass ** skin_obj_ptr)
  580. {
  581. *skin_data_ptr = NULL;
  582. *skin_obj_ptr = NULL;
  583. // loop through the references that our node has
  584. for (int i = 0; i < MaxINode->NumRefs(); i++) {
  585. ReferenceTarget *refTarg = MaxINode->GetReference(i);
  586. // if the reference is a WSM Derived Object.
  587. if (refTarg != NULL && refTarg->ClassID() == Class_ID(WSM_DERIVOB_CLASS_ID,0)) {
  588. IDerivedObject * wsm_der_obj = (IDerivedObject *)refTarg;
  589. // loop through the WSM's attached to this WSM Derived object
  590. for (int j = 0; j < wsm_der_obj->NumModifiers(); j++) {
  591. Modifier * mod = wsm_der_obj->GetModifier(j);
  592. if (mod->ClassID() == SKIN_MOD_CLASS_ID) {
  593. // This is our modifier! Get the data from it!
  594. SkinModifierClass * skinmod = (SkinModifierClass *)mod;
  595. ModContext * mc = wsm_der_obj->GetModContext(j);
  596. *skin_data_ptr = (SkinDataClass *)(mc->localData);
  597. *skin_obj_ptr = (SkinWSMObjectClass *)skinmod->GetReference(SkinModifierClass::OBJ_REF);
  598. }
  599. }
  600. }
  601. }
  602. }
  603. /***********************************************************************************************
  604. * MeshSaveClass::get_htree_bone_index_for_inode -- searches the htree for the given INode *
  605. * *
  606. * INPUT: *
  607. * *
  608. * OUTPUT: *
  609. * *
  610. * WARNINGS: *
  611. * *
  612. * HISTORY: *
  613. * 5/1/2000 gth : Created. *
  614. *=============================================================================================*/
  615. int MeshSaveClass::get_htree_bone_index_for_inode(INode * node)
  616. {
  617. // index of this INode in the hierarchy tree (it better be there :-)
  618. char w3dname[W3D_NAME_LEN];
  619. Set_W3D_Name(w3dname,node->GetName());
  620. int bindex = HTree->Find_Named_Node(w3dname);
  621. // If the desired bone isn't being exported, export the point
  622. // relative to the root.
  623. if (bindex == -1) {
  624. bindex = 0;
  625. }
  626. return bindex;
  627. }
  628. /***********************************************************************************************
  629. * MeshSaveClass::inv_deform_mesh -- preprocess the mesh for skinning *
  630. * *
  631. * INPUT: *
  632. * *
  633. * OUTPUT: *
  634. * *
  635. * WARNINGS: *
  636. * *
  637. * HISTORY: *
  638. * 10/26/1997 GH : Created. *
  639. * 5/1/2000 gth : Created. *
  640. *=============================================================================================*/
  641. void MeshSaveClass::inv_deform_mesh()
  642. {
  643. // Got the skinning info, now pre-deform each vertex and
  644. // create an array of vertex influence indexes.
  645. VertInfluences = new W3dVertInfStruct[Builder.Get_Vertex_Count()];
  646. memset(VertInfluences,0,sizeof(W3dVertInfStruct) * Builder.Get_Vertex_Count());
  647. Header.VertexChannels |= W3D_VERTEX_CHANNEL_BONEID;
  648. for (int vert_index = 0; vert_index < Builder.Get_Vertex_Count(); vert_index++) {
  649. MeshBuilderClass::VertClass & vert = Builder.Get_Vertex(vert_index);
  650. if (vert.BoneIndex == 0) {
  651. // set the influence to 0 (root node) and leave the vert and normal unchanged
  652. // (gth) 07/11/2000: Note that in this case, the mesh coordinates have already been
  653. // transformed relative to the user or scene origin and do not need to be further modified.
  654. VertInfluences[vert_index].BoneIdx = 0;
  655. } else {
  656. // here we go! get the matrix from the hierarchy tree and transform
  657. // the point into the bone's coordinate system.
  658. // (gth) 07/11/2000: The origin_offset_tm is no longer needed because
  659. // skin meshes are transformed into the origin coordinate system before
  660. // we get to this code.
  661. Matrix3 bonetm = HTree->Get_Node_Transform(vert.BoneIndex);
  662. Matrix3 invbonetm = Inverse(bonetm);
  663. Point3 pos;
  664. pos.x = vert.Position.X;
  665. pos.y = vert.Position.Y;
  666. pos.z = vert.Position.Z;
  667. pos = pos * invbonetm;
  668. vert.Position.X = pos.x;
  669. vert.Position.Y = pos.y;
  670. vert.Position.Z = pos.z;
  671. // Now, transform the normal into the bone's coordinate system.
  672. invbonetm.NoTrans();
  673. Point3 norm;
  674. norm.x = vert.Normal.X;
  675. norm.y = vert.Normal.Y;
  676. norm.z = vert.Normal.Z;
  677. norm = norm * invbonetm;
  678. vert.Normal.X = norm.x;
  679. vert.Normal.Y = norm.y;
  680. vert.Normal.Z = norm.z;
  681. VertInfluences[vert_index].BoneIdx = vert.BoneIndex;
  682. }
  683. }
  684. }
  685. /***********************************************************************************************
  686. * MeshSaveClass::Write_To_File -- Append the mesh to an open wtm file *
  687. * *
  688. * INPUT: *
  689. * csave - ChunkSaveClass object to handle writing the chunk-based file *
  690. * export_aabtree - should we generate an aabtree for this mesh *
  691. * *
  692. * OUTPUT: *
  693. * 0 if nothing went wrong, Non-Zero otherwise *
  694. * *
  695. * WARNINGS: *
  696. * *
  697. * *
  698. * HISTORY: *
  699. * 06/10/1997 GH : Created. *
  700. *=============================================================================================*/
  701. int MeshSaveClass::Write_To_File(ChunkSaveClass & csave,bool export_aabtree)
  702. {
  703. if (!csave.Begin_Chunk(W3D_CHUNK_MESH)) {
  704. return 1;
  705. }
  706. if (write_header(csave) != 0) {
  707. return 1;
  708. }
  709. if (write_user_text(csave) != 0) {
  710. return 1;
  711. }
  712. if (write_verts(csave) != 0) {
  713. return 1;
  714. }
  715. if (write_vert_normals(csave) != 0) {
  716. return 1;
  717. }
  718. if (write_triangles(csave) != 0) {
  719. return 1;
  720. }
  721. if (write_vert_influences(csave) != 0) {
  722. return 1;
  723. }
  724. if (write_vert_shade_indices(csave) != 0) {
  725. return 1;
  726. }
  727. if (write_material_info(csave) != 0) {
  728. return 1;
  729. }
  730. if (write_vertex_materials(csave) != 0) {
  731. return 1;
  732. }
  733. if (PS2Material == TRUE) {
  734. // The ps2 shaders must be written out first.
  735. if (write_ps2_shaders(csave) != 0) {
  736. return 1;
  737. }
  738. }
  739. if (write_shaders(csave) != 0) {
  740. return 1;
  741. }
  742. if (write_textures(csave) != 0) {
  743. return 1;
  744. }
  745. for (int pass=0; pass<MaterialDesc.Pass_Count(); pass++) {
  746. if (write_pass(csave,pass) != 0) {
  747. return 1;
  748. }
  749. }
  750. if (export_aabtree == true) {
  751. if (write_aabtree(csave) != 0) {
  752. return 1;
  753. }
  754. }
  755. if (!csave.End_Chunk()) {
  756. return 1;
  757. }
  758. return 0;
  759. }
  760. /***********************************************************************************************
  761. * MeshSaveClass::write_header -- write a mesh header chunk into a wtm file *
  762. * *
  763. * INPUT: *
  764. * csave - chunk save object *
  765. * *
  766. * OUTPUT: *
  767. * 0 if nothing went wrong, Non-Zero otherwise *
  768. * *
  769. * WARNINGS: *
  770. * *
  771. * HISTORY: *
  772. * 06/10/1997 GH : Created. *
  773. *=============================================================================================*/
  774. int MeshSaveClass::write_header(ChunkSaveClass & csave)
  775. {
  776. if (!csave.Begin_Chunk(W3D_CHUNK_MESH_HEADER3)) {
  777. return 1;
  778. }
  779. if (csave.Write(&Header,sizeof(W3dMeshHeader3Struct)) != sizeof(W3dMeshHeader3Struct)) {
  780. return 1;
  781. }
  782. if (!csave.End_Chunk()) {
  783. return 1;
  784. }
  785. return 0;
  786. }
  787. /***********************************************************************************************
  788. * MeshSaveClass::write_user_text -- write the user text chunk *
  789. * *
  790. * INPUT: *
  791. * *
  792. * OUTPUT: *
  793. * *
  794. * WARNINGS: *
  795. * *
  796. * HISTORY: *
  797. * 08/20/1997 GH : Created. *
  798. *=============================================================================================*/
  799. int MeshSaveClass::write_user_text(ChunkSaveClass & csave)
  800. {
  801. // If there's no user text, just don't write the chunk
  802. if (UserText == NULL) {
  803. return 0;
  804. }
  805. if (!csave.Begin_Chunk(W3D_CHUNK_MESH_USER_TEXT)) {
  806. return 1;
  807. }
  808. // write the user text buffer (writing one extra byte to include the NULL)
  809. if (csave.Write(UserText,strlen(UserText) + 1) != strlen(UserText) + 1) {
  810. return 1;
  811. }
  812. if (!csave.End_Chunk()) {
  813. return 1;
  814. }
  815. return 0;
  816. }
  817. /***********************************************************************************************
  818. * MeshSaveClass::write_verts -- write the vertex chunk into a wtm file *
  819. * *
  820. * INPUT: *
  821. * csave - chunk save object *
  822. * *
  823. * OUTPUT: *
  824. * 0 if nothing went wrong, Non-Zero otherwise *
  825. * *
  826. * WARNINGS: *
  827. * *
  828. * HISTORY: *
  829. * 06/10/1997 GH : Created. *
  830. *=============================================================================================*/
  831. int MeshSaveClass::write_verts(ChunkSaveClass & csave)
  832. {
  833. if (!csave.Begin_Chunk(W3D_CHUNK_VERTICES)) {
  834. return 1;
  835. }
  836. assert(Builder.Get_Vertex_Count() > 0);
  837. assert(Builder.Get_Vertex_Count() == (int)Header.NumVertices);
  838. for (int i=0; i<Builder.Get_Vertex_Count(); i++) {
  839. const MeshBuilderClass::VertClass & vert = Builder.Get_Vertex(i);
  840. if ((Header.Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK) != W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN) {
  841. assert(vert.Position.X <= Header.Max.X);
  842. assert(vert.Position.Y <= Header.Max.Y);
  843. assert(vert.Position.Z <= Header.Max.Z);
  844. assert(vert.Position.X >= Header.Min.X);
  845. assert(vert.Position.Y >= Header.Min.Y);
  846. assert(vert.Position.Z >= Header.Min.Z);
  847. }
  848. W3dVectorStruct w3dvert;
  849. w3dvert.X = vert.Position.X;
  850. w3dvert.Y = vert.Position.Y;
  851. w3dvert.Z = vert.Position.Z;
  852. if (csave.Write(&(w3dvert),sizeof(W3dVectorStruct)) != sizeof(W3dVectorStruct)) {
  853. return 1;
  854. }
  855. }
  856. if (!csave.End_Chunk()) {
  857. return 1;
  858. }
  859. return 0;
  860. }
  861. /***********************************************************************************************
  862. * MeshSaveClass::write_vert_normals -- Writes the surrender normal chunk into a wtm file *
  863. * *
  864. * INPUT: *
  865. * csave - chunk save object *
  866. * *
  867. * OUTPUT: *
  868. * 0 if nothing went wrong, Non-Zero otherwise *
  869. * *
  870. * WARNINGS: *
  871. * *
  872. * HISTORY: *
  873. * 06/10/1997 GH : Created. *
  874. *=============================================================================================*/
  875. int MeshSaveClass::write_vert_normals(ChunkSaveClass & csave)
  876. {
  877. if (!(Header.VertexChannels & W3D_VERTEX_CHANNEL_NORMAL)) return 0;
  878. if (!csave.Begin_Chunk(W3D_CHUNK_VERTEX_NORMALS)) {
  879. return 1;
  880. }
  881. for (int i=0; i < Builder.Get_Vertex_Count(); i++) {
  882. const MeshBuilderClass::VertClass & vert = Builder.Get_Vertex(i);
  883. W3dVectorStruct norm;
  884. if (ExportOptions.Is_ZNormals_Enabled()) {
  885. norm.X = 0.0f;
  886. norm.Y = 0.0f;
  887. norm.Z = 1.0f;
  888. } else {
  889. norm.X = vert.Normal.X;
  890. norm.Y = vert.Normal.Y;
  891. norm.Z = vert.Normal.Z;
  892. }
  893. if (csave.Write(&(norm),sizeof(W3dVectorStruct)) != sizeof(W3dVectorStruct)) {
  894. return 1;
  895. }
  896. }
  897. if (!csave.End_Chunk()) {
  898. return 1;
  899. }
  900. return 0;
  901. }
  902. /***********************************************************************************************
  903. * MeshSaveClass::write_vert_influences -- skins will have this chunk that binds verts to bones*
  904. * *
  905. * INPUT: *
  906. * csave - chunk save object *
  907. * *
  908. * OUTPUT: *
  909. * 0 if nothing went wrong, Non-Zero otherwise *
  910. * *
  911. * WARNINGS: *
  912. * *
  913. * HISTORY: *
  914. * 06/10/1997 GH : Created. *
  915. *=============================================================================================*/
  916. int MeshSaveClass::write_vert_influences(ChunkSaveClass & csave)
  917. {
  918. if (((Header.Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK) != W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN) ||
  919. !(Header.VertexChannels & W3D_VERTEX_CHANNEL_BONEID) ||
  920. (VertInfluences == NULL)) {
  921. return 0;
  922. }
  923. if (!csave.Begin_Chunk(W3D_CHUNK_VERTEX_INFLUENCES)) {
  924. return 1;
  925. }
  926. int count = Builder.Get_Vertex_Count();
  927. if (csave.Write(VertInfluences,count * sizeof(W3dVertInfStruct)) != count * sizeof(W3dVertInfStruct)) {
  928. return 1;
  929. }
  930. if (!csave.End_Chunk()) {
  931. return 1;
  932. }
  933. return 0;
  934. }
  935. /***********************************************************************************************
  936. * MeshSaveClass::write_triangles -- write the triangles chunk *
  937. * *
  938. * INPUT: *
  939. * *
  940. * OUTPUT: *
  941. * *
  942. * WARNINGS: *
  943. * *
  944. * HISTORY: *
  945. * 4/7/98 GTH : Created. *
  946. *=============================================================================================*/
  947. int MeshSaveClass::write_triangles(ChunkSaveClass & csave)
  948. {
  949. if (!csave.Begin_Chunk(W3D_CHUNK_TRIANGLES)) {
  950. return 1;
  951. }
  952. assert(Builder.Get_Face_Count() == (int)Header.NumTris);
  953. for (int i=0; i<Builder.Get_Face_Count(); i++) {
  954. const MeshBuilderClass::FaceClass & face = Builder.Get_Face(i);
  955. W3dTriStruct tri;
  956. memset(&tri,0,sizeof(W3dTriStruct));
  957. // convert each triangle into surrender format
  958. tri.Vindex[0] = face.VertIdx[0];
  959. tri.Vindex[1] = face.VertIdx[1];
  960. tri.Vindex[2] = face.VertIdx[2];
  961. tri.Attributes = face.SurfaceType;
  962. tri.Normal.X = face.Normal.X;
  963. tri.Normal.Y = face.Normal.Y;
  964. tri.Normal.Z = face.Normal.Z;
  965. tri.Dist = face.Dist;
  966. // write each triangle
  967. if (csave.Write(&tri,sizeof(W3dTriStruct)) != sizeof(W3dTriStruct)) {
  968. return 1;
  969. }
  970. }
  971. if (!csave.End_Chunk()) {
  972. return 1;
  973. }
  974. return 0;
  975. }
  976. int MeshSaveClass::write_vert_shade_indices(ChunkSaveClass & csave)
  977. {
  978. if (!(Header.VertexChannels & W3D_VERTEX_CHANNEL_NORMAL)) return 0;
  979. if (!csave.Begin_Chunk(W3D_CHUNK_VERTEX_SHADE_INDICES)) {
  980. return 1;
  981. }
  982. for (int i=0; i < Builder.Get_Vertex_Count(); i++) {
  983. const MeshBuilderClass::VertClass & vert = Builder.Get_Vertex(i);
  984. uint32 shade_index = vert.ShadeIndex;
  985. if (csave.Write(&(shade_index),sizeof(shade_index)) != sizeof(shade_index)) {
  986. return 1;
  987. }
  988. }
  989. if (!csave.End_Chunk()) {
  990. return 1;
  991. }
  992. return 0;
  993. }
  994. int MeshSaveClass::write_material_info(ChunkSaveClass & csave)
  995. {
  996. if (!csave.Begin_Chunk(W3D_CHUNK_MATERIAL_INFO)) {
  997. return 1;
  998. }
  999. W3dMaterialInfoStruct matinfo;
  1000. matinfo.PassCount = MaterialDesc.Pass_Count();
  1001. matinfo.VertexMaterialCount = MaterialDesc.Vertex_Material_Count();
  1002. matinfo.ShaderCount = MaterialDesc.Shader_Count();
  1003. matinfo.TextureCount = MaterialDesc.Texture_Count();
  1004. if (csave.Write(&matinfo,sizeof(matinfo)) != sizeof(matinfo)) {
  1005. return 1;
  1006. }
  1007. if (!csave.End_Chunk()) {
  1008. return 1;
  1009. }
  1010. return 0;
  1011. }
  1012. int MeshSaveClass::write_vertex_materials(ChunkSaveClass & csave)
  1013. {
  1014. if (MaterialDesc.Vertex_Material_Count() <= 0) return 0;
  1015. // open a chunk which wraps all of the vertex materials
  1016. if (!csave.Begin_Chunk(W3D_CHUNK_VERTEX_MATERIALS)) {
  1017. return 1;
  1018. }
  1019. for (int i=0; i<MaterialDesc.Vertex_Material_Count(); i++) {
  1020. csave.Begin_Chunk(W3D_CHUNK_VERTEX_MATERIAL);
  1021. // write the filename
  1022. const char * name = MaterialDesc.Get_Vertex_Material_Name(i);
  1023. if (name != NULL) {
  1024. csave.Begin_Chunk(W3D_CHUNK_VERTEX_MATERIAL_NAME);
  1025. if (csave.Write(name,strlen(name) + 1) != strlen(name) + 1) {
  1026. return 1;
  1027. }
  1028. csave.End_Chunk();
  1029. }
  1030. // write the struct
  1031. W3dVertexMaterialStruct * vmat = MaterialDesc.Get_Vertex_Material(i);
  1032. csave.Begin_Chunk(W3D_CHUNK_VERTEX_MATERIAL_INFO);
  1033. if (csave.Write(vmat,sizeof(W3dVertexMaterialStruct)) != sizeof(W3dVertexMaterialStruct)) {
  1034. return 1;
  1035. }
  1036. csave.End_Chunk();
  1037. // write the mapper args
  1038. const char * args = MaterialDesc.Get_Mapper_Args(i, 0);
  1039. if (args != NULL) {
  1040. csave.Begin_Chunk(W3D_CHUNK_VERTEX_MAPPER_ARGS0);
  1041. if (csave.Write(args,strlen(args) + 1) != strlen(args) + 1) {
  1042. return 1;
  1043. }
  1044. csave.End_Chunk();
  1045. }
  1046. args = MaterialDesc.Get_Mapper_Args(i, 1);
  1047. if (args != NULL) {
  1048. csave.Begin_Chunk(W3D_CHUNK_VERTEX_MAPPER_ARGS1);
  1049. if (csave.Write(args,strlen(args) + 1) != strlen(args) + 1) {
  1050. return 1;
  1051. }
  1052. csave.End_Chunk();
  1053. }
  1054. csave.End_Chunk();
  1055. }
  1056. if (!csave.End_Chunk()) {
  1057. return 1;
  1058. }
  1059. return 0;
  1060. }
  1061. int MeshSaveClass::write_shaders(ChunkSaveClass & csave)
  1062. {
  1063. assert(MaterialDesc.Shader_Count() > 0);
  1064. if (PS2Material == TRUE) {
  1065. // Make the PC shader as close to the PS2 shader as possible.
  1066. // This will allow for viewing in W3D View.
  1067. setup_PC_shaders_from_PS2_shaders();
  1068. }
  1069. if (!csave.Begin_Chunk(W3D_CHUNK_SHADERS)) {
  1070. return 1;
  1071. }
  1072. W3dShaderStruct * shader;
  1073. for (int i=0; i<MaterialDesc.Shader_Count(); i++) {
  1074. shader = MaterialDesc.Get_Shader(i);
  1075. if (csave.Write(shader,sizeof(W3dShaderStruct)) != sizeof(W3dShaderStruct)) {
  1076. return 1;
  1077. }
  1078. }
  1079. if (!csave.End_Chunk()) {
  1080. return 1;
  1081. }
  1082. return 0;
  1083. }
  1084. /***********************************************************************************************
  1085. * MeshSaveClass::write_ps2_shaders -- Write shaders specific to the PS2 in their own chunk. *
  1086. * *
  1087. * *
  1088. * *
  1089. * *
  1090. * HISTORY: *
  1091. * 10/20/1999MLL: Created. *
  1092. *=============================================================================================*/
  1093. int MeshSaveClass::write_ps2_shaders(ChunkSaveClass & csave)
  1094. {
  1095. if (!csave.Begin_Chunk(W3D_CHUNK_PS2_SHADERS)) {
  1096. return 1;
  1097. }
  1098. W3dShaderStruct *shader;
  1099. W3dPS2ShaderStruct ps2shader;
  1100. for (int i=0; i<MaterialDesc.Shader_Count(); i++) {
  1101. shader = MaterialDesc.Get_Shader(i);
  1102. ps2shader.AlphaTest = W3d_Shader_Get_Alpha_Test(shader);
  1103. ps2shader.AParam = W3d_Shader_Get_PS2_Param_A(shader);
  1104. ps2shader.BParam = W3d_Shader_Get_PS2_Param_B(shader);
  1105. ps2shader.CParam = W3d_Shader_Get_PS2_Param_C(shader);
  1106. ps2shader.DParam = W3d_Shader_Get_PS2_Param_D(shader);
  1107. // Write out the PS2 native form.
  1108. switch (W3d_Shader_Get_Depth_Compare(shader))
  1109. {
  1110. case PSS_DEPTHCOMPARE_PASS_NEVER:
  1111. ps2shader.DepthCompare = 0;
  1112. break;
  1113. case PSS_DEPTHCOMPARE_PASS_LESS:
  1114. ps2shader.DepthCompare = 3;
  1115. break;
  1116. case PSS_DEPTHCOMPARE_PASS_ALWAYS:
  1117. ps2shader.DepthCompare = 1;
  1118. break;
  1119. case PSS_DEPTHCOMPARE_PASS_LEQUAL:
  1120. ps2shader.DepthCompare = 2;
  1121. break;
  1122. }
  1123. ps2shader.DepthMask = !W3d_Shader_Get_Depth_Mask(shader);
  1124. switch (W3d_Shader_Get_Pri_Gradient(shader))
  1125. {
  1126. case PSS_PRIGRADIENT_MODULATE:
  1127. ps2shader.PriGradient = PSS_PS2_PRIGRADIENT_MODULATE;
  1128. break;
  1129. case PSS_PRIGRADIENT_HIGHLIGHT:
  1130. ps2shader.PriGradient = PSS_PS2_PRIGRADIENT_HIGHLIGHT;
  1131. break;
  1132. case PSS_PRIGRADIENT_HIGHLIGHT2:
  1133. ps2shader.PriGradient = PSS_PS2_PRIGRADIENT_HIGHLIGHT2;
  1134. break;
  1135. case PSS_PRIGRADIENT_DECAL:
  1136. ps2shader.PriGradient = PSS_PS2_PRIGRADIENT_DECAL;
  1137. break;
  1138. }
  1139. ps2shader.Texturing = W3d_Shader_Get_Texturing(shader);
  1140. if (csave.Write(&ps2shader,sizeof(W3dPS2ShaderStruct)) != sizeof(W3dPS2ShaderStruct)) {
  1141. return 1;
  1142. }
  1143. }
  1144. if (!csave.End_Chunk()) {
  1145. return 1;
  1146. }
  1147. return (0);
  1148. }
  1149. void MeshSaveClass::setup_PC_shaders_from_PS2_shaders()
  1150. {
  1151. W3dShaderStruct *shader;
  1152. for (int i=0; i<MaterialDesc.Shader_Count(); i++) {
  1153. shader = MaterialDesc.Get_Shader(i);
  1154. // DepthCompare on the PS2 doesn't have as many options as on the PC.
  1155. switch (W3d_Shader_Get_Depth_Compare(shader))
  1156. {
  1157. case PSS_DEPTHCOMPARE_PASS_NEVER:
  1158. W3d_Shader_Set_Depth_Compare(shader, W3DSHADER_DEPTHCOMPARE_PASS_NEVER);
  1159. break;
  1160. case PSS_DEPTHCOMPARE_PASS_LESS:
  1161. W3d_Shader_Set_Depth_Compare(shader, W3DSHADER_DEPTHCOMPARE_PASS_LESS);
  1162. break;
  1163. case PSS_DEPTHCOMPARE_PASS_LEQUAL:
  1164. W3d_Shader_Set_Depth_Compare(shader, W3DSHADER_DEPTHCOMPARE_PASS_LEQUAL);
  1165. break;
  1166. case PSS_DEPTHCOMPARE_PASS_ALWAYS:
  1167. W3d_Shader_Set_Depth_Compare(shader, W3DSHADER_DEPTHCOMPARE_PASS_ALWAYS);
  1168. break;
  1169. }
  1170. // The PS2 has more gradient functions than the PC.
  1171. switch (W3d_Shader_Get_Pri_Gradient(shader))
  1172. {
  1173. case PSS_PRIGRADIENT_MODULATE:
  1174. W3d_Shader_Set_Pri_Gradient(shader, W3DSHADER_PRIGRADIENT_MODULATE);
  1175. break;
  1176. // No PC equivalent. Set to default: modulate.
  1177. case PSS_PRIGRADIENT_HIGHLIGHT:
  1178. case PSS_PRIGRADIENT_HIGHLIGHT2:
  1179. case PSS_PRIGRADIENT_DECAL:
  1180. W3d_Shader_Set_Pri_Gradient(shader, W3DSHADER_PRIGRADIENT_MODULATE);
  1181. break;
  1182. }
  1183. }
  1184. }
  1185. int MeshSaveClass::write_textures(ChunkSaveClass & csave)
  1186. {
  1187. if (MaterialDesc.Texture_Count() <= 0) return 0;
  1188. // open a chunk which wraps all textures
  1189. if (!csave.Begin_Chunk(W3D_CHUNK_TEXTURES)) {
  1190. return 1;
  1191. }
  1192. for (int i=0; i<MaterialDesc.Texture_Count(); i++) {
  1193. W3dMapClass * map = MaterialDesc.Get_Texture(i);
  1194. csave.Begin_Chunk(W3D_CHUNK_TEXTURE);
  1195. // write the filename
  1196. csave.Begin_Chunk(W3D_CHUNK_TEXTURE_NAME);
  1197. if (csave.Write(map->Filename,strlen(map->Filename) + 1) != strlen(map->Filename) + 1) return 1;
  1198. csave.End_Chunk();
  1199. // optionally write an animation info chunk
  1200. if (map->AnimInfo != NULL) {
  1201. csave.Begin_Chunk(W3D_CHUNK_TEXTURE_INFO);
  1202. if (csave.Write(map->AnimInfo,sizeof(W3dTextureInfoStruct)) != sizeof(W3dTextureInfoStruct)) return 1;
  1203. csave.End_Chunk();
  1204. }
  1205. csave.End_Chunk();
  1206. }
  1207. if (!csave.End_Chunk()) {
  1208. return 1;
  1209. }
  1210. return 0;
  1211. }
  1212. int MeshSaveClass::write_pass(ChunkSaveClass & csave,int pass)
  1213. {
  1214. assert(pass >= 0);
  1215. assert(pass < MaterialDesc.Pass_Count());
  1216. if (!csave.Begin_Chunk(W3D_CHUNK_MATERIAL_PASS)) {
  1217. return 1;
  1218. }
  1219. const MeshBuilderClass::MeshStatsStruct & stats = Builder.Get_Mesh_Stats();
  1220. if (stats.HasVertexMaterial[pass]) {
  1221. write_vertex_material_ids(csave,pass);
  1222. }
  1223. if (stats.HasShader[pass]) {
  1224. write_shader_ids(csave,pass);
  1225. }
  1226. if (stats.HasDiffuseColor[pass]) {
  1227. write_dcg(csave,pass);
  1228. }
  1229. for (int stage = 0; stage < MeshBuilderClass::MAX_STAGES; stage++) {
  1230. write_texture_stage(csave,pass,stage);
  1231. }
  1232. if (!csave.End_Chunk()) {
  1233. return 1;
  1234. }
  1235. return 0;
  1236. }
  1237. int MeshSaveClass::write_vertex_material_ids(ChunkSaveClass & csave,int pass)
  1238. {
  1239. const MeshBuilderClass::MeshStatsStruct & stats = Builder.Get_Mesh_Stats();
  1240. if (!csave.Begin_Chunk(W3D_CHUNK_VERTEX_MATERIAL_IDS)) {
  1241. return 1;
  1242. }
  1243. uint32 matid;
  1244. if (stats.HasPerVertexMaterial[pass]) {
  1245. for (int i=0; i<Builder.Get_Vertex_Count(); i++) {
  1246. matid = Builder.Get_Vertex(i).VertexMaterialIndex[pass];
  1247. if (csave.Write(&matid,sizeof(uint32)) != sizeof(uint32)) return 1;
  1248. }
  1249. } else {
  1250. matid = Builder.Get_Vertex(0).VertexMaterialIndex[pass];
  1251. if (csave.Write(&matid,sizeof(uint32)) != sizeof(uint32)) return 1;
  1252. }
  1253. if (!csave.End_Chunk()) {
  1254. return 1;
  1255. }
  1256. return 0;
  1257. }
  1258. int MeshSaveClass::write_shader_ids(ChunkSaveClass & csave,int pass)
  1259. {
  1260. const MeshBuilderClass::MeshStatsStruct & stats = Builder.Get_Mesh_Stats();
  1261. if (!csave.Begin_Chunk(W3D_CHUNK_SHADER_IDS)) {
  1262. return 1;
  1263. }
  1264. uint32 shaderid;
  1265. if (stats.HasPerPolyShader[pass]) {
  1266. for (int i=0; i<Builder.Get_Face_Count(); i++) {
  1267. shaderid = Builder.Get_Face(i).ShaderIndex[pass];
  1268. if (csave.Write(&shaderid,sizeof(uint32)) != sizeof(uint32)) return 1;
  1269. }
  1270. } else {
  1271. shaderid = Builder.Get_Face(0).ShaderIndex[pass];
  1272. if (csave.Write(&shaderid,sizeof(uint32)) != sizeof(uint32)) return 1;
  1273. }
  1274. if (!csave.End_Chunk()) {
  1275. return 1;
  1276. }
  1277. return 0;
  1278. }
  1279. int MeshSaveClass::write_dcg(ChunkSaveClass & csave,int pass)
  1280. {
  1281. const MeshBuilderClass::MeshStatsStruct & stats = Builder.Get_Mesh_Stats();
  1282. if (!csave.Begin_Chunk(W3D_CHUNK_DCG)) {
  1283. return 1;
  1284. }
  1285. for (int i=0; i<Builder.Get_Vertex_Count(); i++) {
  1286. Vector3 vcolor = Builder.Get_Vertex(i).DiffuseColor[pass];
  1287. W3dRGBAStruct color;
  1288. color.R = (uint8)(255.0f * vcolor.X);
  1289. color.G = (uint8)(255.0f * vcolor.Y);
  1290. color.B = (uint8)(255.0f * vcolor.Z);
  1291. float a = Builder.Get_Vertex(i).Alpha[pass];
  1292. color.A = (uint8)(255.0f * a);
  1293. if (csave.Write(&(color),sizeof(W3dRGBAStruct)) != sizeof(W3dRGBAStruct)) {
  1294. return 1;
  1295. }
  1296. }
  1297. if (!csave.End_Chunk()) {
  1298. return 1;
  1299. }
  1300. return 0;
  1301. }
  1302. int MeshSaveClass::write_texture_stage(ChunkSaveClass & csave,int pass,int stage)
  1303. {
  1304. const MeshBuilderClass::MeshStatsStruct & stats = Builder.Get_Mesh_Stats();
  1305. if (!stats.HasTexture[pass][stage]) return 0;
  1306. if (!csave.Begin_Chunk(W3D_CHUNK_TEXTURE_STAGE)) {
  1307. return 1;
  1308. }
  1309. write_texture_ids(csave,pass,stage);
  1310. write_texture_coords(csave,pass,stage);
  1311. if (!csave.End_Chunk()) {
  1312. return 1;
  1313. }
  1314. return 0;
  1315. }
  1316. int MeshSaveClass::write_texture_ids(ChunkSaveClass & csave,int pass,int stage)
  1317. {
  1318. const MeshBuilderClass::MeshStatsStruct & stats = Builder.Get_Mesh_Stats();
  1319. if (!csave.Begin_Chunk(W3D_CHUNK_TEXTURE_IDS)) {
  1320. return 1;
  1321. }
  1322. uint32 texid;
  1323. if (stats.HasPerPolyTexture[pass][stage]) {
  1324. for (int i=0; i<Builder.Get_Face_Count(); i++) {
  1325. texid = Builder.Get_Face(i).TextureIndex[pass][stage];
  1326. if (csave.Write(&texid,sizeof(uint32)) != sizeof(uint32)) return 1;
  1327. }
  1328. } else {
  1329. texid = Builder.Get_Face(0).TextureIndex[pass][stage];
  1330. if (csave.Write(&texid,sizeof(uint32)) != sizeof(uint32)) return 1;
  1331. }
  1332. if (!csave.End_Chunk()) {
  1333. return 1;
  1334. }
  1335. return 0;
  1336. }
  1337. int MeshSaveClass::write_texture_coords(ChunkSaveClass & csave,int pass,int stage)
  1338. {
  1339. const MeshBuilderClass::MeshStatsStruct & stats = Builder.Get_Mesh_Stats();
  1340. if (stats.HasTexCoords[pass][stage] == false) return 0;
  1341. if (!csave.Begin_Chunk(W3D_CHUNK_STAGE_TEXCOORDS)) {
  1342. return 1;
  1343. }
  1344. for (int i=0; i<Builder.Get_Vertex_Count(); i++) {
  1345. W3dTexCoordStruct tex;
  1346. tex.U = Builder.Get_Vertex(i).TexCoord[pass][stage].X;
  1347. tex.V = Builder.Get_Vertex(i).TexCoord[pass][stage].Y;
  1348. if (csave.Write(&(tex),sizeof(W3dTexCoordStruct)) != sizeof(W3dTexCoordStruct)) {
  1349. return 1;
  1350. }
  1351. }
  1352. if (!csave.End_Chunk()) {
  1353. return 1;
  1354. }
  1355. return 0;
  1356. }
  1357. int MeshSaveClass::write_aabtree(ChunkSaveClass & csave)
  1358. {
  1359. /*
  1360. ** Don't bother with an AABTree if this not a normal mesh or if it has very few polygons
  1361. */
  1362. if ( (Builder.Get_Face_Count() >= MIN_AABTREE_POLYGONS) &&
  1363. ((Header.Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK) == W3D_MESH_FLAG_GEOMETRY_TYPE_NORMAL)
  1364. )
  1365. {
  1366. /*
  1367. ** Build temporary array representations of the mesh
  1368. */
  1369. int vertcount = Builder.Get_Vertex_Count();
  1370. int polycount = Builder.Get_Face_Count();
  1371. Vector3 * verts = new Vector3[vertcount];
  1372. Vector3i * polys = new Vector3i[polycount];
  1373. for (int vi=0; vi<vertcount; vi++) {
  1374. verts[vi] = Builder.Get_Vertex(vi).Position;
  1375. }
  1376. for (int pi=0; pi<polycount; pi++) {
  1377. polys[pi].I = Builder.Get_Face(pi).VertIdx[0];
  1378. polys[pi].J = Builder.Get_Face(pi).VertIdx[1];
  1379. polys[pi].K = Builder.Get_Face(pi).VertIdx[2];
  1380. }
  1381. /*
  1382. ** Build the AABTree and save it
  1383. */
  1384. AABTreeBuilderClass aabtree_builder;
  1385. aabtree_builder.Build_AABTree(polycount,polys,vertcount,verts);
  1386. aabtree_builder.Export(csave);
  1387. /*
  1388. ** Release the allocated resources
  1389. */
  1390. delete[] verts;
  1391. delete[] polys;
  1392. }
  1393. return 0;
  1394. }
  1395. int MeshSaveClass::scan_used_materials(Mesh & mesh,Mtl * nodemtl)
  1396. {
  1397. int face_index;
  1398. int mat_index;
  1399. if ((nodemtl == NULL) || (nodemtl->NumSubMtls() <= 1)) {
  1400. MaterialRemapTable = new int[1];
  1401. MaterialRemapTable[0] = 0;
  1402. return 1;
  1403. } else {
  1404. int sub_mtl_count = nodemtl->NumSubMtls();
  1405. MaterialRemapTable = new int[sub_mtl_count];
  1406. // Initialize each remap to -1 (indicates that the material is un-used)
  1407. for (mat_index=0; mat_index<sub_mtl_count; mat_index++) {
  1408. MaterialRemapTable[mat_index] = -1;
  1409. }
  1410. // Set a 1 for each material actually referenced by the mesh
  1411. for (face_index=0; face_index<mesh.getNumFaces(); face_index++) {
  1412. int max_mat_index = mesh.faces[face_index].getMatID();
  1413. int mat_index = (max_mat_index % sub_mtl_count);
  1414. MaterialRemapTable[mat_index] = 1;
  1415. }
  1416. // Replace each 1 entry with an incrementing material index
  1417. int matcount = 0;
  1418. for (mat_index=0; mat_index<sub_mtl_count; mat_index++) {
  1419. if (MaterialRemapTable[mat_index] == 1) {
  1420. MaterialRemapTable[mat_index] = matcount;
  1421. matcount++;
  1422. }
  1423. }
  1424. assert(matcount > 0);
  1425. return matcount;
  1426. }
  1427. }
  1428. /***********************************************************************************************
  1429. * MeshSaveClass::create_materials -- create the materials for this mesh *
  1430. * *
  1431. * INPUT: *
  1432. * *
  1433. * OUTPUT: *
  1434. * *
  1435. * WARNINGS: *
  1436. * *
  1437. * HISTORY: *
  1438. * 10/26/1997 GH : Created. *
  1439. * 2/8/99 GTH : modified to use the MaterialRemapTable *
  1440. *=============================================================================================*/
  1441. void MeshSaveClass::create_materials(Mtl * nodemtl,DWORD wirecolor)
  1442. {
  1443. bool domaps = !use_simple_rendering(Header.Attributes);
  1444. //////////////////////////////////////////////////////////////////////
  1445. // Create materials
  1446. // Four cases:
  1447. // - Creating a collision object: use a hard-coded material
  1448. // - The material is null: use wire color
  1449. // - The material is a simple material: create one material
  1450. // - The material is a multi-material: create n materials
  1451. //////////////////////////////////////////////////////////////////////
  1452. int geo_type = Header.Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK;
  1453. if ((geo_type == W3D_MESH_FLAG_GEOMETRY_TYPE_AABOX) ||
  1454. (geo_type == W3D_MESH_FLAG_GEOMETRY_TYPE_OBBOX))
  1455. {
  1456. Header.NumMaterials = 1;
  1457. W3dVertexMaterialStruct vmat;
  1458. W3dShaderStruct shader;
  1459. W3dMaterialClass material;
  1460. Color diffuse;
  1461. if (Header.Attributes & W3D_MESH_FLAG_COLLISION_TYPE_PHYSICAL) {
  1462. diffuse.r = 0.0f;
  1463. diffuse.g = 0.0f;
  1464. diffuse.b = 1.0f;
  1465. } else {
  1466. diffuse.r = 0.4f;
  1467. diffuse.g = 1.0f;
  1468. diffuse.b = 0.4f;
  1469. }
  1470. W3d_Shader_Reset(&shader);
  1471. W3d_Shader_Set_Dest_Blend_Func(&shader,W3DSHADER_DESTBLENDFUNC_ONE_MINUS_SRC_ALPHA);
  1472. W3d_Shader_Set_Src_Blend_Func(&shader,W3DSHADER_SRCBLENDFUNC_SRC_ALPHA);
  1473. W3d_Vertex_Material_Reset(&vmat);
  1474. vmat.Opacity = 0.5f;
  1475. // add material 0
  1476. vmat.Diffuse.R = (uint8)(diffuse.r * 255.0f);
  1477. vmat.Diffuse.G = (uint8)(diffuse.g * 255.0f);
  1478. vmat.Diffuse.B = (uint8)(diffuse.b * 255.0f);
  1479. material.Set_Pass_Count(1);
  1480. material.Set_Vertex_Material(vmat,0);
  1481. material.Set_Shader(shader,0);
  1482. MaterialDesc.Add_Material(material);
  1483. assert(MaterialDesc.Material_Count() == 1);
  1484. } else if (!nodemtl) {
  1485. // Create a single material using the wire color
  1486. Header.NumMaterials = 1;
  1487. W3dVertexMaterialStruct vmat;
  1488. W3dShaderStruct shader;
  1489. W3dMaterialClass material;
  1490. W3d_Vertex_Material_Reset(&vmat);
  1491. W3d_Shader_Reset(&shader);
  1492. vmat.Diffuse.R = GetRValue(wirecolor);
  1493. vmat.Diffuse.G = GetGValue(wirecolor);
  1494. vmat.Diffuse.B = GetBValue(wirecolor);
  1495. material.Set_Pass_Count(1);
  1496. material.Set_Vertex_Material(vmat,0);
  1497. material.Set_Shader(shader,0);
  1498. MaterialDesc.Add_Material(material,"WireColor");
  1499. assert(MaterialDesc.Material_Count() == 1);
  1500. } else if (!nodemtl->IsMultiMtl()) {
  1501. Header.NumMaterials = 1;
  1502. W3dMaterialClass mat;
  1503. mat.Init(nodemtl);
  1504. W3dMaterialDescClass::ErrorType err;
  1505. err = MaterialDesc.Add_Material(mat,nodemtl->GetName());
  1506. if (err == W3dMaterialDescClass::MULTIPASS_TRANSPARENT) {
  1507. sprintf(_string1,"Exporting Materials for Mesh: %s\nMaterial %s is multi-pass and transparent\nMulti-pass transparent materials are not allowed.\n",
  1508. Header.MeshName,
  1509. nodemtl->GetName());
  1510. ExportLog::printf(_string1);
  1511. throw ErrorClass(_string1);
  1512. }
  1513. assert(MaterialDesc.Material_Count() == 1);
  1514. } else {
  1515. Header.NumMaterials = nodemtl->NumSubMtls();
  1516. W3dMaterialClass mat;
  1517. for (unsigned mi = 0; mi < Header.NumMaterials; mi++) {
  1518. // only process materials that were found to be used in the scan_used_materials call
  1519. if (MaterialRemapTable[mi] != -1) {
  1520. mat.Init(nodemtl->GetSubMtl(mi));//,domaps);
  1521. char * name;
  1522. W3dMaterialDescClass::ErrorType err;
  1523. name = nodemtl->GetSubMtl(mi)->GetName();
  1524. err = MaterialDesc.Add_Material(mat,name);
  1525. if (err == W3dMaterialDescClass::INCONSISTENT_PASSES) {
  1526. sprintf(_string1,"Exporting Materials for Mesh: %s\nMaterial %s has %d passes.\nThe other materials have %d passes.\nAll Materials must have the same number of passes.\n",
  1527. Header.MeshName,
  1528. nodemtl->GetSubMtl(mi)->GetName(),
  1529. mat.Get_Pass_Count(),
  1530. MaterialDesc.Pass_Count());
  1531. ExportLog::printf(_string1);
  1532. throw ErrorClass(_string1);
  1533. }
  1534. if (err == W3dMaterialDescClass::MULTIPASS_TRANSPARENT) {
  1535. sprintf(_string1,"Exporting Materials for Mesh: %s\nMaterial %s is multi-pass and transparent\nMulti-pass transparent materials are not allowed.\n",
  1536. Header.MeshName,
  1537. nodemtl->GetSubMtl(mi)->GetName());
  1538. throw ErrorClass(_string1);
  1539. }
  1540. if (err == W3dMaterialDescClass::INCONSISTENT_SORT_LEVEL) {
  1541. sprintf(_string1,"Exporting Materials for Mesh: %s\nMaterial %s does not have the same Static Sort Level as other materials used on the mesh.\nAll materials for a mesh must use the same Static Sort Level value.\n",
  1542. Header.MeshName,
  1543. nodemtl->GetSubMtl(mi)->GetName());
  1544. ExportLog::printf(_string1);
  1545. throw ErrorClass(_string1);
  1546. }
  1547. }
  1548. }
  1549. }
  1550. // Store the material's sort level in the mesh header.
  1551. Header.SortLevel = MaterialDesc.Get_Sort_Level();
  1552. }
  1553. /***********************************************************************************************
  1554. * MeshSaveClass::compute_bounding_volumes -- computes a bounding box and bounding sphere for *
  1555. * *
  1556. * INPUT: *
  1557. * *
  1558. * OUTPUT: *
  1559. * *
  1560. * WARNINGS: *
  1561. * *
  1562. * HISTORY: *
  1563. * 08/01/1997 GH : Created. *
  1564. *=============================================================================================*/
  1565. void MeshSaveClass::compute_bounding_volumes(void)
  1566. {
  1567. Vector3 min,max,center;
  1568. float radius;
  1569. Builder.Compute_Bounding_Box(&min,&max);
  1570. Builder.Compute_Bounding_Sphere(&center,&radius);
  1571. Header.SphCenter.X = center.X;
  1572. Header.SphCenter.Y = center.Y;
  1573. Header.SphCenter.Z = center.Z;
  1574. Header.SphRadius = radius;
  1575. Header.Min.X = min.X;
  1576. Header.Min.Y = min.Y;
  1577. Header.Min.Z = min.Z;
  1578. Header.Max.X = max.X;
  1579. Header.Max.Y = max.Y;
  1580. Header.Max.Z = max.Z;
  1581. }
  1582. /***********************************************************************************************
  1583. * MeshSaveClass::compute_physical_properties -- computes the volume and moment of inertia *
  1584. * *
  1585. * INPUT: *
  1586. * *
  1587. * OUTPUT: *
  1588. * *
  1589. * WARNINGS: *
  1590. * *
  1591. * HISTORY: *
  1592. * 08/01/1997 GH : Created. *
  1593. *=============================================================================================*/
  1594. void MeshSaveClass::compute_physical_constants
  1595. (
  1596. INode * inode,
  1597. Progress_Meter_Class & meter,
  1598. bool voxelize
  1599. )
  1600. {
  1601. #if 0 // IF we need this again, move the data to a physics chunk (header doesn't have it anymore)
  1602. if (voxelize) {
  1603. // Create an INodeList object for this mesh
  1604. AnyINodeFilter nodefilt;
  1605. INodeListClass meshlist(CurTime,&nodefilt);
  1606. meshlist.Insert(inode);
  1607. // Create a Voxel object for this mesh
  1608. VoxelClass * voxel = new VoxelClass
  1609. (
  1610. meshlist,
  1611. VOXEL_RESOLUTION,
  1612. ExportSpace,
  1613. CurTime,
  1614. meter
  1615. );
  1616. #if DEBUG_VOXELS
  1617. VoxelDebugWindowClass dbgwin(voxel);
  1618. dbgwin.Display_Window();
  1619. #endif
  1620. double vol[1];
  1621. double cm[3];
  1622. double inertia[9];
  1623. voxel->Compute_Physical_Properties(vol,cm,inertia);
  1624. Header.Volume = (float)vol[0];
  1625. Header.MassCenter.X = (float)cm[0];
  1626. Header.MassCenter.Y = (float)cm[1];
  1627. Header.MassCenter.Z = (float)cm[2];
  1628. Header.Inertia[0] = (float)inertia[0];
  1629. Header.Inertia[1] = (float)inertia[1];
  1630. Header.Inertia[2] = (float)inertia[2];
  1631. Header.Inertia[3] = (float)inertia[3];
  1632. Header.Inertia[4] = (float)inertia[4];
  1633. Header.Inertia[5] = (float)inertia[5];
  1634. Header.Inertia[6] = (float)inertia[6];
  1635. Header.Inertia[7] = (float)inertia[7];
  1636. Header.Inertia[8] = (float)inertia[8];
  1637. } else {
  1638. // Set mass center to the center of the bounding box
  1639. Header.MassCenter.X = (Header.Max.X + Header.Min.X) / 2.0f;
  1640. Header.MassCenter.Y = (Header.Max.Y + Header.Min.Y) / 2.0f;
  1641. Header.MassCenter.Z = (Header.Max.Z + Header.Min.Z) / 2.0f;
  1642. // Set inertia tensor to inertia tensor of the bounding box
  1643. // (gth) !!!! DO THIS !!!!
  1644. Header.Inertia[0] = 1.0f;
  1645. Header.Inertia[1] = 0.0f;
  1646. Header.Inertia[2] = 0.0f;
  1647. Header.Inertia[3] = 0.0f;
  1648. Header.Inertia[4] = 1.0f;
  1649. Header.Inertia[5] = 0.0f;
  1650. Header.Inertia[6] = 0.0f;
  1651. Header.Inertia[7] = 0.0f;
  1652. Header.Inertia[8] = 1.0f;
  1653. Header.Volume = (Header.Max.X - Header.Min.X) * (Header.Max.Y - Header.Min.Y) * (Header.Max.Z - Header.Min.Z);
  1654. }
  1655. #endif
  1656. }
  1657. /***********************************************************************************************
  1658. * MeshSaveClass::prep_mesh -- pre-transform the MAX mesh by a specified matrix *
  1659. * *
  1660. * INPUT: *
  1661. * *
  1662. * OUTPUT: *
  1663. * *
  1664. * WARNINGS: *
  1665. * *
  1666. * HISTORY: *
  1667. * 08/01/1997 GH : Created. *
  1668. *=============================================================================================*/
  1669. void MeshSaveClass::prep_mesh(Mesh & mesh,Matrix3 & objoff)
  1670. {
  1671. int vert_index;
  1672. // Transform the mesh's vertices so that they are relative to the coordinate
  1673. // system that we want to use with the mesh
  1674. for (vert_index = 0; vert_index < mesh.getNumVerts (); vert_index++) {
  1675. mesh.verts[vert_index] = mesh.verts[vert_index] * objoff;
  1676. }
  1677. // Re-Build the normals.
  1678. mesh.buildNormals();
  1679. }