/*==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);
}
}
}