| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292 |
- /*
- ** Command & Conquer Generals Zero Hour(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /* $Header: /Commando/Code/Tools/max2w3d/w3dexp.cpp 78 1/03/01 11:06a Greg_h $ */
- /***********************************************************************************************
- *** Confidential - Westwood Studios ***
- ***********************************************************************************************
- * *
- * Project Name : Commando Tools - W3D export *
- * *
- * $Archive:: /Commando/Code/Tools/max2w3d/w3dexp.cpp $*
- * *
- * $Author:: Greg_h $*
- * *
- * $Modtime:: 1/03/01 11:03a $*
- * *
- * $Revision:: 78 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * W3dExportClass::W3dExportClass -- constructor *
- * W3dExportClass::~W3dExportClass -- destructor *
- * W3dExportClass::Export_Hierarchy -- Export the hierarchy tree *
- * W3dExportClass::Export_Animation -- Export animation data *
- * W3dExportClass::Export_Damage_Animations -- Exports damage animations for the model *
- * W3dExportClass::Export_Geometry -- Export the geometry data *
- * W3dExportClass::get_hierarchy_tree -- get a pointer to the hierarchy tree *
- * W3dExportClass::get_export_options -- get the export options *
- * W3dExportClass::Start_Progress_Bar -- start the MAX progress meter *
- * W3dExportClass::End_Progress_Bar -- end the progress meter *
- * W3dExportClass::get_damage_root_list -- gets the list of damage root nodes *
- * W3dExportClass::Export_HLod -- Export an HLOD description *
- * W3dExportClass::Export_Collection -- exports a collection chunk *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "rawfile.h"
- #include "chunkio.h"
- #include "w3dexp.h"
- #include "w3dutil.h"
- #include "nodelist.h"
- #include "meshsave.h"
- #include "hiersave.h"
- #include "hlodsave.h"
- #include "meshcon.h"
- #include "SnapPoints.h"
- #include "w3ddlg.h"
- #include "progress.h"
- #include "errclass.h"
- #include "motion.h"
- #include "util.h"
- #include "w3ddesc.h"
- #include "colboxsave.h"
- #include "nullsave.h"
- #include "dazzlesave.h"
- #include "maxworldinfo.h"
- #include "exportlog.h"
- #include "geometryexporttask.h"
- #include "geometryexportcontext.h"
- #include <direct.h>
- #include "targa.h"
- // Used to communicate from the exporter to the dialog.
- char W3dExportClass::CurrentExportPath[_MAX_DRIVE + _MAX_DIR + 1] = { '\000' };
- /* local functions */
- static DWORD WINAPI progress_callback( LPVOID arg);
- static HierarchySaveClass * load_hierarchy_file(char * filename);
- static bool dupe_check(const INodeListClass & list);
- static bool check_lod_extensions (INodeListClass &list, INode *origin);
- /*
- ** Struct for export info (AppDataChunk hung off the scene pointer)
- ** This includes the export info struct and some padding.
- ** NOTE: to avoid file versioning issues, new data should be added after
- ** existing data in this struct, the padding array should be made smaller so
- ** the total size remains the same, and the new data should give reasonable
- ** results with a default content of zeros (which is what it will contain if
- ** an older file is loaded).
- */
- struct ExportInfoAppDataChunkStruct {
- W3dExportOptionsStruct ExportOptions;
- unsigned char Padding[89];
- };
- /************************************************************************************************
- **
- ** GeometryFilterClass - filters out nodes which are not marked for W3D geometry export
- **
- ************************************************************************************************/
- class GeometryFilterClass : public INodeFilterClass
- {
- public:
- virtual BOOL Accept_Node(INode * node, TimeValue time)
- {
- Object * obj = node->EvalWorldState(time).obj;
- if
- (
- obj
- // && !Is_Proxy (*node)
- && !Is_Origin(node)
- && !node->IsHidden()
- && Is_Geometry(node)
- )
- {
- return TRUE;
- } else {
- return FALSE;
- }
- }
- };
- /************************************************************************************************
- **
- ** OriginFilterClass - Filters out nodes which are not "origin" objects. Origins are MAX dummy
- ** objects whose parents are the scene root, and are named "origin.*" (ie. first 7 characters
- ** in the name are "origin.". These origin objects will be (0,0,0) for all of its descendants.
- ** This allows an artist to create multiple models within one MAX scene but still have each
- ** mesh's coordinates equal without needing to stack all the models on the world origin.
- ** We iterate through the origin objects when exporting a scene containing multiple LODs of
- ** one model.
- **
- ************************************************************************************************/
- class OriginFilterClass : public INodeFilterClass
- {
- public:
- virtual BOOL Accept_Node(INode * node, TimeValue time) { return Is_Origin(node); }
- };
- /************************************************************************************************
- **
- ** DamageRootFilterClass - Filters out all nodes which are not "damage root" objects. These nodes
- ** are MAX dummy objects whose parents are the scene root, and are named "damage.*" (ie. first 7
- ** characters in the name are "damage.". These damage roots mean that all of its children
- ** represent a damaged model.
- **
- ************************************************************************************************/
- class DamageRootFilterClass : public INodeFilterClass
- {
- public:
- virtual BOOL Accept_Node(INode * node, TimeValue time) { return Is_Damage_Root(node); }
- };
- /************************************************************************************************
- **
- ** DamageRegionFilterClass - Filters out all node that are not a bone which is part of a certain
- ** deformation region. Pass the region ID to the constructor.
- **
- ************************************************************************************************/
- class DamageRegionFilterClass : public INodeFilterClass
- {
- public:
- DamageRegionFilterClass(int region_id) { RegionId = region_id; }
- virtual BOOL Accept_Node(INode * node, TimeValue time)
- {
- if (!Is_Bone(node)) return FALSE;
- // Check it's damage region ID (if it has one).
- AppDataChunk * appdata = node->GetAppDataChunk(W3DUtilityClassID,UTILITY_CLASS_ID,1);
- if (!appdata) return FALSE;
- W3DAppData1Struct *wdata = (W3DAppData1Struct*)(appdata->data);
- return wdata->DamageRegion == RegionId;
- }
- protected:
- int RegionId;
- };
-
-
- /***********************************************************************************************
- * W3dExportClass::DoExport -- This method is called for the plug-in to perform it's file expo *
- * *
- * INPUT: *
- * name - filename to use *
- * export - A pointer the plug-in may use to call methods to enumerate the scene *
- * max - An interface pointer the plug-in may use to call methods of MAX. *
- * *
- * OUTPUT: *
- * Nonzero on successful export; otherwise 0. *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 06/09/1997 GH : Created. *
- * 10/17/2000 gth : Removed the old export code-path, everything goes through an origin now *
- *=============================================================================================*/
- int W3dExportClass::DoExport
- (
- const TCHAR *filename,
- ExpInterface *export,
- Interface *max,
- BOOL suppressPrompts,
- DWORD options
- )
- {
- ExportInterface = export;
- MaxInterface = max;
- RootNode = NULL;
- OriginList = NULL;
- DamageRootList = NULL;
- HierarchyTree = NULL;
- try {
- CurTime = MaxInterface->GetTime();
- FrameRate = GetFrameRate();
- FixupType = HierarchySaveClass::MATRIX_FIXUP_TRANS_ROT;
- /*
- ** The Animation and the Hierarchy will be named with the root portion of the W3D filename
- ** and the path is used by the options dialog
- */
- char rootname[_MAX_FNAME + 1];
- char drivename[_MAX_DRIVE + 1];
- char dirname[_MAX_DIR + 1];
- _splitpath(filename, drivename, dirname, rootname, NULL);
- sprintf(CurrentExportPath, "%s%s", drivename, dirname);
- /*
- ** The batch export process (suppressPrompt == TRUE) needs to know the directory of the
- ** MAX file being exported. This is so that it can use the old relative pathname of the
- ** W3D file containing the hierarchy.
- */
- _splitpath(max->GetCurFilePath(), drivename, dirname, NULL, NULL);
- sprintf(CurrentScenePath, "%s%s", drivename, dirname);
- /*
- ** Get export options
- */
- if (!get_export_options(suppressPrompts)) {
- return 1;
- }
- /*
- ** If no data is going to be exported just bail
- */
- if ((!ExportOptions.ExportHierarchy) && (!ExportOptions.ExportAnimation) && (!ExportOptions.ExportGeometry)) {
- return 1;
- }
- /*
- ** Initialize the logging system
- */
- ExportLog::Init(NULL);
-
- /*
- ** Create a chunk saver to write the w3d file with
- */
- RawFileClass stream(filename);
-
- if (!stream.Open(FileClass::WRITE)) {
- MessageBox(NULL,"Unable to open file.","Error",MB_OK | MB_SETFOREGROUND);
- return 1;
- }
- ChunkSaveClass csave(&stream);
- /*
- ** Export data from the scene.
- **
- ** Are we doing an old export (one model/LOD per scene) or a new export (multiple LODs
- ** for one model in a scene)?
- */
- if (get_origin_list())
- {
- DoOriginBasedExport(rootname, csave);
- }
- /*
- ** Done!
- */
- stream.Close();
-
- if (HierarchyTree != NULL) {
- delete HierarchyTree;
- HierarchyTree = NULL;
- }
- if (OriginList != NULL) {
- delete OriginList;
- OriginList = NULL;
- }
- if (DamageRootList != NULL) {
- delete DamageRootList;
- DamageRootList = NULL;
- }
- } catch (ErrorClass error) {
- MessageBox(NULL,error.error_message,"Error",MB_OK | MB_SETFOREGROUND);
- }
- ExportLog::Shutdown(ExportOptions.ReviewLog);
- MaxInterface->RedrawViews(MaxInterface->GetTime());
- return 1;
- }
- /***********************************************************************************************
- * W3dExportClass::DoOriginBasedExport -- New export codepath. Exports any objects linked to *
- * an origin object. Assumes origins named "origin.01" and greater represent LODs of the *
- * original object ("origin.00"). Also assumes "damage.01" and greater represent damaged *
- * versions of the original object. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 9/13/1999 AJA : Created. *
- * 9/21/1999 AJA : Added support for the new animation exporting process (damage-related). *
- *=============================================================================================*/
- void W3dExportClass::DoOriginBasedExport(char *rootname,ChunkSaveClass &csave)
- {
- /*
- ** Build the damage root list.
- */
- INodeListClass *damage_list = get_damage_root_list();
- assert(damage_list != NULL);
- /*
- ** Start the progress meter
- */
- Start_Progress_Bar();
- Progress_Meter_Class meter(MaxInterface,0.0f,100.0f);
-
- int steps = 0;
- steps++; // Base Pose
- steps+= OriginList->Num_Nodes(); // n Origins
- steps++; // Basic Anim OR Damage Anims
- steps++; // HLOD OR Collection
-
- meter.Finish_In_Steps(steps);
- /*
- ** Find the base object's origin.
- */
- bool is_base_object = false;
- INodeListClass *origin_list = get_origin_list();
- unsigned int i, count = origin_list->Num_Nodes();
- INode *base_origin = NULL;
- for (i = 0; i < count; i++)
- {
- INode *node = (*origin_list)[i];
- if (Is_Base_Origin(node))
- {
- base_origin = node;
- break;
- }
- }
- /*
- ** Write the Hierarchy Tree (if needed)
- */
- Progress_Meter_Class treemeter(meter, meter.Increment);
- if (!Export_Hierarchy(rootname, csave, treemeter, base_origin))
- {
- MessageBox(NULL,"Hierarchy Export Failure!","Error",MB_OK | MB_SETFOREGROUND);
- End_Progress_Bar();
- return;
- }
- meter.Add_Increment();
- if (damage_list->Num_Nodes() <= 0)
- {
- /*
- ** Write the Base Animation (if needed)
- */
- Progress_Meter_Class animmeter(meter, meter.Increment);
- if (!Export_Animation(rootname, csave, animmeter, base_origin))
- {
- MessageBox(NULL,"Animation Export Failure!","Error",MB_OK | MB_SETFOREGROUND);
- End_Progress_Bar();
- return;
- }
- meter.Add_Increment();
- }
- else
- {
- /*
- ** Write the damage animations.
- */
- Progress_Meter_Class damagemeter(meter, meter.Increment);
- for (i = 0; i < damage_list->Num_Nodes(); i++)
- {
- if (!Export_Damage_Animations(rootname, csave, damagemeter, (*damage_list)[i]))
- {
- MessageBox(NULL, "Damage Animation Export Failure!", "Error", MB_OK | MB_SETFOREGROUND);
- End_Progress_Bar();
- return;
- }
- }
- meter.Add_Increment();
- }
- /*
- ** Create an array of pointers to MeshConnectionsClass objects. These objects
- ** will be created below, and will be used to generate the HLOD with the
- ** geometry of all models in the scene.
- */
- MeshConnectionsClass **connections = new MeshConnectionsClass*[count];
- if (!connections)
- {
- MessageBox(NULL, "Memory allocation failure!", "Error", MB_OK | MB_SETFOREGROUND);
- End_Progress_Bar();
- return;
- }
- memset(connections, 0, sizeof(MeshConnectionsClass*) * count);
- /*
- ** For each model in the scene, write its animation and geometry (if needed).
- ** All models share the above hierarchy tree.
- */
- int idx = strlen(rootname);
- rootname[idx+1] = '\0';
-
- /*
- ** If we're not exporting a hierarchical model, only export the "origin.00"
- */
- if (!ExportOptions.LoadHierarchy && !ExportOptions.ExportHierarchy) {
- count = 1;
- }
-
- for (i = 0; i < count; i++)
- {
- /*
- ** Get the current origin.
- */
- INode *origin = (*origin_list)[i];
- /*
- ** Write each mesh (if needed)
- */
- MeshConnectionsClass *meshcon = NULL;
- Progress_Meter_Class meshmeter(meter, meter.Increment);
- if (!Export_Geometry(rootname, csave, meshmeter, origin, &meshcon))
- {
- MessageBox(NULL, "Geometry Export Failure!", "Error", MB_OK | MB_SETFOREGROUND);
- End_Progress_Bar();
- return;
- }
- meter.Add_Increment();
- /*
- ** Put the MeshConnectionsClass object for this model into
- ** the array in order of LOD (top-level last).
- */
- int lod_level = Get_Lod_Level(origin);
- if (lod_level >= count || connections[count - lod_level - 1] != NULL)
- {
- char text[256];
- sprintf(text, "Origin Naming Error! There are %d models defined in this "
- "scene, therefore your origin names should be\n\"Origin.00\" through "
- "\"Origin.%02d\", 00 being the high-poly model and %02d being the "
- "lowest detail LOD.", count, count-1, count-1);
- MessageBox(NULL, text, "Error", MB_OK | MB_SETFOREGROUND);
- End_Progress_Bar();
- return;
- }
- connections[count - lod_level - 1] = meshcon;
- }
- /*
- ** Generate the HLOD based on all the mesh connections.
- */
- if (ExportOptions.LoadHierarchy || ExportOptions.ExportHierarchy) {
- rootname[idx] = '\0'; // remove the trailing character (signifies which lod level)
- HierarchySaveClass *htree = get_hierarchy_tree();
- if (htree)
- {
- Progress_Meter_Class hlod_meter(meter, meter.Increment);
- if (!Export_HLod(rootname, htree->Get_Name(), csave, hlod_meter, connections, count))
- {
- MessageBox(NULL, "HLOD Generation Failure!", "Error", MB_OK | MB_SETFOREGROUND);
- End_Progress_Bar();
- return;
- }
- meter.Add_Increment();
- }
- }
- /*
- ** Deallocate the array of mesh connections.
- */
- for (i = 0; i < count; i++)
- {
- if (connections[i] != NULL)
- delete connections[i];
- }
- delete []connections;
- End_Progress_Bar();
- }
- /***********************************************************************************************
- * W3dExportClass::Export_Hierarchy -- Export the hierarchy tree *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/16/1997 GH : Created. *
- * 13/9/1999 AJA : Split into two calls, one that takes a node list and one that takes a *
- * single root node. *
- * 10/17/2000 gth : Removed the old code-path, we always use an origin now *
- *=============================================================================================*/
- bool W3dExportClass::Export_Hierarchy(char *name,ChunkSaveClass & csave,Progress_Meter_Class & meter,
- INode *root)
- {
- if (!ExportOptions.ExportHierarchy) return true;
- HierarchySaveClass::Enable_Terrain_Optimization(ExportOptions.EnableTerrainMode);
- if (root == NULL) return false;
- try {
- HierarchyTree = new HierarchySaveClass(root,CurTime,meter,name,FixupType);
- } catch (ErrorClass err) {
- MessageBox(NULL, err.error_message,"Error!",MB_OK | MB_SETFOREGROUND);
- return false;
- }
- HierarchyTree->Save(csave);
- return true;
- }
- /***********************************************************************************************
- * W3dExportClass::Export_Animation -- Export animation data *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/16/1997 GH : Created. *
- * 13/9/1999 AJA : Split into two calls, one that takes a node list and one that takes a *
- * single root node. *
- * 10/17/2000 gth : Removed the old code-path, we always use an origin now *
- *=============================================================================================*/
- bool W3dExportClass::Export_Animation(char * name,ChunkSaveClass & csave,Progress_Meter_Class & meter,
- INode *root)
- {
- if (!ExportOptions.ExportAnimation) return true;
- HierarchySaveClass * htree = get_hierarchy_tree();
- if ((root == NULL) || (htree == NULL)) {
- return false;
- }
- MotionClass * motion = NULL;
- try {
- motion = new MotionClass( ExportInterface->theScene,
- root,
- htree,
- ExportOptions,
- FrameRate,
- &meter,
- MaxInterface->GetMAXHWnd(),
- name);
- } catch (ErrorClass err) {
- MessageBox(NULL,err.error_message,"Error!",MB_OK | MB_SETFOREGROUND);
- return false;
- }
- motion->Save(csave);
- delete motion;
-
- return true;
- }
- /***********************************************************************************************
- * W3dExportClass::Export_Damage_Animations -- Exports damage animations for the model *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 1999 AJA : Created. *
- *=============================================================================================*/
- bool W3dExportClass::Export_Damage_Animations(char *name, ChunkSaveClass &csave,
- Progress_Meter_Class &meter,
- INode *damage_root)
- {
- if (!ExportOptions.ExportAnimation) return true;
- HierarchySaveClass *htree = get_hierarchy_tree();
- if ((damage_root == NULL) || (htree == NULL))
- return false;
- int damage_state = Get_Damage_State(damage_root);
- /*
- ** While exporting damage animations, we need the offset from our origin to the real
- ** scene origin.
- */
- Matrix3 originoffset = Inverse(damage_root->GetNodeTM(CurTime));
- /*
- ** For every damage region we find, export an animation.
- */
- bool done = false;
- int current_region = 0;
- int num_damage_bones = 0; // number of bones assigned to a damage region
- for (current_region = 0; current_region < MAX_DAMAGE_REGIONS; current_region++)
- {
- DamageRegionFilterClass region_filter(current_region);
- INodeListClass bone_list(damage_root, CurTime, ®ion_filter);
- num_damage_bones += bone_list.Num_Nodes();
- // Move to the next region if there aren't any bones in this one.
- if (bone_list.Num_Nodes() <= 0)
- continue;
- // Put together an animation name for this damage region.
- char anim_name[W3D_NAME_LEN];
- sprintf(anim_name, "damage%d-%d", current_region, damage_state);
- // Export an animation for this damage region.
- MotionClass *motion = NULL;
- try
- {
- motion = new MotionClass( ExportInterface->theScene,
- &bone_list,
- htree,
- ExportOptions,
- FrameRate,
- &meter,
- MaxInterface->GetMAXHWnd(),
- anim_name,
- originoffset);
- }
- catch (ErrorClass err)
- {
- MessageBox(NULL, err.error_message, "Error!", MB_OK | MB_SETFOREGROUND);
- return false;
- }
- assert(motion != NULL);
- motion->Save(csave);
- delete motion;
- }
- if (num_damage_bones <= 0)
- {
- MessageBox(NULL, "Warning: Your damage bones need to be given damage region numbers. "
- "You can do this in the W3D Tools panel.", name, MB_OK | MB_ICONINFORMATION | MB_SETFOREGROUND);
- }
- return true;
- }
- #define TEAM_COLOR_PALETTE_SIZE 16
- unsigned int houseColorScale[TEAM_COLOR_PALETTE_SIZE]=
- {255,239,223,211,195,174,167,151,135,123,107,91,79,63,47,35};
- /***********************************************************************************************
- * W3dExportClass::Export_Geometry -- Export the geometry data *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/16/1997 GH : Created. *
- * 13/9/1999 AJA : Added an optional "root" parameter to export geometry of the node's *
- * descendants. *
- * 10/17/2000 gth : Made the "root" parameter a requirement, just pass in the scene root *
- * if you want to export all geometry in the scene. *
- * 10/30/2000 gth : If exporting only geometry, only export the first mesh *
- *=============================================================================================*/
- bool W3dExportClass::Export_Geometry(char * name,ChunkSaveClass & csave,Progress_Meter_Class & meter,
- INode *root,MeshConnectionsClass **out_connection)
- {
- unsigned int i;
- assert(root != NULL);
- if (!ExportOptions.ExportGeometry) return true;
- /*
- ** If we're attaching the meshes to a hierarchy, get the tree
- */
- HierarchySaveClass * htree = NULL;
- if (ExportOptions.LoadHierarchy || ExportOptions.ExportHierarchy) {
- htree = get_hierarchy_tree();
- if (htree == NULL) {
- return false;
- }
- }
- DynamicVectorClass<GeometryExportTaskClass *> export_tasks;
- INodeListClass *geometry_list = NULL;
-
- /*
- ** Create the lists of nodes that we're going to work with
- */
- GeometryFilterClass geometryfilter;
- geometry_list = new INodeListClass(root,CurTime,&geometryfilter);
- if (dupe_check(*geometry_list)) {
- return false;
- }
- MaxWorldInfoClass world_info(export_tasks);
- world_info.Allow_Mesh_Smoothing (ExportOptions.SmoothBetweenMeshes);
- unsigned int materialColors[16*16]; ///@todo: MW: Fix this to remove solid colors.
- char materialColorFilename[_MAX_FNAME + 1];
- memset(materialColors,0,sizeof(materialColors));
- for (i=0; i<TEAM_COLOR_PALETTE_SIZE; i++)
- { //preset the first 16 colors to predefined set of house colors
- materialColors[i]=houseColorScale[i] << 16;
- }
-
- /*
- ** Initialize the context object for exporting geometry
- */
- GeometryExportContextClass context( name,
- csave,
- world_info,
- ExportOptions,
- htree,
- root,
- get_origin_list(),
- CurTime,
- materialColors);
- if (ExportOptions.EnableMaterialColorToTextureConversion)
- context.materialColorTexture=materialColorFilename;
- sprintf(materialColorFilename,"%sZMCD_%s.tga",CurrentExportPath,name);
- /*
- ** Initialize a list of geometry export tasks containing all nodes marked for geometry export.
- ** If we're only exporting geometry, only export the first mesh. (no more collections)
- */
- int geometry_count = geometry_list->Num_Nodes();
- if ((htree == NULL) && (geometry_list->Num_Nodes() > 1)) {
- geometry_count = MIN(geometry_count,1);
- ExportLog::printf("\nDiscarding extra meshes since we are not exporting a hierarchical model.\n");
- }
- for (i=0; i<geometry_count; i++) {
- GeometryExportTaskClass * export_task = GeometryExportTaskClass::Create_Task((*geometry_list)[i],context);
- if (export_task != NULL) {
- export_tasks.Add(export_task);
- }
- }
- meter.Finish_In_Steps(export_tasks.Count());
- /*
- ** Optimize the mesh data if the user desired, modifying the list of geometry export tasks.
- */
- if (ExportOptions.EnableOptimizeMeshData) {
- GeometryExportTaskClass::Optimize_Geometry(export_tasks,context);
- }
- /*
- ** If there is only one piece of geometry to export and no place-holders, and we're not
- ** exporting a hierarchical model, then we force the name to match the filename
- */
- if ((export_tasks.Count() == 1) && (htree == NULL))
- {
- export_tasks[0]->Set_Name(name);
- export_tasks[0]->Set_Container_Name("");
- }
-
- /*
- ** Generate the mesh-connections object to return to the caller
- */
- MeshConnectionsClass * meshcon = NULL;
- if (htree != NULL) {
- Progress_Meter_Class mcmeter(meter,meter.Increment);
- try {
- meshcon = new MeshConnectionsClass(export_tasks,context);
- } catch (ErrorClass err) {
- MessageBox(NULL,err.error_message,"Error!",MB_OK | MB_SETFOREGROUND);
- return false;
- }
- *out_connection = meshcon;
- meter.Add_Increment();
- }
-
- /*
- ** Export each piece of geometry
- */
- for (i=0; i<export_tasks.Count(); i++) {
- Progress_Meter_Class meshmeter(meter,meter.Increment);
- context.ProgressMeter = &meshmeter;
- try {
- export_tasks[i]->Export_Geometry(context);
- } catch (ErrorClass err) {
- MessageBox(MaxInterface->GetMAXHWnd(),err.error_message,"Error!",MB_OK | MB_SETFOREGROUND);
- continue;
- }
-
- meter.Add_Increment();
- }
- //Check if any textures need to be generated
- if (context.numMaterialColors || context.numHouseColors)
- {
- Targa targ;
- char imageBuffer[16*16*3];
- int px,py,buf_index;
- unsigned int Diffuse;
- //clear to black
- memset(imageBuffer,0,sizeof(imageBuffer));
- for (i=0; i<(16+context.numMaterialColors); i++)
- {
- //get coordinates of this material within texture page
- px=(i%16); ///@todo: MW: Remove hard-coded texture size
- py=(i/16);
- Diffuse=context.materialColors[i];
- buf_index=(px+py*16)*3;
- imageBuffer[buf_index]=(Diffuse>>16)&0xff;
- imageBuffer[buf_index+1]=(Diffuse>>8)&0xff;
- imageBuffer[buf_index+2]=(Diffuse)&0xff;
- }
- memset(&targ.Header,0,sizeof(targ.Header));
- targ.Header.Width=16;
- targ.Header.Height=16;
- targ.Header.PixelDepth=24;
- targ.Header.ImageType=TGA_TRUECOLOR;
- targ.SetImage(imageBuffer);
- targ.YFlip();
- if (context.numHouseColors)
- sprintf(materialColorFilename,"%sZHCD_%s.tga",CurrentExportPath,name);
- targ.Save(materialColorFilename,TGAF_IMAGE,false);
- }
- /*
- ** Cleanup
- */
- for (i=0; i<export_tasks.Count(); i++) {
- delete export_tasks[i];
- }
-
- export_tasks.Delete_All();
- delete geometry_list;
- return true;
- }
- /***********************************************************************************************
- * W3dExportClass::Export_HLod -- Export an HLOD description *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/17/2000 gth : Created. *
- *=============================================================================================*/
- bool W3dExportClass::Export_HLod( char *name, const char *htree_name, ChunkSaveClass &csave,
- Progress_Meter_Class &meter, MeshConnectionsClass **connections,
- int lod_count)
- {
- if (!ExportOptions.ExportGeometry) return true;
- HLodSaveClass hlod_save(connections, lod_count, CurTime, name, htree_name, meter, get_origin_list());
- if (!hlod_save.Save(csave))
- return false;
- return true;
- }
- /***********************************************************************************************
- * W3dExportClass::get_hierarchy_tree -- get a pointer to the hierarchy tree *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/16/1997 GH : Created. *
- *=============================================================================================*/
- HierarchySaveClass * W3dExportClass::get_hierarchy_tree(void)
- {
- /*
- ** If the hierarchy tree pointer has been initialized, just return it
- */
- if (HierarchyTree != NULL) return HierarchyTree;
- /*
- ** If we are supposed to be loading a hierarchy from disk, then
- ** load it
- */
- if (!ExportOptions.ExportHierarchy) {
- HierarchyTree = load_hierarchy_file(HierarchyFilename);
- if (HierarchyTree) {
- return HierarchyTree;
- } else {
- char buf[256];
- sprintf(buf,"Unable to load hierarchy file: %s\nIf this Max file has been moved, please re-select the hierarchy file.",HierarchyFilename);
- MessageBox(MaxInterface->GetMAXHWnd(),buf,"Error",MB_OK | MB_SETFOREGROUND);
- return NULL;
- }
- }
-
- /*
- ** Should never fall through to here...
- ** This would only happen if ExportHierarchy was true and the Export_Hierarchy
- ** function failed to create a hierarchy tree for us.
- */
- assert(0);
- return NULL;
- }
- /***********************************************************************************************
- * W3dExportClass::get_damage_root_list -- gets the list of damage root nodes *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/17/2000 gth : Created. *
- *=============================================================================================*/
- INodeListClass * W3dExportClass::get_damage_root_list(void)
- {
- if (DamageRootList != NULL) return DamageRootList;
- /*
- ** Create a list of all damage root objects in the scene.
- */
- DamageRootFilterClass nodefilter;
- DamageRootList = new INodeListClass(ExportInterface->theScene, CurTime, &nodefilter);
- return DamageRootList;
- }
- /***********************************************************************************************
- * get_origin_list -- get the list of origin nodes *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 9/13/1999 AJA : Created. *
- *=============================================================================================*/
- INodeListClass * W3dExportClass::get_origin_list(void)
- {
- if (OriginList != NULL) return OriginList;
- /*
- ** Create a list of all origins in the scene.
- */
- static OriginFilterClass originfilter;
- OriginList = new INodeListClass (ExportInterface->theScene, CurTime, &originfilter);
- /*
- ** If we didn't find any origins, add the scene root as an origin.
- ** NOTE: it would also be a problem if the origin list contained both the scene root
- ** and the user placed origins. Thats not happening now because the OriginList
- ** does not collect the scene root... were that to change we'd have to update this
- ** code as well.
- */
- if (OriginList->Num_Nodes() == 0) {
- OriginList->Insert(MaxInterface->GetRootNode());
- }
- return OriginList;
- }
- /***********************************************************************************************
- * W3dExportClass::get_export_options -- get the export options *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/16/1997 GH : Created. *
- * 9/30/1999 AJA : Added support for the MAX suppress_prompts flag. *
- *=============================================================================================*/
- bool W3dExportClass::get_export_options(BOOL suppress_prompts)
- {
- int ticksperframe = GetTicksPerFrame();
- // Get the last export settings from the AppDataChunk attached to the
- // scene pointer. If there is no such AppDataChunk create one and set it
- // to default values.
-
- W3dExportOptionsStruct *options = NULL;
- AppDataChunk * appdata = MaxInterface->GetScenePointer()->GetAppDataChunk(W3D_EXPORTER_CLASS_ID,SCENE_EXPORT_CLASS_ID,0);
- if (appdata) {
- options = &(((ExportInfoAppDataChunkStruct *)(appdata->data))->ExportOptions);
- } else {
- ExportInfoAppDataChunkStruct *appdata_struct =
- (ExportInfoAppDataChunkStruct *)malloc(sizeof(ExportInfoAppDataChunkStruct));
- options = &(appdata_struct->ExportOptions);
- options->ExportHierarchy = true;
- options->LoadHierarchy = false;
- options->ExportAnimation = true;
- options->EnableTerrainMode = false;
- options->ReduceAnimation = false;
- options->ReduceAnimationPercent = 50;
-
- options->CompressAnimation = false;
- options->CompressAnimationFlavor = ANIM_FLAVOR_TIMECODED;
- options->CompressAnimationTranslationError = 0.001f; //DEFAULT_LOSSY_ERROR_TOLERANCE;
- options->CompressAnimationRotationError = 0.050f; //DEFAULT_LOSSY_ERROR_TOLERANCE;
- options->ReviewLog = false;
- options->ExportGeometry = true;
- options->TranslationOnly = false;
- options->SmoothBetweenMeshes = true;
- strcpy(options->HierarchyFilename,"");
- strcpy(options->RelativeHierarchyFilename,"");
- options->StartFrame = MaxInterface->GetAnimRange().Start() / ticksperframe;
- options->EndFrame = MaxInterface->GetAnimRange().End() / ticksperframe;
- options->UseVoxelizer = false;
- options->DisableExportAABTrees = true;
- options->EnableOptimizeMeshData = false;
- options->EnableMaterialColorToTextureConversion = false;
- memset(&(appdata_struct->Padding), 0, sizeof(appdata_struct->Padding));
- MaxInterface->GetScenePointer()->AddAppDataChunk(W3D_EXPORTER_CLASS_ID,
- SCENE_EXPORT_CLASS_ID, 0, sizeof(ExportInfoAppDataChunkStruct),
- appdata_struct);
- }
-
- // (gth) disabling the 'optimize mesh data' feature due to problems with external tools
- options->EnableOptimizeMeshData = false;
- bool retval = true;
- if (suppress_prompts == FALSE)
- {
- W3dOptionsDialogClass dialog(MaxInterface,ExportInterface);
- retval = dialog.Get_Export_Options(options);
- }
- if (suppress_prompts || retval) {
- ExportOptions = *options;
- if ( (suppress_prompts == TRUE) && (options->RelativeHierarchyFilename[0] != 0) )
- {
- // Use the relative pathname WRT the max scene's directory to
- // figure out the absolute directory where the hierarchy file
- // is stored.
- char curdir[_MAX_DRIVE + _MAX_DIR + 1];
- assert(_getcwd(curdir, sizeof(curdir)));
- assert(_chdir(CurrentScenePath) != -1);
- assert(_fullpath(HierarchyFilename, options->RelativeHierarchyFilename,
- sizeof(HierarchyFilename)));
- assert(_chdir(curdir) != -1);
- }
- else
- strcpy(HierarchyFilename,options->HierarchyFilename);
- if (ExportOptions.TranslationOnly) {
- FixupType = HierarchySaveClass::MATRIX_FIXUP_TRANS;
- } else {
- FixupType = HierarchySaveClass::MATRIX_FIXUP_TRANS_ROT;
- }
- }
- return retval;
- }
- /***********************************************************************************************
- * W3dExportClass::Start_Progress_Bar -- start the MAX progress meter *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/16/1997 GH : Created. *
- *=============================================================================================*/
- void W3dExportClass::Start_Progress_Bar(void)
- {
- MaxInterface->ProgressStart(
- "Processing Triangle Mesh",
- TRUE,
- progress_callback,
- NULL);
- }
- /***********************************************************************************************
- * W3dExportClass::End_Progress_Bar -- end the progress meter *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 10/16/1997 GH : Created. *
- *=============================================================================================*/
- void W3dExportClass::End_Progress_Bar(void)
- {
- MaxInterface->ProgressUpdate( 100);
- MaxInterface->ProgressEnd();
- }
- static bool dupe_check(const INodeListClass & list)
- {
- for (unsigned i=0; i<list.Num_Nodes(); i++) {
-
- /*
- ** Don't check aggregate objects, they are allowed to have the same name
- */
- if (!Is_Aggregate(list[i])) {
- for (unsigned j = i+1; j<list.Num_Nodes(); j++) {
- if (stricmp(list[i]->GetName(),list[j]->GetName()) == 0) {
- char buf[256];
- sprintf(buf,"Geometry Nodes with duplicated names found!\nDuplicated Name: %s\n",list[i]->GetName());
- MessageBox(NULL,buf,"Error",MB_OK | MB_SETFOREGROUND);
- return true;
- }
- }
- }
- }
- return false;
- }
- static bool check_lod_extensions (INodeListClass &list, INode *origin)
- {
- /*
- ** Assumptions:
- ** - If origin == NULL, then we're just exporting a single model and don't need to
- ** worry about lod extensions at all.
- ** - If origin is the root of the scene, then we're just exporting a single model as well.
- ** - Otherwise origin actually points to an Origin and not just any INode.
- */
- if (origin == NULL) return true;
- if (origin->IsRootNode()) return true;
- char *extension = strrchr(origin->GetName(), '.');
- int ext_len = strlen(extension);
- for (unsigned i = 0; i < list.Num_Nodes(); i++)
- {
- char *this_ext = strrchr(list[i]->GetName(), '.');
- // Check for the existance of an extension in this node.
- if (this_ext == NULL)
- return false;
- // Check that the extensions are the same.
- if (strcmp(this_ext, extension) != 0)
- return false;
- }
- return true;
- }
- bool W3dExportClass::get_base_object_tm (Matrix3 &tm)
- {
- INodeListClass *origin_list = get_origin_list();
- if (!origin_list)
- return false;
- unsigned int i, count = origin_list->Num_Nodes();
- INode *base_origin = NULL;
- for (i = 0; i < count; i++)
- {
- INode *node = (*origin_list)[i];
- if (Is_Base_Origin(node))
- {
- // we found origin.00, fall through
- base_origin = node;
- break;
- }
- }
- if (!base_origin)
- return false;
- tm = base_origin->GetNodeTM(CurTime);
- return true;
- }
- static DWORD WINAPI progress_callback( LPVOID arg )
- {
- return 0;
- }
- static HierarchySaveClass * load_hierarchy_file(char * filename)
- {
- HierarchySaveClass * hier = NULL;
- RawFileClass file(filename);
- if (!file.Open()) {
- return NULL;
- }
- ChunkLoadClass cload(&file);
- cload.Open_Chunk();
- if (cload.Cur_Chunk_ID() == W3D_CHUNK_HIERARCHY) {
- hier = new HierarchySaveClass();
- hier->Load(cload);
- } else {
- hier = NULL;
- file.Close();
- return NULL;
- }
- cload.Close_Chunk();
- file.Close();
- return hier;
- }
|