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.
448 lines
13 KiB
448 lines
13 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/plPlasmaRefMsgs.h" |
|
|
|
#include "../MaxMain/plMaxNode.h" |
|
#include "../MaxExport/plExportProgressBar.h" |
|
|
|
#include "plXImposter.h" |
|
|
|
#include "../pfAnimation/plFilterCoordInterface.h" |
|
|
|
#include "../pnSceneObject/plSimulationInterface.h" |
|
#include "plPhysical.h" |
|
|
|
const Class_ID FILTERINHERIT_COMP_CID(0x263928d8, 0x548456da); |
|
|
|
void DummyCodeIncludeFuncXImposter() |
|
{ |
|
|
|
} |
|
|
|
//Class that accesses the paramblock below. |
|
////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plXImposterComp, gXImposterDesc, "X-Form", "X-Form", COMP_TYPE_DISTRIBUTOR, XIMPOSTER_COMP_CID) |
|
|
|
ParamBlockDesc2 gXImposterBk |
|
( |
|
plComponent::kBlkComp, _T("X-Form"), 0, &gXImposterDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, plComponent::kRefComp, |
|
|
|
IDD_COMP_XFORM, IDS_COMP_XFORMS, 0, 0, NULL, |
|
|
|
end |
|
); |
|
|
|
plXImposterComp::plXImposterComp() |
|
{ |
|
fClassDesc = &gXImposterDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
hsBool plXImposterComp::SetupProperties(plMaxNode* node, plErrorMsg* pErrMsg) |
|
{ |
|
node->SetRadiateNorms(true); |
|
return true; |
|
} |
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
const Class_ID FORCE_CTT_COMP_CID(0x30ee73b7, 0x4cdd551b); |
|
|
|
class plForceCTTComp : public plComponent |
|
{ |
|
public: |
|
plForceCTTComp(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
virtual hsBool SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg); |
|
virtual hsBool PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) { return true; } |
|
virtual hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg) { return true; } |
|
}; |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plForceCTTComp, gForceCTTDesc, "ForceClick2Turn", "ForceCTT", COMP_TYPE_MISC, FORCE_CTT_COMP_CID) |
|
|
|
ParamBlockDesc2 gForceCTTBk |
|
( |
|
plComponent::kBlkComp, _T("ForceCTT"), 0, &gForceCTTDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, plComponent::kRefComp, |
|
|
|
IDD_COMP_FORCE_CTT, IDS_COMP_FORCE_CTT, 0, 0, NULL, |
|
|
|
end |
|
); |
|
|
|
plForceCTTComp::plForceCTTComp() |
|
{ |
|
fClassDesc = &gForceCTTDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
hsBool plForceCTTComp::SetupProperties(plMaxNode* node, plErrorMsg* pErrMsg) |
|
{ |
|
node->SetForceVisLOS(true); |
|
return true; |
|
} |
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// The filter inheritance component doesn't have anything to do with the XImposter, but there's |
|
// plenty of space here, so blow me. |
|
|
|
class plFilterInheritComp : public plComponent |
|
{ |
|
public: |
|
enum |
|
{ |
|
kActive, |
|
kNoX, |
|
kNoY, |
|
kNoZ |
|
}; |
|
public: |
|
plFilterInheritComp(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
virtual hsBool SetupProperties(plMaxNode* node, plErrorMsg* pErrMsg); |
|
virtual hsBool PreConvert(plMaxNode* node, plErrorMsg* pErrMsg); |
|
virtual hsBool Convert(plMaxNode* node, plErrorMsg* pErrMsg); |
|
|
|
hsBool SetMaxInherit(); |
|
hsBool SetMaxInherit(plMaxNodeBase* targ); |
|
hsBool KillMaxInherit(); |
|
hsBool KillMaxInherit(plMaxNodeBase* targ); |
|
|
|
hsBool Bail(plMaxNode* node, const char* msg, plErrorMsg* pErrMsg); |
|
|
|
virtual void AddTarget(plMaxNodeBase *target); |
|
virtual void DeleteTarget(plMaxNodeBase *target); |
|
virtual void DeleteAllTargets(); |
|
}; |
|
|
|
class FilterInheritCompDlgProc : public ParamMap2UserDlgProc |
|
{ |
|
protected: |
|
void ISetTransEnable(IParamMap2* map) |
|
{ |
|
IParamBlock2* pb = map->GetParamBlock(); |
|
if( !pb->GetInt(plFilterInheritComp::kActive) ) |
|
{ |
|
map->Enable(plFilterInheritComp::kNoX, FALSE); |
|
map->Enable(plFilterInheritComp::kNoY, FALSE); |
|
map->Enable(plFilterInheritComp::kNoZ, FALSE); |
|
} |
|
else |
|
{ |
|
map->Enable(plFilterInheritComp::kNoX, TRUE); |
|
map->Enable(plFilterInheritComp::kNoY, TRUE); |
|
map->Enable(plFilterInheritComp::kNoZ, TRUE); |
|
} |
|
plFilterInheritComp* comp = (plFilterInheritComp*)map->GetParamBlock()->GetOwner(); |
|
comp->SetMaxInherit(); |
|
} |
|
public: |
|
FilterInheritCompDlgProc() {} |
|
~FilterInheritCompDlgProc() {} |
|
|
|
BOOL DlgProc(TimeValue t, IParamMap2* map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) |
|
{ |
|
switch (msg) |
|
{ |
|
case WM_INITDIALOG: |
|
ISetTransEnable(map); |
|
break; |
|
case WM_COMMAND: |
|
ISetTransEnable(map); |
|
break; |
|
} |
|
return FALSE; |
|
} |
|
void DeleteThis() {} |
|
}; |
|
static FilterInheritCompDlgProc gFilterInheritCompDlgProc; |
|
|
|
|
|
|
|
CLASS_DESC(plFilterInheritComp, gFilterInheritDesc, "Filter Inherit", "FiltInherit", COMP_TYPE_MISC, FILTERINHERIT_COMP_CID) |
|
|
|
ParamBlockDesc2 gFilterInheritBk |
|
( |
|
plComponent::kBlkComp, _T("FilterInherit"), 0, &gFilterInheritDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, plComponent::kRefComp, |
|
|
|
IDD_COMP_FILTERINHERIT, IDS_COMP_FILTER, 0, 0, &gFilterInheritCompDlgProc, |
|
|
|
plFilterInheritComp::kActive, _T("Active"), TYPE_BOOL, 0, 0, |
|
p_default, TRUE, |
|
p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_FILTER_ACTIVE, |
|
end, |
|
|
|
plFilterInheritComp::kNoX, _T("NoX"), TYPE_BOOL, 0, 0, |
|
p_default, TRUE, |
|
p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_FILTER_NOX, |
|
end, |
|
|
|
plFilterInheritComp::kNoY, _T("NoY"), TYPE_BOOL, 0, 0, |
|
p_default, TRUE, |
|
p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_FILTER_NOY, |
|
end, |
|
|
|
plFilterInheritComp::kNoZ, _T("NoZ"), TYPE_BOOL, 0, 0, |
|
p_default, TRUE, |
|
p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_FILTER_NOZ, |
|
end, |
|
|
|
end |
|
); |
|
|
|
plFilterInheritComp::plFilterInheritComp() |
|
{ |
|
fClassDesc = &gFilterInheritDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
hsBool plFilterInheritComp::SetupProperties(plMaxNode* node, plErrorMsg* pErrMsg) |
|
{ |
|
if( !fCompPB->GetInt(kActive) ) |
|
return true; |
|
|
|
if( node->GetParentNode()->IsRootNode() ) |
|
return true; |
|
|
|
node->SetFilterInherit(true); |
|
node->SetForceLocal(true); |
|
plMaxNode* parent = (plMaxNode*)node->GetParentNode(); |
|
parent->SetForceLocal(true); |
|
|
|
// Okay, everything works fine as long as you set up your heirarchy, and THEN |
|
// add this component. But if you put this component on the as yet unlinked child, |
|
// and THEN link the child to the parent, Max starts reporting bogus local TM info. |
|
// If you turn off the component (uncheck the disable rotation checkbox), and turn |
|
// it back on, Max is happy again. |
|
// However, if I just turn off the component and turn it right back on again here, |
|
// (a KillMaxInherit() followed by a SetMaxInherit()), apparently Max hasn't had |
|
// enough time to think in between, and so stays confused. |
|
// Soooo, here at the last minute before conversion, we kill all those inherit |
|
// checkboxes for this node, then after we've finished converting, we turn them |
|
// back on. Note that we don't currently give a rat's patooties whether the check |
|
// boxes are set or not, we just want to turn them off and turn them back on |
|
// sometime before export, with enough time in between for Max to get on to the fact. |
|
// See the matching SetMaxInherit() at the end of Convert(). |
|
KillMaxInherit(node); |
|
|
|
return true; |
|
} |
|
|
|
hsBool plFilterInheritComp::PreConvert(plMaxNode* node, plErrorMsg* pErrMsg) |
|
{ |
|
return true; |
|
} |
|
|
|
hsBool plFilterInheritComp::Bail(plMaxNode* node, const char* msg, plErrorMsg* pErrMsg) |
|
{ |
|
pErrMsg->Set(true, node->GetName(), msg).CheckAndAsk(); |
|
pErrMsg->Set(false); |
|
return true; |
|
} |
|
|
|
hsBool plFilterInheritComp::Convert(plMaxNode* node, plErrorMsg* pErrMsg) |
|
{ |
|
if( !fCompPB->GetInt(kActive) ) |
|
return true; |
|
|
|
if( node->GetParentNode()->IsRootNode() ) |
|
return true; |
|
|
|
plSceneObject* so = node->GetSceneObject(); |
|
if( !so ) |
|
{ |
|
return Bail(node, "Error finding scene object for filtered inheritance", pErrMsg); |
|
} |
|
|
|
const plCoordinateInterface* co = so->GetCoordinateInterface(); |
|
if( !co ) |
|
{ |
|
return Bail(node, "Error setting filtered inheritance - no coordinate interface", pErrMsg); |
|
} |
|
|
|
plFilterCoordInterface* filt = plFilterCoordInterface::ConvertNoRef(const_cast<plCoordinateInterface*>(co)); |
|
if( !filt ) |
|
{ |
|
return Bail(node, "Error setting filtered inheritance - wrong coordinate interface", pErrMsg); |
|
} |
|
|
|
const plSimulationInterface* si = so->GetSimulationInterface(); |
|
if (si) |
|
{ |
|
plPhysical* phys = si->GetPhysical(); |
|
// tell the physical not to send transforms back -- they'll be wrong if it tries to compose w/a subworld |
|
// this rules out using transform filters on dynamically simulated objects.... |
|
phys->SetProperty(plSimulationInterface::kPassive, true); |
|
} |
|
|
|
UInt32 mask = plFilterCoordInterface::kNoRotation; |
|
if( fCompPB->GetInt(kNoX) ) |
|
mask |= plFilterCoordInterface::kNoTransX; |
|
if( fCompPB->GetInt(kNoY) ) |
|
mask |= plFilterCoordInterface::kNoTransY; |
|
if( fCompPB->GetInt(kNoZ) ) |
|
mask |= plFilterCoordInterface::kNoTransZ; |
|
|
|
plMaxNode* parent = (plMaxNode*)node->GetParentNode(); |
|
hsMatrix44 parL2W = parent->GetLocalToWorld44(TimeValue(0)); |
|
|
|
filt->SetFilterMask(mask); |
|
filt->SetRefLocalToWorld(parL2W); |
|
|
|
// See the matching KillMaxInherit() in SetupProperties(). |
|
SetMaxInherit(node); |
|
|
|
return true; |
|
} |
|
|
|
hsBool plFilterInheritComp::SetMaxInherit(plMaxNodeBase* targ) |
|
{ |
|
if( !fCompPB->GetInt(kActive) ) |
|
return KillMaxInherit(targ); |
|
|
|
DWORD mask = INHERIT_ROT_X |
|
| INHERIT_ROT_Y |
|
| INHERIT_ROT_Z |
|
| INHERIT_SCL_X |
|
| INHERIT_SCL_Y |
|
| INHERIT_SCL_Z; |
|
|
|
if( fCompPB->GetInt(kNoX) ) |
|
mask |= INHERIT_POS_X; |
|
if( fCompPB->GetInt(kNoY) ) |
|
mask |= INHERIT_POS_Y; |
|
if( fCompPB->GetInt(kNoZ) ) |
|
mask |= INHERIT_POS_Z; |
|
|
|
// Max documentation is a big fat liar |
|
mask = ~mask; |
|
|
|
if( targ ) |
|
{ |
|
targ->GetTMController()->SetInheritanceFlags(mask, true); |
|
targ->GetTMController()->NotifyDependents(FOREVER,0,REFMSG_CHANGE); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
hsBool plFilterInheritComp::SetMaxInherit() |
|
{ |
|
if( !fCompPB->GetInt(kActive) ) |
|
return KillMaxInherit(); |
|
|
|
DWORD mask = INHERIT_ROT_X |
|
| INHERIT_ROT_Y |
|
| INHERIT_ROT_Z |
|
| INHERIT_SCL_X |
|
| INHERIT_SCL_Y |
|
| INHERIT_SCL_Z; |
|
|
|
if( fCompPB->GetInt(kNoX) ) |
|
mask |= INHERIT_POS_X; |
|
if( fCompPB->GetInt(kNoY) ) |
|
mask |= INHERIT_POS_Y; |
|
if( fCompPB->GetInt(kNoZ) ) |
|
mask |= INHERIT_POS_Z; |
|
|
|
// Max documentation is a big fat liar |
|
mask = ~mask; |
|
|
|
int i; |
|
for( i = 0; i < NumTargets(); i++ ) |
|
{ |
|
plMaxNodeBase* targ = GetTarget(i); |
|
if( targ ) |
|
{ |
|
targ->GetTMController()->SetInheritanceFlags(mask, true); |
|
targ->GetTMController()->NotifyDependents(FOREVER,0,REFMSG_CHANGE); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
hsBool plFilterInheritComp::KillMaxInherit(plMaxNodeBase* targ) |
|
{ |
|
// Max documentation is a big fat liar |
|
DWORD mask = ~0; |
|
|
|
targ->GetTMController()->SetInheritanceFlags(mask, true); |
|
targ->GetTMController()->NotifyDependents(FOREVER,0,REFMSG_CHANGE); |
|
|
|
return true; |
|
} |
|
|
|
hsBool plFilterInheritComp::KillMaxInherit() |
|
{ |
|
int i; |
|
for( i = 0; i < NumTargets(); i++ ) |
|
{ |
|
plMaxNodeBase* targ = GetTarget(i); |
|
if( targ ) |
|
{ |
|
KillMaxInherit(targ); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
void plFilterInheritComp::AddTarget(plMaxNodeBase *target) |
|
{ |
|
plComponentBase::AddTarget(target); |
|
|
|
SetMaxInherit(); |
|
} |
|
|
|
void plFilterInheritComp::DeleteTarget(plMaxNodeBase *target) |
|
{ |
|
plComponentBase::DeleteTarget(target); |
|
|
|
KillMaxInherit(target); |
|
} |
|
|
|
void plFilterInheritComp::DeleteAllTargets() |
|
{ |
|
KillMaxInherit(); |
|
|
|
plComponentBase::DeleteAllTargets(); |
|
} |
|
|
|
|
|
|