/* ** 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 . */ /*********************************************************************************************** *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** *********************************************************************************************** * * * Project name : Buccaneer Bay * * * * File name : AlphaModifier.cpp * * * * Programmer : Mike Lytle * * * * Start date : 11/1/1999 * * * * Last update : 11/1/1999 * * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "AlphaModifier.h" enum Alpha_Messages { AM_NOTHING, AM_UPDATE_DATA, AM_INITIALIZE, AM_BOX_CHECKED, }; enum Dialog_Controls { DL_EDIT_VALUE, DL_FIND_CHECK_BOX, }; void AlphaModifierClass::ModifyObject(TimeValue t, ModContext &mc, ObjectState *os, INode *node) { if (!os->obj->IsSubClassOf(triObjectClassID)) { return; } // Get a mesh from input object TriObject *object = (TriObject*)os->obj; Mesh *mesh = &object->mesh; assert(mesh); int numVert = mesh->getNumVerts(); int i = 0; float *vdata = NULL; // Get parameters from pblock float sparam = 0.0f; Interval valid = LocalValidity(t); int pass = 1; pblock->GetValue(DL_EDIT_VALUE, t, sparam, valid); // If needed a control could be put into the dialog box to specify which // pass to apply the alpha values to. At this time, it was decided to // not implement this because of the complexity to the artist and the // performance issues in game. //pblock->GetValue(DL_EDIT_PASS, t, pass, valid); // Start from 0. pass -= 1; assert(pass >= 0); // Use a channel for each pass. vdata = mesh->vertexFloat(ALPHA_VERTEX_CHANNEL + pass); if (!vdata) { // Turn on the channel for vertex alpha support. mesh->setVDataSupport(ALPHA_VERTEX_CHANNEL + pass); vdata = mesh->vertexFloat(ALPHA_VERTEX_CHANNEL + pass); assert(vdata); for (i = 0; i < numVert; i++) { if (mesh->VertSel()[i]) { vdata[i] = 0.0f; } } } // Tracks the state of the FIND check box. int box_checked = 0; if (Message == AM_UPDATE_DATA) { // The user has updated the dialog box, so update the data. assert(vdata); pblock->GetValue(DL_FIND_CHECK_BOX, t, box_checked, valid); if (!box_checked) { for (i = 0; i < numVert; i++) { if (SelectedVertices[i]) { vdata[i] = sparam; } } } } if (Message == AM_BOX_CHECKED) { pblock->GetValue(DL_FIND_CHECK_BOX, t, box_checked, valid); } // The user is trying to find vertices with certain values. if (box_checked) { assert(vdata); // Find the vertices that have the user entered value. for (i = 0; i < numVert; i++) { if (vdata[i] == sparam) { mesh->VertSel().Set(i); SelectedVertices.Set(i); } else { mesh->VertSel().Clear(i); SelectedVertices.Clear(i); } } } if (Message == AM_INITIALIZE) { assert(vdata); SelectedVertices = mesh->VertSel(); for (i = 0; i < numVert; i++) { if (SelectedVertices[i]) { // Set the value in the dialog box to the value of the // first selected vertex. pblock->SetValue(DL_EDIT_VALUE, t, vdata[i]); break; } } } // Always select the vertices that have been saved by the modifier. // This must be done because the mesh changes each time ModfiyObject is called. for (i = 0; i < numVert; i++) { if (SelectedVertices[i]) { mesh->VertSel().Set(i); } else { mesh->VertSel().Clear(i); } } // Display the vertices. mesh->SetDispFlag(DISP_SELVERTS | DISP_VERTTICKS); mesh->selLevel = MESH_VERTEX; object->UpdateValidity(SELECT_CHAN_NUM, object->ChannelValidity (t, SELECT_CHAN_NUM)); // Clear messages. Message = AM_NOTHING; } /*===========================================================================*\ | NotifyInputChanged is called each time the input object is changed in some way | We can find out how it was changed by checking partID and message \*===========================================================================*/ void AlphaModifierClass::NotifyInputChanged(Interval changeInt, PartID partID, RefMessage message, ModContext *mc) { if( (partID&PART_TOPO) || (partID&PART_GEOM) || (partID&PART_SELECT) ) { NotifyDependents(FOREVER, PART_OBJ, REFMSG_CHANGE); } } /*===========================================================================*\ | Class Descriptor OSM \*===========================================================================*/ class AlphaClassDesc : public ClassDesc2 { public: int IsPublic() { return TRUE; } void * Create( BOOL loading ) { return new AlphaModifierClass; } const TCHAR * ClassName() { return Get_String(IDS_ALPHA_MODIFIER_CLASS); } SClass_ID SuperClassID() { return OSM_CLASS_ID; } Class_ID ClassID() { return ALPHA_MODIFIER_CLASSID; } const TCHAR* Category() { return _T(""); } HINSTANCE HInstance() { return AppInstance; } // Hardwired name, used by MAX Script as unique identifier const TCHAR* InternalName() { return _T("AlphaMod"); } }; static AlphaClassDesc AlphaCD; ClassDesc* Get_Alpha_Desc() {return &AlphaCD;} /*===========================================================================*\ | Paramblock2 Descriptor \*===========================================================================*/ static ParamBlockDesc2 alpha_param_blk ( //rollout 0, _T("AlphaModifierParams"), 0, &AlphaCD, P_AUTO_CONSTRUCT + P_AUTO_UI, 0, IDD_ALPHA_MODIFIER, IDS_PARAMETERS, 0, 0, NULL, // params DL_EDIT_VALUE, _T("Custom Data Value"), TYPE_FLOAT, P_ANIMATABLE, IDS_ALPHA_MODIFIER_CLASS, p_default, 0.0f, p_range, 0.0f, 100.0f, p_ui, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_ALPHA_EDIT, IDC_ALPHA_SPIN, 1.0f, end, DL_FIND_CHECK_BOX, _T("1 Custom Data Value"), TYPE_BOOL, 0, IDS_ALPHA_MODIFIER_CLASS, p_default, FALSE, p_ui, TYPE_SINGLECHEKBOX, IDC_ALPHA_CHECKBOX, p_enabled, TRUE, end, /* DL_EDIT_PASS, _T("2 Custom Data Value"), TYPE_INT, P_ANIMATABLE, IDS_ALPHA_MODIFIER_CLASS, p_default, 1, p_range, 1, 4, p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_ALPHA_EDIT2, IDC_ALPHA_SPIN2, 1.0, end, */ end ); /*===========================================================================*\ | Basic implementation of a dialog handler \*===========================================================================*/ BOOL AlphaModDlgProc::DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { int id = LOWORD(wParam); int code = HIWORD(wParam); switch (msg) { case WM_INITDIALOG: AlphaModifier->Message = AM_INITIALIZE; break; case WM_DESTROY: break; case WM_COMMAND: switch (code) { case EN_UPDATE: break; case EN_SETFOCUS: break; case EN_KILLFOCUS: break; case EN_CHANGE: break; } if (id == IDC_ALPHA_EDIT) { AlphaModifier->Message = AM_UPDATE_DATA; } if (id == IDC_ALPHA_CHECKBOX) { AlphaModifier->Message = AM_BOX_CHECKED; } break; case WM_NOTIFY: if (id == IDC_ALPHA_EDIT) { AlphaModifier->Message = AM_UPDATE_DATA; } break; default: break; } return FALSE; } /*===========================================================================*\ | Constructor | Ask the ClassDesc2 to make the AUTO_CONSTRUCT paramblocks and wire them in \*===========================================================================*/ AlphaModifierClass::AlphaModifierClass() { AlphaCD.MakeAutoParamBlocks(this); assert(pblock); Message = 0; } /*===========================================================================*\ | Invalidate our UI (or the recently changed parameter) \*===========================================================================*/ void AlphaModifierClass::InvalidateUI() { alpha_param_blk.InvalidateUI(pblock->LastNotifyParamID()); } /*===========================================================================*\ | Open and Close dialog UIs | We ask the ClassDesc2 to handle Beginning and Ending EditParams for us \*===========================================================================*/ void AlphaModifierClass::BeginEditParams( IObjParam *ip, ULONG flags,Animatable *prev ) { AlphaCD.BeginEditParams(ip, this, flags, prev); alpha_param_blk.SetUserDlgProc(new AlphaModDlgProc(this)); } void AlphaModifierClass::EndEditParams( IObjParam *ip, ULONG flags,Animatable *next ) { AlphaCD.EndEditParams(ip, this, flags, next); } /*===========================================================================*\ | Standard clone \*===========================================================================*/ RefTargetHandle AlphaModifierClass::Clone(RemapDir& remap) { AlphaModifierClass* newmod = new AlphaModifierClass(); newmod->ReplaceReference(0,pblock->Clone(remap)); return(newmod); } /*===========================================================================*\ | Subanim & References support \*===========================================================================*/ Animatable* AlphaModifierClass::SubAnim(int i) { switch (i) { case 0: return pblock; default: return NULL; } } TSTR AlphaModifierClass::SubAnimName(int i) { switch (i) { case 0: return Get_String(IDS_PARAMETERS); default: return _T(""); } } RefTargetHandle AlphaModifierClass::GetReference(int i) { switch (i) { case 0: return pblock; default: assert(TRUE); return NULL; } } void AlphaModifierClass::SetReference(int i, RefTargetHandle rtarg) { switch (i) { case 0: pblock = (IParamBlock2*)rtarg; break; default: assert(TRUE); break; } } RefResult AlphaModifierClass::NotifyRefChanged ( Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message ) { switch (message) { case REFMSG_CHANGE: { alpha_param_blk.InvalidateUI(); } break; } return REF_SUCCEED; } /*===========================================================================*\ | The validity of our parameters | Start at FOREVER, and intersect with the validity of each item \*===========================================================================*/ Interval AlphaModifierClass::GetValidity(TimeValue t) { float f; Interval valid = FOREVER; pblock->GetValue(DL_EDIT_VALUE, t, f, valid); return valid; } Interval AlphaModifierClass::LocalValidity(TimeValue t) { return GetValidity(t); }