/*==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 "hsUtils.h" #include "hsTemplates.h" #include "../plResMgr/plKeyFinder.h" #include "../plResMgr/plPageInfo.h" #include "hsResMgr.h" #include "../MaxMain/plMaxNode.h" #include "plClothingComponent.h" #include "plComponentReg.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); } hsBool 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 targetID = fCompPB->GetInt(kType); //((plMaxNode *)LODNode->GetParentNode())->SetSwappableGeomTarget(targetID); } } return true; } hsBool plClothingComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) { node->SetupBoneHierarchyPalette(); return true; } hsBool plClothingComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) { int i, j; hsTArray spanArray; hsTArray 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 = TRACKED_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 = TRACKED_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; }