/*==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==*/ // 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) { plAppTable::iterator i = fApps.begin(); while( i != fApps.end() ) { plAGApplicator *app = *i; plAGChannel *existingChannel = app->GetChannel(); if(existingChannel) { plAGChannel *replacementChannel = existingChannel->Detach(channel); if (existingChannel != replacementChannel) { app->SetChannel(replacementChannel); if( ! replacementChannel && app->AutoDelete()) { // Don't need to adjust the iterator since we're about to exit the loop fApps.erase(i); delete app; } return true; } } ++i; } return false; } // 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; }