/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, 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 . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ #include "HeadSpin.h" #include "max.h" #include "meshdlib.h" #include "dummy.h" #include "resource.h" #include "plComponent.h" #include "plComponentReg.h" #include "../MaxMain/plPlasmaRefMsgs.h" #include "../MaxMain/plMaxNode.h" #include "plWaterComponent.h" #include "plSoftVolumeComponent.h" #include "hsTypes.h" #include "plTweak.h" #include "../plDrawable/plWaveSetBase.h" #include "../plDrawable/plWaveSet7.h" #include "../plDrawable/plFixedWaterState7.h" #include "../plPipeline/plDynamicEnvMap.h" #include "../MaxMain/plPluginResManager.h" #include "../pnSceneObject/plSceneObject.h" #include "../pnMessage/plObjRefMsg.h" #include "../plScene/plVisRegion.h" static const float kPercentToFrac(1.e-2f); static const float kDegreeToRad(hsScalarPI/180.f); // Preliminary setup bookkeeping void DummyCodeIncludeFuncWater() { } CLASS_DESC(plWaterComponent, gWaterCompDesc, "Large Water", "Water", COMP_TYPE_WATER, WATER_COMP_CID) ParamBlockDesc2 gWaterBk ( plComponent::kBlkComp, _T("Water"), 0, &gWaterCompDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP, plComponent::kRefComp, plWaterComponent::kNumRollups, plWaterComponent::kRef, IDD_COMP_W_REFOBJECT, IDS_COMP_W_REFOBJECT, 0, 0, 0, // plWaterComponent::kBasicWater, IDD_COMP_W_BASICWATER, IDS_COMP_W_BASICWATER, 0, 0, 0, plWaterComponent::kGeoWater, IDD_COMP_W_GEOWATER, IDS_COMP_W_GEOWATER, 0, 0, 0, plWaterComponent::kTexWater, IDD_COMP_W_TEXWATER, IDS_COMP_W_TEXWATER, 0, 0, 0, plWaterComponent::kAdvWater, IDD_COMP_W_ADVWATER, IDS_COMP_W_ADVWATER, 0, 0, 0, plWaterComponent::kEnvMap, IDD_COMP_W_ENVMAP, IDS_COMP_W_ENVMAP, 0, 0, 0, plWaterComponent::kVtxHelp, IDD_COMP_W_VTXHELP, IDS_COMP_W_VTXHELP, 0, 0, 0, plWaterComponent::kBasicShore, IDD_COMP_W_BASICSHORE, IDS_COMP_W_BASICSHORE, 0, 0, 0, plWaterComponent::kAdvShore, IDD_COMP_W_ADVSHORE, IDS_COMP_W_ADVSHORE, 0, 0, 0, plWaterComponent::kRefObject, _T("RefObject"), TYPE_INODE, 0, 0, p_ui, plWaterComponent::kRef, TYPE_PICKNODEBUTTON, IDC_COMP_W_REFOBJECT, p_prompt, IDS_COMP_CHOOSE_OBJECT, end, // WATER BASIC plWaterComponent::kWindSpeed, _T("WindSpeed"), TYPE_FLOAT, 0, 0, // p_default, 30.0, // p_range, -1.0, 50.0, // p_ui, plWaterComponent::kBasicWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, // IDC_COMP_W_WINDSPEED, IDC_COMP_W_WINDSPEED_SPIN, 1.0, end, plWaterComponent::kWaterTint, _T("WaterTint"), TYPE_RGBA, 0, 0, // p_default, Color(0.1, 0.2, 0.2), // p_ui, plWaterComponent::kBasicWater, TYPE_COLORSWATCH, IDC_COMP_W_WATERTINT, end, plWaterComponent::kWaterOpac, _T("WaterOpac"), TYPE_FLOAT, 0, 0, // p_default, 100.0, // p_range, 0.0, 100.0, // p_ui, plWaterComponent::kBasicWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, // IDC_COMP_W_WATEROPAC, IDC_COMP_W_WATEROPAC_SPIN, 1.0, end, plWaterComponent::kSpecularTint, _T("SpecularTint"), TYPE_RGBA, 0, 0, p_default, Color(1.0, 1.0, 1.0), p_ui, plWaterComponent::kGeoWater, TYPE_COLORSWATCH, IDC_COMP_W_SPECULARTINT, end, plWaterComponent::kRippleScale, _T("RippleScale"), TYPE_FLOAT, 0, 0, p_default, 25.0, p_range, 5.0, 1000.0, p_ui, plWaterComponent::kTexWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_TEX_RIPPLESCALE, IDC_COMP_W_TEX_RIPPLESCALE_SPIN, 1.0, end, plWaterComponent::kDispersion, _T("Dispersion"), TYPE_FLOAT, 0, 0, // p_default, 0.0, // p_range, 0.0, 100.0, // p_ui, plWaterComponent::kBasicWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, // IDC_COMP_W_DISPERSION, IDC_COMP_W_DISPERSION_SPIN, 1.0, end, // WATER ADVANCED plWaterComponent::kDepthOpac, _T("DepthOpac"), TYPE_FLOAT, 0, 0, p_default, 3.0, p_range, 0.5, 20.0, p_ui, plWaterComponent::kAdvWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_DEPTHOPAC, IDC_COMP_W_DEPTHOPAC_SPIN, 1.0, end, plWaterComponent::kDepthRefl, _T("DepthRefl"), TYPE_FLOAT, 0, 0, p_default, 3.0, p_range, 0.5, 20.0, p_ui, plWaterComponent::kAdvWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_DEPTHREFL, IDC_COMP_W_DEPTHREFL_SPIN, 1.0, end, plWaterComponent::kDepthWave, _T("DepthWave"), TYPE_FLOAT, 0, 0, p_default, 4.0, p_range, 0.5, 20.0, p_ui, plWaterComponent::kAdvWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_DEPTHWAVE, IDC_COMP_W_DEPTHWAVE_SPIN, 1.0, end, plWaterComponent::kZeroOpac, _T("ZeroOpac"), TYPE_FLOAT, 0, 0, p_default, -1.0, p_range, -10.0, 10.0, p_ui, plWaterComponent::kAdvWater, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_COMP_W_ZEROOPAC, IDC_COMP_W_ZEROOPAC_SPIN, 1.0, end, plWaterComponent::kZeroRefl, _T("ZeroRefl"), TYPE_FLOAT, 0, 0, p_default, 0.0, p_range, -10.0, 10.0, p_ui, plWaterComponent::kAdvWater, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_COMP_W_ZEROREFL, IDC_COMP_W_ZEROREFL_SPIN, 1.0, end, plWaterComponent::kZeroWave, _T("ZeroWave"), TYPE_FLOAT, 0, 0, p_default, 0.0, p_range, -10.0, 10.0, p_ui, plWaterComponent::kAdvWater, TYPE_SPINNER, EDITTYPE_FLOAT, IDC_COMP_W_ZEROWAVE, IDC_COMP_W_ZEROWAVE_SPIN, 1.0, end, // SHORE BASIC plWaterComponent::kShoreTint, _T("ShoreTint"), TYPE_RGBA, 0, 0, p_default, Color(0.2, 0.4, 0.4), p_ui, plWaterComponent::kBasicShore, TYPE_COLORSWATCH, IDC_COMP_W_SHORETINT, end, plWaterComponent::kShoreOpac, _T("ShoreOpac"), TYPE_FLOAT, 0, 0, p_default, 40.0, p_range, 0.0, 100.0, p_ui, plWaterComponent::kBasicShore, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_SHOREOPAC, IDC_COMP_W_SHOREOPAC_SPIN, 1.0, end, plWaterComponent::kWispiness, _T("Wispiness"), TYPE_FLOAT, 0, 0, p_default, 50.0, p_range, 0.0, 200.0, p_ui, plWaterComponent::kBasicShore, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_WISPINESS, IDC_COMP_W_WISPINESS_SPIN, 1.0, end, // SHORE ADVANCED plWaterComponent::kPeriod, _T("Period"), TYPE_FLOAT, 0, 0, p_default, 100.0, p_range, 50.0, 200.0, p_ui, plWaterComponent::kAdvShore, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_PERIOD, IDC_COMP_W_PERIOD_SPIN, 1.0, end, plWaterComponent::kFinger, _T("Finger"), TYPE_FLOAT, 0, 0, p_default, 100.0, p_range, 50.0, 300.0, p_ui, plWaterComponent::kAdvShore, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_FINGER, IDC_COMP_W_FINGER_SPIN, 1.0, end, plWaterComponent::kEnvObject, _T("EnvObject"), TYPE_INODE, 0, 0, p_ui, plWaterComponent::kEnvMap, TYPE_PICKNODEBUTTON, IDC_COMP_W_ENVOBJECT, p_prompt, IDS_COMP_CHOOSE_OBJECT, end, plWaterComponent::kEnvSize, _T("EnvSize"), TYPE_INT, 0, 0, p_default, 256, p_range, 32, 512, p_ui, plWaterComponent::kEnvMap, TYPE_SPINNER, EDITTYPE_INT, IDC_COMP_W_ENVSIZE, IDC_COMP_W_ENVSIZE_SPIN, 1.f, end, plWaterComponent::kEnvRadius, _T("EnvRadius"), TYPE_FLOAT, 0, 0, p_default, 500.0, p_range, 5.0, 10000.0, p_ui, plWaterComponent::kEnvMap, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_ENVRADIUS, IDC_COMP_W_ENVRADIUS_SPIN, 1.0, end, plWaterComponent::kEdgeOpac, _T("EdgeOpac"), TYPE_FLOAT, 0, 0, p_default, 100.0, p_range, 0.0, 100.0, p_ui, plWaterComponent::kAdvShore, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_EDGEOPAC, IDC_COMP_W_EDGEOPAC_SPIN, 1.0, end, plWaterComponent::kEdgeRadius, _T("EdgeRadius"), TYPE_FLOAT, 0, 0, p_default, 100.0, p_range, 50.0, 300.0, p_ui, plWaterComponent::kAdvShore, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_EDGERADIUS, IDC_COMP_W_EDGERADIUS_SPIN, 1.0, end, plWaterComponent::kEnvRefresh, _T("EnvRefresh"), TYPE_FLOAT, 0, 0, p_default, 0.0, p_range, 0.0, 3600.0, p_ui, plWaterComponent::kEnvMap, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_ENVREFRESH, IDC_COMP_W_ENVREFRESH_SPIN, 10.0, end, plWaterComponent::kGeoMinLen, _T("GeoMinLen"), TYPE_FLOAT, 0, 0, p_default, 4.0, p_range, 0.1, 50.0, p_ui, plWaterComponent::kGeoWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_GEO_MINLEN, IDC_COMP_W_GEO_MINLEN_SPIN, 1.0, end, plWaterComponent::kGeoMaxLen, _T("GeoMaxLen"), TYPE_FLOAT, 0, 0, p_default, 8.0, p_range, 0.1, 50.0, p_ui, plWaterComponent::kGeoWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_GEO_MAXLEN, IDC_COMP_W_GEO_MAXLEN_SPIN, 1.0, end, plWaterComponent::kGeoAmpOverLen, _T("GeoAngleDev"), TYPE_FLOAT, 0, 0, p_default, 10.0, p_range, 0.0, 100.0, p_ui, plWaterComponent::kGeoWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_GEO_AMPOVERLEN, IDC_COMP_W_GEO_AMPOVERLEN_SPIN, 1.0, end, plWaterComponent::kGeoAngleDev, _T("GeoAngleDev"), TYPE_FLOAT, 0, 0, p_default, 20.0, p_range, 0.0, 180.0, p_ui, plWaterComponent::kGeoWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_GEO_ANGLEDEV, IDC_COMP_W_GEO_ANGLEDEV_SPIN, 10.0, end, plWaterComponent::kGeoChop, _T("GeoChop"), TYPE_FLOAT, 0, 0, p_default, 50.0, p_range, 0.0, 500.0, p_ui, plWaterComponent::kGeoWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_GEO_CHOP, IDC_COMP_W_GEO_CHOP_SPIN, 1.0, end, plWaterComponent::kTexMinLen, _T("TexMinLen"), TYPE_FLOAT, 0, 0, p_default, 0.1, p_range, 0.01, 4.0, p_ui, plWaterComponent::kTexWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_TEX_MINLEN, IDC_COMP_W_TEX_MINLEN_SPIN, 1.0, end, plWaterComponent::kTexMaxLen, _T("TexMaxLen"), TYPE_FLOAT, 0, 0, p_default, 4.0, p_range, 0.1, 50.0, p_ui, plWaterComponent::kTexWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_TEX_MAXLEN, IDC_COMP_W_TEX_MAXLEN_SPIN, 1.0, end, plWaterComponent::kTexAmpOverLen, _T("TexAngleDev"), TYPE_FLOAT, 0, 0, p_default, 10.0, p_range, 0.0, 100.0, p_ui, plWaterComponent::kTexWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_TEX_AMPOVERLEN, IDC_COMP_W_TEX_AMPOVERLEN_SPIN, 1.0, end, plWaterComponent::kTexAngleDev, _T("TexAngleDev"), TYPE_FLOAT, 0, 0, p_default, 20.0, p_range, 0.0, 180.0, p_ui, plWaterComponent::kTexWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_TEX_ANGLEDEV, IDC_COMP_W_TEX_ANGLEDEV_SPIN, 1.0, end, plWaterComponent::kNoise, _T("Noise"), TYPE_FLOAT, 0, 0, p_default, 50.0, p_range, 0.0, 300.0, p_ui, plWaterComponent::kTexWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_TEX_NOISE, IDC_COMP_W_TEX_NOISE_SPIN, 1.0, end, plWaterComponent::kTexChop, _T("TexChop"), TYPE_FLOAT, 0, 0, p_default, 50.0, p_range, 0.0, 500.0, p_ui, plWaterComponent::kTexWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_TEX_CHOP, IDC_COMP_W_TEX_CHOP_SPIN, 1.0, end, plWaterComponent::kSpecStart, _T("SpecStart"), TYPE_FLOAT, 0, 0, p_default, 50.0, p_range, 0.0, 1000.0, p_ui, plWaterComponent::kTexWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_TEX_SPECSTART, IDC_COMP_W_TEX_SPECSTART_SPIN, 10.0, end, plWaterComponent::kSpecEnd, _T("SpecEnd"), TYPE_FLOAT, 0, 0, p_default, 1000.0, p_range, 0.0, 10000.0, p_ui, plWaterComponent::kTexWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_TEX_SPECEND, IDC_COMP_W_TEX_SPECEND_SPIN, 10.0, end, plWaterComponent::kSpecularMute, _T("SpecularMute"), TYPE_FLOAT, 0, 0, p_default, 30.0, p_range, 0.0, 100.0, p_ui, plWaterComponent::kGeoWater, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_W_GEO_SPECMUTE, IDC_COMP_W_GEO_SPECMUTE_SPIN, 1.0, end, end ); class plWaterCompPostLoadCallback : public PostLoadCallback { public: plWaterComponent* fWaterComp; plWaterCompPostLoadCallback(plWaterComponent* wc) : fWaterComp(wc) {} void proc(ILoad *iload) { fWaterComp->CheckForObsoleteParams(); delete this; } }; IOResult plWaterComponent::Load(ILoad* iLoad) { iLoad->RegisterPostLoadCallback(new plWaterCompPostLoadCallback(this)); return plComponent::Load(iLoad); } void plWaterComponent::CheckForObsoleteParams() { if( (fCompPB->GetFloat(kDispersion) >= 0) ||(fCompPB->GetFloat(kWindSpeed) >= 0) ) { // Okay, these are old. Need to set some default values based // on the old obsolete ones. Basically, we need to go from: // // kDispersion => // GeoAngleDev // TexAngleDev // // kWindSpeed // GeoMinLen // GeoMaxLen // GeoAmpOverLen = 0.1 // // TexMinLen // TexMaxLen // TexAmpOverLen // // Noise // // kEnvRadius // SpecStart = kEnvRadius / 2.f // SpecEnd = kEnvRadius * 2.f // Okay, here we go. hsScalar dispersion = fCompPB->GetFloat(kDispersion) / 100.f; plConst(hsScalar) kMinAng(5.f); plConst(hsScalar) kMaxAng(180.f); hsScalar angleDev = kMinAng + dispersion * (kMaxAng - kMinAng); fCompPB->SetValue(kGeoAngleDev, TimeValue(0), angleDev); fCompPB->SetValue(kTexAngleDev, TimeValue(0), angleDev); hsScalar windSpeed = fCompPB->GetFloat(kWindSpeed); const hsScalar kGravConst(32.f); // ft/s^2 hsScalar waveLen = windSpeed * windSpeed / kGravConst; waveLen /= 2.f; if( waveLen < 1.f ) waveLen = 1.f; fCompPB->SetValue(kGeoMinLen, TimeValue(0), waveLen/2.f); fCompPB->SetValue(kGeoMaxLen, TimeValue(0), waveLen*2.f); fCompPB->SetValue(kGeoAmpOverLen, TimeValue(0), 10.f); hsScalar rippleScale = fCompPB->GetFloat(kRippleScale); fCompPB->SetValue(kTexMinLen, TimeValue(0), 4.f / 256.f * rippleScale); fCompPB->SetValue(kTexMaxLen, TimeValue(0), 32.f / 256.f * rippleScale); hsScalar amp = 0.01f; hsScalar specMute = 0.5f; if( windSpeed < 15.f ) { hsScalar p = windSpeed / 15.f; amp += p * (0.1f - 0.01f); specMute += (1-p)* 0.5f; } fCompPB->SetValue(kTexAmpOverLen, TimeValue(0), amp*100.f); fCompPB->SetValue(kSpecularMute, TimeValue(0), specMute*100.f); fCompPB->SetValue(kNoise, TimeValue(0), 50.f); hsScalar envRad = fCompPB->GetFloat(kEnvRadius); hsScalar specStart = envRad / 2.f; hsScalar specEnd = envRad * 2.f; fCompPB->SetValue(kSpecStart, TimeValue(0), specStart); fCompPB->SetValue(kSpecEnd, TimeValue(0), specEnd); // Set them negative so we don't keep doing this. fCompPB->SetValue(kDispersion, TimeValue(0), -1.f); fCompPB->SetValue(kWindSpeed, TimeValue(0), -1.f); } } // Component implementation plWaterComponent::plWaterComponent() : fWaveSet(nil) { fClassDesc = &gWaterCompDesc; fClassDesc->MakeAutoParamBlocks(this); } hsBool plWaterComponent::SetupProperties(plMaxNode* node, plErrorMsg* pErrMsg) { node->SetRunTimeLight(true); node->SetForceMaterialCopy(true); node->SetForceShadow(false); node->SetNoShadow(true); node->SetSmoothAll(true); node->SetForceSortable(true); node->SetNoSpanSort(true); node->SetNoPreShade(true); // Turn on calculation of edge lengths XXX node->SetCalcEdgeLens(true); // Make a note that we're vertex shaded (at least ripplecomponent needs to know).XXX node->SetVS(true); // Turn off the convexity test. We want to be sorted.XXX node->SetConcave(true); node->SetReverseSort(true); node->SetWaterHeight(IGetWaterHeight()); return true; } hsBool plWaterComponent::PreConvert(plMaxNode* node, plErrorMsg* pErrMsg) { if( !fWaveSet ) IMakeWaveSet(node, pErrMsg); // Do it again in case some idiot is trying to override.XXX pErrMsg->Set(!node->HasLoadMask(), node->GetName(), "PS water has no representation component").CheckAndAsk(); pErrMsg->Set(false); return true; } hsBool plWaterComponent::Convert(plMaxNode* node, plErrorMsg* pErrMsg) { if( !fWaveSet ) return true; plObjRefMsg* refMsg = TRACKED_NEW plObjRefMsg(node->GetKey(), plRefMsg::kOnRequest, -1, plObjRefMsg::kModifier); hsgResMgr::ResMgr()->AddViaNotify(fWaveSet->GetKey(), refMsg, plRefFlags::kActiveRef); return true; } hsBool plWaterComponent::DeInit(plMaxNode* node, plErrorMsg* pErrMsg) { if( fWaveSet ) fWaveSet->GetKey()->UnRefObject(); fWaveSet = nil; return true; } hsBool plWaterComponent::IReadRefObject(plMaxNodeBase* node, plFixedWaterState7& ws) { INode* ref = fCompPB->GetINode(kRefObject); if( !ref ) { ref = node; } if( !ref ) return false; Matrix3 xfm = ref->GetNodeTM(TimeValue(0)); ws.fWaterHeight = xfm.GetTrans().z; Point3 y = xfm.GetRow(1); hsVector3 dir(-y.x, -y.y, 0); dir.Normalize(); ws.fWindDir = dir; return true; } hsBool plWaterComponent::IReadEnvObject(plMaxNode* node, plErrorMsg* pErrMsg, plFixedWaterState7& ws) { INode* ref = fCompPB->GetINode(kEnvObject); if( !ref ) { ref = node; } plDynamicEnvMap* env = plEnvMapComponent::GetEnvMap((plMaxNode*)ref); if( !env ) { UInt32 size = fCompPB->GetInt(kEnvSize); UInt32 i; for( i = 9; i > 5; i-- ) { if( (1UL << i) <= size ) break; } size = UInt32(1 << i); env = TRACKED_NEW plDynamicEnvMap(size, size, 32); hsgResMgr::ResMgr()->NewKey(ref->GetName(), env, node->GetLocation(), node->GetLoadMask()); Point3 pos = ref->GetNodeTM(TimeValue(0)).GetTrans(); env->SetPosition(hsPoint3(pos.x, pos.y, pos.z)); env->SetYon(10000.f); env->SetRefreshRate(fCompPB->GetFloat(kEnvRefresh)); } if( !env ) return false; ws.fEnvCenter = env->GetPosition(); ws.fEnvRefresh = env->GetRefreshRate(); fWaveSet->SetEnvSize(env->GetWidth()); plGenRefMsg* refMsg = TRACKED_NEW plGenRefMsg(fWaveSet->GetKey(), plRefMsg::kOnCreate, -1, plWaveSet7::kRefEnvMap); hsgResMgr::ResMgr()->SendRef(env->GetKey(), refMsg, plRefFlags::kActiveRef); ws.fEnvRadius = fCompPB->GetFloat(kEnvRadius); return true; } hsBool plWaterComponent::IGetRefObject(plMaxNode* node) { plMaxNode* ref = (plMaxNode*)fCompPB->GetINode(kRefObject); if( (ref != node) // We have an exterior reference node && ref->CanConvert() // it's being exported && ref->IsTMAnimated() ) { plSceneObject* refObj = ref->GetSceneObject(); fWaveSet->SetRefObject(refObj); return true; } return false; } hsBool plWaterComponent::IMakeWaveSet(plMaxNode* node, plErrorMsg* pErrMsg) { // Go ahead and create the WaveSet modifier. There will be just // one created by this component, everyone has to share. fWaveSet = TRACKED_NEW plWaveSet7; hsgResMgr::ResMgr()->NewKey( IGetUniqueName(node), fWaveSet, node->GetLocation(), node->GetLoadMask()); // Set up the parameters plFixedWaterState7 ws; // Things we get off the reference (plane) object // First we look to see if it's an animated runtime object we need to keep track of. // Either way, we just grab the static info we need off of it, for init or forever. IGetRefObject(node); IReadRefObject(node, ws); // Things we get from our paramblock plFixedWaterState7::WaveState& geoState = ws.fGeoState; geoState.fMaxLength = fCompPB->GetFloat(kGeoMaxLen); geoState.fMinLength = fCompPB->GetFloat(kGeoMinLen); geoState.fAmpOverLen = fCompPB->GetFloat(kGeoAmpOverLen) * kPercentToFrac; geoState.fChop = fCompPB->GetFloat(kGeoChop) * kPercentToFrac; geoState.fAngleDev = fCompPB->GetFloat(kGeoAngleDev) * kDegreeToRad; plFixedWaterState7::WaveState& texState = ws.fTexState; texState.fMaxLength = fCompPB->GetFloat(kTexMaxLen); texState.fMinLength = fCompPB->GetFloat(kTexMinLen); texState.fAmpOverLen = fCompPB->GetFloat(kTexAmpOverLen) * kPercentToFrac; texState.fChop = fCompPB->GetFloat(kTexChop) * kPercentToFrac; texState.fAngleDev = fCompPB->GetFloat(kTexAngleDev) * kDegreeToRad; hsVector3 specVec; specVec[ws.kNoise] = fCompPB->GetFloat(kNoise) * kPercentToFrac; specVec[ws.kSpecStart] = fCompPB->GetFloat(kSpecStart); specVec[ws.kSpecEnd] = fCompPB->GetFloat(kSpecEnd); ws.fSpecVec = specVec; ws.fWispiness = fCompPB->GetFloat(kWispiness) * kPercentToFrac; ws.fPeriod = fCompPB->GetFloat(kPeriod) * kPercentToFrac; ws.fRippleScale = fCompPB->GetFloat(kRippleScale); ws.fFingerLength = fCompPB->GetFloat(kFinger) * kPercentToFrac; ws.fDepthFalloff = hsVector3(fCompPB->GetFloat(kDepthOpac), fCompPB->GetFloat(kDepthRefl), fCompPB->GetFloat(kDepthWave)); ws. fWaterOffset = hsVector3(-fCompPB->GetFloat(kZeroOpac), -fCompPB->GetFloat(kZeroRefl), -fCompPB->GetFloat(kZeroWave)); ws.fMaxAtten = hsVector3(1.f, 1.f, 1.f); ws.fMinAtten = hsVector3(0, 0, 0); IReadEnvObject(node, pErrMsg, ws); // Some colors ws.fWaterTint = hsColorRGBA().Set(1.f, 1.f, 1.f, 1.f); Color specTint = fCompPB->GetColor(kSpecularTint); float specMute = fCompPB->GetFloat(kSpecularMute) * kPercentToFrac; ws.fSpecularTint = hsColorRGBA().Set(specTint.r, specTint.g, specTint.b, specMute); ws.fMaxColor = hsColorRGBA().Set(1.f, 1.f, 1.f, 1.f); // Always white/opaque? Color shoreTint = fCompPB->GetColor(kShoreTint); float shoreOpac = fCompPB->GetFloat(kShoreOpac) * kPercentToFrac; ws.fMinColor = hsColorRGBA().Set(shoreTint.r, shoreTint.g, shoreTint.b, shoreOpac); // Not really used. ws.fShoreTint = hsColorRGBA().Set(1.f, 1.f, 1.f, 1.f); ws.fEdgeOpac = fCompPB->GetFloat(kEdgeOpac) * kPercentToFrac; ws.fEdgeRadius = fCompPB->GetFloat(kEdgeRadius) * kPercentToFrac; fWaveSet->SetState(ws, 0.f); // Add a ref to the waveset. fWaveSet->GetKey()->RefObject(); return true; } hsScalar plWaterComponent::IGetWaterHeight() { plMaxNodeBase* node = nil; int i; for( i = 0; i < NumTargets(); i++ ) { node = GetTarget(i); if( node ) break; } plFixedWaterState7 ws; IReadRefObject(node, ws); return ws.fWaterHeight; } hsScalar plWaterComponent::GetWaterHeight(INode* node) { if( !node ) return 0.f; plComponentBase *comp = ((plMaxNodeBase*)node)->ConvertToComponent(); if( !comp ) return 0.f; if( comp->ClassID() != WATER_COMP_CID ) return 0.f; plWaterComponent* water = (plWaterComponent*)comp; return water->IGetWaterHeight(); } plWaveSetBase* plWaterComponent::GetWaveSet(INode* node) { if( !node ) return nil; plComponentBase *comp = ((plMaxNodeBase*)node)->ConvertToComponent(); if( !comp ) return nil; if( comp->ClassID() != WATER_COMP_CID ) return nil; plWaterComponent* water = (plWaterComponent*)comp; return water->IGetWaveSet(); } plWaveSetBase* plWaterComponent::GetWaveSetFromNode(plMaxNode* node) { if( !node ) return nil; int n = node->NumAttachedComponents(); int i; for( i = 0; i < n; i++ ) { plComponentBase* comp = node->GetAttachedComponent(i); if( comp && (comp->ClassID() == WATER_COMP_CID) ) { plWaterComponent* water = (plWaterComponent*)comp; return water->IGetWaveSet(); } } return nil; } static void ISetWaterDependencies(plMaxNode* node, INode* waterNode) { if( !waterNode ) return; plComponentBase *comp = ((plMaxNodeBase*)waterNode)->ConvertToComponent(); if( !comp ) return; if( comp->ClassID() != WATER_COMP_CID ) return; INodeTab nodeList; comp->AddTargetsToList(nodeList); int i; for( i = 0; i < nodeList.Count(); i++ ) { if( nodeList[i] ) node->AddRenderDependency((plMaxNodeBase*)nodeList[i]); } } ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// class plShoreCompSelProc : public ParamMap2UserDlgProc { public: BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); void DeleteThis() { } }; #include "plPickNode.h" BOOL plShoreCompSelProc::DlgProc(TimeValue t, IParamMap2 *paramMap, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: { IParamBlock2 *pb = paramMap->GetParamBlock(); INode* node = pb->GetINode(plShoreComponent::kWaveSet); TSTR newName(node ? node->GetName() : "Pick"); ::SetWindowText(::GetDlgItem(hWnd, IDC_COMP_SHORE_CHOSE), newName); } return true; case WM_COMMAND: if( (HIWORD(wParam) == BN_CLICKED) && (LOWORD(wParam) == IDC_COMP_SHORE_CHOSE) ) { IParamBlock2 *pb = paramMap->GetParamBlock(); std::vector cids; cids.push_back(WATER_COMP_CID); if( plPick::Node(pb, plShoreComponent::kWaveSet, &cids, true, true) ) { INode* node = pb->GetINode(plShoreComponent::kWaveSet); TSTR newName(node ? node->GetName() : "Pick"); ::SetWindowText(::GetDlgItem(hWnd, IDC_COMP_SHORE_CHOSE), newName); paramMap->Invalidate(plShoreComponent::kWaveSet); ShowWindow(hWnd, SW_HIDE); ShowWindow(hWnd, SW_SHOW); } return false; } return true; } return false; } plShoreCompSelProc gShoreCompSelProc; CLASS_DESC(plShoreComponent, gShoreCompDesc, "Shore Line", "Shore", COMP_TYPE_WATER, SHORE_COMP_CID) ParamBlockDesc2 gShoreCompBk ( plComponent::kBlkComp, _T("Shore"), 0, &gShoreCompDesc, P_AUTO_CONSTRUCT+P_AUTO_UI, plComponent::kRefComp, IDD_COMP_SHORE, IDS_COMP_SHORE, 0, 0, &gShoreCompSelProc, plShoreComponent::kWaveSet, _T("WaveSet"), TYPE_INODE, 0, 0, end, end ); plShoreComponent::plShoreComponent() { fClassDesc = &gShoreCompDesc; fClassDesc->MakeAutoParamBlocks(this); } // SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading // of properties on the MaxNode, as it's still indeterminant. hsBool plShoreComponent::SetupProperties(plMaxNode* node, plErrorMsg* pErrMsg) { node->SetRunTimeLight(true); node->SetForceMaterialCopy(true); node->SetForceShadow(false); node->SetNoShadow(true); node->SetSmoothAll(true); node->SetForceSortable(true); node->SetNoSpanSort(true); node->SetNoPreShade(true); ISetWaterDependencies(node, fCompPB->GetINode(kWaveSet, 0, 0)); // Turn on calculation of edge lengths XXX node->SetCalcEdgeLens(true); // Make a note that we're vertex shaded (at least ripplecomponent needs to know).XXX node->SetVS(true); // Turn off the convexity test. We want to be sorted.XXX node->SetConcave(true); node->SetReverseSort(true); node->SetWaterHeight(plWaterComponent::GetWaterHeight(fCompPB->GetINode(kWaveSet, 0, 0))); return true; } hsBool plShoreComponent::PreConvert(plMaxNode* node, plErrorMsg* pErrMsg) { pErrMsg->Set(!node->HasLoadMask(), node->GetName(), "PS shore has no representation component").CheckAndAsk(); pErrMsg->Set(false); return true; } hsBool plShoreComponent::Convert(plMaxNode* node, plErrorMsg* pErrMsg) { plWaveSetBase* waveSet = plWaterComponent::GetWaveSet(fCompPB->GetINode(kWaveSet, 0, 0)); if( waveSet ) { plSceneObject* obj = node->GetSceneObject(); if( obj ) { waveSet->AddShore(obj->GetKey()); } else { pErrMsg->Set(true, node->GetName(), "Invalid object selected for shore. Ignoring").CheckAndAsk(); pErrMsg->Set(false); } } else { pErrMsg->Set(true, node->GetName(), "No Water Component selected for shore. Ignoring").CheckAndAsk(); pErrMsg->Set(false); } return true; } ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// class plWDecalCompSelProc : public ParamMap2UserDlgProc { public: BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); void DeleteThis() { } }; #include "plPickNode.h" BOOL plWDecalCompSelProc::DlgProc(TimeValue t, IParamMap2 *paramMap, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: { IParamBlock2 *pb = paramMap->GetParamBlock(); INode* node = pb->GetINode(plWDecalComponent::kWaveSet); TSTR newName(node ? node->GetName() : "Pick"); ::SetWindowText(::GetDlgItem(hWnd, IDC_COMP_WDECAL_CHOSE), newName); } return true; case WM_COMMAND: if( (HIWORD(wParam) == BN_CLICKED) && (LOWORD(wParam) == IDC_COMP_WDECAL_CHOSE) ) { IParamBlock2 *pb = paramMap->GetParamBlock(); std::vector cids; cids.push_back(WATER_COMP_CID); if( plPick::Node(pb, plWDecalComponent::kWaveSet, &cids, true, true) ) { INode* node = pb->GetINode(plWDecalComponent::kWaveSet); TSTR newName(node ? node->GetName() : "Pick"); ::SetWindowText(::GetDlgItem(hWnd, IDC_COMP_WDECAL_CHOSE), newName); paramMap->Invalidate(plWDecalComponent::kWaveSet); ShowWindow(hWnd, SW_HIDE); ShowWindow(hWnd, SW_SHOW); } return false; } return true; } return false; } plWDecalCompSelProc gWDecalCompSelProc; CLASS_DESC(plWDecalComponent, gWDecalCompDesc, "Water Decal", "WDecal", COMP_TYPE_WATER, WDECAL_COMP_CID) ParamBlockDesc2 gWDecalCompBk ( plComponent::kBlkComp, _T("WDecal"), 0, &gWDecalCompDesc, P_AUTO_CONSTRUCT+P_AUTO_UI, plComponent::kRefComp, IDD_COMP_WDECAL, IDS_COMP_WDECAL, 0, 0, &gWDecalCompSelProc, plWDecalComponent::kWaveSet, _T("WaveSet"), TYPE_INODE, 0, 0, end, plWDecalComponent::kEnv, _T("Env"), TYPE_BOOL, 0, 0, p_default, FALSE, p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_WDECAL_ENV, end, end ); plWDecalComponent::plWDecalComponent() { fClassDesc = &gWDecalCompDesc; fClassDesc->MakeAutoParamBlocks(this); } // SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading // of properties on the MaxNode, as it's still indeterminant. hsBool plWDecalComponent::SetupProperties(plMaxNode* node, plErrorMsg* pErrMsg) { node->SetRunTimeLight(true); node->SetForceMaterialCopy(true); node->SetForceShadow(false); node->SetNoShadow(true); node->SetSmoothAll(true); node->SetForceSortable(true); node->SetNoSpanSort(true); node->SetNoPreShade(true); // This should be optional. if( fCompPB->GetInt(kEnv) ) node->SetWaterDecEnv(true); ISetWaterDependencies(node, fCompPB->GetINode(kWaveSet, 0, 0)); // Turn on calculation of edge lengths XXX node->SetCalcEdgeLens(true); // Make a note that we're vertex shaded (at least ripplecomponent needs to know).XXX node->SetVS(true); // Turn off the convexity test. We want to be sorted.XXX node->SetConcave(true); node->SetReverseSort(true); node->SetWaterHeight(plWaterComponent::GetWaterHeight(fCompPB->GetINode(kWaveSet, 0, 0))); return true; } hsBool plWDecalComponent::PreConvert(plMaxNode* node, plErrorMsg* pErrMsg) { pErrMsg->Set(!node->HasLoadMask(), node->GetName(), "PS water decal has no representation component").CheckAndAsk(); pErrMsg->Set(false); return true; } hsBool plWDecalComponent::Convert(plMaxNode* node, plErrorMsg* pErrMsg) { plWaveSetBase* waveSet = plWaterComponent::GetWaveSet(fCompPB->GetINode(kWaveSet, 0, 0)); if( waveSet ) { plSceneObject* obj = node->GetSceneObject(); if( obj ) { waveSet->AddDecal(obj->GetKey()); } else { pErrMsg->Set(true, node->GetName(), "Invalid object selected for decal. Ignoring").CheckAndAsk(); pErrMsg->Set(false); } } else { pErrMsg->Set(true, node->GetName(), "No Water Component selected for decal. Ignoring").CheckAndAsk(); pErrMsg->Set(false); } return true; } ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////// class plEnvMapCompSelProc : public ParamMap2UserDlgProc { public: BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: { for(int i = 0; i < map->GetParamBlock()->Count(plEnvMapComponent::kVisSetNames); i++ ) { HWND hList = GetDlgItem(hWnd, IDC_COMP_ENVMAP_NAMES_LISTBOX); ListBox_AddString(hList, map->GetParamBlock()->GetStr(plEnvMapComponent::kVisSetNames, 0, i)); } } return true; case WM_COMMAND: if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_ADD_TARGS) { std::vector cids; cids.push_back(EFFVISSET_CID); IParamBlock2 *pb = map->GetParamBlock(); plPick::Node(pb, plEnvMapComponent::kVisSets, &cids, false, false); map->Invalidate(plEnvMapComponent::kVisSets); return TRUE; } else if(HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_COMP_ENVMAP_ADD_STRING) { char str[256]; char *pStr = str; ICustEdit *custEdit = GetICustEdit(GetDlgItem(hWnd, IDC_COMP_ENVMAP_ADD_STRING_BOX)); custEdit->GetText(str, 256); custEdit->SetText(""); // clear text box if(!strcmp(str, "")) // don't allow empty strings return TRUE; HWND hList = GetDlgItem(hWnd, IDC_COMP_ENVMAP_NAMES_LISTBOX); ListBox_AddString(hList, pStr); map->GetParamBlock()->Append(plEnvMapComponent::kVisSetNames, 1, &pStr); return TRUE; } else if(HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_COMP_ENVMAP_REMOVE_STRING) { HWND hList = GetDlgItem(hWnd, IDC_COMP_ENVMAP_NAMES_LISTBOX); int curSel = ((int)(DWORD)SNDMSG((hList), LB_GETCURSEL, 0L, 0L)); ListBox_DeleteString(hList, curSel); if (curSel >= 0) map->GetParamBlock()->Delete(ParamID(plEnvMapComponent::kVisSetNames), curSel, 1); return TRUE; } break; } return false; } void DeleteThis() {} }; static plEnvMapCompSelProc gEnvMapCompSelProc; CLASS_DESC(plEnvMapComponent, gEnvMapCompDesc, "Environment Map", "EnvMap", COMP_TYPE_WATER, ENVMAP_COMP_CID) ParamBlockDesc2 gEnvMapCompBk ( plComponent::kBlkComp, _T("EnvMap"), 0, &gEnvMapCompDesc, P_AUTO_CONSTRUCT+P_AUTO_UI, plComponent::kRefComp, IDD_COMP_ENVMAP, IDS_COMP_ENVMAP, 0, 0, &gEnvMapCompSelProc, plEnvMapComponent::kVisSets, _T("VisSets"), TYPE_INODE_TAB, 0, 0, 0, p_ui, TYPE_NODELISTBOX, IDC_LIST_TARGS, 0, 0, IDC_DEL_TARGS, end, plEnvMapComponent::kHither, _T("Hither"), TYPE_FLOAT, 0, 0, p_default, 1.0, p_range, 0.0, 500.0, // p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT, // IDC_COMP_ENVMAP_HITHER, IDC_COMP_ENVMAP_HITHER_SPIN, 1.0, end, plEnvMapComponent::kYon, _T("Yon"), TYPE_FLOAT, 0, 0, p_default, 1000.0, p_range, 10.0, 50000.0, p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_ENVMAP_YON, IDC_COMP_ENVMAP_YON_SPIN, 1.0, end, plEnvMapComponent::kFogEnable, _T("FogEnable"), TYPE_BOOL, 0, 0, p_default, FALSE, // p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_ENVMAP_FOGENABLE, // p_enable_ctrls, 2, plEnvMapComponent::kFogStart, plEnvMapComponent::kFogColor, end, plEnvMapComponent::kFogStart, _T("FogStart"), TYPE_FLOAT, 0, 0, p_default, 0.0, p_range, 0.0, 200.0, p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_ENVMAP_FOGSTART, IDC_COMP_ENVMAP_FOGSTART_SPIN, 1.0, end, plEnvMapComponent::kFogColor, _T("FogColor"), TYPE_RGBA, 0, 0, p_ui, TYPE_COLORSWATCH, IDC_COMP_ENVMAP_FOGCOLOR, p_default, Color(0,0,0), end, plEnvMapComponent::kRefreshRate, _T("RefreshRate"), TYPE_FLOAT, 0, 0, p_default, 0.0, p_range, 0.0, 3600.0, p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_COMP_ENVMAP_REFRESHRATE, IDC_COMP_ENVMAP_REFRESHRATE_SPIN, 1.0, end, plEnvMapComponent::kEnvSize, _T("EnvSize"), TYPE_INT, 0, 0, p_default, 256, p_range, 32, 1024, p_ui, TYPE_SPINNER, EDITTYPE_INT, IDC_COMP_ENVMAP_ENVSIZE, IDC_COMP_ENVMAP_ENVSIZE_SPIN, 1.f, end, plEnvMapComponent::kIncChars, _T("IncChars"), TYPE_BOOL, 0, 0, p_default, FALSE, p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_ENVMAP_INCCHARS, end, plEnvMapComponent::kMapType, _T("mapType"), TYPE_INT, 0, 0, p_ui, TYPE_RADIO, 2, IDC_COMP_ENVMAP_CUBIC, IDC_COMP_ENVMAP_SINGLE_CAM, p_vals, plEnvMapComponent::kMapCubic, plEnvMapComponent::kMapSingle, p_default, plEnvMapComponent::kMapCubic, end, plEnvMapComponent::kVisSetNames, _T("VisSetNames"), TYPE_STRING_TAB, 0, 0, 0, end, end ); plEnvMapComponent::plEnvMapComponent() { fClassDesc = &gEnvMapCompDesc; fClassDesc->MakeAutoParamBlocks(this); } // SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading // of properties on the MaxNode, as it's still indeterminant. hsBool plEnvMapComponent::SetupProperties(plMaxNode* node, plErrorMsg* pErrMsg) { fMap = nil; node->SetForceLocal(true); return true; } hsBool plEnvMapComponent::PreConvert(plMaxNode* node, plErrorMsg* pErrMsg) { return true; } hsBool plEnvMapComponent::Convert(plMaxNode* node, plErrorMsg* pErrMsg) { // If we make a handler that will update the EnvMap's position when this object // moves, we can put it's creation here. Otherwise, there's nought to do, since // we generate the envmap on demand. return true; } plDynamicEnvMap* plEnvMapComponent::GetEnvMap() { return plDynamicEnvMap::ConvertNoRef(IGetMap()); } plDynamicCamMap* plEnvMapComponent::GetCamMap() { return plDynamicCamMap::ConvertNoRef(IGetMap()); } plRenderTarget* plEnvMapComponent::IGetMap() { plMaxNode* firstTarg = nil; int numTarg = NumTargets(); int i; for( i = 0; i < numTarg; i++ ) { if( GetTarget(i) ) { firstTarg = (plMaxNode*)GetTarget(i); break; } } if( !firstTarg ) return nil; if( !fMap ) { UInt32 size = fCompPB->GetInt(kEnvSize); for( i = 9; i > 5; i-- ) { if( (1UL << UInt32(i)) <= size ) break; } size = 1 << UInt32(i); plDynamicEnvMap* env = nil; plDynamicCamMap* cam = nil; fMap = nil; if (fCompPB->GetInt((ParamID(kMapType))) == kMapCubic) fMap = env = TRACKED_NEW plDynamicEnvMap(size, size, 32); else if (fCompPB->GetInt((ParamID(kMapType))) == kMapSingle) fMap = cam = TRACKED_NEW plDynamicCamMap(size, size, 32); // Need to assign the key before we call all the setup functions. hsgResMgr::ResMgr()->NewKey(GetINode()->GetName(), fMap, firstTarg->GetLocation(), firstTarg->GetLoadMask()); if (fCompPB->GetInt((ParamID(kMapType))) == kMapCubic) { Point3 pos = firstTarg->GetNodeTM(TimeValue(0)).GetTrans(); env->SetPosition(hsPoint3(pos.x, pos.y, pos.z)); env->SetRefreshRate(fCompPB->GetFloat(kRefreshRate)); env->SetHither(fCompPB->GetFloat(kHither)); env->SetYon(fCompPB->GetFloat(kYon)); env->SetFogStart(fCompPB->GetFloat(kFogStart) * kPercentToFrac); Color fogColor = fCompPB->GetColor(kFogColor); env->SetColor(hsColorRGBA().Set(fogColor.r, fogColor.g, fogColor.b, 1.f)); } else if (fCompPB->GetInt((ParamID(kMapType))) == kMapSingle) { cam->SetRefreshRate(fCompPB->GetFloat(ParamID(kRefreshRate))); cam->fHither = fCompPB->GetFloat(ParamID(kHither)); cam->fYon = fCompPB->GetFloat(ParamID(kYon)); cam->fFogStart = fCompPB->GetFloat(ParamID(kFogStart)) * kPercentToFrac; Color fogColor = fCompPB->GetColor(kFogColor); cam->fColor.Set(fogColor.r, fogColor.g, fogColor.b, 1.f); } if (!fMap) return nil; int visGot = 0; int numVis = fCompPB->Count(kVisSets); for( i = 0; i < numVis; i++ ) { plEffVisSetComponent* effComp = plEffVisSetComponent::ConvertToEffVisSetComponent((plMaxNode*)fCompPB->GetINode(kVisSets, 0, i)); if( effComp ) { plVisRegion* effReg = effComp->GetVisRegion(firstTarg); if( effReg ) { plGenRefMsg* refMsg = TRACKED_NEW plGenRefMsg(fMap->GetKey(), plRefMsg::kOnCreate, -1, plDynamicEnvMap::kRefVisSet); hsgResMgr::ResMgr()->SendRef(effReg->GetKey(), refMsg, plRefFlags::kPassiveRef); visGot++; } } } // This allows you to enter the name of an effect vis set(key name), from another max file and use it // as if it we're in the same max file. int numVisNames = fCompPB->Count(kVisSetNames); for( i = 0; i < numVisNames; i++) { fMap->SetVisRegionName(fCompPB->GetStr(kVisSetNames, 0, i)); } if (visGot) { if (env) env->SetIncludeCharacters(fCompPB->GetInt(ParamID(kIncChars)) != 0); if (cam) cam->SetIncludeCharacters(fCompPB->GetInt(ParamID(kIncChars)) != 0); } // Right now, the envMap doesn't use this, but I plan to make it do so, so I'm // going ahead and adding the ref regardless of which type of map we made. UInt8 refType = cam ? plDynamicCamMap::kRefRootNode : plDynamicEnvMap::kRefRootNode; hsgResMgr::ResMgr()->AddViaNotify(firstTarg->GetSceneObject()->GetKey(), TRACKED_NEW plGenRefMsg(fMap->GetKey(), plRefMsg::kOnCreate, -1, refType), plRefFlags::kPassiveRef); } return fMap; } plDynamicEnvMap* plEnvMapComponent::GetEnvMap(plMaxNode* node) { plEnvMapComponent* envComp = GetEnvMapComponent(node); if (envComp) return envComp->GetEnvMap(); return nil; } plDynamicCamMap* plEnvMapComponent::GetCamMap(plMaxNode *node) { plEnvMapComponent *envComp = GetEnvMapComponent(node); if (envComp) return envComp->GetCamMap(); return nil; } plEnvMapComponent *plEnvMapComponent::GetEnvMapComponent(plMaxNode *node) { if (!node) return nil; int n = node->NumAttachedComponents(); int i; for (i = 0; i < n; i++) { plComponentBase *comp = node->GetAttachedComponent(i); if (comp && (comp->ClassID() == ENVMAP_COMP_CID)) { return (plEnvMapComponent*)comp; } } return nil; }