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.
368 lines
13 KiB
368 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/>. |
|
|
|
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 "hsResMgr.h" |
|
#include "hsTemplates.h" |
|
|
|
#include "plComponent.h" |
|
#include "plComponentReg.h" |
|
#include "MaxMain/plMaxNode.h" |
|
|
|
#include <iparamm2.h> |
|
#include "resource.h" |
|
#pragma hdrstop |
|
|
|
#include "plResMgr/plKeyFinder.h" |
|
#include "plResMgr/plPageInfo.h" |
|
|
|
#include "plClothingComponent.h" |
|
|
|
#include "MaxPlasmaMtls/Materials/plClothingMtl.h" |
|
#include "pnMessage/plRefMsg.h" |
|
#include "plAvatar/plAvatarClothing.h" |
|
#include "pnSceneObject/plSceneObject.h" |
|
#include "MaxConvert/hsMaterialConverter.h" |
|
#include "MaxConvert/plMeshConverter.h" |
|
#include "plPickMaterialMap.h" |
|
#include "MaxMain/plMtlCollector.h" |
|
#include "plAvatarComponent.h" |
|
#include "MaxMain/plPlasmaRefMsgs.h" |
|
#include "plDrawable/plSharedMesh.h" |
|
#include "plDrawable/plDrawableSpans.h" |
|
#include "plDrawable/plMorphSequence.h" |
|
#include "plScene/plSceneNode.h" |
|
#include "plDrawable/plGeometrySpan.h" |
|
|
|
void DummyCodeIncludeFuncClothing() |
|
{ |
|
} |
|
|
|
CLASS_DESC(plClothingComponent, gClothingDesc, "Avatar Clothing", "AvatarClothing", COMP_TYPE_MISC, CLOTHING_COMPONENT_CLASS_ID) |
|
|
|
static plClothingComponentProc gClothingComponentProc; |
|
|
|
class plClothingAccessor : public PBAccessor |
|
{ |
|
public: |
|
|
|
//! Public Accessor Class, used in ParamBlock2 processing. |
|
/*! |
|
Workhorse for this Accessor Class (derived from Max's PBAccessor). |
|
|
|
When one of our parameters that is a ref changes, send out the component ref |
|
changed message. Normally, messages from component refs are ignored since |
|
they pass along all the messages of the ref, which generates a lot of false |
|
converts. |
|
*/ |
|
|
|
void Set(PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t) |
|
{ |
|
if (id == plClothingComponent::kMeshNodeAddBtn) |
|
{ |
|
plClothingComponent *comp = (plClothingComponent *)owner; |
|
IParamBlock2 *pb = comp->GetParamBlockByID(plClothingComponent::kBlkComp); |
|
int state = pb->GetInt(plClothingComponent::kLODState); |
|
|
|
INode *node = pb->GetINode(plClothingComponent::kMeshNodeAddBtn); |
|
if (node) |
|
pb->SetValue(plClothingComponent::kMeshNodeTab, 0, node, state); |
|
} |
|
|
|
if (id == plClothingComponent::kMeshNodeTab) |
|
{ |
|
plComponentBase *comp = (plComponentBase*)owner; |
|
comp->NotifyDependents(FOREVER, PART_ALL, REFMSG_USER_COMP_REF_CHANGED); |
|
} |
|
} |
|
}; |
|
|
|
plClothingAccessor gClothingAccessor; |
|
|
|
ParamBlockDesc2 gClothingBk |
|
( |
|
|
|
plComponent::kBlkComp, _T("Clothing"), 0, &gClothingDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, plComponent::kRefComp, |
|
|
|
//Roll out |
|
IDD_COMP_CLOTHING, IDS_COMP_CLOTHING, 0, 0, &gClothingComponentProc, |
|
|
|
plClothingComponent::kMaterials, _T("ClothingMaterials"), TYPE_MTL_TAB, 0, 0, 0, |
|
end, |
|
|
|
plClothingComponent::kGroup, _T("ClothingGroup"), TYPE_INT, 0, 0, |
|
end, |
|
|
|
plClothingComponent::kType, _T("ClothingType"), TYPE_INT, 0, 0, |
|
end, |
|
|
|
plClothingComponent::kLODState, _T("LODState"), TYPE_INT, 0, 0, |
|
p_default, 0, |
|
end, |
|
|
|
plClothingComponent::kMeshNodeTab, _T("MeshObject"), TYPE_INODE_TAB, plLODAvatarComponent::kMaxNumLODLevels, 0, 0, |
|
p_accessor, &gClothingAccessor, |
|
end, |
|
|
|
plClothingComponent::kMeshNodeAddBtn, _T("MshNodePicker"), TYPE_INODE, 0, 0, |
|
p_ui, TYPE_PICKNODEBUTTON, IDC_COMP_LOD_CLOTHING_MESH_PICKB, |
|
p_sclassID, GEOMOBJECT_CLASS_ID, |
|
p_prompt, IDS_COMP_AVATAR_PROXYS, |
|
p_accessor, &gClothingAccessor, |
|
end, |
|
|
|
end |
|
); |
|
|
|
plClothingComponent::plClothingComponent() |
|
{ |
|
fClassDesc = &gClothingDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
bool plClothingComponent::SetupProperties(plMaxNode* node, plErrorMsg* pErrMsg) |
|
{ |
|
int i; |
|
for (i = 0; i < fCompPB->Count(kMeshNodeTab); i++) |
|
{ |
|
plMaxNode *LODNode = (plMaxNode *)fCompPB->GetINode(kMeshNodeTab, 0, i); |
|
if (LODNode != nil) |
|
{ |
|
char *dbgNodeName = LODNode->GetName(); |
|
//LODNode->SetCanConvert(false); |
|
LODNode->SetDrawable(false); |
|
LODNode->SetForceShadow(true); |
|
LODNode->SetForceMatShade(true); |
|
if (!LODNode->GetSwappableGeom()) |
|
LODNode->SetSwappableGeom(new plSharedMesh); |
|
|
|
//uint32_t targetID = fCompPB->GetInt(kType); |
|
//((plMaxNode *)LODNode->GetParentNode())->SetSwappableGeomTarget(targetID); |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
bool plClothingComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
node->SetupBoneHierarchyPalette(); |
|
|
|
return true; |
|
} |
|
|
|
bool plClothingComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
int i, j; |
|
hsTArray<plGeometrySpan*> spanArray; |
|
hsTArray<plKey> keys; |
|
plMaxNode *LODNode = nil; |
|
plMaxNode *locationNode = nil; |
|
|
|
|
|
if (fCompPB->Count(plClothingComponent::kMaterials) <= 0) |
|
return true; |
|
|
|
for (i = 0; i < fCompPB->Count(kMeshNodeTab); i++) |
|
{ |
|
spanArray.Reset(); |
|
//plSharedMesh *mesh = new plSharedMesh; |
|
LODNode = (plMaxNode *)fCompPB->GetINode(kMeshNodeTab, 0, i); |
|
if (LODNode != nil) |
|
{ |
|
char *dbgNodeName = LODNode->GetName(); |
|
keys.Append(LODNode->GetSwappableGeom()->GetKey()); |
|
locationNode = LODNode; |
|
|
|
if (fCompPB->GetInt(ParamID(kType)) != plClothingMgr::kTypeFace) |
|
{ |
|
// We only save state for the face node. |
|
LODNode->GetSwappableGeom()->fFlags |= plSharedMesh::kDontSaveMorphState; |
|
} |
|
else |
|
{ |
|
// The face's weight for the first layer (0) is to be applied to all |
|
// meshes on that node. |
|
LODNode->GetSwappableGeom()->fFlags |= plSharedMesh::kLayer0GlobalToMod; |
|
} |
|
} |
|
else |
|
{ |
|
keys.Append(nil); |
|
//delete mesh; |
|
} |
|
} |
|
|
|
const plPageInfo* thisInfo = plKeyFinder::Instance().GetLocationInfo(locationNode ? locationNode->GetLocation() : node->GetLocation()); |
|
const plLocation &loc = plKeyFinder::Instance().FindLocation("GlobalClothing", thisInfo->GetPage()); |
|
|
|
for (i = 0; i < fCompPB->Count(plClothingComponent::kMaterials); i++) |
|
{ |
|
plClothingMtl *mtl = (plClothingMtl *)fCompPB->GetMtl(ParamID(plClothingComponent::kMaterials), 0, i); |
|
plClothingItem *cloth = hsMaterialConverter::Instance().GenerateClothingItem(mtl, loc); |
|
cloth->fGroup = fCompPB->GetInt(ParamID(kGroup)); |
|
cloth->fType = fCompPB->GetInt(ParamID(kType)); |
|
|
|
plGenRefMsg *refMsg; |
|
for (j = 0; j < keys.GetCount(); j++) |
|
{ |
|
if (keys[j] != nil) |
|
{ |
|
refMsg = new plGenRefMsg(cloth->GetKey(), plRefMsg::kOnCreate, j, -1); |
|
hsgResMgr::ResMgr()->AddViaNotify(keys[j], refMsg, plRefFlags::kActiveRef); |
|
} |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
//////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
BOOL plClothingComponentProc::DlgProc(TimeValue t, IParamMap2 *pm, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) |
|
{ |
|
IParamBlock2 *pb = pm->GetParamBlock(); |
|
HWND hList = GetDlgItem(hWnd, IDC_CLOTHING_LIST); |
|
HWND hGroup = GetDlgItem(hWnd, IDC_CLOTHING_GROUP); |
|
HWND hType = GetDlgItem(hWnd, IDC_CLOTHING_TYPE); |
|
HWND hLOD = GetDlgItem(hWnd, IDC_COMP_LOD_CLOTHING_STATE); |
|
switch (msg) |
|
{ |
|
case WM_INITDIALOG: |
|
{ |
|
ListBox_ResetContent(hList); |
|
int i; |
|
for (i = 0; i < pb->Count(plClothingComponent::kMaterials); i++) |
|
ListBox_AddString(hList, pb->GetMtl(ParamID(plClothingComponent::kMaterials), 0, i)->GetName()); |
|
|
|
ListBox_SetCurSel(hList, -1); |
|
|
|
for (i = 0; i < plClothingMgr::kMaxGroup; i++) |
|
ComboBox_AddString(hGroup, plClothingMgr::GroupStrings[i]); |
|
ComboBox_SetCurSel(hGroup, pb->GetInt(plClothingComponent::kGroup)); |
|
|
|
for (i = 0; i < plClothingMgr::kMaxType; i++) |
|
ComboBox_AddString(hType, plClothingMgr::TypeStrings[i]); |
|
ComboBox_SetCurSel(hType, pb->GetInt(plClothingComponent::kType)); |
|
|
|
ComboBox_AddString(hLOD, "High"); |
|
ComboBox_AddString(hLOD, "Medium"); |
|
ComboBox_AddString(hLOD, "Low"); |
|
ComboBox_SetCurSel(hLOD, pb->GetInt(plClothingComponent::kLODState)); |
|
} |
|
return TRUE; |
|
|
|
|
|
case WM_COMMAND: |
|
if (HIWORD(wParam) == BN_CLICKED) |
|
{ |
|
if (LOWORD(wParam) == IDC_CLOTHING_ADD) |
|
{ |
|
Mtl *pickedMtl = plPickMaterialMap::PickMaterial(plMtlCollector::kClothingMtlOnly); |
|
if (pickedMtl != nil) |
|
{ |
|
LRESULT stringIdx = ListBox_FindStringExact(hList, -1, pickedMtl->GetName()); |
|
if (stringIdx == LB_ERR) // It's not already there, go and add it |
|
{ |
|
pb->Append(ParamID(plClothingComponent::kMaterials), 1, &pickedMtl, 0); |
|
ListBox_AddString(hList, pickedMtl->GetName()); |
|
} |
|
} |
|
return TRUE; |
|
} |
|
// Remove the currently selected material |
|
else if (LOWORD(wParam) == IDC_CLOTHING_REMOVE) |
|
{ |
|
int sel = ListBox_GetCurSel(hList); |
|
if (sel != LB_ERR) |
|
{ |
|
pb->Delete(plClothingComponent::kMaterials, sel, 1); |
|
ListBox_DeleteString(hList, sel); |
|
} |
|
return TRUE; |
|
} |
|
else if( LOWORD( wParam ) == IDC_CLOTHING_CLEARMESH ) |
|
{ |
|
int state = pb->GetInt(plClothingComponent::kLODState); |
|
pb->SetValue(plClothingComponent::kMeshNodeTab, 0, (INode*)nil, state ); |
|
pb->Reset(plClothingComponent::kMeshNodeAddBtn); |
|
} |
|
} |
|
else if (LOWORD(wParam) == IDC_CLOTHING_GROUP) |
|
{ |
|
int setIdx = ComboBox_GetCurSel(hGroup); |
|
pb->SetValue(plClothingComponent::kGroup, 0, setIdx); |
|
|
|
return TRUE; |
|
} |
|
else if (LOWORD(wParam) == IDC_CLOTHING_TYPE) |
|
{ |
|
int setIdx = ComboBox_GetCurSel(hType); |
|
pb->SetValue(plClothingComponent::kType, 0, setIdx); |
|
|
|
return TRUE; |
|
} |
|
else |
|
{ |
|
int state = pb->GetInt(plClothingComponent::kLODState); |
|
|
|
INode *node = pb->GetINode(plClothingComponent::kMeshNodeAddBtn); |
|
if (node) |
|
pb->SetValue(plClothingComponent::kMeshNodeTab, 0, node, state); |
|
|
|
if(LOWORD(wParam) == IDC_COMP_LOD_CLOTHING_STATE && HIWORD(wParam) == CBN_SELCHANGE) |
|
{ |
|
int idx = SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0); |
|
pb->SetValue(plClothingComponent::kLODState, 0, idx); |
|
|
|
node = pb->GetINode(plClothingComponent::kMeshNodeTab, 0, idx); |
|
if (node) |
|
pb->SetValue(plClothingComponent::kMeshNodeAddBtn, 0, node); |
|
else |
|
pb->Reset(plClothingComponent::kMeshNodeAddBtn); |
|
|
|
return TRUE; |
|
} |
|
} |
|
} |
|
|
|
return FALSE; |
|
}
|
|
|