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
12 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();
}