You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

449 lines
14 KiB

/*==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 <http://www.gnu.org/licenses/>.
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 "resource.h"
#include "plComponent.h"
#include "plComponentReg.h"
#include "MaxMain/plMaxNode.h"
#include "MaxExport/plExportProgressBar.h"
#include "hsTypes.h"
#include "plShadowComponents.h"
#include "pnSceneObject/plSceneObject.h"
#include "pnMessage/plObjRefMsg.h"
#include "plGLight/plLightInfo.h"
#include "plGLight/plShadowCaster.h"
#include "plGLight/plPointShadowMaster.h"
#include "plGLight/plDirectShadowMaster.h"
#include "hsResMgr.h"
void DummyCodeIncludeFuncShadow()
{
}
static UInt16 QualityBitToMask(int q) { return ~((1 << q) - 1); }
#define WM_ROLLOUT_OPEN WM_USER+1
static const int kNumQualities = 4;
static const char* kQualityStrings[kNumQualities] = {
"Low",
"Medium",
"High",
"Ultra"
};
template <class T> class plQualityProc : public ParamMap2UserDlgProc
{
public:
BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_INITDIALOG:
{
PostMessage(hWnd, WM_ROLLOUT_OPEN, 0, 0);
HWND cbox = GetDlgItem(hWnd, IDC_COMP_SHADOW_QUALITY);
int i;
for( i = 0; i < kNumQualities; i++ )
{
SendMessage(cbox, CB_ADDSTRING, 0, (LPARAM)kQualityStrings[i]);
}
SendMessage(cbox, CB_SETCURSEL, map->GetParamBlock()->GetInt(T::kQuality), 0);
}
return true;
case WM_COMMAND:
switch( LOWORD(wParam) )
{
case IDC_COMP_SHADOW_QUALITY:
map->GetParamBlock()->SetValue(T::kQuality, t, SendMessage(GetDlgItem(hWnd, LOWORD(wParam)), CB_GETCURSEL, 0, 0));
return TRUE;
}
break;
}
return false;
}
void DeleteThis() {}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Contains (in order)
// ShadowCast
// ShadowRcv
// ShadowLight
////////////////////////////////////////////////////////////////////////////////////////////////////
// ShadowCast
CLASS_DESC(plShadowCastComponent, gShadowCastDesc, "Shadow Caster", "ShadowCast", COMP_TYPE_SHADOW, SHADOWCAST_COMP_CID)
static plQualityProc<plShadowCastComponent> gCastQualityProc;
ParamBlockDesc2 gShadowCastBk
(
plComponent::kBlkComp, _T("ShadowCast"), 0, &gShadowCastDesc, P_AUTO_CONSTRUCT+P_AUTO_UI, plComponent::kRefComp,
IDD_COMP_SHADOW_CAST, IDS_COMP_SHADOW_CAST, 0, 0, &gCastQualityProc,
plShadowCastComponent::kSelfShadow, _T("SelfShadow"), TYPE_BOOL, 0, 0,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_SHADOW_CAST_SELFSHADOW,
end,
plShadowCastComponent::kBlur, _T("Blur"), TYPE_BOOL, 0, 0,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_SHADOW_CAST_BLUR,
p_enable_ctrls, 1, plShadowCastComponent::kBlurScale,
end,
plShadowCastComponent::kBlurScale, _T("BlurScale"), TYPE_FLOAT, 0, 0,
p_default, 0.0,
p_range, 0.0, 100.0,
p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_SHADOW_CAST_BLURSCALE, IDC_COMP_SHADOW_CAST_BLURSCALE_SPIN, 1.0,
end,
plShadowCastComponent::kAtten, _T("Atten"), TYPE_BOOL, 0, 0,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_SHADOW_CAST_ATTEN,
p_enable_ctrls, 1, plShadowCastComponent::kAttenScale,
end,
plShadowCastComponent::kAttenScale, _T("AttenScale"), TYPE_FLOAT, 0, 0,
p_default, 100.0,
p_range, 25.0, 1000.0,
p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_SHADOW_CAST_ATTENSCALE, IDC_COMP_SHADOW_CAST_ATTENSCALE_SPIN, 1.0,
end,
plShadowCastComponent::kBoost, _T("Boost"), TYPE_FLOAT, 0, 0,
p_default, 100.0,
p_range, 0.0, 5000.0,
p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_SHADOW_CAST_BOOST, IDC_COMP_SHADOW_CAST_BOOST_SPIN, 1.0,
end,
plShadowCastComponent::kQuality, _T("Quality"), TYPE_INT, 0, 0,
p_default, 0,
end,
plShadowCastComponent::kLimitRes, _T("Limit"), TYPE_INT, 0, 0,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_SHADOW_CAST_LIMIT,
end,
end
);
plShadowCastComponent::plShadowCastComponent()
: fCaster(nil)
{
fClassDesc = &gShadowCastDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
hsBool plShadowCastComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
{
plSceneObject* so = node->GetSceneObject();
if( !so )
return true;
const float kBlurPercentToAbs = 1.e-2f * 1.5f;
const float kAttenPercentToAbs = 1.e-2f;
const float kBoostPercentToAbs = 1.e-2f;
if( !fCaster )
{
fCaster = TRACKED_NEW plShadowCaster;
plLoadMask lm(QualityBitToMask(fCompPB->GetInt(kQuality)), QualityBitToMask(0));
hsgResMgr::ResMgr()->NewKey(IGetUniqueName(node), fCaster, node->GetLocation(), lm);
fCaster->SetSelfShadow(fCompPB->GetInt(kSelfShadow));
if( fCompPB->GetInt(kBlur) )
fCaster->SetBlurScale(fCompPB->GetFloat(kBlurScale) * kBlurPercentToAbs);
if( fCompPB->GetInt(kAtten) )
fCaster->SetAttenScale(fCompPB->GetFloat(kAttenScale) * kAttenPercentToAbs);
fCaster->SetBoost(fCompPB->GetFloat(kBoost) * kBoostPercentToAbs);
if( fCompPB->GetInt(kLimitRes) )
fCaster->SetLimitRes(true);
}
AddShadowCastModifier(so, fCaster);
return true;
}
hsBool plShadowCastComponent::SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg)
{
fCaster = nil;
return true;
}
hsBool plShadowCastComponent::PreConvert(plMaxNode* pNode, plErrorMsg* pErrMsg)
{
return true;
}
hsBool plShadowCastComponent::AddShadowCastModifier(plMaxNode* pNode, plShadowCaster* caster)
{
if( !pNode->CanConvert() )
return false;
plSceneObject* so = pNode->GetSceneObject();
if( !so )
return false;
return plShadowCastComponent::AddShadowCastModifier(so, caster);
}
hsBool plShadowCastComponent::AddShadowCastModifier(plSceneObject* so, plShadowCaster* caster)
{
// First off, ensure that we NEVER NEVER NEVER have more than one shadowcaster on an object.
// That would be BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD BAD.
int i;
for( i = 0; i < so->GetNumModifiers(); i++ )
{
if( plShadowCaster::ConvertNoRef(so->GetModifier(i)) )
return false;
}
// Okay, we're clear, just add via notify.
hsgResMgr::ResMgr()->AddViaNotify(caster->GetKey(), TRACKED_NEW plObjRefMsg(so->GetKey(), plRefMsg::kOnCreate, -1, plObjRefMsg::kModifier), plRefFlags::kActiveRef);
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// ShadowRcv
CLASS_DESC(plShadowRcvComponent, gShadowRcvDesc, "Shadow Receiver", "ShadowRcv", COMP_TYPE_SHADOW, SHADOWRCV_COMP_CID)
ParamBlockDesc2 gShadowRcvBk
(
plComponent::kBlkComp, _T("ShadowRcv"), 0, &gShadowRcvDesc, P_AUTO_CONSTRUCT+P_AUTO_UI, plComponent::kRefComp,
IDD_COMP_SHADOW_RCV, IDS_COMP_SHADOW_RCV, 0, 0, nil,
plShadowRcvComponent::kForceRadio, _T("ForceShadow"), TYPE_INT, 0, 0,
p_ui, TYPE_RADIO, 2, IDC_RADIO_FORCE_ON, IDC_RADIO_FORCE_OFF,
p_vals, plShadowRcvComponent::kForceOn, plShadowRcvComponent::kForceOff,
p_default, plShadowRcvComponent::kForceOff,
end,
end
);
plShadowRcvComponent::plShadowRcvComponent()
{
fClassDesc = &gShadowRcvDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
hsBool plShadowRcvComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
{
return true;
}
hsBool plShadowRcvComponent::SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg)
{
if( fCompPB->GetInt(kForceRadio) == kForceOn )
{
pNode->SetForceShadow(true);
pNode->SetNoShadow(false);
}
else if( fCompPB->GetInt(kForceRadio) == kForceOff )
{
pNode->SetForceShadow(false);
pNode->SetNoShadow(true);
}
return true;
}
hsBool plShadowRcvComponent::PreConvert(plMaxNode* pNode, plErrorMsg* pErrMsg)
{
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// ShadowLight
CLASS_DESC(plShadowLightComponent, gShadowLightDesc, "Shadow Light", "ShadowLight", COMP_TYPE_SHADOW, SHADOWLIGHT_COMP_CID)
static plQualityProc<plShadowLightComponent> gLightQualityProc;
ParamBlockDesc2 gShadowLightBk
(
plComponent::kBlkComp, _T("ShadowLight"), 0, &gShadowLightDesc, P_AUTO_CONSTRUCT+P_AUTO_UI, plComponent::kRefComp,
IDD_COMP_SHADOW_LIGHT, IDS_COMP_SHADOW_LIGHT, 0, 0, &gLightQualityProc,
plShadowLightComponent::kFalloff, _T("Falloff"), TYPE_FLOAT, 0, 0,
p_default, 10.0,
p_range, 5.0, 50.0,
p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_SHADOW_LIGHT_FALLOFF, IDC_COMP_SHADOW_LIGHT_FALLOFF_SPIN, 1.0,
end,
plShadowLightComponent::kMaxDist, _T("MaxDist"), TYPE_FLOAT, 0, 0,
p_default, 0.0,
p_range, 0.0, 500.0,
p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_SHADOW_LIGHT_MAXDIST, IDC_COMP_SHADOW_LIGHT_MAXDIST_SPIN, 1.0,
end,
plShadowLightComponent::kPower, _T("Power"), TYPE_FLOAT, 0, 0,
p_default, 100.0,
p_range, 0.0, 200.0,
p_ui, TYPE_SPINNER, EDITTYPE_POS_FLOAT,
IDC_COMP_SHADOW_LIGHT_POWER, IDC_COMP_SHADOW_LIGHT_POWER_SPIN, 1.0,
end,
plShadowLightComponent::kShadowOnly, _T("ShadowOnly"), TYPE_BOOL, 0, 0,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_SHADOW_LIGHT_SHADOWONLY,
end,
plShadowLightComponent::kObeyGroups, _T("ObeyGroups"), TYPE_BOOL, 0, 0,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_SHADOW_LIGHT_OBEYGROUPS,
end,
plShadowLightComponent::kSelfShadow, _T("SelfShadow"), TYPE_BOOL, 0, 0,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_SHADOW_LIGHT_SELFSHADOW,
end,
plShadowLightComponent::kQuality, _T("Quality"), TYPE_INT, 0, 0,
p_default, 0,
end,
end
);
plShadowLightComponent::plShadowLightComponent()
{
fClassDesc = &gShadowLightDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
hsBool plShadowLightComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
{
plSceneObject* so = node->GetSceneObject();
if( !so )
return true;
plLightInfo* liInfo = plLightInfo::ConvertNoRef(so->GetGenericInterface(plLightInfo::Index()));
if( !liInfo )
return true;
if( fCompPB->GetInt(kShadowOnly) )
liInfo->SetProperty(plLightInfo::kLPShadowOnly, true);
if( fCompPB->GetInt(kObeyGroups) )
liInfo->SetProperty(plLightInfo::kLPShadowLightGroup, true);
plDirectionalLightInfo* dirLiInfo = plDirectionalLightInfo::ConvertNoRef(liInfo);
if( dirLiInfo )
return IAddDirectMaster(node, so);
plOmniLightInfo* omniLiInfo = plOmniLightInfo::ConvertNoRef(liInfo);
if( omniLiInfo )
return IAddPointMaster(node, so);
plSpotLightInfo* spotLiInfo = plSpotLightInfo::ConvertNoRef(liInfo);
if( spotLiInfo )
return IAddPointMaster(node, so);
return true;
}
hsBool plShadowLightComponent::IAddDirectMaster(plMaxNode* node, plSceneObject* so)
{
plDirectShadowMaster* directMaster = TRACKED_NEW plDirectShadowMaster;
plLoadMask lm(QualityBitToMask(fCompPB->GetInt(kQuality)), QualityBitToMask(0));
hsgResMgr::ResMgr()->NewKey(IGetUniqueName(node), directMaster, node->GetLocation(), lm);
directMaster->SetAttenDist(fCompPB->GetFloat(kFalloff));
directMaster->SetMaxDist(fCompPB->GetFloat(kMaxDist));
directMaster->SetPower(fCompPB->GetFloat(kPower) * 1.e-2f);
directMaster->SetProperty(plShadowMaster::kSelfShadow, fCompPB->GetInt(kSelfShadow));
hsgResMgr::ResMgr()->AddViaNotify(directMaster->GetKey(), TRACKED_NEW plObjRefMsg(so->GetKey(), plRefMsg::kOnCreate, -1, plObjRefMsg::kInterface), plRefFlags::kActiveRef);
return true;
}
hsBool plShadowLightComponent::IAddPointMaster(plMaxNode* node, plSceneObject* so)
{
plPointShadowMaster* pointMaster = TRACKED_NEW plPointShadowMaster;
plLoadMask lm(QualityBitToMask(fCompPB->GetInt(kQuality)), QualityBitToMask(0));
hsgResMgr::ResMgr()->NewKey(IGetUniqueName(node), pointMaster, node->GetLocation(), lm);
pointMaster->SetAttenDist(fCompPB->GetFloat(kFalloff));
pointMaster->SetMaxDist(fCompPB->GetFloat(kMaxDist));
pointMaster->SetPower(fCompPB->GetFloat(kPower) * 1.e-2f);
pointMaster->SetProperty(plShadowMaster::kSelfShadow, fCompPB->GetInt(kSelfShadow));
hsgResMgr::ResMgr()->AddViaNotify(pointMaster->GetKey(), TRACKED_NEW plObjRefMsg(so->GetKey(), plRefMsg::kOnCreate, -1, plObjRefMsg::kInterface), plRefFlags::kActiveRef);
return true;
}
hsBool plShadowLightComponent::SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg)
{
return true;
}
hsBool plShadowLightComponent::PreConvert(plMaxNode* pNode, plErrorMsg* pErrMsg)
{
return true;
}