Richard Boegli's CnC_Generals_Zero_Hour Fork WIP
This is documentation of Richard Boegil's Zero Hour Fork
 
Loading...
Searching...
No Matches
meshsave.cpp
Go to the documentation of this file.
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/* $Header: /Commando/Code/Tools/max2w3d/meshsave.cpp 107 8/21/01 10:28a Greg_h $ */
20/***********************************************************************************************
21 *** Confidential - Westwood Studios ***
22 ***********************************************************************************************
23 * *
24 * Project Name : Commando / G *
25 * *
26 * File Name : MESHSAVE.CPP *
27 * *
28 * Programmer : Greg Hjelstrom *
29 * *
30 * Start Date : 06/10/97 *
31 * *
32 * Last Update : 10/20/1999997 [GH] *
33 * *
34 *---------------------------------------------------------------------------------------------*
35 * Functions: *
36 * MeshSaveClass::MeshSaveClass -- constructor, processes a Max mesh *
37 * MeshSaveClass::~MeshSaveClass -- destructor, frees all allocated memory *
38 * MeshSaveClass::write_verts -- write the vertex chunk into a wtm file *
39 * MeshSaveClass::write_header -- write a mesh header chunk into a wtm file *
40 * MeshSaveClass::Write_To_File -- Append the mesh to an open wtm file *
41 * MeshSaveClass::write_normals -- writes the vertex normals chunk into a wtm file *
42 * MeshSaveClass::write_vert_normals -- Writes the surrender normal chunk into a wtm file *
43 * MeshSaveClass::write_triangles -- Write the triangles chunk into a wtm file. *
44 * MeshSaveClass::write_sr_triangles -- writes the triangles in surrender friendly format *
45 * MeshSaveClass::write_triangles -- write the triangles chunk *
46 * MeshSaveClass::compute_surrender_vertex -- Compute the surrender vertex normals *
47 * MeshSaveClass::setup_material -- Gets the texture names and base colors for a material *
48 * MeshSaveClass::compute_bounding_volumes -- computes a bounding box and bounding sphere for*
49 * MeshSaveClass::set_transform -- set the default transformation matrix for the mesh *
50 * MeshSaveClass::compute_physical_properties -- computes the volume and moment of inertia *
51 * MeshSaveClass::prep_mesh -- pre-transform the MAX mesh by a specified matrix *
52 * MeshSaveClass::write_user_text -- write the user text chunk *
53 * MeshSaveClass::get_htree_bone_index_for_inode -- searches the htree for the given INode *
54 * MeshSaveClass::get_skin_modifier_objects -- Searches for the WWSkin modifier for this mes *
55 * MeshSaveClass::inv_deform_mesh -- preprocess the mesh for skinning *
56 * MeshSaveClass::create_materials -- create the materials for this mesh *
57 * MeshSaveClass::write_ps2_shaders -- Write shaders specific to the PS2 in their own chunk. *
58 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
59
60
61#include "meshsave.h"
62#include <Max.h>
63#include <stdmat.h>
64#include <modstack.h>
65#include "gamemtl.h"
66#include "errclass.h"
67#include "vxl.h"
68#include "vxldbg.h"
69#include "nodelist.h"
70#include "hiersave.h"
71#include "util.h"
72#include "w3dappdata.h"
73#include "skin.h"
74#include "skindata.h"
75#include "meshbuild.h"
76#include "alphamodifier.h"
77#include "aabtreebuilder.h"
78#include "exportlog.h"
79
80
81static char _string1[512];
82const int VOXEL_RESOLUTION = 64; // resolution to use when computing I, V and CM
83
84#define DEBUG_VOXELS 0
85#define MIN_AABTREE_POLYGONS 8
86#define DIFFUSE_HOUSECOLOR_TEXTURE_PREFIX 0x4443485A //'ZHCD' prefix put on all code generated textures
87#define DIFFUSE_COLOR_TEXTURE_PREFIX 0x44434d5A //'ZMCD' prefix put on all code generated textures
88#define DIFFUSE_COLOR_TEXTURE_MASK 0x4443005A
89
90/************************************************************************************
91**
92** Compute the determinant of the 3x3 portion of the given matrix
93**
94************************************************************************************/
96{
97 float det = tm[0][0] * (tm[1][1]*tm[2][2] - tm[1][2]*tm[2][1]);
98 det -= tm[0][1] * (tm[1][0]*tm[2][2] - tm[1][2]*tm[2][0]);
99 det += tm[0][2] * (tm[1][0]*tm[2][1] - tm[1][1]*tm[2][0]);
100
101 return det;
102}
103
104/************************************************************************************
105**
106** check if this is a mesh which should use a simple rendering method. I don't
107** compute vertex normals or store u-v's in that case (prevents vertex splitting)
108**
109************************************************************************************/
110bool use_simple_rendering(int geo_type)
111{
113
115 (geo_type == W3D_MESH_FLAG_GEOMETRY_TYPE_AABOX) ||
116 (geo_type == W3D_MESH_FLAG_GEOMETRY_TYPE_OBBOX) )
117 {
118 return true;
119 } else {
120 return false;
121 }
122}
123
124/************************************************************************************
125**
126** build the bitfield of W3D mesh attributes for the given node
127**
128************************************************************************************/
130{
131 uint32 attributes = W3D_MESH_FLAG_NONE;
132
133 /*
134 ** Mesh will be one of:
135 ** W3D_MESH_FLAG_NONE,
136 ** W3D_MESH_FLAG_COLLISION_BOX,
137 ** W3D_MESH_FLAG_SKIN,
138 ** W3D_MESH_FLAG_ALIGNED
139 ** W3D_MESH_FLAG_ORIENTED
140 */
141 if (Is_Collision_AABox(node)) {
143 } else if (Is_Collision_OBBox(node)) {
145 } else if (Is_Skin(node)) {
147 } else if (Is_Camera_Aligned_Mesh(node)) {
149 } else if (Is_Camera_Oriented_Mesh(node)) {
151 }
152
153 /*
154 ** And, a mesh may have one or more types of collision detection enabled.
155 ** W3D_MESH_FLAG_COLLISION_TYPE_PHYSICAL
156 ** W3D_MESH_FLAG_COLLISION_TYPE_PROJECTILE
157 ** However, if the mesh is SKIN, SHADOW, ALIGNED, ORIENTED or NULL, don't let
158 ** the collision bits get set...
159 */
160 if ( attributes != W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN &&
163 {
164
165 if (Is_Physical_Collision(node)) {
167 }
168
169 if (Is_Projectile_Collision(node)) {
171 }
172
173 if (Is_Vis_Collision(node)) {
175 }
176
177 if (Is_Camera_Collision(node)) {
179 }
180
181 if (Is_Vehicle_Collision(node)) {
183 }
184
185 }
186
187 /*
188 ** A mesh may have one of the following bits set as well
189 */
190 if (Is_Hidden(node)) {
191 attributes |= W3D_MESH_FLAG_HIDDEN;
192 }
193 if (Is_Two_Sided(node)) {
194 attributes |= W3D_MESH_FLAG_TWO_SIDED;
195 }
196 if (Is_Shadow(node)) {
197 attributes |= W3D_MESH_FLAG_CAST_SHADOW;
198 }
199 if (Is_Shatterable(node)) {
200 attributes |= W3D_MESH_FLAG_SHATTERABLE;
201 }
202 if (Is_NPatchable(node)) {
203 attributes |= W3D_MESH_FLAG_NPATCHABLE;
204 }
205
206 return attributes;
207}
208
209
210
211/***********************************************************************************************
212 * MeshSaveClass::MeshSaveClass -- constructor, processes a Max mesh *
213 * *
214 * This class takes a MAX mesh and computes the information for a W3D mesh or skin. *
215 * *
216 * INPUT: *
217 * *
218 * inode - the max INode containing the mesh/skin to export *
219 * exportspace - matrix defining the desired coordinate system for the mesh *
220 * htree - hierarchy tree that this mesh is being connected to *
221 * curtime - current time in Max. *
222 * meter - progress meter *
223 * mesh_name - name to use for the mesh *
224 * container_name - name of the container *
225 * *
226 * OUTPUT: *
227 * *
228 * WARNINGS: *
229 * *
230 * HISTORY: *
231 * 06/10/1997 GH : Created. *
232 *=============================================================================================*/
234(
235 char * mesh_name,
236 char * container_name,
237 INode * inode,
238 const Mesh * input_mesh,
239 Matrix3 & exportspace,
240 W3DAppData2Struct & exportoptions,
241 HierarchySaveClass * htree,
242 TimeValue curtime,
243 Progress_Meter_Class & meter,
244 unsigned int * materialColors,
245 int &numMaterialColors,
246 int &numHouseColors,
247 char *materialColorTexture,
248 WorldInfoClass * world_info
249) :
250 MaxINode(inode),
251 ExportOptions(exportoptions),
252 CurTime(curtime),
253 ExportSpace(exportspace),
254 HTree(htree),
255 UserText(NULL),
256 VertInfluences(NULL),
257 MaterialRemapTable(NULL)
258{
259 Mesh mesh = *input_mesh; // copy the mesh so we can modify it
260 Mtl * nodemtl = inode->GetMtl();
261 DWORD wirecolor = inode->GetWireColor();
262
263 PS2Material = FALSE;
264
265 // Check to see if the mesh uses PS2 game materials. If so, set a flag so
266 // that write_shaders will know to make a PS2 shader chunk.
267 if (nodemtl) {
268 if (nodemtl->ClassID() == PS2GameMaterialClassID) {
269 PS2Material = TRUE;
270 } else if (nodemtl->IsMultiMtl()) {
271 for (int i = 0; i < nodemtl->NumSubMtls(); i++) {
272 Mtl *sub = nodemtl->GetSubMtl(i);
273 if (sub->ClassID() == PS2GameMaterialClassID) {
274 PS2Material = TRUE;
275 }
276 }
277 }
278 }
279
281 // Check if the mesh is being inverted by its transform. If this
282 // is the case, then we will need to reverse the winding of all
283 // polygons later.
285 Matrix3 objtm = MaxINode->GetObjectTM(curtime);
286 MeshInverted = (Compute_3x3_Determinant(objtm) < 0.0f);
287
289 // Prep the mesh by transforming it by the delta between exportspace
290 // and this INodes current space
291 // (this is the delta between the bone and the mesh if one exists...)
293 MeshToExportSpace = objtm * Inverse(ExportSpace);
294 prep_mesh(mesh,MeshToExportSpace);
295
297 // Prepare the mesh header.
299 assert(mesh_name != NULL);
300 assert(container_name != NULL);
301
302 memset(&Header,0,sizeof(Header));
303 Set_W3D_Name(Header.MeshName,mesh_name);
304 Set_W3D_Name(Header.ContainerName,container_name);
305
306 Header.Version = W3D_CURRENT_MESH_VERSION;
307 Header.Attributes = setup_mesh_attributes(MaxINode);
308
309 meter.Finish_In_Steps(
310 3*Header.NumTris + // normals
311 Header.NumVertices + // surrender normals
312 64 // voxelization
313 );
314
315 ExportLog::printf("\nProcessing Mesh: %s\n",Header.MeshName);
316
318 // Enforce that we have enough data to actually make a mesh
320 if (mesh.getNumFaces() <= 0) {
321 throw ErrorClass("No Triangles in Mesh: %s",Header.MeshName);
322 }
323
324 if (mesh.getNumVerts() <= 0) {
325 throw ErrorClass("No Vertices in Mesh: %s",Header.MeshName);
326 }
327
329 // process the materials
331 DebugPrint("processing materials\n");
332 scan_used_materials(mesh,nodemtl);
333 create_materials(nodemtl,wirecolor,materialColorTexture);
334
336 // what face and vertex attributes are we going to export?
338 Header.FaceChannels = W3D_FACE_CHANNEL_FACE;
339 Header.VertexChannels = W3D_VERTEX_CHANNEL_LOCATION;
340
341 if (!use_simple_rendering(Header.Attributes)) {
342 Header.VertexChannels |= W3D_VERTEX_CHANNEL_NORMAL;
343 }
344
345 if (((Header.Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK) == W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN) && (HTree != NULL)) {
346 Header.VertexChannels |= W3D_VERTEX_CHANNEL_BONEID;
347 }
348
350 // Process the mesh
352 Builder.Set_World_Info (world_info);
353 Build_Mesh(mesh, nodemtl, materialColors, numMaterialColors, numHouseColors);
354
355 if (materialColorTexture)
356 { //diffuse color materials are replaced by textures
357 //set diffuse to 255,255,255 so it has no effect.
358 fix_diffuse_materials(numHouseColors != 0);
359 }
360
362 // Create damage (deform) information for the mesh
364 Object *ref_obj = MaxINode->GetObjectRef ();
365 DeformSave.Initialize(Builder, ref_obj, mesh, &MeshToExportSpace);
366
368 // Determine if the deformer should use alpha or v-color info
370 if (ExportOptions.Is_Vertex_Alpha_Enabled()) {
371 unsigned int alpha_passes = 0;
372 for (int pass=0; pass < MaterialDesc.Pass_Count(); pass++) {
373 if (MaterialDesc.Pass_Uses_Vertex_Alpha(pass)) {
374 alpha_passes |= (1 << pass);
375 }
376 }
377 DeformSave.Set_Alpha_Passes(alpha_passes);
378 }
379
381 // Set the counts in the mesh header
383 Header.NumTris = Builder.Get_Face_Count();
384 Header.NumVertices = Builder.Get_Vertex_Count();
385
387 // Compute the mesh's bounding box and sphere. This must be done
388 // before we pre-deform the mesh (if its a skin).
390 compute_bounding_volumes();
391
393 // Voxelize the mesh and compute the Moment of Inertia and
394 // Center of Mass. This must come after we compute the bounding
395 // volumes and before we pre-deform the mesh.
397 Progress_Meter_Class voxelmeter(meter, 64.0f * meter.Increment);
398 compute_physical_constants(MaxINode,voxelmeter,false /*usevoxelizer*/);
399
401 // If this is a skin, pre-deform the mesh.
403 if (((Header.Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK) == W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN) && (HTree != NULL)) {
404 inv_deform_mesh();
405 }
406
408 // Get the user text from MAX's properties window.
410 TSTR usertext;
411 MaxINode->GetUserPropBuffer(usertext);
412 CStr usertext8 = usertext;
413
414 if (usertext8.Length() > 0) {
415 UserText = new char[usertext8.Length() + 1];
416 memset(UserText,0,usertext8.Length() + 1);
417 memcpy(UserText,usertext8.data(),usertext8.Length());
418 }
419}
420
421/***********************************************************************************************
422 * MeshSaveClass::~MeshSaveClass -- destructor, frees all allocated memory *
423 * *
424 * INPUT: *
425 * *
426 * OUTPUT: *
427 * *
428 * WARNINGS: *
429 * *
430 * HISTORY: *
431 * 06/10/1997 GH : Created. *
432 *=============================================================================================*/
434{
435 if (UserText) {
436 delete[] UserText;
437 UserText = NULL;
438 }
439
440 if (VertInfluences) {
441 delete[] VertInfluences;
442 VertInfluences = NULL;
443 }
444
445 if (MaterialRemapTable) {
446 delete[] MaterialRemapTable;
447 MaterialRemapTable = NULL;
448 }
449}
450
451//search through previously found material colors and return index. house colors are always placed in top row.
452void getMaterialUV(UVVert &tvert,unsigned int diffuse, unsigned int *materialColors, int &numMaterialColors, int &numHouseColors, bool house)
453{
454 int i;
455
456 if (house)
457 { //this material is a house color, place it in first row.
458 for (i=0; i<16; i++)
459 {
460 if (materialColors[i]==diffuse)
461 {
462 tvert.x=((double)(i%16)+0.5)/16.0;
463 tvert.y=1.0-((double)(i/16)+0.5)/16.0;
464 numHouseColors=16;
465 return;
466 }
467 }
468
469 ExportLog::printf("\nUndefined House Color %d,%d,%d",(diffuse>>16)&0xff,(diffuse>>8)&0xff,diffuse&0xff);
470 assert(0); //all house colors must be from a predefined range of reds
471 }
472
473 for (i=16; i<(16+numMaterialColors); i++)
474 {
475 if (materialColors[i]==diffuse)
476 {
477 tvert.x=((double)(i%16)+0.5)/16.0;
478 tvert.y=1.0-((double)(i/16)+0.5)/16.0;
479 return;
480 }
481 }
482
483 //new color found
484 tvert.x=((double)(i%16)+0.5)/16.0;
485 tvert.y=1.0-((double)(i/16)+0.5)/16.0;
486
487 materialColors[i]=diffuse;
488 numMaterialColors++;
489}
490
491void MeshSaveClass::Build_Mesh(Mesh & mesh, Mtl *node_mtl, unsigned int *materialColors, int &numMaterialColors, int &numHouseColors)
492{
493 int vert_counter;
494 int face_index;
495 int pass;
496 int stage;
497 float *vdata = NULL;
498 int firstSolidColoredMaterial=-1;
499
500 Builder.Reset(true,mesh.getNumFaces(),mesh.getNumFaces()/3);
501
502 // Get a pointer to the channel that has alpha values entered by the artist.
503 // This pointer will be NULL if they didn't use the channel.
504 vdata = mesh.vertexFloat(ALPHA_VERTEX_CHANNEL);
505
506 /*
507 ** Get the skin info
508 */
509 bool is_skin = false;
510 SkinDataClass * skindata = NULL;
511 SkinWSMObjectClass * skinobj = NULL;
512
513 get_skin_modifier_objects(&skindata,&skinobj);
514
516 (HTree != NULL) )
517 {
518 is_skin = ((skindata != NULL) && (skinobj != NULL));
519 }
520
521 /*
522 ** Submit all of the faces
523 */
524 MeshBuilderClass::FaceClass face;
525 for (face_index = 0; face_index < mesh.getNumFaces(); face_index++) {
526
527 Face maxface = mesh.faces[face_index];
528
529 int mat_index = 0;
530 if (Header.NumMaterials > 0) {
531 mat_index = MaterialRemapTable[(maxface.getMatID() % Header.NumMaterials)];
532 }
533 assert(mat_index != -1);
534
535 for (pass=0; pass<MaterialDesc.Pass_Count(); pass++) {
536 face.ShaderIndex[pass] = MaterialDesc.Get_Shader_Index(mat_index,pass);
537 for (stage=0; stage<W3dMaterialClass::MAX_STAGES; stage++) {
538 face.TextureIndex[pass][stage] = MaterialDesc.Get_Texture_Index(mat_index,pass,stage);
539 }
540 }
541
542 int geo_type = Header.Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK;
543
544 if ( use_simple_rendering(geo_type) ) {
545 face.SmGroup = 0xFFFFFFFF;
546 } else {
547 face.SmGroup = maxface.getSmGroup();
548 }
549
550 face.Index = face_index;
551 face.Attributes = 0;
552 face.SurfaceType = 0;
553
554 /*
555 ** Lookup this face's surface type
556 */
557 Mtl *mtl_to_use = node_mtl;
558 if ((node_mtl != NULL) && (node_mtl->NumSubMtls() > 1)) {
559 mtl_to_use = node_mtl->GetSubMtl (maxface.getMatID() % node_mtl->NumSubMtls());
560 }
561
562 if ((mtl_to_use != NULL) && ((mtl_to_use->ClassID() == GameMaterialClassID) ||
563 (mtl_to_use->ClassID() == PS2GameMaterialClassID))) {
564 face.SurfaceType = ((GameMtl *)mtl_to_use)->Get_Surface_Type ();
565 }
566
567 for (vert_counter = 0; vert_counter < 3; vert_counter++) {
568
569 /*
570 ** if this mesh is being inverted, we need to insert the verts in
571 ** the opposite order. max_vert_counter will count backwards
572 ** in this case; causing all vertex data to be entered in the
573 ** reverse winding.
574 */
575 int max_vert_counter;
576
577 if (MeshInverted) {
578 max_vert_counter = 2 - vert_counter;
579 } else {
580 max_vert_counter = vert_counter;
581 }
582
583 int max_vert_index = maxface.v[max_vert_counter];
584
585 /*
586 ** Vertex Id, to prevent unwanted welding!
587 */
588 face.Verts[vert_counter].Id = max_vert_index;
589
590 /*
591 ** Vertex Position
592 */
593 face.Verts[vert_counter].Position.X = mesh.verts[max_vert_index].x;
594 face.Verts[vert_counter].Position.Y = mesh.verts[max_vert_index].y;
595 face.Verts[vert_counter].Position.Z = mesh.verts[max_vert_index].z;
596
597 if (vdata) {
598
599 // If an alpha channel has been created, use its value.
600 for (int pass=0; pass < MaterialDesc.Pass_Count(); pass++) {
601 if (MaterialDesc.Pass_Uses_Vertex_Alpha(pass)) {
602 // Mulitiply by .01 to change from percentage.
603 face.Verts[vert_counter].Alpha[pass] = vdata[max_vert_index] * .01;
604 }
605 }
606 }
607
608
609 /*
610 ** Texture coordinate. Apply uv coords if the mesh has them and is not being
611 ** instructed to ignore them.
612 ** - check if the mesh needs them (uses_simple_rendering() == false)
613 ** - for each pass and stage, look up what map channel this face's material is using
614 ** - ask Max for the tfaces and tverts for that map channel
615 ** - copy the values into each vertex
616 */
617 for (pass=0; pass<MaterialDesc.Pass_Count(); pass++) {
618 for (stage=0; stage<W3dMaterialClass::MAX_STAGES; stage++) {
619
620 /*
621 ** Start with a 0,0 uv coordinate
622 */
623 UVVert tvert(0.0,0.0,0.0);
624
625 W3dVertexMaterialStruct *vmat=MaterialDesc.Get_Vertex_Material(mat_index, pass);
626 //Check if this material needs material color texture substitution.
627 W3dMapClass *map3d=MaterialDesc.Get_Texture(mat_index,pass,stage);
628 if (map3d && map3d->Filename && *((unsigned int *)map3d->Filename) == DIFFUSE_COLOR_TEXTURE_PREFIX) //check for prefix
629 {
630 double Diffuse = vmat->Diffuse.Get_Color() >> 8; //get material color
631
632 //MW: Encode the material color into the u texture coordinate
633 tvert.x=Diffuse;
634 tvert.y=Diffuse;
635
636 //find out material color location within texture page
637 if (strnicmp(MaterialDesc.Get_Vertex_Material_Name(mat_index,pass),"HouseColor",10)==0)
638 getMaterialUV(tvert,vmat->Diffuse.Get_Color() >> 8, materialColors, numMaterialColors, numHouseColors, true);
639 else
640 getMaterialUV(tvert,vmat->Diffuse.Get_Color() >> 8, materialColors, numMaterialColors, numHouseColors, false);
641
642 //Keep track of first vertex material converted, so we can remap all other non-textured
643 //materials to use the same material.
644 if (firstSolidColoredMaterial == -1)
645 firstSolidColoredMaterial=MaterialDesc.Get_Vertex_Material_Index(mat_index,pass);
646 }
647
648 /*
649 ** If the mesh needs uv coords and they are present, copy the uv into tvert
650 */
651 else
652 if (!use_simple_rendering(Header.Attributes)) {
653
654 int channel = MaterialDesc.Get_Map_Channel(mat_index,pass,stage);
655
656 UVVert * uvarray = mesh.mapVerts(channel);
657 TVFace * tvfacearray = mesh.mapFaces(channel);
658
660 W3dMapClass *map3d=MaterialDesc.Get_Texture(mat_index,pass,stage);
661
662 if (map3d && (uvarray != NULL) && (tvfacearray != NULL)) {
663
664 int tvert_index = tvfacearray[face_index].t[max_vert_counter];
665 tvert = uvarray[tvert_index];
666 }
667 }
668
669 /*
670 ** Copy the texture coordinate into the vertex structure
671 */
672 face.Verts[vert_counter].TexCoord[pass][stage].X = tvert.x;
673 face.Verts[vert_counter].TexCoord[pass][stage].Y = tvert.y;
674
675 }
676 }
677
678 /*
679 ** Vertex Color
680 */
681 if (mesh.vcFace) {
682
683 /*
684 ** If the mesh is being mirrored, remap the index
685 */
686 int max_cvert_index = mesh.vcFace[face_index].t[max_vert_counter];
687
688 VertColor vc;
689 vc = mesh.vertCol[max_cvert_index];
690
691 /*
692 ** If Vertex Alpha is specified, the vertex color is converted
693 ** to alpha. If the (obsolete) Node-flag for vertex alpha is enabled,
694 ** the alpha is put into each pass which has alpha enabled. Otherwise,
695 ** we check the material settings for which passes should get the alpha
696 ** values. If neither alpha options are enabled, we put the color
697 ** value into the first pass.
698 */
699 if (ExportOptions.Is_Vertex_Alpha_Enabled()) {
700
701 float alpha = (vc.x + vc.y + vc.z) / 3.0f;
702 for (int pass=0; pass < MaterialDesc.Pass_Count(); pass++) {
703 if (MaterialDesc.Pass_Uses_Vertex_Alpha(pass)) {
704 face.Verts[vert_counter].Alpha[pass] = alpha;
705 }
706 }
707 } else {
708 face.Verts[vert_counter].DiffuseColor[0].X = vc.x;
709 face.Verts[vert_counter].DiffuseColor[0].Y = vc.y;
710 face.Verts[vert_counter].DiffuseColor[0].Z = vc.z;
711 }
712
713 face.Verts[vert_counter].MaxVertColIndex = max_cvert_index;
714
715 } else {
716 face.Verts[vert_counter].MaxVertColIndex = 0;
717 }
718
719 /*
720 ** Vertex materials (get's index of sub-material)
721 */
722 for (pass = 0; pass<MaterialDesc.Pass_Count(); pass++) {
723
724 //if solid-color texture substitution, replace the vertex material with first solid one found.
725 W3dMapClass *map3d=MaterialDesc.Get_Texture(mat_index,pass,0);
726 if (map3d && map3d->Filename && *((unsigned int *)map3d->Filename) == DIFFUSE_COLOR_TEXTURE_PREFIX) //check for prefix
727 face.Verts[vert_counter].VertexMaterialIndex[pass]=firstSolidColoredMaterial;
728 else
729 face.Verts[vert_counter].VertexMaterialIndex[pass] = MaterialDesc.Get_Vertex_Material_Index(mat_index,pass);
730 }
731
732 face.Verts[vert_counter].Attribute0 = max_vert_index;
733 face.Verts[vert_counter].Attribute1 = face_index;
734
735 /*
736 ** Skin attachment
737 */
738 face.Verts[vert_counter].BoneIndex = 0;
739 if (is_skin) {
740
741 int skin_bone_index = skindata->VertData[max_vert_index].BoneIdx[0];
742
743 // If this is a valid bone, try to find the corresponding bone index in the HTree
744 if ( (skin_bone_index != -1) &&
745 (skin_bone_index < skinobj->Num_Bones()) &&
746 (skinobj->BoneTab[skin_bone_index] != NULL) )
747 {
748 face.Verts[vert_counter].BoneIndex = get_htree_bone_index_for_inode(skinobj->BoneTab[skin_bone_index]);
749 }
750 }
751 }
752
753 Builder.Add_Face(face);
754 }
755
756 /*
757 ** Process the mesh
758 */
759 Builder.Build_Mesh(true);
760
761 const MeshBuilderClass::MeshStatsStruct & stats = Builder.Get_Mesh_Stats();
762 int vcount = Builder.Get_Vertex_Count();
763 int pcount = mesh.numFaces;
764 float vert_poly_ratio = (float)vcount / (float)pcount;
765
766 ExportLog::printf(" triangle count: %d\n",pcount);
767 ExportLog::printf(" final vertex count: %d\n",vcount);
768 ExportLog::printf(" vertex/triangle ratio: %f\n",vert_poly_ratio);
769 ExportLog::printf(" strip count: %d\n",stats.StripCount);
770 ExportLog::printf(" average strip length: %f\n",stats.AvgStripLength);
771 ExportLog::printf(" longest strip: %d\n",stats.MaxStripLength);
772}
773
774
775/***********************************************************************************************
776 * MeshSaveClass::get_skin_modifier_objects -- Searches for the WWSkin modifier for this mesh *
777 * *
778 * INPUT: *
779 * *
780 * OUTPUT: *
781 * *
782 * WARNINGS: *
783 * *
784 * HISTORY: *
785 *=============================================================================================*/
786void MeshSaveClass::get_skin_modifier_objects(SkinDataClass ** skin_data_ptr,SkinWSMObjectClass ** skin_obj_ptr)
787{
788 *skin_data_ptr = NULL;
789 *skin_obj_ptr = NULL;
790
791 // loop through the references that our node has
792 for (int i = 0; i < MaxINode->NumRefs(); i++) {
793
794 ReferenceTarget *refTarg = MaxINode->GetReference(i);
795
796 // if the reference is a WSM Derived Object.
797 if (refTarg != NULL && refTarg->ClassID() == Class_ID(WSM_DERIVOB_CLASS_ID,0)) {
798
799 IDerivedObject * wsm_der_obj = (IDerivedObject *)refTarg;
800
801 // loop through the WSM's attached to this WSM Derived object
802 for (int j = 0; j < wsm_der_obj->NumModifiers(); j++) {
803 Modifier * mod = wsm_der_obj->GetModifier(j);
804 if (mod->ClassID() == SKIN_MOD_CLASS_ID) {
805
806 // This is our modifier! Get the data from it!
807 SkinModifierClass * skinmod = (SkinModifierClass *)mod;
808 ModContext * mc = wsm_der_obj->GetModContext(j);
809 *skin_data_ptr = (SkinDataClass *)(mc->localData);
810 *skin_obj_ptr = (SkinWSMObjectClass *)skinmod->GetReference(SkinModifierClass::OBJ_REF);
811 }
812 }
813 }
814 }
815}
816
817
818/***********************************************************************************************
819 * MeshSaveClass::get_htree_bone_index_for_inode -- searches the htree for the given INode *
820 * *
821 * INPUT: *
822 * *
823 * OUTPUT: *
824 * *
825 * WARNINGS: *
826 * *
827 * HISTORY: *
828 * 5/1/2000 gth : Created. *
829 *=============================================================================================*/
830int MeshSaveClass::get_htree_bone_index_for_inode(INode * node)
831{
832 // index of this INode in the hierarchy tree (it better be there :-)
833 char w3dname[W3D_NAME_LEN];
834 Set_W3D_Name(w3dname,node->GetName());
835 int bindex = HTree->Find_Named_Node(w3dname);
836
837 // If the desired bone isn't being exported, export the point
838 // relative to the root.
839 if (bindex == -1) {
840 bindex = 0;
841 }
842
843 return bindex;
844}
845
846/***********************************************************************************************
847 * MeshSaveClass::inv_deform_mesh -- preprocess the mesh for skinning *
848 * *
849 * INPUT: *
850 * *
851 * OUTPUT: *
852 * *
853 * WARNINGS: *
854 * *
855 * HISTORY: *
856 * 10/26/1997 GH : Created. *
857 * 5/1/2000 gth : Created. *
858 *=============================================================================================*/
859void MeshSaveClass::inv_deform_mesh()
860{
861 // Got the skinning info, now pre-deform each vertex and
862 // create an array of vertex influence indexes.
863 VertInfluences = new W3dVertInfStruct[Builder.Get_Vertex_Count()];
864 memset(VertInfluences,0,sizeof(W3dVertInfStruct) * Builder.Get_Vertex_Count());
865 Header.VertexChannels |= W3D_VERTEX_CHANNEL_BONEID;
866
867 for (int vert_index = 0; vert_index < Builder.Get_Vertex_Count(); vert_index++) {
868
869 MeshBuilderClass::VertClass & vert = Builder.Get_Vertex(vert_index);
870
871 if (vert.BoneIndex == 0) {
872
873 // set the influence to 0 (root node) and leave the vert and normal unchanged
874 // (gth) 07/11/2000: Note that in this case, the mesh coordinates have already been
875 // transformed relative to the user or scene origin and do not need to be further modified.
876 VertInfluences[vert_index].BoneIdx = 0;
877
878 } else {
879
880 // here we go! get the matrix from the hierarchy tree and transform
881 // the point into the bone's coordinate system.
882 // (gth) 07/11/2000: The origin_offset_tm is no longer needed because
883 // skin meshes are transformed into the origin coordinate system before
884 // we get to this code.
885 Matrix3 bonetm = HTree->Get_Node_Transform(vert.BoneIndex);
886 Matrix3 invbonetm = Inverse(bonetm);
887 Point3 pos;
888
889 pos.x = vert.Position.X;
890 pos.y = vert.Position.Y;
891 pos.z = vert.Position.Z;
892
893 pos = pos * invbonetm;
894
895 vert.Position.X = pos.x;
896 vert.Position.Y = pos.y;
897 vert.Position.Z = pos.z;
898
899 // Now, transform the normal into the bone's coordinate system.
900 invbonetm.NoTrans();
901 Point3 norm;
902
903 norm.x = vert.Normal.X;
904 norm.y = vert.Normal.Y;
905 norm.z = vert.Normal.Z;
906
907 norm = norm * invbonetm;
908
909 vert.Normal.X = norm.x;
910 vert.Normal.Y = norm.y;
911 vert.Normal.Z = norm.z;
912
913 VertInfluences[vert_index].BoneIdx = vert.BoneIndex;
914 }
915 }
916}
917
918
919/***********************************************************************************************
920 * MeshSaveClass::Write_To_File -- Append the mesh to an open wtm file *
921 * *
922 * INPUT: *
923 * csave - ChunkSaveClass object to handle writing the chunk-based file *
924 * export_aabtree - should we generate an aabtree for this mesh *
925 * *
926 * OUTPUT: *
927 * 0 if nothing went wrong, Non-Zero otherwise *
928 * *
929 * WARNINGS: *
930 * *
931 * *
932 * HISTORY: *
933 * 06/10/1997 GH : Created. *
934 *=============================================================================================*/
935int MeshSaveClass::Write_To_File(ChunkSaveClass & csave,bool export_aabtree)
936{
937 if (!csave.Begin_Chunk(W3D_CHUNK_MESH)) {
938 return 1;
939 }
940
941 if (write_header(csave) != 0) {
942 return 1;
943 }
944
945 if (write_user_text(csave) != 0) {
946 return 1;
947 }
948
949 if (write_verts(csave) != 0) {
950 return 1;
951 }
952
953 if (write_vert_normals(csave) != 0) {
954 return 1;
955 }
956
957 if (write_triangles(csave) != 0) {
958 return 1;
959 }
960
961 if (write_vert_influences(csave) != 0) {
962 return 1;
963 }
964
965 if (write_vert_shade_indices(csave) != 0) {
966 return 1;
967 }
968
969 if (write_material_info(csave) != 0) {
970 return 1;
971 }
972
973 if (write_vertex_materials(csave) != 0) {
974 return 1;
975 }
976
977 if (PS2Material == TRUE) {
978
979 // The ps2 shaders must be written out first.
980 if (write_ps2_shaders(csave) != 0) {
981 return 1;
982 }
983 }
984
985 if (write_shaders(csave) != 0) {
986 return 1;
987 }
988
989
990 if (write_textures(csave) != 0) {
991 return 1;
992 }
993
994 for (int pass=0; pass<MaterialDesc.Pass_Count(); pass++) {
995 if (write_pass(csave,pass) != 0) {
996 return 1;
997 }
998 }
999
1000 if (DeformSave.Export (csave) != true) {
1001 return 1;
1002 }
1003
1004 if (export_aabtree == true) {
1005 if (write_aabtree(csave) != 0) {
1006 return 1;
1007 }
1008 }
1009
1010 if (!csave.End_Chunk()) {
1011 return 1;
1012 }
1013
1014 return 0;
1015}
1016
1017/***********************************************************************************************
1018 * MeshSaveClass::write_header -- write a mesh header chunk into a wtm file *
1019 * *
1020 * INPUT: *
1021 * csave - chunk save object *
1022 * *
1023 * OUTPUT: *
1024 * 0 if nothing went wrong, Non-Zero otherwise *
1025 * *
1026 * WARNINGS: *
1027 * *
1028 * HISTORY: *
1029 * 06/10/1997 GH : Created. *
1030 *=============================================================================================*/
1031int MeshSaveClass::write_header(ChunkSaveClass & csave)
1032{
1033 if (!csave.Begin_Chunk(W3D_CHUNK_MESH_HEADER3)) {
1034 return 1;
1035 }
1036
1037 if (csave.Write(&Header,sizeof(W3dMeshHeader3Struct)) != sizeof(W3dMeshHeader3Struct)) {
1038 return 1;
1039 }
1040
1041 if (!csave.End_Chunk()) {
1042 return 1;
1043 }
1044
1045 return 0;
1046}
1047
1048/***********************************************************************************************
1049 * MeshSaveClass::write_user_text -- write the user text chunk *
1050 * *
1051 * INPUT: *
1052 * *
1053 * OUTPUT: *
1054 * *
1055 * WARNINGS: *
1056 * *
1057 * HISTORY: *
1058 * 08/20/1997 GH : Created. *
1059 *=============================================================================================*/
1060int MeshSaveClass::write_user_text(ChunkSaveClass & csave)
1061{
1062 // If there's no user text, just don't write the chunk
1063 if (UserText == NULL) {
1064 return 0;
1065 }
1066
1068 return 1;
1069 }
1070
1071 // write the user text buffer (writing one extra byte to include the NULL)
1072 if (csave.Write(UserText,strlen(UserText) + 1) != strlen(UserText) + 1) {
1073 return 1;
1074 }
1075
1076 if (!csave.End_Chunk()) {
1077 return 1;
1078 }
1079
1080 return 0;
1081}
1082
1083/***********************************************************************************************
1084 * MeshSaveClass::write_verts -- write the vertex chunk into a wtm file *
1085 * *
1086 * INPUT: *
1087 * csave - chunk save object *
1088 * *
1089 * OUTPUT: *
1090 * 0 if nothing went wrong, Non-Zero otherwise *
1091 * *
1092 * WARNINGS: *
1093 * *
1094 * HISTORY: *
1095 * 06/10/1997 GH : Created. *
1096 *=============================================================================================*/
1097int MeshSaveClass::write_verts(ChunkSaveClass & csave)
1098{
1099 if (!csave.Begin_Chunk(W3D_CHUNK_VERTICES)) {
1100 return 1;
1101 }
1102
1103 assert(Builder.Get_Vertex_Count() > 0);
1104 assert(Builder.Get_Vertex_Count() == (int)Header.NumVertices);
1105
1106 for (int i=0; i<Builder.Get_Vertex_Count(); i++) {
1107
1108 const MeshBuilderClass::VertClass & vert = Builder.Get_Vertex(i);
1109
1111
1112 assert(vert.Position.X <= Header.Max.X);
1113 assert(vert.Position.Y <= Header.Max.Y);
1114 assert(vert.Position.Z <= Header.Max.Z);
1115
1116 assert(vert.Position.X >= Header.Min.X);
1117 assert(vert.Position.Y >= Header.Min.Y);
1118 assert(vert.Position.Z >= Header.Min.Z);
1119
1120 }
1121
1122 W3dVectorStruct w3dvert;
1123 w3dvert.X = vert.Position.X;
1124 w3dvert.Y = vert.Position.Y;
1125 w3dvert.Z = vert.Position.Z;
1126
1127 if (csave.Write(&(w3dvert),sizeof(W3dVectorStruct)) != sizeof(W3dVectorStruct)) {
1128 return 1;
1129 }
1130 }
1131
1132 if (!csave.End_Chunk()) {
1133 return 1;
1134 }
1135 return 0;
1136}
1137
1138
1139/***********************************************************************************************
1140 * MeshSaveClass::write_vert_normals -- Writes the surrender normal chunk into a wtm file *
1141 * *
1142 * INPUT: *
1143 * csave - chunk save object *
1144 * *
1145 * OUTPUT: *
1146 * 0 if nothing went wrong, Non-Zero otherwise *
1147 * *
1148 * WARNINGS: *
1149 * *
1150 * HISTORY: *
1151 * 06/10/1997 GH : Created. *
1152 *=============================================================================================*/
1153int MeshSaveClass::write_vert_normals(ChunkSaveClass & csave)
1154{
1155 if (!(Header.VertexChannels & W3D_VERTEX_CHANNEL_NORMAL)) return 0;
1156
1158 return 1;
1159 }
1160
1161 for (int i=0; i < Builder.Get_Vertex_Count(); i++) {
1162
1163 const MeshBuilderClass::VertClass & vert = Builder.Get_Vertex(i);
1164
1165 W3dVectorStruct norm;
1166
1167 if (ExportOptions.Is_ZNormals_Enabled()) {
1168 norm.X = 0.0f;
1169 norm.Y = 0.0f;
1170 norm.Z = 1.0f;
1171 } else {
1172 norm.X = vert.Normal.X;
1173 norm.Y = vert.Normal.Y;
1174 norm.Z = vert.Normal.Z;
1175 }
1176
1177 if (csave.Write(&(norm),sizeof(W3dVectorStruct)) != sizeof(W3dVectorStruct)) {
1178 return 1;
1179 }
1180 }
1181
1182 if (!csave.End_Chunk()) {
1183 return 1;
1184 }
1185
1186 return 0;
1187}
1188
1189/***********************************************************************************************
1190 * MeshSaveClass::write_vert_influences -- skins will have this chunk that binds verts to bones*
1191 * *
1192 * INPUT: *
1193 * csave - chunk save object *
1194 * *
1195 * OUTPUT: *
1196 * 0 if nothing went wrong, Non-Zero otherwise *
1197 * *
1198 * WARNINGS: *
1199 * *
1200 * HISTORY: *
1201 * 06/10/1997 GH : Created. *
1202 *=============================================================================================*/
1203int MeshSaveClass::write_vert_influences(ChunkSaveClass & csave)
1204{
1206 !(Header.VertexChannels & W3D_VERTEX_CHANNEL_BONEID) ||
1207 (VertInfluences == NULL)) {
1208 return 0;
1209 }
1210
1212 return 1;
1213 }
1214
1215 int count = Builder.Get_Vertex_Count();
1216 if (csave.Write(VertInfluences,count * sizeof(W3dVertInfStruct)) != count * sizeof(W3dVertInfStruct)) {
1217 return 1;
1218 }
1219
1220 if (!csave.End_Chunk()) {
1221 return 1;
1222 }
1223
1224 return 0;
1225}
1226
1227
1228/***********************************************************************************************
1229 * MeshSaveClass::write_triangles -- write the triangles chunk *
1230 * *
1231 * INPUT: *
1232 * *
1233 * OUTPUT: *
1234 * *
1235 * WARNINGS: *
1236 * *
1237 * HISTORY: *
1238 * 4/7/98 GTH : Created. *
1239 *=============================================================================================*/
1240int MeshSaveClass::write_triangles(ChunkSaveClass & csave)
1241{
1242 if (!csave.Begin_Chunk(W3D_CHUNK_TRIANGLES)) {
1243 return 1;
1244 }
1245
1246 assert(Builder.Get_Face_Count() == (int)Header.NumTris);
1247 for (int i=0; i<Builder.Get_Face_Count(); i++) {
1248
1249 const MeshBuilderClass::FaceClass & face = Builder.Get_Face(i);
1250
1251 W3dTriStruct tri;
1252 memset(&tri,0,sizeof(W3dTriStruct));
1253
1254 // convert each triangle into surrender format
1255 tri.Vindex[0] = face.VertIdx[0];
1256 tri.Vindex[1] = face.VertIdx[1];
1257 tri.Vindex[2] = face.VertIdx[2];
1258
1259 tri.Attributes = face.SurfaceType;
1260 tri.Normal.X = face.Normal.X;
1261 tri.Normal.Y = face.Normal.Y;
1262 tri.Normal.Z = face.Normal.Z;
1263 tri.Dist = face.Dist;
1264
1265 // write each triangle
1266 if (csave.Write(&tri,sizeof(W3dTriStruct)) != sizeof(W3dTriStruct)) {
1267 return 1;
1268 }
1269 }
1270
1271 if (!csave.End_Chunk()) {
1272 return 1;
1273 }
1274
1275 return 0;
1276}
1277
1278int MeshSaveClass::write_vert_shade_indices(ChunkSaveClass & csave)
1279{
1280 if (!(Header.VertexChannels & W3D_VERTEX_CHANNEL_NORMAL)) return 0;
1281
1283 return 1;
1284 }
1285
1286 for (int i=0; i < Builder.Get_Vertex_Count(); i++) {
1287
1288 const MeshBuilderClass::VertClass & vert = Builder.Get_Vertex(i);
1289
1290 uint32 shade_index = vert.ShadeIndex;
1291
1292 if (csave.Write(&(shade_index),sizeof(shade_index)) != sizeof(shade_index)) {
1293 return 1;
1294 }
1295 }
1296
1297 if (!csave.End_Chunk()) {
1298 return 1;
1299 }
1300
1301 return 0;
1302}
1303
1304int MeshSaveClass::write_material_info(ChunkSaveClass & csave)
1305{
1307 return 1;
1308 }
1309
1310 W3dMaterialInfoStruct matinfo;
1311 matinfo.PassCount = MaterialDesc.Pass_Count();
1312 matinfo.VertexMaterialCount = MaterialDesc.Vertex_Material_Count();
1313 matinfo.ShaderCount = MaterialDesc.Shader_Count();
1314 matinfo.TextureCount = MaterialDesc.Texture_Count();
1315
1316 if (csave.Write(&matinfo,sizeof(matinfo)) != sizeof(matinfo)) {
1317 return 1;
1318 }
1319
1320 if (!csave.End_Chunk()) {
1321 return 1;
1322 }
1323 return 0;
1324}
1325
1326int MeshSaveClass::write_vertex_materials(ChunkSaveClass & csave)
1327{
1328 if (MaterialDesc.Vertex_Material_Count() <= 0) return 0;
1329
1330 // open a chunk which wraps all of the vertex materials
1332 return 1;
1333 }
1334
1335 for (int i=0; i<MaterialDesc.Vertex_Material_Count(); i++) {
1336
1338
1339 // write the filename
1340 const char * name = MaterialDesc.Get_Vertex_Material_Name(i);
1341 if (name != NULL) {
1343 if (csave.Write(name,strlen(name) + 1) != strlen(name) + 1) {
1344 return 1;
1345 }
1346 csave.End_Chunk();
1347 }
1348
1349 // write the struct
1350 W3dVertexMaterialStruct * vmat = MaterialDesc.Get_Vertex_Material(i);
1352 if (csave.Write(vmat,sizeof(W3dVertexMaterialStruct)) != sizeof(W3dVertexMaterialStruct)) {
1353 return 1;
1354 }
1355 csave.End_Chunk();
1356
1357 // write the mapper args
1358 const char * args = MaterialDesc.Get_Mapper_Args(i, 0);
1359 if (args != NULL) {
1361 if (csave.Write(args,strlen(args) + 1) != strlen(args) + 1) {
1362 return 1;
1363 }
1364 csave.End_Chunk();
1365 }
1366 args = MaterialDesc.Get_Mapper_Args(i, 1);
1367 if (args != NULL) {
1369 if (csave.Write(args,strlen(args) + 1) != strlen(args) + 1) {
1370 return 1;
1371 }
1372 csave.End_Chunk();
1373 }
1374
1375 csave.End_Chunk();
1376 }
1377
1378 if (!csave.End_Chunk()) {
1379 return 1;
1380 }
1381 return 0;
1382}
1383
1384int MeshSaveClass::write_shaders(ChunkSaveClass & csave)
1385{
1386 assert(MaterialDesc.Shader_Count() > 0);
1387
1388 if (PS2Material == TRUE) {
1389
1390 // Make the PC shader as close to the PS2 shader as possible.
1391 // This will allow for viewing in W3D View.
1392 setup_PC_shaders_from_PS2_shaders();
1393 }
1394
1395 if (!csave.Begin_Chunk(W3D_CHUNK_SHADERS)) {
1396 return 1;
1397 }
1398
1399 W3dShaderStruct * shader;
1400
1401 for (int i=0; i<MaterialDesc.Shader_Count(); i++) {
1402 shader = MaterialDesc.Get_Shader(i);
1403 if (csave.Write(shader,sizeof(W3dShaderStruct)) != sizeof(W3dShaderStruct)) {
1404 return 1;
1405 }
1406 }
1407
1408 if (!csave.End_Chunk()) {
1409 return 1;
1410 }
1411 return 0;
1412}
1413
1414
1415/***********************************************************************************************
1416 * MeshSaveClass::write_ps2_shaders -- Write shaders specific to the PS2 in their own chunk. *
1417 * *
1418 * *
1419 * *
1420 * *
1421 * HISTORY: *
1422 * 10/20/1999MLL: Created. *
1423 *=============================================================================================*/
1424int MeshSaveClass::write_ps2_shaders(ChunkSaveClass & csave)
1425{
1426
1427 if (!csave.Begin_Chunk(W3D_CHUNK_PS2_SHADERS)) {
1428 return 1;
1429 }
1430
1431 W3dShaderStruct *shader;
1432 W3dPS2ShaderStruct ps2shader;
1433
1434 for (int i=0; i<MaterialDesc.Shader_Count(); i++) {
1435 shader = MaterialDesc.Get_Shader(i);
1436
1437 ps2shader.AlphaTest = W3d_Shader_Get_Alpha_Test(shader);
1438 ps2shader.AParam = W3d_Shader_Get_PS2_Param_A(shader);
1439 ps2shader.BParam = W3d_Shader_Get_PS2_Param_B(shader);
1440 ps2shader.CParam = W3d_Shader_Get_PS2_Param_C(shader);
1441 ps2shader.DParam = W3d_Shader_Get_PS2_Param_D(shader);
1442
1443 // Write out the PS2 native form.
1444 switch (W3d_Shader_Get_Depth_Compare(shader))
1445 {
1447 ps2shader.DepthCompare = 0;
1448 break;
1450 ps2shader.DepthCompare = 3;
1451 break;
1453 ps2shader.DepthCompare = 1;
1454 break;
1456 ps2shader.DepthCompare = 2;
1457 break;
1458 }
1459
1460 ps2shader.DepthMask = !W3d_Shader_Get_Depth_Mask(shader);
1461
1462 switch (W3d_Shader_Get_Pri_Gradient(shader))
1463 {
1466 break;
1467
1470 break;
1471
1474 break;
1475
1478 break;
1479
1480 }
1481
1482 ps2shader.Texturing = W3d_Shader_Get_Texturing(shader);
1483
1484 if (csave.Write(&ps2shader,sizeof(W3dPS2ShaderStruct)) != sizeof(W3dPS2ShaderStruct)) {
1485 return 1;
1486 }
1487 }
1488
1489 if (!csave.End_Chunk()) {
1490 return 1;
1491 }
1492
1493 return (0);
1494}
1495
1496void MeshSaveClass::setup_PC_shaders_from_PS2_shaders()
1497{
1498
1499 W3dShaderStruct *shader;
1500
1501 for (int i=0; i<MaterialDesc.Shader_Count(); i++) {
1502 shader = MaterialDesc.Get_Shader(i);
1503
1504 // DepthCompare on the PS2 doesn't have as many options as on the PC.
1505 switch (W3d_Shader_Get_Depth_Compare(shader))
1506 {
1509 break;
1512 break;
1515 break;
1518 break;
1519 }
1520
1521 // The PS2 has more gradient functions than the PC.
1522 switch (W3d_Shader_Get_Pri_Gradient(shader))
1523 {
1526 break;
1527
1528 // No PC equivalent. Set to default: modulate.
1533 break;
1534 }
1535
1536
1537 }
1538
1539}
1540
1541int MeshSaveClass::write_textures(ChunkSaveClass & csave)
1542{
1543 if (MaterialDesc.Texture_Count() <= 0) return 0;
1544
1545 // open a chunk which wraps all textures
1546 if (!csave.Begin_Chunk(W3D_CHUNK_TEXTURES)) {
1547 return 1;
1548 }
1549
1550 for (int i=0; i<MaterialDesc.Texture_Count(); i++) {
1551
1552 W3dMapClass * map = MaterialDesc.Get_Texture(i);
1553
1555
1556 // write the filename
1558 if (csave.Write(map->Filename,strlen(map->Filename) + 1) != strlen(map->Filename) + 1) return 1;
1559 csave.End_Chunk();
1560
1561 // optionally write an animation info chunk
1562 if (map->AnimInfo != NULL) {
1564 if (csave.Write(map->AnimInfo,sizeof(W3dTextureInfoStruct)) != sizeof(W3dTextureInfoStruct)) return 1;
1565 csave.End_Chunk();
1566 }
1567
1568 csave.End_Chunk();
1569 }
1570
1571 if (!csave.End_Chunk()) {
1572 return 1;
1573 }
1574 return 0;
1575}
1576
1577int MeshSaveClass::write_pass(ChunkSaveClass & csave,int pass)
1578{
1579 assert(pass >= 0);
1580 assert(pass < MaterialDesc.Pass_Count());
1581
1583 return 1;
1584 }
1585
1586 const MeshBuilderClass::MeshStatsStruct & stats = Builder.Get_Mesh_Stats();
1587
1588 if (stats.HasVertexMaterial[pass]) {
1589 write_vertex_material_ids(csave,pass);
1590 }
1591
1592 if (stats.HasShader[pass]) {
1593 write_shader_ids(csave,pass);
1594 }
1595
1596 if (stats.HasDiffuseColor[pass] || DeformSave.Does_Deformer_Modify_DCG ()) {
1597 write_dcg(csave,pass);
1598 }
1599
1600 for (int stage = 0; stage < MeshBuilderClass::MAX_STAGES; stage++) {
1601 write_texture_stage(csave,pass,stage);
1602 }
1603
1604 if (!csave.End_Chunk()) {
1605 return 1;
1606 }
1607 return 0;
1608}
1609
1610int MeshSaveClass::write_vertex_material_ids(ChunkSaveClass & csave,int pass)
1611{
1612 const MeshBuilderClass::MeshStatsStruct & stats = Builder.Get_Mesh_Stats();
1613
1615 return 1;
1616 }
1617
1618 uint32 matid;
1619
1620 if (stats.HasPerVertexMaterial[pass]) {
1621 for (int i=0; i<Builder.Get_Vertex_Count(); i++) {
1622 matid = Builder.Get_Vertex(i).VertexMaterialIndex[pass];
1623 if (csave.Write(&matid,sizeof(uint32)) != sizeof(uint32)) return 1;
1624 }
1625 } else {
1626 matid = Builder.Get_Vertex(0).VertexMaterialIndex[pass];
1627 if (csave.Write(&matid,sizeof(uint32)) != sizeof(uint32)) return 1;
1628 }
1629
1630 if (!csave.End_Chunk()) {
1631 return 1;
1632 }
1633 return 0;
1634}
1635
1636int MeshSaveClass::write_shader_ids(ChunkSaveClass & csave,int pass)
1637{
1638 const MeshBuilderClass::MeshStatsStruct & stats = Builder.Get_Mesh_Stats();
1639
1640 if (!csave.Begin_Chunk(W3D_CHUNK_SHADER_IDS)) {
1641 return 1;
1642 }
1643
1644 uint32 shaderid;
1645 if (stats.HasPerPolyShader[pass]) {
1646 for (int i=0; i<Builder.Get_Face_Count(); i++) {
1647 shaderid = Builder.Get_Face(i).ShaderIndex[pass];
1648 if (csave.Write(&shaderid,sizeof(uint32)) != sizeof(uint32)) return 1;
1649 }
1650 } else {
1651 shaderid = Builder.Get_Face(0).ShaderIndex[pass];
1652 if (csave.Write(&shaderid,sizeof(uint32)) != sizeof(uint32)) return 1;
1653 }
1654
1655 if (!csave.End_Chunk()) {
1656 return 1;
1657 }
1658 return 0;
1659}
1660
1661int MeshSaveClass::write_dcg(ChunkSaveClass & csave,int pass)
1662{
1663 const MeshBuilderClass::MeshStatsStruct & stats = Builder.Get_Mesh_Stats();
1664
1665 if (!csave.Begin_Chunk(W3D_CHUNK_DCG)) {
1666 return 1;
1667 }
1668
1669 for (int i=0; i<Builder.Get_Vertex_Count(); i++) {
1670 Vector3 vcolor = Builder.Get_Vertex(i).DiffuseColor[pass];
1671 W3dRGBAStruct color;
1672 color.R = (uint8)(255.0f * vcolor.X);
1673 color.G = (uint8)(255.0f * vcolor.Y);
1674 color.B = (uint8)(255.0f * vcolor.Z);
1675
1676 float a = Builder.Get_Vertex(i).Alpha[pass];
1677 color.A = (uint8)(255.0f * a);
1678
1679 if (csave.Write(&(color),sizeof(W3dRGBAStruct)) != sizeof(W3dRGBAStruct)) {
1680 return 1;
1681 }
1682 }
1683
1684 if (!csave.End_Chunk()) {
1685 return 1;
1686 }
1687 return 0;
1688}
1689
1690int MeshSaveClass::write_texture_stage(ChunkSaveClass & csave,int pass,int stage)
1691{
1692 const MeshBuilderClass::MeshStatsStruct & stats = Builder.Get_Mesh_Stats();
1693 if (!stats.HasTexture[pass][stage]) return 0;
1694
1696 return 1;
1697 }
1698
1699 write_texture_ids(csave,pass,stage);
1700 write_texture_coords(csave,pass,stage);
1701
1702 if (!csave.End_Chunk()) {
1703 return 1;
1704 }
1705 return 0;
1706}
1707
1708
1709int MeshSaveClass::write_texture_ids(ChunkSaveClass & csave,int pass,int stage)
1710{
1711 const MeshBuilderClass::MeshStatsStruct & stats = Builder.Get_Mesh_Stats();
1712
1713 if (!csave.Begin_Chunk(W3D_CHUNK_TEXTURE_IDS)) {
1714 return 1;
1715 }
1716
1717 uint32 texid;
1718 if (stats.HasPerPolyTexture[pass][stage]) {
1719 for (int i=0; i<Builder.Get_Face_Count(); i++) {
1720 texid = Builder.Get_Face(i).TextureIndex[pass][stage];
1721 if (csave.Write(&texid,sizeof(uint32)) != sizeof(uint32)) return 1;
1722 }
1723 } else {
1724 texid = Builder.Get_Face(0).TextureIndex[pass][stage];
1725 if (csave.Write(&texid,sizeof(uint32)) != sizeof(uint32)) return 1;
1726 }
1727
1728 if (!csave.End_Chunk()) {
1729 return 1;
1730 }
1731 return 0;
1732}
1733
1734int MeshSaveClass::write_texture_coords(ChunkSaveClass & csave,int pass,int stage)
1735{
1736 const MeshBuilderClass::MeshStatsStruct & stats = Builder.Get_Mesh_Stats();
1737 if (stats.HasTexCoords[pass][stage] == false) return 0;
1738
1740 return 1;
1741 }
1742
1743 for (int i=0; i<Builder.Get_Vertex_Count(); i++) {
1744 W3dTexCoordStruct tex;
1745 tex.U = Builder.Get_Vertex(i).TexCoord[pass][stage].X;
1746 tex.V = Builder.Get_Vertex(i).TexCoord[pass][stage].Y;
1747
1748 if (csave.Write(&(tex),sizeof(W3dTexCoordStruct)) != sizeof(W3dTexCoordStruct)) {
1749 return 1;
1750 }
1751 }
1752
1753 if (!csave.End_Chunk()) {
1754 return 1;
1755 }
1756 return 0;
1757}
1758
1759int MeshSaveClass::write_aabtree(ChunkSaveClass & csave)
1760{
1761 /*
1762 ** Don't bother with an AABTree if this not a normal mesh or if it has very few polygons
1763 */
1764 if ( (Builder.Get_Face_Count() >= MIN_AABTREE_POLYGONS) &&
1766 )
1767 {
1768
1769 /*
1770 ** Build temporary array representations of the mesh
1771 */
1772 int vertcount = Builder.Get_Vertex_Count();
1773 int polycount = Builder.Get_Face_Count();
1774 Vector3 * verts = new Vector3[vertcount];
1775 Vector3i * polys = new Vector3i[polycount];
1776
1777 for (int vi=0; vi<vertcount; vi++) {
1778 verts[vi] = Builder.Get_Vertex(vi).Position;
1779 }
1780
1781 for (int pi=0; pi<polycount; pi++) {
1782 polys[pi].I = Builder.Get_Face(pi).VertIdx[0];
1783 polys[pi].J = Builder.Get_Face(pi).VertIdx[1];
1784 polys[pi].K = Builder.Get_Face(pi).VertIdx[2];
1785 }
1786
1787 /*
1788 ** Build the AABTree and save it
1789 */
1790 AABTreeBuilderClass aabtree_builder;
1791 aabtree_builder.Build_AABTree(polycount,polys,vertcount,verts);
1792 aabtree_builder.Export(csave);
1793
1794 /*
1795 ** Release the allocated resources
1796 */
1797 delete[] verts;
1798 delete[] polys;
1799 }
1800
1801 return 0;
1802}
1803
1804int MeshSaveClass::scan_used_materials(Mesh & mesh,Mtl * nodemtl)
1805{
1806 int face_index;
1807 int mat_index;
1808
1809 if ((nodemtl == NULL) || (nodemtl->NumSubMtls() <= 1)) {
1810
1811 MaterialRemapTable = new int[1];
1812 MaterialRemapTable[0] = 0;
1813 return 1;
1814
1815 } else {
1816
1817 int sub_mtl_count = nodemtl->NumSubMtls();
1818 MaterialRemapTable = new int[sub_mtl_count];
1819
1820 // Initialize each remap to -1 (indicates that the material is un-used)
1821 for (mat_index=0; mat_index<sub_mtl_count; mat_index++) {
1822 MaterialRemapTable[mat_index] = -1;
1823 }
1824
1825 // Set a 1 for each material actually referenced by the mesh
1826 for (face_index=0; face_index<mesh.getNumFaces(); face_index++) {
1827 int max_mat_index = mesh.faces[face_index].getMatID();
1828 int mat_index = (max_mat_index % sub_mtl_count);
1829 MaterialRemapTable[mat_index] = 1;
1830 }
1831
1832 // Replace each 1 entry with an incrementing material index
1833 int matcount = 0;
1834 for (mat_index=0; mat_index<sub_mtl_count; mat_index++) {
1835 if (MaterialRemapTable[mat_index] == 1) {
1836 MaterialRemapTable[mat_index] = matcount;
1837 matcount++;
1838 }
1839 }
1840
1841 assert(matcount > 0);
1842 return matcount;
1843 }
1844}
1845
1846//Check if material is solid, non-textured.
1848{
1849 Texmap * tmap;
1850
1851 tmap = mtl->GetSubTexmap(ID_DI);
1852 if (mtl->ClassID() == GameMaterialClassID)
1853 {
1854 GameMtl * gamemtl=(GameMtl *)mtl;
1855
1856 for (int pass=0;pass<gamemtl->Get_Pass_Count(); pass++)
1857 {
1858 for (int stage=0; stage < W3dMaterialClass::MAX_STAGES; stage++)
1859 { if (gamemtl->Get_Texture_Enable(pass,stage) && gamemtl->Get_Texture(pass,stage))
1860 return 1; //using a texture
1861 }
1862 }
1863 return 0;
1864 }
1865 else
1866 {
1867 return (tmap && tmap->ClassID() == Class_ID(BMTEX_CLASS_ID,0));
1868 }
1869}
1870
1871//count number of used solid materials (no texture)
1872int MeshSaveClass::getNumSolidMaterials(Mtl * nodemtl)
1873{
1874 int mat_index;
1875 int numSolid=0;
1876
1877 if ((nodemtl == NULL) || (nodemtl->NumSubMtls() <= 1))
1878 { //Check if diffuse texture present
1879 if (isTexturedMaterial(nodemtl))
1880 return 00;
1881 return 1;
1882 }
1883 else
1884 {
1885 int sub_mtl_count = nodemtl->NumSubMtls();
1886
1887 for (mat_index=0; mat_index<sub_mtl_count; mat_index++)
1888 {
1889 if (MaterialRemapTable[mat_index] != -1)
1890 { //material is used on some faces
1891 if (isTexturedMaterial(nodemtl->GetSubMtl(mat_index)))
1892 continue;
1893 numSolid++;
1894 }
1895 }
1896 return numSolid;
1897 }
1898}
1899
1900//Cancels out the material colors by setting them to white.
1901//Also changes prefix on texture names to use DIFFUSE_HOUSECOLOR_TEXTURE_PREFIX
1902//if house color is used.
1903void MeshSaveClass::fix_diffuse_materials(bool isHouseColor)
1904{
1905 uint8 color=255;
1906 char materialColorFilename[_MAX_FNAME + 1];
1907
1908 for (int mat_index=0; mat_index<MaterialDesc.Material_Count(); mat_index++)
1909 {
1910 for (int pass=0; pass<MaterialDesc.Pass_Count(); pass++)
1911 {
1912 W3dVertexMaterialStruct *vmat=MaterialDesc.Get_Vertex_Material(mat_index,pass);
1913
1914 for (int stage=0; stage<W3dMaterialClass::MAX_STAGES; stage++)
1915 {
1916 W3dMapClass *map3d=MaterialDesc.Get_Texture(mat_index,pass,stage);
1917 if (map3d && map3d->Filename && (*((unsigned int *)map3d->Filename) & 0xffff00ff) == DIFFUSE_COLOR_TEXTURE_MASK) //check for 'TXC^' prefix
1918 { //found a material which had its material color replaced by a texture
1919 //set the material color to white so it's not being used.
1920 vmat->Diffuse.Set(color,color,color);
1921 vmat->Ambient.Set(color,color,color);
1922
1923 if (isHouseColor && *(map3d->Filename+1) != 'H')
1924 { //our material texture contains house colors, adjust the name
1925 //by adding H prefix.
1926 sprintf(materialColorFilename,"%s%s","ZHCD",map3d->Filename+4);
1927 map3d->Set_Filename(materialColorFilename);
1928 }
1929 }
1930 }
1931 }
1932 }
1933}
1934
1935/***********************************************************************************************
1936 * MeshSaveClass::create_materials -- create the materials for this mesh *
1937 * *
1938 * INPUT: *
1939 * *
1940 * OUTPUT: *
1941 * *
1942 * WARNINGS: *
1943 * *
1944 * HISTORY: *
1945 * 10/26/1997 GH : Created. *
1946 * 2/8/99 GTH : modified to use the MaterialRemapTable *
1947 *=============================================================================================*/
1948void MeshSaveClass::create_materials(Mtl * nodemtl,DWORD wirecolor, char *materialColorTexture)
1949{
1950 bool domaps = !use_simple_rendering(Header.Attributes);
1951
1953 // Create materials
1954 // Four cases:
1955 // - Creating a collision object: use a hard-coded material
1956 // - The material is null: use wire color
1957 // - The material is a simple material: create one material
1958 // - The material is a multi-material: create n materials
1960 int geo_type = Header.Attributes & W3D_MESH_FLAG_GEOMETRY_TYPE_MASK;
1961 if ((geo_type == W3D_MESH_FLAG_GEOMETRY_TYPE_AABOX) ||
1962 (geo_type == W3D_MESH_FLAG_GEOMETRY_TYPE_OBBOX))
1963 {
1964 Header.NumMaterials = 1;
1965
1966 W3dVertexMaterialStruct vmat;
1967 W3dShaderStruct shader;
1968 W3dMaterialClass material;
1969
1970 Color diffuse;
1971 if (Header.Attributes & W3D_MESH_FLAG_COLLISION_TYPE_PHYSICAL) {
1972 diffuse.r = 0.0f;
1973 diffuse.g = 0.0f;
1974 diffuse.b = 1.0f;
1975 } else {
1976 diffuse.r = 0.4f;
1977 diffuse.g = 1.0f;
1978 diffuse.b = 0.4f;
1979 }
1980
1981 W3d_Shader_Reset(&shader);
1984
1986 vmat.Opacity = 0.5f;
1987
1988 // add material 0
1989 vmat.Diffuse.R = (uint8)(diffuse.r * 255.0f);
1990 vmat.Diffuse.G = (uint8)(diffuse.g * 255.0f);
1991 vmat.Diffuse.B = (uint8)(diffuse.b * 255.0f);
1992 material.Set_Pass_Count(1);
1993 material.Set_Vertex_Material(vmat,0);
1994 material.Set_Shader(shader,0);
1995 MaterialDesc.Add_Material(material);
1996
1997 assert(MaterialDesc.Material_Count() == 1);
1998
1999 } else if (!nodemtl) {
2000
2001 // Create a single material using the wire color
2002 Header.NumMaterials = 1;
2003
2004 W3dVertexMaterialStruct vmat;
2005 W3dShaderStruct shader;
2006 W3dMaterialClass material;
2007
2009 W3d_Shader_Reset(&shader);
2010
2011 vmat.Diffuse.R = GetRValue(wirecolor);
2012 vmat.Diffuse.G = GetGValue(wirecolor);
2013 vmat.Diffuse.B = GetBValue(wirecolor);
2014
2015 material.Set_Pass_Count(1);
2016 material.Set_Vertex_Material(vmat,0);
2017 material.Set_Shader(shader,0);
2018
2019 MaterialDesc.Add_Material(material,"WireColor");
2020 assert(MaterialDesc.Material_Count() == 1);
2021
2022 } else if (!nodemtl->IsMultiMtl()) {
2023
2024 Header.NumMaterials = 1;
2025 W3dMaterialClass mat;
2026
2027 if (isTexturedMaterial(nodemtl) == 0)
2028 mat.Init(nodemtl,materialColorTexture);
2029 else
2030 mat.Init(nodemtl,NULL);
2031
2033 err = MaterialDesc.Add_Material(mat,nodemtl->GetName());
2035 sprintf(_string1,"Exporting Materials for Mesh: %s\nMaterial %s is multi-pass and transparent\nMulti-pass transparent materials are not allowed.\n",
2036 Header.MeshName,
2037 nodemtl->GetName());
2038 ExportLog::printf(_string1);
2039 throw ErrorClass(_string1);
2040 }
2041 assert(MaterialDesc.Material_Count() == 1);
2042
2043 } else {
2044
2045 Header.NumMaterials = nodemtl->NumSubMtls();
2046 W3dMaterialClass mat;
2047
2048 for (unsigned mi = 0; mi < Header.NumMaterials; mi++) {
2049
2050 // only process materials that were found to be used in the scan_used_materials call
2051 if (MaterialRemapTable[mi] != -1) {
2052
2053 if (isTexturedMaterial(nodemtl->GetSubMtl(mi)) == 0)
2054 mat.Init(nodemtl->GetSubMtl(mi),materialColorTexture);
2055 else
2056 mat.Init(nodemtl->GetSubMtl(mi),NULL);
2057
2058 char * name;
2060
2061 name = nodemtl->GetSubMtl(mi)->GetName();
2062 err = MaterialDesc.Add_Material(mat,name);
2063
2065 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",
2066 Header.MeshName,
2067 nodemtl->GetSubMtl(mi)->GetName(),
2068 mat.Get_Pass_Count(),
2069 MaterialDesc.Pass_Count());
2070 ExportLog::printf(_string1);
2071 throw ErrorClass(_string1);
2072 }
2074 sprintf(_string1,"Exporting Materials for Mesh: %s\nMaterial %s is multi-pass and transparent\nMulti-pass transparent materials are not allowed.\n",
2075 Header.MeshName,
2076 nodemtl->GetSubMtl(mi)->GetName());
2077 throw ErrorClass(_string1);
2078 }
2080 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",
2081 Header.MeshName,
2082 nodemtl->GetSubMtl(mi)->GetName());
2083 ExportLog::printf(_string1);
2084 throw ErrorClass(_string1);
2085 }
2086 }
2087 }
2088 }
2089
2090 // Store the material's sort level in the mesh header.
2091 Header.SortLevel = MaterialDesc.Get_Sort_Level();
2092}
2093
2094/***********************************************************************************************
2095 * MeshSaveClass::compute_bounding_volumes -- computes a bounding box and bounding sphere for *
2096 * *
2097 * INPUT: *
2098 * *
2099 * OUTPUT: *
2100 * *
2101 * WARNINGS: *
2102 * *
2103 * HISTORY: *
2104 * 08/01/1997 GH : Created. *
2105 *=============================================================================================*/
2106void MeshSaveClass::compute_bounding_volumes(void)
2107{
2108 Vector3 min,max,center;
2109 float radius;
2110
2111 Builder.Compute_Bounding_Box(&min,&max);
2112 Builder.Compute_Bounding_Sphere(&center,&radius);
2113
2114 Header.SphCenter.X = center.X;
2115 Header.SphCenter.Y = center.Y;
2116 Header.SphCenter.Z = center.Z;
2117 Header.SphRadius = radius;
2118
2119 Header.Min.X = min.X;
2120 Header.Min.Y = min.Y;
2121 Header.Min.Z = min.Z;
2122 Header.Max.X = max.X;
2123 Header.Max.Y = max.Y;
2124 Header.Max.Z = max.Z;
2125}
2126
2127
2128/***********************************************************************************************
2129 * MeshSaveClass::compute_physical_properties -- computes the volume and moment of inertia *
2130 * *
2131 * INPUT: *
2132 * *
2133 * OUTPUT: *
2134 * *
2135 * WARNINGS: *
2136 * *
2137 * HISTORY: *
2138 * 08/01/1997 GH : Created. *
2139 *=============================================================================================*/
2140void MeshSaveClass::compute_physical_constants
2141(
2142 INode * inode,
2143 Progress_Meter_Class & meter,
2144 bool voxelize
2145)
2146{
2147
2148#if 0 // IF we need this again, move the data to a physics chunk (header doesn't have it anymore)
2149
2150 if (voxelize) {
2151
2152 // Create an INodeList object for this mesh
2153 AnyINodeFilter nodefilt;
2154 INodeListClass meshlist(CurTime,&nodefilt);
2155 meshlist.Insert(inode);
2156
2157 // Create a Voxel object for this mesh
2158 VoxelClass * voxel = new VoxelClass
2159 (
2160 meshlist,
2162 ExportSpace,
2163 CurTime,
2164 meter
2165 );
2166
2167#if DEBUG_VOXELS
2168 VoxelDebugWindowClass dbgwin(voxel);
2169 dbgwin.Display_Window();
2170#endif
2171
2172 double vol[1];
2173 double cm[3];
2174 double inertia[9];
2175
2176 voxel->Compute_Physical_Properties(vol,cm,inertia);
2177
2178 Header.Volume = (float)vol[0];
2179
2180 Header.MassCenter.X = (float)cm[0];
2181 Header.MassCenter.Y = (float)cm[1];
2182 Header.MassCenter.Z = (float)cm[2];
2183
2184 Header.Inertia[0] = (float)inertia[0];
2185 Header.Inertia[1] = (float)inertia[1];
2186 Header.Inertia[2] = (float)inertia[2];
2187 Header.Inertia[3] = (float)inertia[3];
2188 Header.Inertia[4] = (float)inertia[4];
2189 Header.Inertia[5] = (float)inertia[5];
2190 Header.Inertia[6] = (float)inertia[6];
2191 Header.Inertia[7] = (float)inertia[7];
2192 Header.Inertia[8] = (float)inertia[8];
2193
2194 } else {
2195
2196 // Set mass center to the center of the bounding box
2197 Header.MassCenter.X = (Header.Max.X + Header.Min.X) / 2.0f;
2198 Header.MassCenter.Y = (Header.Max.Y + Header.Min.Y) / 2.0f;
2199 Header.MassCenter.Z = (Header.Max.Z + Header.Min.Z) / 2.0f;
2200
2201 // Set inertia tensor to inertia tensor of the bounding box
2202 // (gth) !!!! DO THIS !!!!
2203 Header.Inertia[0] = 1.0f;
2204 Header.Inertia[1] = 0.0f;
2205 Header.Inertia[2] = 0.0f;
2206 Header.Inertia[3] = 0.0f;
2207 Header.Inertia[4] = 1.0f;
2208 Header.Inertia[5] = 0.0f;
2209 Header.Inertia[6] = 0.0f;
2210 Header.Inertia[7] = 0.0f;
2211 Header.Inertia[8] = 1.0f;
2212
2213 Header.Volume = (Header.Max.X - Header.Min.X) * (Header.Max.Y - Header.Min.Y) * (Header.Max.Z - Header.Min.Z);
2214 }
2215
2216#endif
2217}
2218
2219
2220/***********************************************************************************************
2221 * MeshSaveClass::prep_mesh -- pre-transform the MAX mesh by a specified matrix *
2222 * *
2223 * INPUT: *
2224 * *
2225 * OUTPUT: *
2226 * *
2227 * WARNINGS: *
2228 * *
2229 * HISTORY: *
2230 * 08/01/1997 GH : Created. *
2231 *=============================================================================================*/
2232void MeshSaveClass::prep_mesh(Mesh & mesh,Matrix3 & objoff)
2233{
2234 int vert_index;
2235
2236 // Transform the mesh's vertices so that they are relative to the coordinate
2237 // system that we want to use with the mesh
2238 for (vert_index = 0; vert_index < mesh.getNumVerts (); vert_index++) {
2239 mesh.verts[vert_index] = mesh.verts[vert_index] * objoff;
2240 }
2241
2242 // Re-Build the normals.
2243 mesh.buildNormals();
2244}
2245
2246
#define ALPHA_VERTEX_CHANNEL
#define NULL
Definition BaseType.h:92
#define TRUE
Definition BaseType.h:109
#define FALSE
Definition BaseType.h:113
#define min(x, y)
Definition BaseType.h:101
#define max(x, y)
Definition BaseType.h:105
#define DebugPrint
Definition DebugPrint.h:60
int W3d_Shader_Get_Depth_Compare(const W3dPS2ShaderStruct *s)
Definition w3d_file.h:975
void W3d_Shader_Reset(W3dShaderStruct *s)
Definition w3d_file.h:925
int W3d_Shader_Get_PS2_Param_D(const W3dShaderStruct *s)
Definition w3d_file.h:968
int W3d_Shader_Get_Pri_Gradient(const W3dPS2ShaderStruct *s)
Definition w3d_file.h:977
#define W3D_MESH_FLAG_COLLISION_TYPE_PHYSICAL
Definition w3d_file.h:1145
int W3d_Shader_Get_PS2_Param_B(const W3dShaderStruct *s)
Definition w3d_file.h:966
#define W3D_MESH_FLAG_GEOMETRY_TYPE_MASK
Definition w3d_file.h:1157
#define W3D_MESH_FLAG_COLLISION_TYPE_VIS
Definition w3d_file.h:1147
#define W3D_MESH_FLAG_TWO_SIDED
Definition w3d_file.h:1152
void W3d_Shader_Set_Dest_Blend_Func(W3dShaderStruct *s, int val)
Definition w3d_file.h:946
@ W3DSHADER_PRIGRADIENT_MODULATE
Definition w3d_file.h:783
@ W3DSHADER_DEPTHCOMPARE_PASS_LESS
Definition w3d_file.h:756
@ W3DSHADER_SRCBLENDFUNC_SRC_ALPHA
Definition w3d_file.h:796
@ W3DSHADER_DESTBLENDFUNC_ONE_MINUS_SRC_ALPHA
Definition w3d_file.h:778
@ W3DSHADER_DEPTHCOMPARE_PASS_NEVER
Definition w3d_file.h:755
@ W3DSHADER_DEPTHCOMPARE_PASS_ALWAYS
Definition w3d_file.h:762
@ W3DSHADER_DEPTHCOMPARE_PASS_LEQUAL
Definition w3d_file.h:758
#define OBSOLETE_W3D_MESH_FLAG_GEOMETRY_TYPE_SHADOW
Definition w3d_file.h:1161
#define W3D_MESH_FLAG_NONE
Definition w3d_file.h:1137
#define W3D_MESH_FLAG_COLLISION_TYPE_PROJECTILE
Definition w3d_file.h:1146
#define W3D_MESH_FLAG_COLLISION_TYPE_VEHICLE
Definition w3d_file.h:1149
#define W3D_NAME_LEN
Definition w3d_file.h:319
#define W3D_MESH_FLAG_GEOMETRY_TYPE_OBBOX
Definition w3d_file.h:1163
int W3d_Shader_Get_PS2_Param_A(const W3dShaderStruct *s)
Definition w3d_file.h:965
void W3d_Shader_Set_Pri_Gradient(W3dShaderStruct *s, int val)
Definition w3d_file.h:947
void W3d_Shader_Set_Src_Blend_Func(W3dShaderStruct *s, int val)
Definition w3d_file.h:949
#define W3D_MESH_FLAG_HIDDEN
Definition w3d_file.h:1151
#define W3D_VERTEX_CHANNEL_BONEID
Definition w3d_file.h:1190
#define W3D_MESH_FLAG_NPATCHABLE
Definition w3d_file.h:1173
IOVector3Struct W3dVectorStruct
Definition w3d_file.h:532
#define W3D_MESH_FLAG_CAST_SHADOW
Definition w3d_file.h:1155
@ W3D_CHUNK_TEXTURE_NAME
Definition w3d_file.h:368
@ W3D_CHUNK_STAGE_TEXCOORDS
Definition w3d_file.h:380
@ W3D_CHUNK_MATERIAL_PASS
Definition w3d_file.h:371
@ W3D_CHUNK_TRIANGLES
Definition w3d_file.h:347
@ W3D_CHUNK_TEXTURE_INFO
Definition w3d_file.h:369
@ W3D_CHUNK_DCG
Definition w3d_file.h:374
@ W3D_CHUNK_VERTEX_MAPPER_ARGS1
Definition w3d_file.h:364
@ W3D_CHUNK_VERTEX_SHADE_INDICES
Definition w3d_file.h:348
@ W3D_CHUNK_MESH
Definition w3d_file.h:341
@ W3D_CHUNK_MESH_USER_TEXT
Definition w3d_file.h:344
@ W3D_CHUNK_VERTEX_NORMALS
Definition w3d_file.h:343
@ W3D_CHUNK_SHADERS
Definition w3d_file.h:357
@ W3D_CHUNK_VERTEX_MATERIALS
Definition w3d_file.h:359
@ W3D_CHUNK_TEXTURE
Definition w3d_file.h:367
@ W3D_CHUNK_TEXTURE_STAGE
Definition w3d_file.h:378
@ W3D_CHUNK_PS2_SHADERS
Definition w3d_file.h:389
@ W3D_CHUNK_TEXTURES
Definition w3d_file.h:366
@ W3D_CHUNK_VERTEX_MATERIAL_NAME
Definition w3d_file.h:361
@ W3D_CHUNK_MESH_HEADER3
Definition w3d_file.h:346
@ W3D_CHUNK_VERTEX_MAPPER_ARGS0
Definition w3d_file.h:363
@ W3D_CHUNK_VERTEX_MATERIAL
Definition w3d_file.h:360
@ W3D_CHUNK_VERTEX_INFLUENCES
Definition w3d_file.h:345
@ W3D_CHUNK_SHADER_IDS
Definition w3d_file.h:373
@ W3D_CHUNK_VERTEX_MATERIAL_INFO
Definition w3d_file.h:362
@ W3D_CHUNK_VERTICES
Definition w3d_file.h:342
@ W3D_CHUNK_TEXTURE_IDS
Definition w3d_file.h:379
@ W3D_CHUNK_VERTEX_MATERIAL_IDS
Definition w3d_file.h:372
@ W3D_CHUNK_MATERIAL_INFO
Definition w3d_file.h:355
int W3d_Shader_Get_Alpha_Test(const W3dPS2ShaderStruct *s)
Definition w3d_file.h:979
#define W3D_MESH_FLAG_COLLISION_TYPE_CAMERA
Definition w3d_file.h:1148
#define W3D_MESH_FLAG_GEOMETRY_TYPE_NORMAL
Definition w3d_file.h:1158
#define W3D_MESH_FLAG_SHATTERABLE
Definition w3d_file.h:1172
void W3d_Vertex_Material_Reset(W3dVertexMaterialStruct *vmat)
Definition w3d_file.h:738
#define W3D_MESH_FLAG_GEOMETRY_TYPE_AABOX
Definition w3d_file.h:1162
int W3d_Shader_Get_PS2_Param_C(const W3dShaderStruct *s)
Definition w3d_file.h:967
@ PSS_DEPTHCOMPARE_PASS_LESS
Definition w3d_file.h:860
@ PSS_DEPTHCOMPARE_PASS_NEVER
Definition w3d_file.h:859
@ PSS_PS2_PRIGRADIENT_DECAL
Definition w3d_file.h:854
@ PSS_DEPTHCOMPARE_PASS_ALWAYS
Definition w3d_file.h:861
@ PSS_PRIGRADIENT_HIGHLIGHT
Definition w3d_file.h:849
@ PSS_PS2_PRIGRADIENT_HIGHLIGHT2
Definition w3d_file.h:856
@ PSS_PS2_PRIGRADIENT_MODULATE
Definition w3d_file.h:853
@ PSS_PRIGRADIENT_MODULATE
Definition w3d_file.h:848
@ PSS_PRIGRADIENT_HIGHLIGHT2
Definition w3d_file.h:850
@ PSS_PRIGRADIENT_DECAL
Definition w3d_file.h:847
@ PSS_PS2_PRIGRADIENT_HIGHLIGHT
Definition w3d_file.h:855
@ PSS_DEPTHCOMPARE_PASS_LEQUAL
Definition w3d_file.h:862
int W3d_Shader_Get_Depth_Mask(const W3dPS2ShaderStruct *s)
Definition w3d_file.h:976
void W3d_Shader_Set_Depth_Compare(W3dShaderStruct *s, int val)
Definition w3d_file.h:944
#define W3D_MESH_FLAG_GEOMETRY_TYPE_SKIN
Definition w3d_file.h:1160
#define W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ALIGNED
Definition w3d_file.h:1159
int W3d_Shader_Get_Texturing(const W3dPS2ShaderStruct *s)
Definition w3d_file.h:978
#define W3D_VERTEX_CHANNEL_LOCATION
Definition w3d_file.h:1186
#define W3D_CURRENT_MESH_VERSION
Definition w3d_file.h:1184
#define W3D_FACE_CHANNEL_FACE
Definition w3d_file.h:1192
#define W3D_VERTEX_CHANNEL_NORMAL
Definition w3d_file.h:1187
#define W3D_MESH_FLAG_GEOMETRY_TYPE_CAMERA_ORIENTED
Definition w3d_file.h:1164
unsigned long uint32
Definition bittype.h:46
unsigned char uint8
Definition bittype.h:44
unsigned long DWORD
Definition bittype.h:57
Int Color
Definition Xfer.h:45
void Build_AABTree(int polycount, TriIndex *polys, int vertcount, Vector3 *verts)
void Export(ChunkSaveClass &csave)
uint32 Write(const void *buf, uint32 nbytes)
Definition chunkio.cpp:264
bool Begin_Chunk(uint32 id)
Definition chunkio.cpp:108
bool End_Chunk()
Definition chunkio.cpp:148
static void printf(char *,...)
int Get_Texture_Enable(int pass, int stage)
Definition GameMtl.cpp:2661
Texmap * Get_Texture(int pass, int stage)
Definition GameMtl.cpp:2791
int Get_Pass_Count(void)
Definition GameMtl.cpp:2529
int ShaderIndex[MAX_PASSES]
Definition meshbuild.h:167
int TextureIndex[MAX_PASSES][MAX_STAGES]
Definition meshbuild.h:166
Vector3 DiffuseColor[MAX_PASSES]
Definition meshbuild.h:132
int VertexMaterialIndex[MAX_PASSES]
Definition meshbuild.h:136
float Alpha[MAX_PASSES]
Definition meshbuild.h:135
Vector2 TexCoord[MAX_PASSES][MAX_STAGES]
Definition meshbuild.h:131
MeshSaveClass(char *mesh_name, char *container_name, INode *inode, const Mesh *input_mesh, Matrix3 &exportspace, W3DAppData2Struct &exportoptions, HierarchySaveClass *htree, TimeValue curtime, Progress_Meter_Class &meter, unsigned int *materialColors, int &numMaterialColors, int &numHouseColors, char *materialColorTexture, WorldInfoClass *world_info=NULL)
Definition meshsave.cpp:234
int Write_To_File(ChunkSaveClass &csave, bool export_aabtrees=false)
Definition meshsave.cpp:935
~MeshSaveClass(void)
Definition meshsave.cpp:433
void Finish_In_Steps(int number_of_steps)
Definition PROGRESS.H:74
Tab< InfluenceStruct > VertData
Definition skindata.h:147
RefTargetHandle GetReference(int i)
Definition skin.cpp:730
INodeTab BoneTab
Definition skin.h:194
float Y
Definition vector2.h:79
float X
Definition vector2.h:74
float X
Definition vector3.h:90
float Z
Definition vector3.h:92
float Y
Definition vector3.h:91
int J
Definition Vector3i.h:52
int K
Definition Vector3i.h:53
int I
Definition Vector3i.h:51
void Compute_Physical_Properties(double Volume[1], double CM[3], double I[9])
Definition vxl.cpp:616
void Set_Filename(const char *name)
Definition w3dmtl.cpp:94
char * Filename
Definition w3dmtl.h:71
W3dTextureInfoStruct * AnimInfo
Definition w3dmtl.h:72
void Set_Vertex_Material(const W3dVertexMaterialStruct &vmat, int pass=0)
Definition w3dmtl.cpp:224
void Set_Shader(const W3dShaderStruct &shader, int pass=0)
Definition w3dmtl.cpp:253
int Get_Pass_Count(void) const
Definition w3dmtl.cpp:289
void Set_Pass_Count(int count)
Definition w3dmtl.cpp:217
void Init(Mtl *mtl, char *materialColorTexture=NULL)
Definition w3dmtl.cpp:339
Class_ID PS2GameMaterialClassID
Class_ID GameMaterialClassID
#define DIFFUSE_COLOR_TEXTURE_PREFIX
Definition meshsave.cpp:87
const int VOXEL_RESOLUTION
Definition meshsave.cpp:82
#define DIFFUSE_COLOR_TEXTURE_MASK
Definition meshsave.cpp:88
int isTexturedMaterial(Mtl *mtl)
uint32 setup_mesh_attributes(INode *node)
Definition meshsave.cpp:129
float Compute_3x3_Determinant(const Matrix3 &tm)
Definition meshsave.cpp:95
void getMaterialUV(UVVert &tvert, unsigned int diffuse, unsigned int *materialColors, int &numMaterialColors, int &numHouseColors, bool house)
Definition meshsave.cpp:452
#define MIN_AABTREE_POLYGONS
Definition meshsave.cpp:85
bool use_simple_rendering(int geo_type)
Definition meshsave.cpp:110
WWINLINE Quaternion Inverse(const Quaternion &a)
Definition quat.h:117
#define SKIN_MOD_CLASS_ID
Definition skin.h:50
bool HasVertexMaterial[MAX_PASSES]
Definition meshbuild.h:251
bool HasPerPolyTexture[MAX_PASSES][MAX_STAGES]
Definition meshbuild.h:253
bool HasTexture[MAX_PASSES][MAX_STAGES]
Definition meshbuild.h:249
bool HasPerPolyShader[MAX_PASSES]
Definition meshbuild.h:254
bool HasTexCoords[MAX_PASSES][MAX_STAGES]
Definition meshbuild.h:261
bool HasPerVertexMaterial[MAX_PASSES]
Definition meshbuild.h:255
unsigned Get_Color()
Definition w3d_file.h:606
void Set(uint8 r, uint8 g, uint8 b)
Definition w3d_file.h:566
uint32 Vindex[3]
Definition w3d_file.h:1051
uint32 Attributes
Definition w3d_file.h:1052
float32 Dist
Definition w3d_file.h:1054
W3dVectorStruct Normal
Definition w3d_file.h:1053
W3dRGBStruct Ambient
Definition w3d_file.h:729
W3dRGBStruct Diffuse
Definition w3d_file.h:730
void Set_W3D_Name(char *set_name, const char *src)
Definition util.cpp:112
bool Is_Collision_OBBox(INode *node)
bool Is_Hidden(INode *node)
bool Is_Shatterable(INode *node)
bool Is_Camera_Oriented_Mesh(INode *node)
bool Is_Camera_Aligned_Mesh(INode *node)
bool Is_Skin(INode *node)
bool Is_Projectile_Collision(INode *node)
bool Is_Collision_AABox(INode *node)
bool Is_Two_Sided(INode *node)
bool Is_Vis_Collision(INode *node)
bool Is_Camera_Collision(INode *node)
bool Is_NPatchable(INode *node)
bool Is_Physical_Collision(INode *node)
bool Is_Shadow(INode *node)
bool Is_Vehicle_Collision(INode *node)