/*==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 "resource.h"
#include "plComponent.h"
#include "plComponentReg.h"
#include "../MaxMain/plMaxNode.h"
#include "hsTypes.h"
#include "../plDrawable/plDrawableSpans.h"
// The AccMeshSmooth now does everything the InterMeshSmooth and AvMeshSmooth
// components did, only better and with fewer bugs.
//#include "../plDrawable/plInterMeshSmooth.h"
#include "../plDrawable/plAvMeshSmooth.h"
#include "../plDrawable/plAccMeshSmooth.h"
#include "../plDrawable/plGeometrySpan.h"
#include "../plDrawable/plSharedMesh.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../pnSceneObject/plDrawInterface.h"
const Class_ID CID_SMOOTHCOMP(0x7f926cbc, 0x58df5a44);
const Class_ID CID_SMOOTHAV(0xaf37a4f, 0x8c00991);
const Class_ID CID_SMOOTHBASE(0xebd3ccd, 0x8e85ea6);
const Class_ID CID_SMOOTHSNAP(0x7768074c, 0x65197b77);
void DummyCodeIncludeFuncSmooth()
{
}
//Class that accesses the paramblock below.
class plSmoothComponent : public plComponent
{
public:
enum {
kSmoothAngle,
kSmoothPos,
kSmoothColor
};
protected:
hsBool fDoneThis;
hsBool IDoSmooth(plErrorMsg* pErrMsg, hsTArray& spans);
hsBool IGetSpans(plErrorMsg* pErrMsg, hsTArray& spans);
hsBool IReShade(plErrorMsg* pErrMsg);
hsBool ISmoothAll(plErrorMsg* pErrMsg);
public:
plSmoothComponent();
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) { fDoneThis = false; return true; }
virtual hsBool PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) { fDoneThis = false; return true; }
virtual hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg);
};
//Max desc stuff necessary below.
CLASS_DESC(plSmoothComponent, gSmoothDesc, "Smooth", "Smooth", COMP_TYPE_GRAPHICS, CID_SMOOTHCOMP)
ParamBlockDesc2 gSmoothBk
(
plComponent::kBlkComp, _T("Smooth"), 0, &gSmoothDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, plComponent::kRefComp,
IDD_COMP_SMOOTH, IDS_COMP_SMOOTHS, 0, 0, NULL,
plSmoothComponent::kSmoothAngle, _T("SmoothAngle"), TYPE_FLOAT, 0, 0,
p_default, 75.0f,
p_range, 0.0, 180.0,
p_ui, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_COMP_SMOOTH_ANGLE, IDC_COMP_SMOOTH_ANGLE_SPIN, 1.f,
end,
plSmoothComponent::kSmoothPos, _T("SmoothPos"), TYPE_BOOL, 0, 0,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_SMOOTH_POS,
end,
plSmoothComponent::kSmoothColor, _T("SmoothColor"), TYPE_BOOL, 0, 0,
p_default, FALSE,
p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_SMOOTH_COLOR,
end,
end
);
plSmoothComponent::plSmoothComponent()
{
fClassDesc = &gSmoothDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
hsBool plSmoothComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
{
ISmoothAll(pErrMsg);
return true;
}
hsBool plSmoothComponent::ISmoothAll(plErrorMsg* pErrMsg)
{
if( !fDoneThis )
{
hsTArray spans;
IGetSpans(pErrMsg, spans);
IDoSmooth(pErrMsg, spans);
fDoneThis = true;
}
return true;
}
hsBool plSmoothComponent::IGetSpans(plErrorMsg* pErrMsg, hsTArray& spans)
{
spans.SetCount(0);
UInt32 count = NumTargets();
UInt32 i;
for( i = 0; i < count; i++ )
{
plMaxNode *node = (plMaxNode*)GetTarget(i);
if( !(node && node->CanConvert() && node->GetDrawable()) )
continue;
plSceneObject* obj = node->GetSceneObject();
if( !obj )
continue;
const plDrawInterface* di = obj->GetDrawInterface();
if( !di )
continue;
UInt8 iDraw;
for( iDraw = 0; iDraw < di->GetNumDrawables(); iDraw++ )
{
plDrawableSpans* dr = plDrawableSpans::ConvertNoRef(di->GetDrawable(iDraw));
if( !dr )
continue;
plDISpanIndex disi = dr->GetDISpans(di->GetDrawableMeshIndex(iDraw));
int i;
for( i = 0; i < disi.fIndices.GetCount(); i++ )
{
spans.Append(dr->GetSourceSpans()[disi.fIndices[i]]);
}
}
}
return true;
}
hsBool plSmoothComponent::IDoSmooth(plErrorMsg* pErrMsg, hsTArray& spans)
{
// if( spans.GetCount() > 1 )
{
plAccMeshSmooth smoother;
smoother.SetAngle(fCompPB->GetFloat(kSmoothAngle));
smoother.SetFlags(plAccMeshSmooth::kSmoothNorm);
if( fCompPB->GetInt(kSmoothPos) )
smoother.SetFlags(smoother.GetFlags() | plAccMeshSmooth::kSmoothPos);
if( fCompPB->GetInt(kSmoothColor) )
smoother.SetFlags(smoother.GetFlags() | plAccMeshSmooth::kSmoothDiffuse);
smoother.Smooth(spans);
}
return true;
}
hsBool plSmoothComponent::IReShade(plErrorMsg* pErrMsg)
{
UInt32 count = NumTargets();
UInt32 i;
for( i = 0; i < count; i++ )
{
plMaxNode *node = (plMaxNode*)GetTarget(i);
if( node )
node->ShadeMesh(pErrMsg, nil);
}
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
// Now an avatar specific version
///////////////////////////////////////////////////////////////////////////////////////////////
//Class that accesses the paramblock below.
class plSmoothAvComponent : public plComponent
{
public:
enum {
kSmoothAngle,
kDistTol,
kSmoothPos
};
protected:
hsBool fDoneThis;
hsBool IDoSmooth(plErrorMsg* pErrMsg, hsTArray& spans);
hsBool IGetSpans(plErrorMsg* pErrMsg, hsTArray& spans);
hsBool IReShade(plErrorMsg* pErrMsg);
hsBool ISmoothAll(plErrorMsg* pErrMsg);
public:
plSmoothAvComponent();
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) { fDoneThis = false; return true; }
virtual hsBool PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) { fDoneThis = false; return true; }
virtual hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg);
};
//Max desc stuff necessary below.
CLASS_DESC(plSmoothAvComponent, gSmoothAvDesc, "Avatar Smooth", "AvSmooth", COMP_TYPE_GRAPHICS, CID_SMOOTHAV)
ParamBlockDesc2 gSmoothAvBk
(
plComponent::kBlkComp, _T("SmoothAv"), 0, &gSmoothAvDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, plComponent::kRefComp,
IDD_COMP_SMOOTHAV, IDS_COMP_SMOOTHAV, 0, 0, NULL,
plSmoothAvComponent::kSmoothAngle, _T("SmoothAngle"), TYPE_FLOAT, 0, 0,
p_default, 75.0f,
p_range, 0.0, 180.0,
p_ui, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_COMP_SMOOTHAV_ANGLE, IDC_COMP_SMOOTHAV_ANGLE_SPIN, 1.f,
end,
plSmoothAvComponent::kDistTol, _T("DistTol"), TYPE_FLOAT, 0, 0,
p_default, 0.001f,
p_range, 0.0, 1.0,
p_ui, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_COMP_SMOOTHAV_DIST, IDC_COMP_SMOOTHAV_DIST_SPIN, 0.01f,
end,
plSmoothAvComponent::kSmoothPos, _T("SmoothPos"), TYPE_BOOL, 0, 0,
p_default, TRUE,
p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_SMOOTHAV_POS,
end,
end
);
plSmoothAvComponent::plSmoothAvComponent()
{
fClassDesc = &gSmoothAvDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
hsBool plSmoothAvComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
{
ISmoothAll(pErrMsg);
return true;
}
hsBool plSmoothAvComponent::ISmoothAll(plErrorMsg* pErrMsg)
{
if( !fDoneThis )
{
hsTArray spans;
IGetSpans(pErrMsg, spans);
IDoSmooth(pErrMsg, spans);
fDoneThis = true;
}
return true;
}
hsBool plSmoothAvComponent::IGetSpans(plErrorMsg* pErrMsg, hsTArray& spans)
{
spans.SetCount(0);
UInt32 count = NumTargets();
UInt32 i;
for( i = 0; i < count; i++ )
{
plMaxNode *node = (plMaxNode*)GetTarget(i);
if( !node )
continue;
plSharedMesh* sharedMesh = node->GetSwappableGeom();
if( !sharedMesh )
continue;
int j;
for( j = 0; j < sharedMesh->fSpans.GetCount(); j++ )
{
if( sharedMesh->fSpans[j] )
spans.Append(sharedMesh->fSpans[j]);
}
}
return true;
}
hsBool plSmoothAvComponent::IDoSmooth(plErrorMsg* pErrMsg, hsTArray& spans)
{
if( spans.GetCount() > 1 )
{
plAccMeshSmooth smoother;
smoother.SetAngle(fCompPB->GetFloat(kSmoothAngle));
smoother.SetDistTol(fCompPB->GetFloat(kDistTol));
smoother.SetFlags(plAccMeshSmooth::kSmoothNorm);
if( fCompPB->GetInt(kSmoothPos) )
smoother.SetFlags(smoother.GetFlags() | plAccMeshSmooth::kSmoothPos);
smoother.Smooth(spans);
}
return true;
}
hsBool plSmoothAvComponent::IReShade(plErrorMsg* pErrMsg)
{
UInt32 count = NumTargets();
UInt32 i;
for( i = 0; i < count; i++ )
{
plMaxNode *node = (plMaxNode*)GetTarget(i);
if( node )
node->ShadeMesh(pErrMsg, nil);
}
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
// Tiny component to reference a bunch of meshes. These meshes will be used for reference,
// but not actually exported (unless someone else grabs them too.)
///////////////////////////////////////////////////////////////////////////////////////////////////
class plSmoothBaseComponent : public plComponent
{
protected:
hsTArray fSpans;
public:
enum {
kSmoothAngle,
kDistTol,
kSmoothPos
};
plSmoothBaseComponent();
void DeleteThis() { delete this; }
hsTArray& GetSpans(plErrorMsg* pErrMsg);
float GetSmoothAngle() const { return fCompPB->GetFloat(kSmoothAngle); }
float GetDistTol() const { return fCompPB->GetFloat(kDistTol); }
bool SmoothPosition() const { return 0 != fCompPB->GetInt(kSmoothPos); }
static plSmoothBaseComponent* GetSmoothBaseComp(INode* node);
// 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 Convert(plMaxNode *node, plErrorMsg *pErrMsg);
};
//Max desc stuff necessary below.
CLASS_DESC(plSmoothBaseComponent, gSmoothBaseDesc, "Smoothing Base", "SmoothBase", COMP_TYPE_GRAPHICS, CID_SMOOTHBASE)
ParamBlockDesc2 gSmoothBaseBk
(
plComponent::kBlkComp, _T("SmoothBase"), 0, &gSmoothBaseDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, plComponent::kRefComp,
IDD_COMP_SMOOTHBASE, IDS_COMP_SMOOTHBASE, 0, 0, NULL,
plSmoothBaseComponent::kSmoothAngle, _T("SmoothAngle"), TYPE_FLOAT, 0, 0,
p_default, 75.0f,
p_range, 0.0, 180.0,
p_ui, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_COMP_SMOOTHBASE_ANGLE, IDC_COMP_SMOOTHBASE_ANGLE_SPIN, 1.f,
end,
plSmoothBaseComponent::kDistTol, _T("DistTol"), TYPE_FLOAT, 0, 0,
p_default, 0.001f,
p_range, 0.0, 1.0,
p_ui, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_COMP_SMOOTHBASE_DIST, IDC_COMP_SMOOTHBASE_DIST_SPIN, 0.01f,
end,
plSmoothBaseComponent::kSmoothPos, _T("SmoothPos"), TYPE_BOOL, 0, 0,
p_default, TRUE,
p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_SMOOTHBASE_POS,
end,
end
);
plSmoothBaseComponent::plSmoothBaseComponent()
{
fClassDesc = &gSmoothBaseDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
hsBool plSmoothBaseComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg)
{
node->SetDrawable(false);
if (!node->GetSwappableGeom())
node->SetSwappableGeom(new plSharedMesh);
fSpans.SetCount(0);
return true;
}
hsBool plSmoothBaseComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
{
GetSpans(pErrMsg);
return true;
}
plSmoothBaseComponent* plSmoothBaseComponent::GetSmoothBaseComp(INode* node)
{
if( !node )
return nil;
plComponentBase *comp = ((plMaxNodeBase*)node)->ConvertToComponent();
if( comp == nil )
return nil;
if( comp->ClassID() == CID_SMOOTHBASE )
return (plSmoothBaseComponent*)comp;
return nil;
}
// Only valid after the MakeMesh phase.
hsTArray& plSmoothBaseComponent::GetSpans(plErrorMsg* pErrMsg)
{
if( !fSpans.GetCount() )
{
UInt32 count = NumTargets();
UInt32 i;
hsTArray spans;
for( i = 0; i < count; i++ )
{
plMaxNode *node = (plMaxNode*)GetTarget(i);
if( !node )
continue;
plSharedMesh* sharedMesh = node->GetSwappableGeom();
if( !sharedMesh )
continue;
int j;
for( j = 0; j < sharedMesh->fSpans.GetCount(); j++ )
{
if( sharedMesh->fSpans[j] )
{
spans.Append(sharedMesh->fSpans[j]);
plAvMeshSmooth::XfmSpan xfmSpan;
xfmSpan.fSpan = sharedMesh->fSpans[j];
xfmSpan.fSpanToNeutral = node->GetOTM44() * node->GetLocalToVert44();
xfmSpan.fSpanToNeutral.GetInverse(&xfmSpan.fNeutralToSpan);
xfmSpan.fSpanToNeutral.GetTranspose(&xfmSpan.fNormNeutralToSpan);
xfmSpan.fNeutralToSpan.GetTranspose(&xfmSpan.fNormSpanToNeutral);
fSpans.Append(xfmSpan);
}
}
}
if( spans.GetCount() > 1 )
{
plAccMeshSmooth smoother;
smoother.SetAngle(fCompPB->GetFloat(kSmoothAngle));
smoother.SetDistTol(fCompPB->GetFloat(kDistTol));
smoother.SetFlags(plAccMeshSmooth::kSmoothNorm);
if( fCompPB->GetInt(kSmoothPos) )
smoother.SetFlags(smoother.GetFlags() | plAccMeshSmooth::kSmoothPos);
smoother.Smooth(spans);
}
}
return fSpans;
}
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
// Now another avatar specific version
///////////////////////////////////////////////////////////////////////////////////////////////
//Class that accesses the paramblock below.
class plSmoothSnapComponent : public plComponent
{
public:
enum {
kSmoothBase,
kSmoothAngle,
kDistTol,
kSmoothPos
};
protected:
hsBool fDoneThis;
hsTArray& IGetSrcSpans(plErrorMsg* pErrMsg);
hsBool IDoSmooth(plErrorMsg* pErrMsg, hsTArray& srcSpans, hsTArray& dstSpans);
hsBool IGetDstSpans(plErrorMsg* pErrMsg, hsTArray& spans);
hsBool IReShade(plErrorMsg* pErrMsg);
hsBool ISmoothAll(plErrorMsg* pErrMsg);
public:
plSmoothSnapComponent();
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) { fDoneThis = false; return true; }
virtual hsBool PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) { fDoneThis = false; return true; }
virtual hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg);
};
class plSmoothBaseSelProc : public ParamMap2UserDlgProc
{
public:
BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void DeleteThis() { }
};
#include "plPickNode.h"
BOOL plSmoothBaseSelProc::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(plSmoothSnapComponent::kSmoothBase);
TSTR newName(node ? node->GetName() : "Pick");
::SetWindowText(::GetDlgItem(hWnd, IDC_COMP_SMOOTH_CHOSE), newName);
}
return true;
case WM_COMMAND:
if( (HIWORD(wParam) == BN_CLICKED) && (LOWORD(wParam) == IDC_COMP_SMOOTH_CHOSE) )
{
IParamBlock2 *pb = paramMap->GetParamBlock();
std::vector cids;
cids.push_back(CID_SMOOTHBASE);
if( plPick::Node(pb, plSmoothSnapComponent::kSmoothBase, &cids, true, true) )
{
INode* node = pb->GetINode(plSmoothSnapComponent::kSmoothBase);
TSTR newName(node ? node->GetName() : "Pick");
::SetWindowText(::GetDlgItem(hWnd, IDC_COMP_SMOOTH_CHOSE), newName);
paramMap->Invalidate(plSmoothSnapComponent::kSmoothBase);
ShowWindow(hWnd, SW_HIDE);
ShowWindow(hWnd, SW_SHOW);
}
return false;
}
return true;
}
return false;
}
plSmoothBaseSelProc gSmoothBaseSelProc;
//Max desc stuff necessary below.
CLASS_DESC(plSmoothSnapComponent, gSmoothSnapDesc, "Snap to Base", "SnapTo", COMP_TYPE_GRAPHICS, CID_SMOOTHSNAP)
ParamBlockDesc2 gSmoothSnapBk
(
plComponent::kBlkComp, _T("SmoothSnap"), 0, &gSmoothSnapDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, plComponent::kRefComp,
IDD_COMP_SMOOTHSNAP, IDS_COMP_SMOOTHSNAP, 0, 0, &gSmoothBaseSelProc,
plSmoothSnapComponent::kSmoothBase, _T("SmoothBase"), TYPE_INODE, 0, 0,
end,
plSmoothSnapComponent::kSmoothAngle, _T("SmoothAngle"), TYPE_FLOAT, 0, 0,
p_default, 75.0f,
p_range, 0.0, 180.0,
p_ui, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_COMP_SMOOTHSNAP_ANGLE, IDC_COMP_SMOOTHSNAP_ANGLE_SPIN, 1.f,
end,
plSmoothSnapComponent::kDistTol, _T("DistTol"), TYPE_FLOAT, 0, 0,
p_default, 0.01f,
p_range, 0.0, 1.0,
p_ui, TYPE_SPINNER, EDITTYPE_FLOAT,
IDC_COMP_SMOOTHSNAP_DIST, IDC_COMP_SMOOTHSNAP_DIST_SPIN, 0.01f,
end,
plSmoothSnapComponent::kSmoothPos, _T("SmoothPos"), TYPE_BOOL, 0, 0,
p_default, TRUE,
p_ui, TYPE_SINGLECHEKBOX, IDC_COMP_SMOOTHSNAP_POS,
end,
end
);
plSmoothSnapComponent::plSmoothSnapComponent()
{
fClassDesc = &gSmoothSnapDesc;
fClassDesc->MakeAutoParamBlocks(this);
}
hsBool plSmoothSnapComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
{
ISmoothAll(pErrMsg);
return true;
}
hsBool plSmoothSnapComponent::ISmoothAll(plErrorMsg* pErrMsg)
{
if( !fDoneThis )
{
fDoneThis = true;
hsTArray& srcSpans = IGetSrcSpans(pErrMsg);
if( !srcSpans.GetCount() )
return true;
hsTArray dstSpans;
if( !IGetDstSpans(pErrMsg, dstSpans) )
return true;
IDoSmooth(pErrMsg, srcSpans, dstSpans);
}
return true;
}
hsTArray& plSmoothSnapComponent::IGetSrcSpans(plErrorMsg* pErrMsg)
{
static hsTArray emptySpans;
plSmoothBaseComponent* baseComp = plSmoothBaseComponent::GetSmoothBaseComp(fCompPB->GetINode(kSmoothBase, 0, 0));
if( !baseComp )
return emptySpans;
return baseComp->GetSpans(pErrMsg);
}
hsBool plSmoothSnapComponent::IGetDstSpans(plErrorMsg* pErrMsg, hsTArray& spans)
{
hsTArray geoSpans;
spans.SetCount(0);
UInt32 count = NumTargets();
UInt32 i;
for( i = 0; i < count; i++ )
{
plMaxNode *node = (plMaxNode*)GetTarget(i);
if( !node )
continue;
plSharedMesh* sharedMesh = node->GetSwappableGeom();
if( !sharedMesh )
continue;
int j;
for( j = 0; j < sharedMesh->fSpans.GetCount(); j++ )
{
if( sharedMesh->fSpans[j] )
{
geoSpans.Append(sharedMesh->fSpans[j]);
plAvMeshSmooth::XfmSpan xfmSpan;
xfmSpan.fSpan = sharedMesh->fSpans[j];
xfmSpan.fSpanToNeutral = node->GetOTM44() * node->GetLocalToVert44();
xfmSpan.fSpanToNeutral.GetInverse(&xfmSpan.fNeutralToSpan);
xfmSpan.fSpanToNeutral.GetTranspose(&xfmSpan.fNormNeutralToSpan);
xfmSpan.fNeutralToSpan.GetTranspose(&xfmSpan.fNormSpanToNeutral);
spans.Append(xfmSpan);
}
}
}
// Smooth them with themselves before we pass them off to be snapped to the base.
// We'll use the base component's parameters, because ours will be sloppier to
// ensure proper snapping.
if( geoSpans.GetCount() )
{
plSmoothBaseComponent* baseComp = plSmoothBaseComponent::GetSmoothBaseComp(fCompPB->GetINode(kSmoothBase, 0, 0));
if( !baseComp )
return 0;
plAccMeshSmooth smoother;
smoother.SetAngle(baseComp->GetSmoothAngle());
smoother.SetDistTol(baseComp->GetDistTol());
smoother.SetFlags(plAccMeshSmooth::kSmoothNorm);
if( baseComp->SmoothPosition() )
smoother.SetFlags(smoother.GetFlags() | plAccMeshSmooth::kSmoothPos);
smoother.Smooth(geoSpans);
}
return spans.GetCount();
}
hsBool plSmoothSnapComponent::IDoSmooth(plErrorMsg* pErrMsg, hsTArray& srcSpans, hsTArray& dstSpans)
{
if( srcSpans.GetCount() && dstSpans.GetCount() )
{
plAvMeshSmooth smoother;
smoother.SetAngle(fCompPB->GetFloat(kSmoothAngle));
smoother.SetDistTol(fCompPB->GetFloat(kDistTol));
smoother.SetFlags(plAccMeshSmooth::kSmoothNorm);
if( fCompPB->GetInt(kSmoothPos) )
smoother.SetFlags(smoother.GetFlags() | plAccMeshSmooth::kSmoothPos);
smoother.Smooth(srcSpans, dstSpans);
}
return true;
}
hsBool plSmoothSnapComponent::IReShade(plErrorMsg* pErrMsg)
{
UInt32 count = NumTargets();
UInt32 i;
for( i = 0; i < count; i++ )
{
plMaxNode *node = (plMaxNode*)GetTarget(i);
if( node )
node->ShadeMesh(pErrMsg, nil);
}
return true;
}