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.

306 lines
7.6 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/>.
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==*/
// local
#include "plAGModifier.h"
#include "plMatrixChannel.h"
// global
#include "hsResMgr.h"
#include "hsTimer.h"
// other
#include "pnSceneObject/plSceneObject.h"
#include "pnSceneObject/plCoordinateInterface.h"
#include "pnSceneObject/plSimulationInterface.h"
/////////////////
//
// PLAGMODIFIER
//
/////////////////
// Applies animation graph output to a single scene object.
// CTOR
plAGModifier::plAGModifier()
: plSingleModifier()
{
fChannelName = nil;
fAutoApply = true;
fEnabled = true;
}
// CTOR(name)
plAGModifier::plAGModifier(const char *name, hsBool autoApply)
: plSingleModifier(), fAutoApply(autoApply)
{
fChannelName = hsStrcpy(name);
fEnabled = true;
}
// DTOR
plAGModifier::~plAGModifier()
{
if(fChannelName)
{
delete[] fChannelName;
fChannelName = nil;
}
int i;
for (i = 0; i < fApps.size(); i++)
{
delete fApps[i];
}
}
// GETCHANNELNAME
const char * plAGModifier::GetChannelName() const
{
return fChannelName;
}
// ENABLE
void plAGModifier::Enable(hsBool val)
{
fEnabled = val;
}
// SETCHANNELNAME
void plAGModifier::SetChannelName(char * name)
{
fChannelName = hsStrcpy(name);
}
// IAPPLYCHANNELS (time)
// One AGModifier, although applied to a single scene object, can have
// multiple channels on it affecting, say, position, color, aroma, etc.
//
// There are cases where we want to call this and won't know the delta,
// we don't seem to ever need it for this function, so I'm taking it out.
// If you run into a case where you think it's necessary, see me. -Bob
void plAGModifier::Apply(double time) const
{
if (!fEnabled)
return;
for (int i = 0; i < fApps.size(); i++)
{
plAGApplicator *app = fApps[i];
app->Apply(this, time);
}
}
// IEVAL
// Apply our channels to our scene object
hsBool plAGModifier::IEval(double time, hsScalar delta, UInt32 dirty)
{
if(fAutoApply) {
// Apply(time, delta);
}
return true;
}
// GETAPPLICATOR
plAGApplicator * plAGModifier::GetApplicator(plAGPinType pinType) const
{
int numApps = fApps.size();
for (int i = 0; i < numApps; i++)
{
plAGApplicator *app = fApps[i];
plAGPinType otherType = app->GetPinType();
if(otherType == pinType)
return app;
}
return nil;
}
// SETAPPLICATOR
void plAGModifier::SetApplicator(plAGApplicator *newApp)
{
int numApps = fApps.size();
plAGPinType newPinType = newApp->GetPinType();
// *** NOTE: this code is completely untested. Since I happened to be here
// I sketched out how it *should* work and implemented the base protocol.
// In reality, most of these code paths are not accessed now...
// -- mm
for(int i = 0; i < numApps; i++)
{
plAGApplicator *existingApp = fApps[i];
plAGPinType extPinType = existingApp->GetPinType();
if(extPinType == newPinType)
{
hsStatusMessage("Two applicators accessing same pin type...congratulations for being the first to test this.");
// these applicators both try to set the same thing; try to merge them
plAGChannel *newChannel = newApp->GetChannel();
hsAssert(newChannel = nil, "Trying to merge in new applicator which already has channel. Incomplete.");
// *** right now I just want to support the case of putting in a new applicator - not merging animations
plAGChannel *extChannel = existingApp->GetChannel();
newApp->SetChannel(extChannel);
existingApp->SetChannel(nil);
fApps[i] = newApp;
delete existingApp;
return;
// NOTE: we should make these arbitrate, but I'm not going to right now because
// there's not currently an (easy) way to merge two applicators without allowing a blend.
// if(existingApp->CanCombine(newApp))
// {
// // the existing applicator promises to provide the functionality we need...merge into it.
// existingApp->MergeChannel(newApp);
// } else {
// // couldn't merge into the existing channel; can we merge it into us instead?
// if(newApp->CanCombine(extApp))
// {
// // okay, WE can provide the functionality of the existing applicator.
// fApps[i] = newApp; // take over its spot in the applicators
// newApp->MergeChannel(existingApp); // and merge it into us
// }
// }
}
}
// didn't find any conflicts; just add our app on the end
fApps.push_back(newApp);
}
// MERGECHANNEL
// Intended as a replacement for attach/blend channel. You want to add a channel to this node,
// we do that for you. Don't ask us how, you shouldn't have to know.
plAGChannel * plAGModifier::MergeChannel(plAGApplicator *app,
plAGChannel *channel,
plScalarChannel *blend,
plAGAnimInstance *anim,
int priority)
{
int numApps = fApps.size();
plAGChannel * result = nil;
for (int i = 0; i < numApps; i++)
{
plAGApplicator *existingApp = fApps[i];
result = existingApp->MergeChannel(app, channel, blend, priority);
if (result)
return result;
}
if (!result)
{
// didn't blend or combine with an existing channel; add a new channel
plAGApplicator *newApp = app->CloneWithChannel(channel);
fApps.push_back(newApp);
}
return result;
}
// DETACHCHANNEL
hsBool plAGModifier::DetachChannel(plAGChannel * channel)
{
size_t i = 0;
hsBool done = false;
for( ; i != fApps.size(); i++)
{
plAGApplicator *app = fApps[i];
plAGChannel *existingChannel = app->GetChannel();
if(existingChannel)
{
plAGChannel *replacementChannel = existingChannel->Detach(channel);
if (existingChannel != replacementChannel)
{
app->SetChannel(replacementChannel);
if( ! replacementChannel && app->AutoDelete())
{
fApps.erase(fApps.begin()+i);
i--;
delete app;
}
done = true;
break;
}
}
}
return done;
}
// READ
void plAGModifier::Read(hsStream *stream, hsResMgr *mgr)
{
plSingleModifier::Read(stream, mgr);
// read in the name of the modifier
fChannelName = stream->ReadSafeString();
}
// WRITE
void plAGModifier::Write(hsStream *stream, hsResMgr *mgr)
{
plSingleModifier::Write(stream, mgr);
// write out the name of the modifier
stream->WriteSafeString(fChannelName);
}
/////////////////////////////////////////
/////////////////////////////////////////
//
// MOVE
//
/////////////////////////////////////////
/////////////////////////////////////////
const plModifier * FindModifierByClass(const plSceneObject *obj, int classID)
{
if(obj)
{
int modCount = obj->GetNumModifiers();
for (int i = 0; i < modCount; i++)
{
const plModifier *mod = obj->GetModifier(i);
if(mod) // modifier might not be loaded yet
{
if(mod->ClassIndex() == classID)
{
return mod;
}
}
}
}
return nil;
}