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.
805 lines
25 KiB
805 lines
25 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/>. |
|
|
|
Additional permissions under GNU GPL version 3 section 7 |
|
|
|
If you modify this Program, or any covered work, by linking or |
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
|
(or a modified version of those libraries), |
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
|
licensors of this Program grant you additional |
|
permission to convey the resulting work. Corresponding Source for a |
|
non-source form of such a combination shall include the source code for |
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
|
work. |
|
|
|
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 "HeadSpin.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: |
|
bool fDoneThis; |
|
bool IDoSmooth(plErrorMsg* pErrMsg, hsTArray<plGeometrySpan*>& spans); |
|
bool IGetSpans(plErrorMsg* pErrMsg, hsTArray<plGeometrySpan*>& spans); |
|
bool IReShade(plErrorMsg* pErrMsg); |
|
bool 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 bool SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) { fDoneThis = false; return true; } |
|
virtual bool PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) { fDoneThis = false; return true; } |
|
virtual bool 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); |
|
} |
|
|
|
bool plSmoothComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
ISmoothAll(pErrMsg); |
|
|
|
return true; |
|
} |
|
|
|
bool plSmoothComponent::ISmoothAll(plErrorMsg* pErrMsg) |
|
{ |
|
if( !fDoneThis ) |
|
{ |
|
hsTArray<plGeometrySpan*> spans; |
|
|
|
IGetSpans(pErrMsg, spans); |
|
|
|
IDoSmooth(pErrMsg, spans); |
|
|
|
fDoneThis = true; |
|
} |
|
return true; |
|
} |
|
|
|
bool plSmoothComponent::IGetSpans(plErrorMsg* pErrMsg, hsTArray<plGeometrySpan*>& spans) |
|
{ |
|
spans.SetCount(0); |
|
|
|
uint32_t count = NumTargets(); |
|
uint32_t 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_t 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; |
|
} |
|
|
|
bool plSmoothComponent::IDoSmooth(plErrorMsg* pErrMsg, hsTArray<plGeometrySpan*>& 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; |
|
} |
|
|
|
bool plSmoothComponent::IReShade(plErrorMsg* pErrMsg) |
|
{ |
|
uint32_t count = NumTargets(); |
|
uint32_t 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: |
|
bool fDoneThis; |
|
bool IDoSmooth(plErrorMsg* pErrMsg, hsTArray<plGeometrySpan*>& spans); |
|
bool IGetSpans(plErrorMsg* pErrMsg, hsTArray<plGeometrySpan*>& spans); |
|
bool IReShade(plErrorMsg* pErrMsg); |
|
bool 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 bool SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) { fDoneThis = false; return true; } |
|
virtual bool PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) { fDoneThis = false; return true; } |
|
virtual bool 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); |
|
} |
|
|
|
bool plSmoothAvComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
ISmoothAll(pErrMsg); |
|
|
|
return true; |
|
} |
|
|
|
bool plSmoothAvComponent::ISmoothAll(plErrorMsg* pErrMsg) |
|
{ |
|
if( !fDoneThis ) |
|
{ |
|
hsTArray<plGeometrySpan*> spans; |
|
|
|
IGetSpans(pErrMsg, spans); |
|
|
|
IDoSmooth(pErrMsg, spans); |
|
|
|
fDoneThis = true; |
|
} |
|
return true; |
|
} |
|
|
|
bool plSmoothAvComponent::IGetSpans(plErrorMsg* pErrMsg, hsTArray<plGeometrySpan*>& spans) |
|
{ |
|
spans.SetCount(0); |
|
|
|
uint32_t count = NumTargets(); |
|
uint32_t 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; |
|
} |
|
|
|
bool plSmoothAvComponent::IDoSmooth(plErrorMsg* pErrMsg, hsTArray<plGeometrySpan*>& 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; |
|
} |
|
|
|
bool plSmoothAvComponent::IReShade(plErrorMsg* pErrMsg) |
|
{ |
|
uint32_t count = NumTargets(); |
|
uint32_t 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<plAvMeshSmooth::XfmSpan> fSpans; |
|
|
|
public: |
|
enum { |
|
kSmoothAngle, |
|
kDistTol, |
|
kSmoothPos |
|
}; |
|
|
|
plSmoothBaseComponent(); |
|
void DeleteThis() { delete this; } |
|
|
|
hsTArray<plAvMeshSmooth::XfmSpan>& 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 bool SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg); |
|
virtual bool 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); |
|
} |
|
|
|
bool plSmoothBaseComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
node->SetDrawable(false); |
|
if (!node->GetSwappableGeom()) |
|
node->SetSwappableGeom(new plSharedMesh); |
|
|
|
fSpans.SetCount(0); |
|
|
|
return true; |
|
} |
|
|
|
bool 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<plAvMeshSmooth::XfmSpan>& plSmoothBaseComponent::GetSpans(plErrorMsg* pErrMsg) |
|
{ |
|
if( !fSpans.GetCount() ) |
|
{ |
|
uint32_t count = NumTargets(); |
|
uint32_t i; |
|
hsTArray<plGeometrySpan*> 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: |
|
bool fDoneThis; |
|
|
|
hsTArray<plAvMeshSmooth::XfmSpan>& IGetSrcSpans(plErrorMsg* pErrMsg); |
|
|
|
bool IDoSmooth(plErrorMsg* pErrMsg, hsTArray<plAvMeshSmooth::XfmSpan>& srcSpans, hsTArray<plAvMeshSmooth::XfmSpan>& dstSpans); |
|
bool IGetDstSpans(plErrorMsg* pErrMsg, hsTArray<plAvMeshSmooth::XfmSpan>& spans); |
|
bool IReShade(plErrorMsg* pErrMsg); |
|
bool 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 bool SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) { fDoneThis = false; return true; } |
|
virtual bool PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) { fDoneThis = false; return true; } |
|
virtual bool 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<Class_ID> 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); |
|
} |
|
|
|
bool plSmoothSnapComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
ISmoothAll(pErrMsg); |
|
|
|
return true; |
|
} |
|
|
|
bool plSmoothSnapComponent::ISmoothAll(plErrorMsg* pErrMsg) |
|
{ |
|
if( !fDoneThis ) |
|
{ |
|
fDoneThis = true; |
|
|
|
hsTArray<plAvMeshSmooth::XfmSpan>& srcSpans = IGetSrcSpans(pErrMsg); |
|
|
|
if( !srcSpans.GetCount() ) |
|
return true; |
|
|
|
hsTArray<plAvMeshSmooth::XfmSpan> dstSpans; |
|
|
|
if( !IGetDstSpans(pErrMsg, dstSpans) ) |
|
return true; |
|
|
|
IDoSmooth(pErrMsg, srcSpans, dstSpans); |
|
|
|
} |
|
return true; |
|
} |
|
|
|
hsTArray<plAvMeshSmooth::XfmSpan>& plSmoothSnapComponent::IGetSrcSpans(plErrorMsg* pErrMsg) |
|
{ |
|
static hsTArray<plAvMeshSmooth::XfmSpan> emptySpans; |
|
|
|
plSmoothBaseComponent* baseComp = plSmoothBaseComponent::GetSmoothBaseComp(fCompPB->GetINode(kSmoothBase, 0, 0)); |
|
if( !baseComp ) |
|
return emptySpans; |
|
|
|
return baseComp->GetSpans(pErrMsg); |
|
} |
|
|
|
bool plSmoothSnapComponent::IGetDstSpans(plErrorMsg* pErrMsg, hsTArray<plAvMeshSmooth::XfmSpan>& spans) |
|
{ |
|
hsTArray<plGeometrySpan*> geoSpans; |
|
spans.SetCount(0); |
|
|
|
uint32_t count = NumTargets(); |
|
uint32_t 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(); |
|
} |
|
|
|
bool plSmoothSnapComponent::IDoSmooth(plErrorMsg* pErrMsg, hsTArray<plAvMeshSmooth::XfmSpan>& srcSpans, hsTArray<plAvMeshSmooth::XfmSpan>& 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; |
|
} |
|
|
|
bool plSmoothSnapComponent::IReShade(plErrorMsg* pErrMsg) |
|
{ |
|
uint32_t count = NumTargets(); |
|
uint32_t i; |
|
for( i = 0; i < count; i++ ) |
|
{ |
|
plMaxNode *node = (plMaxNode*)GetTarget(i); |
|
if( node ) |
|
node->ShadeMesh(pErrMsg, nil); |
|
} |
|
return true; |
|
} |
|
|
|
|