/*==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 "plMorphSequenceSDLMod.h" #include "plMorphSequence.h" #include "plSharedMesh.h" #include "hsResMgr.h" #include "../pnSceneObject/plSceneObject.h" #include "../pnMessage/plSDLModifierMsg.h" #include "../plSDL/plSDL.h" // static vars char plMorphSequenceSDLMod::kStrMorphArrayDescName[]="MorphArray"; char plMorphSequenceSDLMod::kStrWeights[]="weights"; char plMorphSequenceSDLMod::kStrMorphSetDescName[]="MorphSet"; char plMorphSequenceSDLMod::kStrMesh[]="mesh"; char plMorphSequenceSDLMod::kStrArrays[]="arrays"; char plMorphSequenceSDLMod::kStrTargetID[]="targetID"; char plMorphSequenceSDLMod::kStrMorphs[]="morphs"; void plMorphSequenceSDLMod::PutCurrentStateIn(plStateDataRecord* dstState) { IPutCurrentStateIn(dstState); } void plMorphSequenceSDLMod::IPutCurrentStateIn(plStateDataRecord* dstState) { plSceneObject* sobj=GetTarget(); hsAssert(sobj, "plMorphSequenceSDLMod, nil target"); const plMorphSequence *kMorphMod = nil; int i, j; kMorphMod = plMorphSequence::ConvertNoRef(sobj->GetModifierByType(plMorphSequence::Index())); if (!kMorphMod) { hsAssert(false, "Couldn't find a morph sequence."); return; } plMorphSequence *morphMod = const_cast(kMorphMod); //dstState->FindVar(kStrTarget)->Set(morphMod->GetKey()); plSDStateVariable *morphSD = dstState->FindSDVar(kStrMorphs); int numMorphs = morphMod->fSharedMeshes.GetCount() + 1; // 1 for the non-sharedMesh morph hsTArray keys; for (i = 0; i < numMorphs; i++) { if (i == morphMod->fSharedMeshes.GetCount()) { // the non-sharedMesh morph if (morphMod->GetNumLayers(nil) != 0) keys.Append(nil); } else { if (!(morphMod->fSharedMeshes[i].fMesh->fFlags & plSharedMesh::kDontSaveMorphState)) keys.Append(morphMod->fSharedMeshes[i].fMesh->GetKey()); } } if (morphSD->GetCount() != keys.GetCount()) morphSD->Alloc(keys.GetCount()); for (i = 0; i < keys.GetCount(); i++) { plKey meshKey = keys[i]; morphSD->GetStateDataRecord(i)->FindVar(kStrMesh)->Set(meshKey); plSimpleStateVariable *weights = morphSD->GetStateDataRecord(i)->FindVar(kStrWeights); int numLayers = morphMod->GetNumLayers(meshKey); if (weights->GetCount() != numLayers) weights->Alloc(numLayers); for (j = 0; j < numLayers; j++) { int numDeltas = morphMod->GetNumDeltas(j, meshKey); if (numDeltas != 2) continue; // plMorphSequenceSDLMod assumes 2 deltas (pos/neg) per layer, so that we can // store both in a single byte // Translate the range [-1.0, 1.0] into a 0-255 byte UInt8 weight = (UInt8)((1.f + morphMod->GetWeight(j, 0, meshKey) - morphMod->GetWeight(j, 1, meshKey)) * 255 / 2); weights->Set(&weight, j); } } } void plMorphSequenceSDLMod::SetCurrentStateFrom(const plStateDataRecord* srcState) { ISetCurrentStateFrom(srcState); } void plMorphSequenceSDLMod::ISetCurrentStateFrom(const plStateDataRecord* srcState) { plSceneObject* sobj=GetTarget(); hsAssert(sobj, "plMorphSequenceSDLMod, nil target"); if (strcmp(srcState->GetDescriptor()->GetName(), kSDLMorphSequence)) { hsAssert(false, "Wrong type of state data record passed into plMorphSequenceSDLMod."); return; } int i, j; const plMorphSequence *kMorphMod = plMorphSequence::ConvertNoRef(sobj->GetModifierByType(plMorphSequence::Index())); if (!kMorphMod) { hsAssert(false, "Couldn't find a morph sequence."); return; } plMorphSequence *morphMod = const_cast(kMorphMod); plSDStateVariable *morphSD = srcState->FindSDVar(kStrMorphs); for (i = 0; i < morphSD->GetCount(); i++) { plKey meshKey; morphSD->GetStateDataRecord(i)->FindVar(kStrMesh)->Get(&meshKey); if (meshKey && !meshKey->GetUoid().GetClassType() == plSharedMesh::Index()) continue; // meshKey will be nil when dealing with non-sharedMesh data if (meshKey) hsgResMgr::ResMgr()->AddViaNotify(meshKey, TRACKED_NEW plGenRefMsg(morphMod->GetKey(), plRefMsg::kOnCreate, -1, -1), plRefFlags::kPassiveRef); plSimpleStateVariable *weights = morphSD->GetStateDataRecord(i)->FindVar(kStrWeights); // Count down so that we do the high index first and the pending state struct // of plMorphSequence only has to resize the array once. for (j = weights->GetCount() - 1; j >= 0; j--) { UInt8 weight; weights->Get(&weight, j); hsScalar posWeight = weight * 2.f / 255.f - 1.f; hsScalar negWeight = 0; if (posWeight < 0) { negWeight = -posWeight; posWeight = 0; } morphMod->SetWeight(j, 1, negWeight, meshKey); morphMod->SetWeight(j, 0, posWeight, meshKey); } } }