/* ** 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 . */ /* $Header: /Commando/Code/Tools/max2w3d/w3dutil.cpp 45 8/21/01 10:28a Greg_h $ */ /*********************************************************************************************** *** Confidential - Westwood Studios *** *********************************************************************************************** * * * Project Name : Commando Tools - W3D export * * * * $Archive:: /Commando/Code/Tools/max2w3d/w3dutil.cpp $* * * * $Author:: Greg_h $* * * * $Modtime:: 8/21/01 9:41a $* * * * $Revision:: 45 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "w3dutil.h" #include "w3ddesc.h" #include "rcmenu.h" #include "util.h" #include "nodelist.h" #include "tchar.h" #include "gamemtl.h" #include "notify.h" #include "gennamesdialog.h" #include "genmtlnamesdialog.h" #include "genlodextensiondialog.h" #include "floaterdialog.h" #include #define DAZZLE_SETTINGS_FILENAME "dazzle.ini" #define DAZZLE_TYPES_SECTION "Dazzles_List" #define DAZZLE_SECTION_BUFFERSIZE 32767 static BOOL CALLBACK _settings_form_dlg_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); static BOOL CALLBACK _w3d_utility_tools_dlg_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); static VisibleSelectedINodeFilter _INodeFilter; /********************************************************************************************** ** ** MaterialReferenceMaker - Class to support Export Utilities in the W3D Tools panel. ** **********************************************************************************************/ class MaterialReferenceMaker : public ReferenceMaker { public: ~MaterialReferenceMaker() {DeleteAllRefs();} virtual int NumRefs(); virtual RefTargetHandle GetReference (int i); virtual void SetReference (int i, RefTargetHandle rtarg); RefResult NotifyRefChanged (Interval changeInt,RefTargetHandle hTarget,PartID& partID, RefMessage message); Mtl *MaterialPtr; static int ReferenceCount; }; int MaterialReferenceMaker::NumRefs() { return (ReferenceCount); } RefTargetHandle MaterialReferenceMaker::GetReference (int i) { assert (i < ReferenceCount); return (MaterialPtr); } void MaterialReferenceMaker::SetReference (int i, RefTargetHandle rtarg) { assert (i < ReferenceCount); MaterialPtr = (Mtl*) rtarg; } RefResult MaterialReferenceMaker::NotifyRefChanged(Interval changeInt,RefTargetHandle hTarget,PartID& partID, RefMessage message) { return (REF_SUCCEED); } int MaterialReferenceMaker::ReferenceCount; /********************************************************************************************** ** ** SettingsFormClass - code for the W3DUTILITY_SETTINGS_DIALOG. Used in the command panel ** and in the floating settings dialog. ** **********************************************************************************************/ class SettingsFormClass { public: SettingsFormClass(HWND hwnd); ~SettingsFormClass(void); bool Dialog_Proc(HWND hWnd,UINT message,WPARAM wParam,LPARAM); void Selection_Changed(void); static void Update_All_Instances(void); private: void Init(void); void Destroy(void); void Disable_Controls(void); void Update_Controls(INodeListClass * nodelist = NULL); HWND Hwnd; ISpinnerControl * RegionSpin; SettingsFormClass * Next; static SettingsFormClass * ActiveList; }; /********************************************************************************************** ** ** W3DUtilityClass - Utility plugin which presents windows controls for setting all of ** the W3D export options for the currently selected nodes ** **********************************************************************************************/ class W3DUtilityClass : public UtilityObj { public: W3DUtilityClass(); ~W3DUtilityClass(); void BeginEditParams(Interface *ip,IUtil *iu); void EndEditParams(Interface *ip,IUtil *iu); void SelectionSetChanged(Interface *ip,IUtil *iu); void DeleteThis() {} void Select_Hierarchy(void); void Select_Geometry(void); void Select_Alpha(void); void Select_Physical(void); void Select_Projectile(void); void Select_Vis(void); public: Interface * InterfacePtr; FloaterDialogClass SettingsFloater; HWND SettingsPanelHWND; HWND ToolsPanelHWND; bool UpdateSpinnerValue; GenNamesDialogClass::OptionsStruct NameOptions; GenMtlNamesDialogClass::OptionsStruct MtlNameOptions; GenLodExtensionDialogClass::OptionsStruct LodExtensionOptions; int WorkingNameIndex; enum { NONE = 0, HIDE, SELECT_GEOM, SELECT_HIER, SELECT_ALPHA, SELECT_PHYSICAL, SELECT_PROJECTILE, SELECT_VIS, GENERATE_NAME, GENERATE_MATERIAL_NAME, GENERATE_LOD_EXTENSION }; enum MaterialConversionEnum { GAME_REFERENCE_COUNT, GAME_TO_STANDARD, STANDARD_TO_GAME }; struct NodeStatesStruct { int ExportHierarchy; int ExportGeometry; int GeometryTwoSided; int GeometryHidden; int GeometryZNormals; int GeometryVertexAlpha; int GeometryCastShadow; int GeometryShatterable; int GeometryNPatch; int CollisionPhysical; int CollisionProjectile; int CollisionVis; int CollisionCamera; int CollisionVehicle; bool GeometryCameraAligned; bool GeometryCameraOriented; bool GeometryNormal; bool GeometryAABox; bool GeometryOBBox; bool GeometryNull; bool GeometryDazzle; bool GeometryAggregate; int DamageRegion; int DazzleCount; char DazzleType[128]; }; /* ** Evaluate the status of nodes in the given list */ static int eval_tri_state(int totalcount,int oncount); static void eval_node_states(INodeListClass * node_list,NodeStatesStruct * ns); /* ** Update the controls in any active settings panels */ static void update_settings_controls(INodeListClass * node_list = NULL); /* ** Modify the state of all selected nodes */ static void set_hierarchy_in_all_selected(INodeListClass * list,bool onoff); static void set_geometry_in_all_selected(INodeListClass * list,bool onoff); static void enable_hidden_in_all_selected(INodeListClass * list,bool onoff); static void enable_two_sided_in_all_selected(INodeListClass * list,bool onoff); static void enable_znormals_in_all_selected(INodeListClass * list,bool onoff); static void enable_vertex_alpha_in_all_selected(INodeListClass * list,bool onoff); static void enable_shadow_in_all_selected(INodeListClass * list,bool onoff); static void enable_shatterable_in_all_selected(INodeListClass * list,bool onoff); static void enable_npatches_in_all_selected(INodeListClass * list,bool onoff); static void enable_physical_collision_in_all_selected(INodeListClass * list,bool onoff); static void enable_projectile_collision_in_all_selected(INodeListClass * list,bool onoff); static void enable_vis_collision_in_all_selected(INodeListClass * list,bool onoff); static void enable_camera_collision_in_all_selected(INodeListClass * list,bool onoff); static void enable_vehicle_collision_in_all_selected(INodeListClass * list,bool onoff); static void set_geometry_type_in_all_selected(INodeListClass * list,int geotype); static void set_dazzle_type_in_all_selected(INodeListClass * list,char * dazzletype); static void set_region_in_all_selected(INodeListClass * list,char region); /* ** Functions used by the tools rollup in the command panel */ void descend_tree(INode * node,int action); void hide_node(INode * node); void select_geometry_node(INode * node); void select_hierarchy_node(INode * node); void select_alpha_node(INode * node); void select_physical_node(INode * node); void select_projectile_node(INode * node); void select_vis_node(INode * node); bool is_alpha_material(Mtl * nodemtl); bool is_alpha_mesh(INode * node,Mtl * nodemtl); void generate_names(void); void generate_node_name(INode * node); void generate_material_names(void); void generate_material_names_for_node(INode * node); void generate_material_names(Mtl * mtl); void generate_lod_extensions(void); void generate_lod_ext(INode * node); void create_floater(void); void export_with_standard_materials(); int convert_materials (MaterialConversionEnum conversion, MaterialReferenceMaker *gamenodematerials); StdMat * new_standard_material (GameMtl *gamemtl); static W3DAppData0Struct * get_app_data_0(INode * node); static W3DAppData1Struct * get_app_data_1(INode * node); static W3DAppData2Struct * get_app_data_2(INode * node); static W3DDazzleAppDataStruct * get_dazzle_app_data(INode * node); }; static W3DUtilityClass TheW3DUtility; /********************************************************************************************** ** ** W3DUtilityClassDesc - Class Descriptor for the W3D Utility ** **********************************************************************************************/ class W3DUtilityClassDesc:public ClassDesc { public: int IsPublic() { return 1; } void * Create(BOOL loading = FALSE) { return &TheW3DUtility; } const TCHAR * ClassName() { return Get_String(IDS_W3D_UTILITY_CLASS_NAME); } SClass_ID SuperClassID() { return UTILITY_CLASS_ID; } Class_ID ClassID() { return W3DUtilityClassID; } const TCHAR* Category() { return Get_String(IDS_W3DMENU_CATEGORY); } }; static W3DUtilityClassDesc W3DUtilityDesc; ClassDesc * Get_W3D_Utility_Desc(void) { return &W3DUtilityDesc; } /********************************************************************************************** ** ** W3DUtilityClass Implementation ** **********************************************************************************************/ W3DUtilityClass::W3DUtilityClass(void) { InterfacePtr = NULL; SettingsPanelHWND = NULL; ToolsPanelHWND = NULL; UpdateSpinnerValue = true; } W3DUtilityClass::~W3DUtilityClass(void) { } void W3DUtilityClass::BeginEditParams(Interface *ip,IUtil *iu) { InterfacePtr = ip; SettingsPanelHWND = InterfacePtr->AddRollupPage( AppInstance, MAKEINTRESOURCE(IDD_W3DUTILITY_SETTINGS_DIALOG), _settings_form_dlg_proc, Get_String(IDS_W3DUTILITY_SETTINGS), 0); ToolsPanelHWND = InterfacePtr->AddRollupPage( AppInstance, MAKEINTRESOURCE(IDD_W3DUTILITY_TOOLS_DIALOG), _w3d_utility_tools_dlg_proc, Get_String(IDS_W3DUTILITY_TOOLS), 0); // TheRCMenu.Bind(TheW3DUtility.InterfacePtr,&TheW3DUtility); // RightClickMenuManager *rcm = ip->GetRightClickMenuManager(); // if (TheRCMenu.Installed!=TRUE) { // rcm->Register(&TheRCMenu); // } SettingsFormClass::Update_All_Instances(); } void W3DUtilityClass::EndEditParams(Interface *ip,IUtil *iu) { InterfacePtr = NULL; ip->DeleteRollupPage(SettingsPanelHWND); ip->DeleteRollupPage(ToolsPanelHWND); SettingsPanelHWND = NULL; ToolsPanelHWND = NULL; } void W3DUtilityClass::SelectionSetChanged(Interface *ip,IUtil *iu) { // (gth) the settings panels which need to respond to the selection set changing // are now registered directly with MAX and don't need to be updated here // update_dialog(); } int W3DUtilityClass::eval_tri_state(int totalcount,int oncount) { if (oncount == 0) { return 0; } if (oncount == totalcount) { return 1; } return 2; } void W3DUtilityClass::eval_node_states(INodeListClass * list,NodeStatesStruct * ns) { // initialize the counters and booleans ns->ExportHierarchy = 0; ns->ExportGeometry = 0; ns->GeometryHidden = 0; ns->GeometryTwoSided = 0; ns->GeometryZNormals = 0; ns->GeometryVertexAlpha = 0; ns->GeometryCastShadow = 0; ns->GeometryShatterable = 0; ns->GeometryNPatch = 0; ns->CollisionPhysical = 0; ns->CollisionProjectile = 0; ns->CollisionVis = 0; ns->CollisionCamera = 0; ns->CollisionVehicle = 0; ns->GeometryCameraAligned = false; ns->GeometryCameraOriented = false; ns->GeometryNormal = false; ns->GeometryAABox = false; ns->GeometryOBBox = false; ns->GeometryNull = false; ns->GeometryDazzle = false; ns->GeometryAggregate = false; /* ** ns->DamageRegion will be MAX_DAMAGE_REGIONS if not all ** of the selected nodes are in the same damage region. If ** they are, then ns->DamageRegion will be the region they ** share. */ if (list->Num_Nodes() > 0) { // Use the first damage region for comparing to the others. W3DAppData1Struct *wdata = get_app_data_1((*list)[0]); ns->DamageRegion = wdata->DamageRegion; } else ns->DamageRegion = MAX_DAMAGE_REGIONS; /* ** ns->DazzleType will be DEFAULT if not all of the selected ** nodes are the same. If they are the same, it will be the ** dazzle type that they all share */ ns->DazzleCount = 0; if (list->Num_Nodes() > 0) { W3DDazzleAppDataStruct * dazzledata = get_dazzle_app_data((*list)[0]); strncpy(ns->DazzleType,dazzledata->DazzleType,sizeof(ns->DazzleType)); } else { strcpy(ns->DazzleType,"DEFAULT"); } /* ** evaluate each node */ for (unsigned int ni=0; niNum_Nodes(); ni++) { W3DAppData2Struct * wdata = get_app_data_2((*list)[ni]); assert(wdata); ns->ExportHierarchy += (wdata->Is_Bone() ? 1 : 0); ns->ExportGeometry += (wdata->Is_Geometry() ? 1 : 0); ns->GeometryHidden += (wdata->Is_Hidden_Enabled() ? 1 : 0); ns->GeometryTwoSided += (wdata->Is_Two_Sided_Enabled() ? 1 : 0); ns->GeometryZNormals += (wdata->Is_ZNormals_Enabled() ? 1 : 0); ns->GeometryVertexAlpha += (wdata->Is_Vertex_Alpha_Enabled() ? 1 : 0); ns->GeometryCastShadow += (wdata->Is_Shadow_Enabled() ? 1 : 0); ns->GeometryShatterable += (wdata->Is_Shatterable_Enabled() ? 1 : 0); ns->GeometryNPatch += (wdata->Is_NPatchable_Enabled() ? 1 : 0); ns->CollisionPhysical += (wdata->Is_Physical_Collision_Enabled() ? 1 : 0); ns->CollisionProjectile += (wdata->Is_Projectile_Collision_Enabled() ? 1 : 0); ns->CollisionVis += (wdata->Is_Vis_Collision_Enabled() ? 1 : 0); ns->CollisionCamera += (wdata->Is_Camera_Collision_Enabled() ? 1 : 0); ns->CollisionVehicle += (wdata->Is_Vehicle_Collision_Enabled() ? 1 : 0); switch (wdata->Get_Geometry_Type()) { case W3DAppData2Struct::GEO_TYPE_CAMERA_ALIGNED: ns->GeometryCameraAligned = true; break; case W3DAppData2Struct::GEO_TYPE_CAMERA_ORIENTED: ns->GeometryCameraOriented = true; break; case W3DAppData2Struct::GEO_TYPE_NORMAL_MESH: ns->GeometryNormal = true; break; case W3DAppData2Struct::GEO_TYPE_AABOX: ns->GeometryAABox = true; break; case W3DAppData2Struct::GEO_TYPE_OBBOX: ns->GeometryOBBox = true; break; case W3DAppData2Struct::GEO_TYPE_NULL: ns->GeometryNull = true; break; case W3DAppData2Struct::GEO_TYPE_DAZZLE: ns->GeometryDazzle = true; ns->DazzleCount++; break; case W3DAppData2Struct::GEO_TYPE_AGGREGATE: ns->GeometryAggregate = true; break; } // Compare this damage region to our existing one. If it's not the same, // use MAX_DAMAGE_REGION (an invalid value) as a sentinel value. if (ns->DamageRegion != MAX_DAMAGE_REGIONS) { W3DAppData1Struct *wdata1 = get_app_data_1((*list)[ni]); assert(wdata1); if (wdata1->DamageRegion != ns->DamageRegion) ns->DamageRegion = MAX_DAMAGE_REGIONS; } // compare this objects dazzle type to our existing one. If its not // the same, use 'DEFAULT'. W3DDazzleAppDataStruct * dazzledata = get_dazzle_app_data((*list)[ni]); if (strcmp(ns->DazzleType,dazzledata->DazzleType) != 0) { strcpy(ns->DazzleType,"DEFAULT"); } } // If any of the counters are zero, that means none of the objects had that // bit set. If any of them are equal to the number of objects, then they // all had that bit set. Otherwise, there was a mix and we should use the // third state for the checkbox (greyed out check). int count = list->Num_Nodes(); ns->ExportHierarchy = eval_tri_state(count, ns->ExportHierarchy); ns->ExportGeometry = eval_tri_state(count, ns->ExportGeometry); ns->GeometryHidden = eval_tri_state(count, ns->GeometryHidden); ns->GeometryTwoSided = eval_tri_state(count, ns->GeometryTwoSided); ns->GeometryZNormals = eval_tri_state(count, ns->GeometryZNormals); ns->GeometryVertexAlpha = eval_tri_state(count, ns->GeometryVertexAlpha); ns->GeometryCastShadow = eval_tri_state(count, ns->GeometryCastShadow); ns->GeometryShatterable = eval_tri_state(count, ns->GeometryShatterable); ns->GeometryNPatch = eval_tri_state(count, ns->GeometryNPatch); ns->CollisionPhysical = eval_tri_state(count, ns->CollisionPhysical); ns->CollisionProjectile = eval_tri_state(count, ns->CollisionProjectile); ns->CollisionVis = eval_tri_state(count, ns->CollisionVis); ns->CollisionCamera = eval_tri_state(count, ns->CollisionCamera); ns->CollisionVehicle = eval_tri_state(count, ns->CollisionVehicle); } void W3DUtilityClass::update_settings_controls(INodeListClass * node_list) { SettingsFormClass::Update_All_Instances(); } void W3DUtilityClass::set_hierarchy_in_all_selected(INodeListClass * node_list,bool onoff) { for (unsigned int ni=0; niNum_Nodes(); ni++) { W3DAppData2Struct * wdata = get_app_data_2((*node_list)[ni]); wdata->Enable_Export_Transform(onoff); } update_settings_controls(node_list); } void W3DUtilityClass::set_geometry_in_all_selected(INodeListClass * node_list,bool onoff) { for (unsigned int ni=0; niNum_Nodes(); ni++) { W3DAppData2Struct * wdata = get_app_data_2((*node_list)[ni]); wdata->Enable_Export_Geometry(onoff); } update_settings_controls(node_list); } void W3DUtilityClass::enable_hidden_in_all_selected(INodeListClass * node_list,bool onoff) { for (unsigned int ni=0; niNum_Nodes(); ni++) { W3DAppData2Struct * wdata = get_app_data_2((*node_list)[ni]); wdata->Enable_Hidden(onoff); } update_settings_controls(node_list); } void W3DUtilityClass::enable_two_sided_in_all_selected(INodeListClass * node_list,bool onoff) { for (unsigned int ni=0; niNum_Nodes(); ni++) { W3DAppData2Struct * wdata = get_app_data_2((*node_list)[ni]); wdata->Enable_Two_Sided(onoff); } update_settings_controls(node_list); } void W3DUtilityClass::enable_znormals_in_all_selected(INodeListClass * node_list,bool onoff) { for (unsigned int ni=0; niNum_Nodes(); ni++) { W3DAppData2Struct * wdata = get_app_data_2((*node_list)[ni]); wdata->Enable_ZNormals(onoff); } update_settings_controls(node_list); } void W3DUtilityClass::enable_vertex_alpha_in_all_selected(INodeListClass * node_list,bool onoff) { for (unsigned int ni=0; niNum_Nodes(); ni++) { W3DAppData2Struct * wdata = get_app_data_2((*node_list)[ni]); wdata->Enable_Vertex_Alpha(onoff); } update_settings_controls(node_list); } void W3DUtilityClass::enable_shadow_in_all_selected(INodeListClass * node_list,bool onoff) { for (unsigned int ni=0; niNum_Nodes(); ni++) { W3DAppData2Struct * wdata = get_app_data_2((*node_list)[ni]); wdata->Enable_Shadow(onoff); } update_settings_controls(node_list); } void W3DUtilityClass::enable_shatterable_in_all_selected(INodeListClass * node_list,bool onoff) { for (unsigned int ni=0; niNum_Nodes(); ni++) { W3DAppData2Struct * wdata = get_app_data_2((*node_list)[ni]); wdata->Enable_Shatterable(onoff); } update_settings_controls(node_list); } void W3DUtilityClass::enable_npatches_in_all_selected(INodeListClass * node_list,bool onoff) { for (unsigned int ni=0; niNum_Nodes(); ni++) { W3DAppData2Struct * wdata = get_app_data_2((*node_list)[ni]); wdata->Enable_NPatchable(onoff); } update_settings_controls(node_list); } void W3DUtilityClass::enable_physical_collision_in_all_selected(INodeListClass * node_list,bool onoff) { for (unsigned int ni=0; niNum_Nodes(); ni++) { W3DAppData2Struct * wdata = get_app_data_2((*node_list)[ni]); wdata->Enable_Physical_Collision(onoff); } update_settings_controls(node_list); } void W3DUtilityClass::enable_projectile_collision_in_all_selected(INodeListClass * node_list,bool onoff) { for (unsigned int ni=0; niNum_Nodes(); ni++) { W3DAppData2Struct * wdata = get_app_data_2((*node_list)[ni]); wdata->Enable_Projectile_Collision(onoff); } update_settings_controls(node_list); } void W3DUtilityClass::enable_vis_collision_in_all_selected(INodeListClass * node_list,bool onoff) { for (unsigned int ni=0; niNum_Nodes(); ni++) { W3DAppData2Struct * wdata = get_app_data_2((*node_list)[ni]); wdata->Enable_Vis_Collision(onoff); } update_settings_controls(node_list); } void W3DUtilityClass::enable_camera_collision_in_all_selected(INodeListClass * node_list,bool onoff) { for (unsigned int ni=0; niNum_Nodes(); ni++) { W3DAppData2Struct * wdata = get_app_data_2((*node_list)[ni]); wdata->Enable_Camera_Collision(onoff); } update_settings_controls(node_list); } void W3DUtilityClass::enable_vehicle_collision_in_all_selected(INodeListClass * node_list,bool onoff) { for (unsigned int ni=0; niNum_Nodes(); ni++) { W3DAppData2Struct * wdata = get_app_data_2((*node_list)[ni]); wdata->Enable_Vehicle_Collision(onoff); } update_settings_controls(node_list); } void W3DUtilityClass::set_geometry_type_in_all_selected(INodeListClass * node_list,int geotype) { for (unsigned int ni=0; niNum_Nodes(); ni++) { W3DAppData2Struct * wdata = get_app_data_2((*node_list)[ni]); wdata->Set_Geometry_Type((W3DAppData2Struct::GeometryTypeEnum)geotype); } update_settings_controls(node_list); } void W3DUtilityClass::set_dazzle_type_in_all_selected(INodeListClass * node_list,char * dazzle_type) { for (unsigned int ni=0; niNum_Nodes(); ni++) { W3DDazzleAppDataStruct * dazzledata = get_dazzle_app_data((*node_list)[ni]); strncpy(dazzledata->DazzleType,dazzle_type,sizeof(dazzledata->DazzleType) - 1); } update_settings_controls(node_list); } void W3DUtilityClass::set_region_in_all_selected(INodeListClass * list,char region) { if (list->Num_Nodes() == 0) return; // Damage regions are stored in each node's AppData1. for (int i = 0; i < list->Num_Nodes(); i++) { W3DAppData1Struct *wdata = get_app_data_1((*list)[i]); wdata->DamageRegion = region; } update_settings_controls(list); } void W3DUtilityClass::generate_names(void) { GenNamesDialogClass dialog(InterfacePtr); bool retval = dialog.Get_Options(&NameOptions); WorkingNameIndex = NameOptions.NameIndex; if (retval) { descend_tree(InterfacePtr->GetRootNode(),GENERATE_NAME); } } void W3DUtilityClass::generate_material_names(void) { GenMtlNamesDialogClass dialog(InterfacePtr); bool retval = dialog.Get_Options(&MtlNameOptions); WorkingNameIndex = MtlNameOptions.NameIndex; if (retval) { descend_tree(InterfacePtr->GetRootNode(),GENERATE_MATERIAL_NAME); } } void W3DUtilityClass::generate_lod_extensions(void) { GenLodExtensionDialogClass dialog(InterfacePtr); bool retval = dialog.Get_Options(&LodExtensionOptions); if (retval) { descend_tree(InterfacePtr->GetRootNode(),GENERATE_LOD_EXTENSION); } } void W3DUtilityClass::generate_lod_ext(INode * node) { /* ** Only works on selected nodes. */ if (!node->Selected()) return; /* ** If this node already has an LOD extension, we'll replace it ** with the new LOD index. Otherwise we'll tack it on the end. ** Display a error message if the name is too long to append ** the extension, and skip the node without changing the name. */ char msg[256]; char newname[W3D_NAME_LEN]; char *oldname = node->GetName(); char *ext = strrchr(oldname, '.'); int old_lod; if ( (ext != NULL) && (sscanf(ext, ".%d", &old_lod) == 1) ) { /* ** An existing LOD index. If it's different than the new ** one, replace it. */ if (old_lod == LodExtensionOptions.LodIndex) return; // same lod index /* ** Room for the new extension? (2 because when we export, the extension will, ** be replaced by a single character [A..Z] to indicate the LOD level. ** ie. 2==strlen("A")+1) */ if (ext - oldname + 2 <= W3D_NAME_LEN) { *ext = '\0'; sprintf(newname, "%s.%02d", oldname, LodExtensionOptions.LodIndex); *ext = '.'; node->SetName(newname); } else { *ext = '\0'; sprintf(msg, "The maximum W3D object name is %d characters. Adding the LOD " "extension to \"%s\" will pass this limit! Please shorten its name.", W3D_NAME_LEN - 1, oldname); *ext = '.'; MessageBox(NULL, msg, "Error", MB_OK); } } else { /* ** Room for the new extension? (2 because when we export, the extension will, ** be replaced by a single character [A..Z] to indicate the LOD level. ** ie. 2==strlen("A")+1) */ if (strlen(oldname) + 2 <= W3D_NAME_LEN) { sprintf(newname, "%s.%02d", oldname, LodExtensionOptions.LodIndex); node->SetName(newname); } else { sprintf(msg, "The maximum W3D object name is %d characters. Adding the LOD " "extension to \"%s\" will pass this limit! Please shorten its name.", W3D_NAME_LEN - 1, oldname); MessageBox(NULL, msg, "Error", MB_OK); } } } void W3DUtilityClass::create_floater(void) { SettingsFloater.Create(InterfacePtr,IDD_W3DUTILITY_SETTINGS_DIALOG,_settings_form_dlg_proc); SettingsFormClass::Update_All_Instances(); } void W3DUtilityClass::export_with_standard_materials() { char *convertingmessage = "Converting materials..."; // Count the no. of references to game materials. MaterialReferenceMaker::ReferenceCount = convert_materials (GAME_REFERENCE_COUNT, NULL); MaterialReferenceMaker *gamenodematerials = NULL; if (MaterialReferenceMaker::ReferenceCount > 0) { gamenodematerials = new MaterialReferenceMaker [MaterialReferenceMaker::ReferenceCount]; assert (gamenodematerials != NULL); } InterfacePtr->PushPrompt (convertingmessage); SetCursor (LoadCursor (NULL, IDC_WAIT)); convert_materials (GAME_TO_STANDARD, gamenodematerials); InterfacePtr->PopPrompt(); InterfacePtr->FileExport(); UpdateWindow (InterfacePtr->GetMAXHWnd()); InterfacePtr->PushPrompt (convertingmessage); SetCursor (LoadCursor (NULL, IDC_WAIT)); convert_materials (STANDARD_TO_GAME, gamenodematerials); InterfacePtr->PopPrompt(); // Clean-up. if (gamenodematerials != NULL) delete [] gamenodematerials; } int W3DUtilityClass::convert_materials (MaterialConversionEnum conversion, MaterialReferenceMaker *gamenodematerials) { int gamenodematerialindex = 0; INode *rootnode = InterfacePtr->GetRootNode(); if (rootnode != NULL) { INodeListClass *meshlist = new INodeListClass (rootnode, 0); if (meshlist != NULL) { for (unsigned nodeindex = 0; nodeindex < meshlist->Num_Nodes(); nodeindex++) { Mtl *nodemtl = ((*meshlist) [nodeindex])->GetMtl(); // Is this a non-null material? if (nodemtl != NULL) { // Is this not a multi-material? if (!nodemtl->IsMultiMtl()) { switch (conversion) { case GAME_REFERENCE_COUNT: if (nodemtl->ClassID() == GameMaterialClassID) { assert (((GameMtl*) nodemtl)->Substitute_Material() == NULL); } break; case GAME_TO_STANDARD: if (nodemtl->ClassID() == GameMaterialClassID) { // Make a reference to the game material to ensure that it is not deleted by the system. gamenodematerials [gamenodematerialindex].MakeRefByID (FOREVER, gamenodematerialindex, nodemtl); // Does this material already have an equivalent standard material? if (((GameMtl*) nodemtl)->Substitute_Material() == NULL) { ((GameMtl*) nodemtl)->Set_Substitute_Material (new_standard_material ((GameMtl*) nodemtl)); } ((*meshlist) [nodeindex])->SetMtl (((GameMtl*) nodemtl)->Substitute_Material()); } else { gamenodematerials [gamenodematerialindex].MaterialPtr = NULL; } break; case STANDARD_TO_GAME: // Change materials to game materials if they were previously game materials before being // converted to standard materials. if (gamenodematerials [gamenodematerialindex].MaterialPtr != NULL) { ((*meshlist) [nodeindex])->SetMtl (gamenodematerials [gamenodematerialindex].MaterialPtr); ((GameMtl*) gamenodematerials [gamenodematerialindex].MaterialPtr)->Set_Substitute_Material (NULL); } break; } gamenodematerialindex++; } else { // For each sub-material... for (int materialindex = 0; materialindex < nodemtl->NumSubMtls(); materialindex++) { Mtl *submaterial = nodemtl->GetSubMtl (materialindex); // Is this a non-null submaterial? if (submaterial != NULL) { switch (conversion) { case GAME_REFERENCE_COUNT: if (submaterial->ClassID() == GameMaterialClassID) { assert (((GameMtl*) submaterial)->Substitute_Material() == NULL); } break; case GAME_TO_STANDARD: if (submaterial->ClassID() == GameMaterialClassID) { // Make a reference to the game material to ensure that it is not deleted by the system. gamenodematerials [gamenodematerialindex].MakeRefByID (FOREVER, gamenodematerialindex, submaterial); // Does this material already have an equivalent standard material? if (((GameMtl*) submaterial)->Substitute_Material() == NULL) { ((GameMtl*) submaterial)->Set_Substitute_Material (new_standard_material ((GameMtl*) submaterial)); } nodemtl->SetSubMtl (materialindex, ((GameMtl*) submaterial)->Substitute_Material()); } else { gamenodematerials [gamenodematerialindex].MaterialPtr = NULL; } break; case STANDARD_TO_GAME: // Change materials to game materials if they were previously game materials before being // converted to standard materials. if (gamenodematerials [gamenodematerialindex].MaterialPtr != NULL) { nodemtl->SetSubMtl (materialindex, gamenodematerials [gamenodematerialindex].MaterialPtr); ((GameMtl*) gamenodematerials [gamenodematerialindex].MaterialPtr)->Set_Substitute_Material (NULL); } break; } gamenodematerialindex++; } } } } } // Clean-up. delete meshlist; } } return (gamenodematerialindex); } StdMat *W3DUtilityClass::new_standard_material (GameMtl *gamemtl) { Color emissive; // Create a new standard material. StdMat *stdmtl = NewDefaultStdMat(); // Set its properties by translating the supplied game material. // NOTE 0: Only consider pass 0 in the game material - ignore all other passes. // NOTE 1: Use defaults for all standard material attributes that cannot be // converted from the game material in a meaningful way. stdmtl->SetName (gamemtl->GetName()); stdmtl->SetAmbient (gamemtl->GetAmbient(), 0); stdmtl->SetDiffuse (gamemtl->GetDiffuse(), 0); stdmtl->SetSpecular (gamemtl->GetSpecular(), 0); stdmtl->SetOpacity (gamemtl->Get_Opacity (0, 0), 0); stdmtl->SetShininess (gamemtl->Get_Shininess (0, 0), 0); stdmtl->SetShinStr (gamemtl->GetShinStr(), 0); stdmtl->SetSubTexmap (ID_DI, gamemtl->Get_Texture (0, 0)); emissive = gamemtl->Get_Emissive (0, 0); stdmtl->SetSelfIllum ((emissive.r + emissive.g + emissive.b) / 3.0f, 0); return (stdmtl); } void W3DUtilityClass::Select_Hierarchy(void) { InterfacePtr->SelectNode(NULL); INode * root = InterfacePtr->GetRootNode(); descend_tree(root,SELECT_HIER); InterfacePtr->ForceCompleteRedraw(); } void W3DUtilityClass::Select_Geometry(void) { InterfacePtr->SelectNode(NULL); INode * root = InterfacePtr->GetRootNode(); descend_tree(root,SELECT_GEOM); InterfacePtr->ForceCompleteRedraw(); } void W3DUtilityClass::Select_Alpha(void) { InterfacePtr->SelectNode(NULL); INode * root = InterfacePtr->GetRootNode(); descend_tree(root,SELECT_ALPHA); InterfacePtr->ForceCompleteRedraw(); } void W3DUtilityClass::Select_Physical(void) { InterfacePtr->SelectNode(NULL); INode * root = InterfacePtr->GetRootNode(); descend_tree(root,SELECT_PHYSICAL); InterfacePtr->ForceCompleteRedraw(); } void W3DUtilityClass::Select_Projectile(void) { InterfacePtr->SelectNode(NULL); INode * root = InterfacePtr->GetRootNode(); descend_tree(root,SELECT_PROJECTILE); InterfacePtr->ForceCompleteRedraw(); } void W3DUtilityClass::Select_Vis(void) { InterfacePtr->SelectNode(NULL); INode * root = InterfacePtr->GetRootNode(); descend_tree(root,SELECT_VIS); InterfacePtr->ForceCompleteRedraw(); } void W3DUtilityClass::descend_tree(INode * node,int func) { if (!node) return; switch (func) { case HIDE: hide_node(node); break; case SELECT_GEOM: select_geometry_node(node); break; case SELECT_HIER: select_hierarchy_node(node); break; case SELECT_ALPHA: select_alpha_node(node); break; case SELECT_PHYSICAL: select_physical_node(node); break; case SELECT_PROJECTILE: select_projectile_node(node); break; case SELECT_VIS: select_vis_node(node); break; case GENERATE_NAME: generate_node_name(node); break; case GENERATE_MATERIAL_NAME: generate_material_names_for_node(node); break; case GENERATE_LOD_EXTENSION: generate_lod_ext(node); break; default: break; }; for (int i=0; iNumberOfChildren(); i++) { INode * child = node->GetChildNode(i); descend_tree(child,func); } } void W3DUtilityClass::hide_node(INode * node) { if (!node->IsHidden()) node->Hide(TRUE); InterfacePtr->NodeInvalidateRect(node); } void W3DUtilityClass::select_geometry_node(INode * node) { if (Is_Geometry(node) && !node->IsHidden()) { InterfacePtr->SelectNode(node,0); } } void W3DUtilityClass::select_hierarchy_node(INode * node) { if (Is_Bone(node) && !node->IsHidden()) { InterfacePtr->SelectNode(node,0); } } void W3DUtilityClass::select_alpha_node(INode * node) { if (node->IsHidden() || !Is_Geometry(node)) { return; } Mtl * nodemtl = node->GetMtl(); if (is_alpha_material(nodemtl)) { if (is_alpha_mesh(node,nodemtl)) { InterfacePtr->SelectNode(node,0); } } } void W3DUtilityClass::select_physical_node(INode * node) { if (!node->IsHidden() && Is_Geometry(node) && Is_Physical_Collision(node)) { InterfacePtr->SelectNode(node,0); } } void W3DUtilityClass::select_projectile_node(INode * node) { if (!node->IsHidden() && Is_Geometry(node) && Is_Projectile_Collision(node)) { InterfacePtr->SelectNode(node,0); } } void W3DUtilityClass::select_vis_node(INode * node) { if (!node->IsHidden() && Is_Geometry(node) && Is_Vis_Collision(node)) { InterfacePtr->SelectNode(node,0); } } bool W3DUtilityClass::is_alpha_material(Mtl * nodemtl) { if (nodemtl == NULL) { return false; } bool is_alpha = false; if (nodemtl->IsMultiMtl()) { for (int mi=0; miNumSubMtls(); mi++) { is_alpha |= is_alpha_material(nodemtl->GetSubMtl(mi)); } } else { if (nodemtl->ClassID() == GameMaterialClassID) { GameMtl * gamemtl = (GameMtl *)nodemtl; if ( (gamemtl->Get_Dest_Blend(0) == W3DSHADER_DESTBLENDFUNC_SRC_ALPHA) || (gamemtl->Get_Dest_Blend(0) == W3DSHADER_DESTBLENDFUNC_ONE_MINUS_SRC_ALPHA) || (gamemtl->Get_Src_Blend(0) == W3DSHADER_SRCBLENDFUNC_SRC_ALPHA) || (gamemtl->Get_Src_Blend(0) == W3DSHADER_SRCBLENDFUNC_ONE_MINUS_SRC_ALPHA) || (gamemtl->Get_Alpha_Test(0) == W3DSHADER_ALPHATEST_ENABLE) ) { is_alpha = true; } } } return is_alpha; } bool W3DUtilityClass::is_alpha_mesh(INode * node,Mtl * nodemtl) { Object * obj = node->EvalWorldState(0).obj; TriObject * tri = (TriObject *)obj->ConvertToType(0, triObjectClassID); if (tri != NULL) { Mesh & mesh = tri->mesh; int face_index; int mat_index; if (nodemtl == NULL) { return false; } else if (nodemtl->NumSubMtls() <= 1) { return is_alpha_material(nodemtl); } else { int sub_mtl_count = nodemtl->NumSubMtls(); bool * sub_mtl_flags = new bool[sub_mtl_count]; // Initialize each sub-material flag to false (indicates that the material is un-used) for (mat_index=0; mat_indexGetSubMtl(mat_index))) { return true; } } } } } return false; } void W3DUtilityClass::generate_node_name(INode * node) { TCHAR temp_string[256]; if (NameOptions.OnlyAffectSelected && !node->Selected()) { return; } if (!Is_Bone(node) && !Is_Geometry(node)) { return; } if (NameOptions.AssignNames) { _stprintf(temp_string,"%s%03d",NameOptions.RootName,WorkingNameIndex); node->SetName(temp_string); WorkingNameIndex++; } if (NameOptions.AssignPrefix) { _stprintf(temp_string,"%s%s",NameOptions.PrefixName,node->GetName()); node->SetName(temp_string); } if (NameOptions.AssignSuffix) { _stprintf(temp_string,"%s%s",node->GetName(),NameOptions.SuffixName); node->SetName(temp_string); } if (NameOptions.AssignCollisionBits) { W3DAppData2Struct * wdata = W3DAppData2Struct::Get_App_Data(node); assert(wdata); wdata->Enable_Physical_Collision(NameOptions.PhysicalCollision); wdata->Enable_Projectile_Collision(NameOptions.ProjectileCollision); wdata->Enable_Vis_Collision(NameOptions.VisCollision); wdata->Enable_Camera_Collision(NameOptions.CameraCollision); wdata->Enable_Vehicle_Collision(NameOptions.VehicleCollision); } } void W3DUtilityClass::generate_material_names_for_node(INode * node) { if (MtlNameOptions.OnlyAffectSelected && !node->Selected()) { return; } generate_material_names(node->GetMtl()); } void W3DUtilityClass::generate_material_names(Mtl * mtl) { if (mtl == NULL) { return; } // set the name of this material and increment the index TCHAR newname[GenMtlNamesDialogClass::MAX_MATERIAL_NAME_LEN]; _stprintf(newname,"%s%03d",MtlNameOptions.RootName,WorkingNameIndex); mtl->SetName(newname); WorkingNameIndex++; // recurse into children if (mtl->IsMultiMtl()) { for (int mi=0; miNumSubMtls(); mi++) { generate_material_names(mtl->GetSubMtl(mi)); } } } W3DAppData0Struct * W3DUtilityClass::get_app_data_0(INode * node) { /* ** Try to get our AppData which has the export flags */ W3DAppData0Struct * wdata = NULL; AppDataChunk * appdata = node->GetAppDataChunk(W3DUtilityClassID,UTILITY_CLASS_ID,0); /* ** If there wasn't one, return NULL since this app data chunk is obsolete now. ** If there was one, get the data from it */ if (appdata) { wdata = (W3DAppData0Struct *)(appdata->data); } return wdata; } W3DAppData1Struct * W3DUtilityClass::get_app_data_1(INode * node) { // Try to get our AppData which has the damage region W3DAppData1Struct * wdata = NULL; AppDataChunk * appdata = node->GetAppDataChunk(W3DUtilityClassID,UTILITY_CLASS_ID,1); // If there wasn't one, add one. If there was one, get the data from it if (appdata) { wdata = (W3DAppData1Struct *)(appdata->data); } else { wdata = new W3DAppData1Struct; node->AddAppDataChunk(W3DUtilityClassID,UTILITY_CLASS_ID,1,sizeof(W3DAppData1Struct),wdata); appdata = node->GetAppDataChunk(W3DUtilityClassID,UTILITY_CLASS_ID,1); assert(appdata); } return wdata; } W3DAppData2Struct * W3DUtilityClass::get_app_data_2(INode * node) { return W3DAppData2Struct::Get_App_Data(node); } W3DDazzleAppDataStruct * W3DUtilityClass::get_dazzle_app_data(INode * node) { return W3DDazzleAppDataStruct::Get_App_Data(node); } /********************************************************************************************** ** ** Dialog procs for the W3DUtilityClass ** **********************************************************************************************/ static BOOL CALLBACK _w3d_utility_tools_dlg_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_MOUSEMOVE: TheW3DUtility.InterfacePtr->RollupMouseMessage(hWnd,msg,wParam,lParam); break; case WM_COMMAND: { switch (LOWORD(wParam)) { /* ** Buttons */ case IDC_SELECT_GEOMETRY: TheW3DUtility.Select_Geometry(); break; case IDC_SELECT_HIERARCHY: TheW3DUtility.Select_Hierarchy(); break; case IDC_SELECT_ALPHA_MESHES: TheW3DUtility.Select_Alpha(); break; case IDC_SELECT_PHYSICAL: TheW3DUtility.Select_Physical(); break; case IDC_SELECT_PROJECTILE: TheW3DUtility.Select_Projectile(); break; case IDC_SELECT_VIS: TheW3DUtility.Select_Vis(); break; case IDC_COLLECTION_NAMES_GENERATE: TheW3DUtility.generate_names(); TheW3DUtility.update_settings_controls(); break; case IDC_MATERIAL_NAMES_GENERATE: TheW3DUtility.generate_material_names(); TheW3DUtility.update_settings_controls(); break; case IDC_LOD_EXTENSION_GENERATE: TheW3DUtility.generate_lod_extensions(); TheW3DUtility.update_settings_controls(); break; case IDC_EXPORT_STANDARD_MATERIALS: TheW3DUtility.export_with_standard_materials(); break; case IDC_CREATE_SETTINGS_FLOATER: TheW3DUtility.create_floater(); break; } return TRUE; } default: return FALSE; } return TRUE; } /********************************************************************************************** ** ** SettingsFormClass Implementation ** NOTE: When you use the _settings_form_dlg_proc, a SettingsFormClass will automatically ** be allocated and attached to the dialog. You can cause all of the active forms to ** refresh their status by calling Update_All_Instances. The forms will be destroyed when ** the window is destroyed. ** **********************************************************************************************/ SettingsFormClass * SettingsFormClass::ActiveList = NULL; BOOL CALLBACK _settings_form_dlg_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { if (msg == WM_INITDIALOG) { SettingsFormClass * form = new SettingsFormClass(hWnd); ::SetProp(hWnd,"SettingsFormClass",(HANDLE)form); } SettingsFormClass * form = (SettingsFormClass *)::GetProp(hWnd,"SettingsFormClass"); if (form) { return form->Dialog_Proc(hWnd,msg,wParam,lParam); } else { return FALSE; } } static void _settings_form_selection_changed_callback(void * param,NotifyInfo * info) { ((SettingsFormClass*)param)->Selection_Changed(); } SettingsFormClass::SettingsFormClass(HWND hwnd) : Hwnd(hwnd), RegionSpin(NULL) { /* ** Link into the active list */ Next = ActiveList; ActiveList = this; /* ** Register with MAX */ ::RegisterNotification(_settings_form_selection_changed_callback, this, NOTIFY_SELECTIONSET_CHANGED); } SettingsFormClass::~SettingsFormClass(void) { /* ** Unregister from MAX */ ::UnRegisterNotification(_settings_form_selection_changed_callback, this, NOTIFY_SELECTIONSET_CHANGED); /* ** Unlink from the active list */ if (ActiveList == this) { ActiveList = Next; } else { SettingsFormClass * prev = ActiveList; SettingsFormClass * cur = ActiveList->Next; while ((cur != this) && (cur != NULL)) { cur = cur->Next; prev = prev->Next; } assert(cur == this); if (cur == this) { prev->Next = cur->Next; } } Hwnd = NULL; } void SettingsFormClass::Update_All_Instances(void) { if (ActiveList == NULL) { return; } /* ** Build a list of the selected nodes */ INodeListClass node_list( ::GetCOREInterface()->GetRootNode(), ::GetCOREInterface()->GetTime(), &_INodeFilter ); /* ** Update all settings forms */ SettingsFormClass * form = ActiveList; while (form != NULL) { form->Update_Controls(&node_list); form = form->Next; } } void SettingsFormClass::Init(void) { // Initialize the contents of the dazzle combo // Reset the dazzle combo HWND dazzle_combo = GetDlgItem(Hwnd,IDC_DAZZLE_COMBO); assert(dazzle_combo != NULL); SendMessage(dazzle_combo,CB_RESETCONTENT,0,0); // Load the section of Dazzle.INI that defines all of the types. The windows function // that I'm using here, reads in a NULL-terminated string for each entry in the section. Each // string is of the form 'key=value'. Based on my testing, it appears that windows removes any white // space before or after the equal sign as well. char dllpath[_MAX_PATH]; ::GetModuleFileName(AppInstance,dllpath,sizeof(dllpath)); char * last_slash = strrchr(dllpath,'\\'); last_slash++; strcpy(last_slash,DAZZLE_SETTINGS_FILENAME); char * dazzle_types_buffer = new char[DAZZLE_SECTION_BUFFERSIZE]; // max size of a section for Win95 ::GetPrivateProfileSection( DAZZLE_TYPES_SECTION, dazzle_types_buffer, DAZZLE_SECTION_BUFFERSIZE, dllpath); // Now we need to handle each string in the section buffer; skipping the 'key=' and adding // the dazzle type name into the combo box. char * entry = dazzle_types_buffer; if (entry != NULL) { while (*entry != NULL) { entry = strchr(entry,'='); if (entry != NULL) { entry++; ::SendMessage(dazzle_combo,CB_ADDSTRING,0,(LPARAM)entry); entry += strlen(entry) + 1; } } } else { ::SendMessage(dazzle_combo,CB_ADDSTRING,0,(LPARAM)"Default"); } ::SendMessage(dazzle_combo,CB_SETCURSEL,(WPARAM)0,0); delete dazzle_types_buffer; /* ** Setup the damage region spinner control. */ RegionSpin = SetupIntSpinner ( Hwnd, IDC_DAMREG_INDEX_SPIN, IDC_DAMREG_INDEX_EDIT, NO_DAMAGE_REGION, MAX_DAMAGE_REGIONS-1, NO_DAMAGE_REGION ); } void SettingsFormClass::Destroy(void) { ReleaseISpinner(RegionSpin); RegionSpin = NULL; } bool SettingsFormClass::Dialog_Proc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam) { int check; switch (message) { case WM_INITDIALOG: Init(); break; case WM_DESTROY: Destroy(); delete this; break; case WM_COMMAND: { /* ** handle the tri-state checkboxes. ** MAKE SURE YOU PUT ANY NEW CHECKBOX ID's IN HERE!!! */ int control_id = LOWORD(wParam); if ( (control_id == IDC_HIERARCHY_CHECK) || (control_id == IDC_GEOMETRY_CHECK) || (control_id == IDC_GEOMETRY_HIDE) || (control_id == IDC_GEOMETRY_TWO_SIDED) || (control_id == IDC_GEOMETRY_ZNORMALS) || (control_id == IDC_GEOMETRY_VERTEX_ALPHA) || (control_id == IDC_GEOMETRY_CAST_SHADOW) || (control_id == IDC_GEOMETRY_SHATTERABLE) || (control_id == IDC_GEOMETRY_NPATCH) || (control_id == IDC_COLLISION_PHYSICAL) || (control_id == IDC_COLLISION_PROJECTILE) || (control_id == IDC_COLLISION_VIS) || (control_id == IDC_COLLISION_CAMERA) || (control_id == IDC_COLLISION_VEHICLE)) { check = !SendDlgItemMessage(hWnd,LOWORD(wParam),BM_GETCHECK,0,0L); SendDlgItemMessage(hWnd,LOWORD(wParam),BM_SETCHECK,check,0L); } INodeListClass node_list( ::GetCOREInterface()->GetRootNode(), ::GetCOREInterface()->GetTime(), &_INodeFilter ); switch (LOWORD(wParam)) { /* ** Tri-State Checkboxes, make sure that the ID of all checkboxes is present ** in the 'if' statement above! */ case IDC_HIERARCHY_CHECK: W3DUtilityClass::set_hierarchy_in_all_selected(&node_list,check == BST_CHECKED); break; case IDC_GEOMETRY_CHECK: W3DUtilityClass::set_geometry_in_all_selected(&node_list,check == BST_CHECKED); break; case IDC_GEOMETRY_HIDE: W3DUtilityClass::enable_hidden_in_all_selected(&node_list,check == BST_CHECKED); break; case IDC_GEOMETRY_TWO_SIDED: W3DUtilityClass::enable_two_sided_in_all_selected(&node_list,check == BST_CHECKED); break; case IDC_GEOMETRY_ZNORMALS: W3DUtilityClass::enable_znormals_in_all_selected(&node_list,check == BST_CHECKED); break; case IDC_GEOMETRY_VERTEX_ALPHA: W3DUtilityClass::enable_vertex_alpha_in_all_selected(&node_list,check == BST_CHECKED); break; case IDC_GEOMETRY_CAST_SHADOW: W3DUtilityClass::enable_shadow_in_all_selected(&node_list,check == BST_CHECKED); break; case IDC_GEOMETRY_SHATTERABLE: W3DUtilityClass::enable_shatterable_in_all_selected(&node_list,check == BST_CHECKED); break; case IDC_GEOMETRY_NPATCH: W3DUtilityClass::enable_npatches_in_all_selected(&node_list,check == BST_CHECKED); break; case IDC_COLLISION_PHYSICAL: W3DUtilityClass::enable_physical_collision_in_all_selected(&node_list,check == BST_CHECKED); break; case IDC_COLLISION_PROJECTILE: W3DUtilityClass::enable_projectile_collision_in_all_selected(&node_list,check == BST_CHECKED); break; case IDC_COLLISION_VIS: W3DUtilityClass::enable_vis_collision_in_all_selected(&node_list,check == BST_CHECKED); break; case IDC_COLLISION_CAMERA: W3DUtilityClass::enable_camera_collision_in_all_selected(&node_list,check == BST_CHECKED); break; case IDC_COLLISION_VEHICLE: W3DUtilityClass::enable_vehicle_collision_in_all_selected(&node_list,check == BST_CHECKED); break; /* ** Radio buttons for the Geometry type */ case IDC_GEOMETRY_NORMAL: W3DUtilityClass::set_geometry_type_in_all_selected(&node_list,W3DAppData2Struct::GEO_TYPE_NORMAL_MESH); break; case IDC_GEOMETRY_CAMERA_ALIGNED: W3DUtilityClass::set_geometry_type_in_all_selected(&node_list,W3DAppData2Struct::GEO_TYPE_CAMERA_ALIGNED); break; case IDC_GEOMETRY_CAMERA_ORIENTED: W3DUtilityClass::set_geometry_type_in_all_selected(&node_list,W3DAppData2Struct::GEO_TYPE_CAMERA_ORIENTED); break; case IDC_GEOMETRY_NULL: W3DUtilityClass::set_geometry_type_in_all_selected(&node_list,W3DAppData2Struct::GEO_TYPE_NULL); break; case IDC_GEOMETRY_AABOX: W3DUtilityClass::set_geometry_type_in_all_selected(&node_list,W3DAppData2Struct::GEO_TYPE_AABOX); break; case IDC_GEOMETRY_OBBOX: W3DUtilityClass::set_geometry_type_in_all_selected(&node_list,W3DAppData2Struct::GEO_TYPE_OBBOX); break; case IDC_GEOMETRY_AGGREGATE: W3DUtilityClass::set_geometry_type_in_all_selected(&node_list,W3DAppData2Struct::GEO_TYPE_AGGREGATE); break; case IDC_GEOMETRY_DAZZLE: W3DUtilityClass::set_geometry_type_in_all_selected(&node_list,W3DAppData2Struct::GEO_TYPE_DAZZLE); break; /* ** Dazzle type setting. Whenever the user changes the selected dazzle type, apply ** the new setting to all selected nodes. */ case IDC_DAZZLE_COMBO: if (HIWORD(wParam) == CBN_SELCHANGE) { HWND dazzle_combo = GetDlgItem(hWnd,IDC_DAZZLE_COMBO); if (dazzle_combo != NULL) { char dazzle_type[128]; int cursel = ::SendMessage(dazzle_combo,CB_GETCURSEL,0,0); int len = ::SendMessage(dazzle_combo,CB_GETLBTEXTLEN,cursel,0); if (len < 128) { ::SendMessage(dazzle_combo,CB_GETLBTEXT,(WPARAM)cursel,(LPARAM)dazzle_type); W3DUtilityClass::set_dazzle_type_in_all_selected(&node_list,dazzle_type); } } } break; } return TRUE; } /* ** Spinners */ case CC_SPINNER_CHANGE: { INodeListClass node_list( ::GetCOREInterface()->GetRootNode(), ::GetCOREInterface()->GetTime(), &_INodeFilter ); W3DUtilityClass::set_region_in_all_selected(&node_list,RegionSpin->GetIVal()); break; } /* ** Max Custom Edit boxes */ case WM_CUSTEDIT_ENTER: { INodeListClass node_list( ::GetCOREInterface()->GetRootNode(), ::GetCOREInterface()->GetTime(), &_INodeFilter ); ICustEdit * edit_ctrl = GetICustEdit(GetDlgItem(hWnd,wParam)); if (wParam == IDC_OBJ_NAME) { if (edit_ctrl && node_list.Num_Nodes() == 1) { char buffer[64]; edit_ctrl->GetText(buffer,sizeof(buffer)); node_list[0]->SetName(buffer); Update_All_Instances(); } } ReleaseICustEdit(edit_ctrl); break; } default: return FALSE; } return TRUE; } void SettingsFormClass::Selection_Changed(void) { INodeListClass node_list( ::GetCOREInterface()->GetRootNode(), ::GetCOREInterface()->GetTime(), &_INodeFilter ); Update_Controls(&node_list); } void SettingsFormClass::Update_Controls(INodeListClass * node_list) { /* ** Update name of currently selected object ** "Multiple" if more than one, "None" if no selected objs... */ ICustEdit * edit_ctrl = GetICustEdit(GetDlgItem(Hwnd,IDC_OBJ_NAME)); if (edit_ctrl != NULL) { if (node_list->Num_Nodes() == 0) { edit_ctrl->Enable(FALSE); edit_ctrl->SetText(Get_String(IDS_NO_OBJECT)); } else if (node_list->Num_Nodes() == 1) { edit_ctrl->Enable(TRUE); edit_ctrl->SetText((*node_list)[0]->GetName()); } else { edit_ctrl->Enable(FALSE); edit_ctrl->SetText(Get_String(IDS_MULTIPLE_OBJECTS)); } ReleaseICustEdit(edit_ctrl); } if (node_list->Num_Nodes() == 0) { Disable_Controls(); return; } W3DUtilityClass::NodeStatesStruct ns; W3DUtilityClass::eval_node_states(node_list,&ns); /* ** Enable hierarchy and geometry checks since they are always available */ EnableWindow(GetDlgItem(Hwnd,IDC_HIERARCHY_CHECK),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_CHECK),TRUE); /* ** Enable/Disable the geometry controls */ if (ns.ExportGeometry == 1) { EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_CAMERA_ALIGNED),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_CAMERA_ORIENTED),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_NORMAL),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_NULL),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_AABOX),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_OBBOX),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_AGGREGATE),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_DAZZLE),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_HIDE),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_TWO_SIDED),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_ZNORMALS),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_VERTEX_ALPHA),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_CAST_SHADOW),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_SHATTERABLE),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_NPATCH),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_COLLISION_PHYSICAL),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_COLLISION_PROJECTILE),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_COLLISION_VIS),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_COLLISION_CAMERA),TRUE); EnableWindow(GetDlgItem(Hwnd,IDC_COLLISION_VEHICLE),TRUE); } else { EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_CAMERA_ALIGNED),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_CAMERA_ORIENTED),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_NORMAL),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_NULL),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_AABOX),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_OBBOX),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_AGGREGATE),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_DAZZLE),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_HIDE),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_TWO_SIDED),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_ZNORMALS),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_VERTEX_ALPHA),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_CAST_SHADOW),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_SHATTERABLE),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_NPATCH),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_COLLISION_PHYSICAL),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_COLLISION_PROJECTILE),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_COLLISION_VIS),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_COLLISION_CAMERA),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_COLLISION_VEHICLE),FALSE); } /* ** Set the checks based on the nodes states: ** no check - none of the selected nodes had this setting ** check - all of the selected nodes had this setting ** grey check - some of the selected nodes had this setting */ SendDlgItemMessage(Hwnd,IDC_HIERARCHY_CHECK,BM_SETCHECK,ns.ExportHierarchy,0L); SendDlgItemMessage(Hwnd,IDC_GEOMETRY_CHECK,BM_SETCHECK,ns.ExportGeometry,0L); SendDlgItemMessage(Hwnd,IDC_GEOMETRY_HIDE,BM_SETCHECK,ns.GeometryHidden,0L); SendDlgItemMessage(Hwnd,IDC_GEOMETRY_TWO_SIDED,BM_SETCHECK,ns.GeometryTwoSided,0L); SendDlgItemMessage(Hwnd,IDC_GEOMETRY_ZNORMALS,BM_SETCHECK,ns.GeometryZNormals,0L); SendDlgItemMessage(Hwnd,IDC_GEOMETRY_VERTEX_ALPHA,BM_SETCHECK,ns.GeometryVertexAlpha,0L); SendDlgItemMessage(Hwnd,IDC_GEOMETRY_CAST_SHADOW,BM_SETCHECK,ns.GeometryCastShadow,0L); SendDlgItemMessage(Hwnd,IDC_GEOMETRY_SHATTERABLE,BM_SETCHECK,ns.GeometryShatterable,0L); SendDlgItemMessage(Hwnd,IDC_GEOMETRY_NPATCH,BM_SETCHECK,ns.GeometryNPatch,0L); SendDlgItemMessage(Hwnd,IDC_COLLISION_PHYSICAL,BM_SETCHECK,ns.CollisionPhysical,0L); SendDlgItemMessage(Hwnd,IDC_COLLISION_PROJECTILE,BM_SETCHECK,ns.CollisionProjectile,0L); SendDlgItemMessage(Hwnd,IDC_COLLISION_VIS,BM_SETCHECK,ns.CollisionVis,0L); SendDlgItemMessage(Hwnd,IDC_COLLISION_CAMERA,BM_SETCHECK,ns.CollisionCamera,0L); SendDlgItemMessage(Hwnd,IDC_COLLISION_VEHICLE,BM_SETCHECK,ns.CollisionVehicle,0L); /* ** The damage region spinner should only be enabled if ** Export Hierarchy is checked for all selected nodes. */ BOOL spinner_enable = false; if (ns.ExportHierarchy == 1) { if (ns.DamageRegion != MAX_DAMAGE_REGIONS) { // Show the damage region in the spinner. RegionSpin->SetIndeterminate(FALSE); RegionSpin->SetValue(ns.DamageRegion, FALSE); } else { // The selected objects aren't all in the same region. RegionSpin->SetIndeterminate(TRUE); } spinner_enable = true; } EnableWindow(GetDlgItem(Hwnd,IDC_DAMREG_INDEX_EDIT),spinner_enable); EnableWindow(GetDlgItem(Hwnd,IDC_DAMREG_INDEX_SPIN),spinner_enable); /* ** The dazzle combo box should only be enabled if ** Export Geometry, and geometry type dazzle is set for all ** selected nodes. */ bool dazzle_combo_enable = false; if (ns.ExportGeometry == 1) { if (ns.DazzleCount == node_list->Num_Nodes()) { dazzle_combo_enable = true; } } HWND dazzle_combo = GetDlgItem(Hwnd,IDC_DAZZLE_COMBO); EnableWindow(dazzle_combo,dazzle_combo_enable); int selindex = ::SendMessage(dazzle_combo,CB_FINDSTRING,(WPARAM)0,(LPARAM)ns.DazzleType); if (selindex != CB_ERR) { ::SendMessage(dazzle_combo,CB_SETCURSEL,(WPARAM)selindex,(LPARAM)0); } else { ::SendMessage(dazzle_combo,CB_SETCURSEL,(WPARAM)0,(LPARAM)0); } /* ** Set any radio buttons present */ CheckDlgButton(Hwnd,IDC_GEOMETRY_CAMERA_ALIGNED,(ns.GeometryCameraAligned ? BST_CHECKED : BST_UNCHECKED)); CheckDlgButton(Hwnd,IDC_GEOMETRY_CAMERA_ORIENTED,(ns.GeometryCameraOriented ? BST_CHECKED : BST_UNCHECKED)); CheckDlgButton(Hwnd,IDC_GEOMETRY_NORMAL,(ns.GeometryNormal ? BST_CHECKED : BST_UNCHECKED)); CheckDlgButton(Hwnd,IDC_GEOMETRY_NULL,(ns.GeometryNull ? BST_CHECKED : BST_UNCHECKED)); CheckDlgButton(Hwnd,IDC_GEOMETRY_AABOX,(ns.GeometryAABox ? BST_CHECKED : BST_UNCHECKED)); CheckDlgButton(Hwnd,IDC_GEOMETRY_OBBOX,(ns.GeometryOBBox ? BST_CHECKED : BST_UNCHECKED)); CheckDlgButton(Hwnd,IDC_GEOMETRY_AGGREGATE,(ns.GeometryAggregate ? BST_CHECKED : BST_UNCHECKED)); CheckDlgButton(Hwnd,IDC_GEOMETRY_DAZZLE,(ns.GeometryDazzle ? BST_CHECKED : BST_UNCHECKED)); } void SettingsFormClass::Disable_Controls(void) { EnableWindow(GetDlgItem(Hwnd,IDC_OBJ_NAME),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_HIERARCHY_CHECK),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_CHECK),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_DAMREG_INDEX_EDIT),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_DAMREG_INDEX_SPIN),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_NORMAL),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_CAMERA_ALIGNED),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_CAMERA_ORIENTED),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_AABOX),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_OBBOX),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_NULL),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_AGGREGATE),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_DAZZLE),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_HIDE),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_TWO_SIDED),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_ZNORMALS),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_VERTEX_ALPHA),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_CAST_SHADOW),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_SHATTERABLE),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_GEOMETRY_NPATCH),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_COLLISION_PHYSICAL),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_COLLISION_PROJECTILE),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_COLLISION_VIS),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_COLLISION_CAMERA),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_COLLISION_VEHICLE),FALSE); EnableWindow(GetDlgItem(Hwnd,IDC_DAZZLE_COMBO),FALSE); CheckDlgButton(Hwnd,IDC_HIERARCHY_CHECK,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_GEOMETRY_CHECK,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_GEOMETRY_CAMERA_ALIGNED,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_GEOMETRY_CAMERA_ORIENTED,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_GEOMETRY_NORMAL,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_GEOMETRY_AABOX,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_GEOMETRY_OBBOX,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_GEOMETRY_NULL,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_GEOMETRY_AGGREGATE,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_GEOMETRY_DAZZLE,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_GEOMETRY_HIDE,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_GEOMETRY_TWO_SIDED,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_GEOMETRY_ZNORMALS,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_GEOMETRY_VERTEX_ALPHA,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_GEOMETRY_CAST_SHADOW,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_GEOMETRY_SHATTERABLE,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_GEOMETRY_NPATCH,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_COLLISION_PHYSICAL,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_COLLISION_PROJECTILE,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_COLLISION_VIS,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_COLLISION_CAMERA,BST_UNCHECKED); CheckDlgButton(Hwnd,IDC_COLLISION_VEHICLE,BST_UNCHECKED); } /* ** Functions to access the W3D AppData of any INode. */ W3DAppData0Struct * GetW3DAppData0 (INode *node) { return TheW3DUtility.get_app_data_0(node); } W3DAppData1Struct * GetW3DAppData1 (INode *node) { return TheW3DUtility.get_app_data_1(node); } W3DAppData2Struct * GetW3DAppData2 (INode *node) { return TheW3DUtility.get_app_data_2(node); } W3DDazzleAppDataStruct * GetW3DDazzleAppData(INode *node) { return TheW3DUtility.get_dazzle_app_data(node); }