/*==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((char*)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;
}