mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-18 19:29:09 +00:00
Move AniGraph classes from plAvatar -> plAnimation.
This commit is contained in:
43
Sources/Plasma/PubUtilLib/plAnimation/CMakeLists.txt
Normal file
43
Sources/Plasma/PubUtilLib/plAnimation/CMakeLists.txt
Normal file
@ -0,0 +1,43 @@
|
||||
include_directories("../../CoreLib")
|
||||
include_directories("../../FeatureLib")
|
||||
include_directories("../../NucleusLib/inc")
|
||||
include_directories("../../NucleusLib")
|
||||
include_directories("../../PubUtilLib")
|
||||
|
||||
set(plAnimation_SOURCES
|
||||
plAGAnim.cpp
|
||||
plAGAnimInstance.cpp
|
||||
plAGApplicator.cpp
|
||||
plAGChannel.cpp
|
||||
plAGMasterMod.cpp
|
||||
plAGModifier.cpp
|
||||
plMatrixChannel.cpp
|
||||
plPointChannel.cpp
|
||||
plQuatChannel.cpp
|
||||
plScalarChannel.cpp
|
||||
)
|
||||
|
||||
set(plAnimation_HEADERS
|
||||
plAGAnim.h
|
||||
plAGAnimInstance.h
|
||||
plAGApplicator.h
|
||||
plAGChannel.h
|
||||
plAGDefs.h
|
||||
plAGMasterMod.h
|
||||
plAGModifier.h
|
||||
plAnimationCreatable.h
|
||||
plMatrixChannel.h
|
||||
plPointChannel.h
|
||||
plQuatChannel.h
|
||||
plScalarChannel.h
|
||||
)
|
||||
|
||||
add_library(plAnimation STATIC ${plAnimation_SOURCES} ${plAnimation_HEADERS})
|
||||
|
||||
target_link_libraries(plAnimation pnModifier)
|
||||
target_link_libraries(plAnimation plInterp)
|
||||
target_link_libraries(plAnimation plSDL)
|
||||
target_link_libraries(plAnimation plTransform)
|
||||
|
||||
source_group("Source Files" FILES ${plAnimation_SOURCES})
|
||||
source_group("Header Files" FILES ${plAnimation_HEADERS})
|
756
Sources/Plasma/PubUtilLib/plAnimation/plAGAnim.cpp
Normal file
756
Sources/Plasma/PubUtilLib/plAnimation/plAGAnim.cpp
Normal file
@ -0,0 +1,756 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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==*/
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDES
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// singular
|
||||
#include "plAGAnim.h"
|
||||
|
||||
// local
|
||||
#include "plMatrixChannel.h"
|
||||
|
||||
// global
|
||||
#include "hsResMgr.h"
|
||||
|
||||
// other
|
||||
#include "plInterp/plAnimEaseTypes.h"
|
||||
#include "plMessage/plAnimCmdMsg.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// STATICS
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plAGAnim::plAnimMap plAGAnim::fAllAnims;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// plAGAnim
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ctor ------------
|
||||
// -----
|
||||
plAGAnim::plAGAnim()
|
||||
: plSynchedObject()
|
||||
{
|
||||
}
|
||||
|
||||
// ctor ------------------------------------------------------
|
||||
// -----
|
||||
plAGAnim::plAGAnim(const plString &name, double start, double end)
|
||||
: fStart((float)start),
|
||||
fEnd((float)end),
|
||||
fName(name)
|
||||
{
|
||||
}
|
||||
|
||||
// dtor -------------
|
||||
// -----
|
||||
plAGAnim::~plAGAnim()
|
||||
{
|
||||
if (!fName.IsNull())
|
||||
{
|
||||
RemoveAnim(fName);
|
||||
}
|
||||
|
||||
//int numChannels = fChannels.size();
|
||||
int numApps = fApps.size();
|
||||
|
||||
for (int i = 0; i < numApps; i++)
|
||||
{
|
||||
plAGApplicator *app = fApps[i];
|
||||
if (app)
|
||||
{
|
||||
plAGChannel *channel = app->GetChannel();
|
||||
if(channel)
|
||||
delete channel;
|
||||
|
||||
delete app;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetChannelCount ------------------
|
||||
// ----------------
|
||||
int plAGAnim::GetChannelCount() const
|
||||
{
|
||||
return fApps.size();
|
||||
}
|
||||
|
||||
// GetChannel -------------------------------------
|
||||
// -----------
|
||||
plAGChannel * plAGAnim::GetChannel(int index) const
|
||||
{
|
||||
plAGApplicator *app = fApps[index];
|
||||
return (app ? app->GetChannel() : nil);
|
||||
}
|
||||
|
||||
// GetChannel --------------------------------------------
|
||||
// -----------
|
||||
plAGChannel * plAGAnim::GetChannel(const plString &name) const
|
||||
{
|
||||
int appCount = fApps.size();
|
||||
|
||||
for(int i = 0; i < appCount; i++)
|
||||
{
|
||||
plAGApplicator *app = fApps[i];
|
||||
plAGChannel *channel = app->GetChannel();
|
||||
plString channelName = app->GetChannelName();
|
||||
|
||||
if(name.Compare(channelName, plString::kCaseInsensitive) == 0)
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
// GetApplicatorCount ------------------
|
||||
// -------------------
|
||||
int plAGAnim::GetApplicatorCount() const
|
||||
{
|
||||
return fApps.size();
|
||||
}
|
||||
|
||||
// GetApplicator -----------------------------------
|
||||
// --------------
|
||||
plAGApplicator *plAGAnim::GetApplicator(int i) const
|
||||
{
|
||||
return fApps[i];
|
||||
}
|
||||
|
||||
// AddApplicator -------------------------------
|
||||
// --------------
|
||||
int plAGAnim::AddApplicator(plAGApplicator *app)
|
||||
{
|
||||
hsAssert(app->GetChannel(), "Adding an applicator with no channel");
|
||||
fApps.push_back(app);
|
||||
|
||||
// return the index of the channel
|
||||
return(fApps.size() - 1);
|
||||
}
|
||||
|
||||
// RemoveApplicator ------------------------
|
||||
// -----------------
|
||||
bool plAGAnim::RemoveApplicator(int index)
|
||||
{
|
||||
hsAssert(index < fApps.size(), "Out of range index for plAGAnim::RemoveApp()");
|
||||
|
||||
if(index < fApps.size())
|
||||
{
|
||||
fApps.erase(fApps.begin() + index);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ExtendToLength ----------------------------
|
||||
// ---------------
|
||||
void plAGAnim::ExtendToLength(float length)
|
||||
{
|
||||
if (length > GetEnd())
|
||||
SetEnd(length);
|
||||
}
|
||||
|
||||
// GetChannelName ------------------------------
|
||||
// ---------------
|
||||
plString plAGAnim::GetChannelName(int index)
|
||||
{
|
||||
hsAssert(index < fApps.size(), "Out of range index for plAGAnim::GetChannelName()");
|
||||
|
||||
if(index < fApps.size())
|
||||
{
|
||||
return fApps[index]->GetChannel()->GetName();
|
||||
} else {
|
||||
return plString::Null;
|
||||
}
|
||||
}
|
||||
|
||||
// Read --------------------------------------------
|
||||
// -----
|
||||
void plAGAnim::Read(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plSynchedObject::Read(stream, mgr);
|
||||
|
||||
// read in the name of the animation itself
|
||||
fName = stream->ReadSafeString();
|
||||
|
||||
fStart = stream->ReadLEScalar();
|
||||
fEnd = stream->ReadLEScalar();
|
||||
|
||||
int numApps = stream->ReadLE32();
|
||||
|
||||
fApps.reserve(numApps); // pre-allocate for performance
|
||||
int i;
|
||||
for (i = 0; i < numApps; i++)
|
||||
{
|
||||
plAGApplicator * app = plAGApplicator::ConvertNoRef(mgr->ReadCreatable(stream));
|
||||
app->SetChannel(plAGChannel::ConvertNoRef(mgr->ReadCreatable(stream)));
|
||||
fApps.push_back(app);
|
||||
}
|
||||
plAGAnim::AddAnim(fName, this);
|
||||
}
|
||||
|
||||
// Write --------------------------------------------
|
||||
// ------
|
||||
void plAGAnim::Write(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plSynchedObject::Write(stream, mgr);
|
||||
|
||||
stream->WriteSafeString(fName);
|
||||
|
||||
stream->WriteLEScalar(fStart);
|
||||
stream->WriteLEScalar(fEnd);
|
||||
|
||||
int numApps = fApps.size();
|
||||
|
||||
stream->WriteLE32(numApps);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < numApps; i++)
|
||||
{
|
||||
plAGApplicator *app = fApps[i];
|
||||
hsAssert(app, "Missing applicator during write.");
|
||||
plAGChannel *channel = nil;
|
||||
if (app)
|
||||
channel = app->GetChannel();
|
||||
|
||||
hsAssert(channel, "Missing channel during write.");
|
||||
mgr->WriteCreatable(stream, app);
|
||||
mgr->WriteCreatable(stream, channel);
|
||||
}
|
||||
}
|
||||
|
||||
void plAGAnim::ClearAnimationRegistry()
|
||||
{
|
||||
fAllAnims.clear();
|
||||
}
|
||||
|
||||
// AddAnim ----------------------------------------------
|
||||
// --------
|
||||
void plAGAnim::AddAnim(const plString & name, plAGAnim *anim)
|
||||
{
|
||||
// Only register the animation if it's got a "real" name. Unnamed animations
|
||||
// all get the same standard name.
|
||||
if(name.Compare(ENTIRE_ANIMATION_NAME) != 0)
|
||||
{
|
||||
hsAssert(anim, "registering nil anim");
|
||||
fAllAnims[name] = anim;
|
||||
}
|
||||
}
|
||||
|
||||
// FindAnim -----------------------------------
|
||||
// ---------
|
||||
plAGAnim * plAGAnim::FindAnim(const plString &name)
|
||||
{
|
||||
plAnimMap::iterator i = fAllAnims.find(name);
|
||||
|
||||
if(i != fAllAnims.end())
|
||||
{
|
||||
return (*i).second;
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveAnim -------------------------------
|
||||
// -----------
|
||||
bool plAGAnim::RemoveAnim(const plString &name)
|
||||
{
|
||||
plAnimMap::iterator i = fAllAnims.find(name);
|
||||
|
||||
if(i != fAllAnims.end())
|
||||
{
|
||||
fAllAnims.erase(i);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// DumpAnimationRegistry -------------
|
||||
// ----------------------
|
||||
void plAGAnim::DumpAnimationRegistry()
|
||||
{
|
||||
plAnimMap::iterator i = fAllAnims.begin();
|
||||
int j = 0;
|
||||
|
||||
do {
|
||||
plAGAnim *anim = (*i).second;
|
||||
plString name = anim->GetName();
|
||||
hsStatusMessageF("GLOBAL ANIMS [%d]: <%s>", j++, name.c_str());
|
||||
} while(++i != fAllAnims.end());
|
||||
}
|
||||
|
||||
// SharesPinsWith -----------------------------------------
|
||||
// ---------------
|
||||
bool plAGAnim::SharesPinsWith(const plAGAnim *anim) const
|
||||
{
|
||||
int i, j;
|
||||
for (i = 0; i < fApps.size(); i++)
|
||||
{
|
||||
for (j = 0; j < anim->fApps.size(); j++)
|
||||
{
|
||||
if (!fApps[i]->GetChannelName().Compare(anim->fApps[j]->GetChannelName()) &&
|
||||
fApps[i]->CanBlend(anim->fApps[j]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// plATCAnim
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ctor --------------
|
||||
// -----
|
||||
plATCAnim::plATCAnim()
|
||||
: plAGAnim()
|
||||
{
|
||||
}
|
||||
|
||||
// ctor --------------------------------------------------------
|
||||
// -----
|
||||
plATCAnim::plATCAnim(const plString &name, double start, double end)
|
||||
: plAGAnim(name, start, end),
|
||||
fInitial(-1),
|
||||
fAutoStart(true),
|
||||
fLoopStart((float)start),
|
||||
fLoopEnd((float)end),
|
||||
fLoop(false),
|
||||
fEaseInType(plAnimEaseTypes::kNoEase),
|
||||
fEaseOutType(plAnimEaseTypes::kNoEase),
|
||||
fEaseInLength(0),
|
||||
fEaseOutLength(0),
|
||||
fEaseInMin(0.f),
|
||||
fEaseInMax(0.f),
|
||||
fEaseOutMin(0.f),
|
||||
fEaseOutMax(0.f)
|
||||
{
|
||||
}
|
||||
|
||||
// dtor ---------------
|
||||
// -----
|
||||
plATCAnim::~plATCAnim()
|
||||
{
|
||||
fMarkers.clear();
|
||||
fLoops.clear();
|
||||
fStopPoints.clear();
|
||||
}
|
||||
|
||||
// Read ---------------------------------------------
|
||||
// -----
|
||||
void plATCAnim::Read(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plAGAnim::Read(stream, mgr);
|
||||
|
||||
fInitial = stream->ReadLEScalar();
|
||||
fAutoStart = stream->ReadBool();
|
||||
fLoopStart = stream->ReadLEScalar();
|
||||
fLoopEnd = stream->ReadLEScalar();
|
||||
fLoop = stream->ReadBool();
|
||||
|
||||
fEaseInType = stream->ReadByte();
|
||||
fEaseInMin = stream->ReadLEScalar();
|
||||
fEaseInMax = stream->ReadLEScalar();
|
||||
fEaseInLength = stream->ReadLEScalar();
|
||||
fEaseOutType = stream->ReadByte();
|
||||
fEaseOutMin = stream->ReadLEScalar();
|
||||
fEaseOutMax = stream->ReadLEScalar();
|
||||
fEaseOutLength = stream->ReadLEScalar();
|
||||
|
||||
int i;
|
||||
int numMarkers = stream->ReadLE32();
|
||||
for (i = 0; i < numMarkers; i++)
|
||||
{
|
||||
plString name = stream->ReadSafeString();
|
||||
float time = stream->ReadLEFloat();
|
||||
fMarkers[name] = time;
|
||||
}
|
||||
|
||||
int numLoops = stream->ReadLE32();
|
||||
for (i = 0; i < numLoops; i++)
|
||||
{
|
||||
plString name = stream->ReadSafeString();
|
||||
float begin = stream->ReadLEScalar();
|
||||
float end = stream->ReadLEScalar();
|
||||
fLoops[name] = std::pair<float,float>(begin,end);
|
||||
}
|
||||
|
||||
int numStops = stream->ReadLE32();
|
||||
for (i = 0; i < numStops; i++)
|
||||
fStopPoints.push_back(stream->ReadLEScalar());
|
||||
}
|
||||
|
||||
// Write ---------------------------------------------
|
||||
// ------
|
||||
void plATCAnim::Write(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plAGAnim::Write(stream, mgr);
|
||||
|
||||
stream->WriteLEScalar(fInitial);
|
||||
stream->WriteBool(fAutoStart);
|
||||
stream->WriteLEScalar(fLoopStart);
|
||||
stream->WriteLEScalar(fLoopEnd);
|
||||
stream->WriteBool(fLoop);
|
||||
|
||||
stream->WriteByte(fEaseInType);
|
||||
stream->WriteLEScalar(fEaseInMin);
|
||||
stream->WriteLEScalar(fEaseInMax);
|
||||
stream->WriteLEScalar(fEaseInLength);
|
||||
stream->WriteByte(fEaseOutType);
|
||||
stream->WriteLEScalar(fEaseOutMin);
|
||||
stream->WriteLEScalar(fEaseOutMax);
|
||||
stream->WriteLEScalar(fEaseOutLength);
|
||||
|
||||
stream->WriteLE32(fMarkers.size());
|
||||
for (MarkerMap::iterator it = fMarkers.begin(); it != fMarkers.end(); it++)
|
||||
{
|
||||
stream->WriteSafeString(it->first);
|
||||
stream->WriteLEFloat(it->second);
|
||||
}
|
||||
|
||||
stream->WriteLE32(fLoops.size());
|
||||
for (LoopMap::iterator loopIt = fLoops.begin(); loopIt != fLoops.end(); loopIt++)
|
||||
{
|
||||
stream->WriteSafeString(loopIt->first);
|
||||
std::pair<float,float>& loop = loopIt->second;
|
||||
stream->WriteLEFloat(loop.first);
|
||||
stream->WriteLEFloat(loop.second);
|
||||
}
|
||||
|
||||
int i;
|
||||
stream->WriteLE32(fStopPoints.size());
|
||||
for (i = 0; i < fStopPoints.size(); i++)
|
||||
stream->WriteLEScalar(fStopPoints[i]);
|
||||
}
|
||||
|
||||
// CheckLoop --------------
|
||||
// ----------
|
||||
void plATCAnim::CheckLoop()
|
||||
{
|
||||
if (fLoopStart == fLoopEnd)
|
||||
{
|
||||
fLoopStart = fStart;
|
||||
fLoopEnd = fEnd;
|
||||
}
|
||||
}
|
||||
|
||||
// AddLoop ------------------------------------------------------
|
||||
// --------
|
||||
void plATCAnim::AddLoop(const plString &name, float start, float end)
|
||||
{
|
||||
fLoops[name] = std::pair<float,float>(start, end);
|
||||
}
|
||||
|
||||
// GetLoop --------------------------------------------------------------
|
||||
// --------
|
||||
bool plATCAnim::GetLoop(const plString &name, float &start, float &end) const
|
||||
{
|
||||
LoopMap::const_iterator it = fLoops.find(name);
|
||||
if (it != fLoops.end())
|
||||
{
|
||||
const std::pair<float,float>& loop = (*it).second;
|
||||
start = loop.first;
|
||||
end = loop.second;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// GetLoop --------------------------------------------------------
|
||||
// --------
|
||||
bool plATCAnim::GetLoop(uint32_t num, float &start, float &end) const
|
||||
{
|
||||
if (num >= fLoops.size())
|
||||
return false;
|
||||
|
||||
LoopMap::const_iterator it = fLoops.begin();
|
||||
|
||||
while (num > 0)
|
||||
{
|
||||
it++;
|
||||
num--;
|
||||
}
|
||||
const std::pair<float,float>& loop = (*it).second;
|
||||
start = loop.first;
|
||||
end = loop.second;
|
||||
return true;
|
||||
}
|
||||
|
||||
// GetNumLoops ----------------------
|
||||
// ------------
|
||||
uint32_t plATCAnim::GetNumLoops() const
|
||||
{
|
||||
return fLoops.size();
|
||||
}
|
||||
|
||||
// AddMarker ------------------------------------------
|
||||
// ----------
|
||||
void plATCAnim::AddMarker(const plString &name, float time)
|
||||
{
|
||||
fMarkers[name] = time;
|
||||
}
|
||||
|
||||
// GetMarker -------------------------------------
|
||||
// ----------
|
||||
float plATCAnim::GetMarker(const plString &name) const
|
||||
{
|
||||
if (fMarkers.find(name) != fMarkers.end())
|
||||
return (*fMarkers.find(name)).second;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// CopyMarkerNames -------------------------------------
|
||||
// ----------------
|
||||
void plATCAnim::CopyMarkerNames(std::vector<plString> &out)
|
||||
{
|
||||
MarkerMap::iterator it = fMarkers.begin();
|
||||
|
||||
out.reserve(fMarkers.size());
|
||||
for (; it != fMarkers.end(); it++)
|
||||
{
|
||||
out.push_back((*it).first);
|
||||
}
|
||||
}
|
||||
|
||||
// AddStopPoint ---------------------------
|
||||
// -------------
|
||||
void plATCAnim::AddStopPoint(float time)
|
||||
{
|
||||
fStopPoints.push_back(time);
|
||||
}
|
||||
|
||||
// NumStopPoints ----------------
|
||||
// --------------
|
||||
uint32_t plATCAnim::NumStopPoints()
|
||||
{
|
||||
return fStopPoints.size();
|
||||
}
|
||||
|
||||
// GetStopPoint --------------------------
|
||||
// -------------
|
||||
float plATCAnim::GetStopPoint(uint32_t i)
|
||||
{
|
||||
hsAssert(i < fStopPoints.size(), "Invalid index for GetStopPoint");
|
||||
return fStopPoints[i];
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// plEmoteAnim
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ctor ------------------
|
||||
// -----
|
||||
plEmoteAnim::plEmoteAnim()
|
||||
: fBodyUsage(kBodyFull)
|
||||
{
|
||||
}
|
||||
|
||||
// ctor ------------------------------------------------------------------------------
|
||||
// -----
|
||||
plEmoteAnim::plEmoteAnim(const plString &animName, double begin, double end, float fadeIn,
|
||||
float fadeOut, BodyUsage bodyUsage)
|
||||
: plATCAnim(animName, begin, end),
|
||||
fFadeIn(fadeIn),
|
||||
fFadeOut(fadeOut),
|
||||
fBodyUsage(bodyUsage)
|
||||
{
|
||||
}
|
||||
|
||||
// Read -----------------------------------------------
|
||||
// -----
|
||||
void plEmoteAnim::Read(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plATCAnim::Read(stream, mgr);
|
||||
|
||||
// plAGAnim::RegisterEmote(fName, this);
|
||||
fFadeIn = stream->ReadLEScalar();
|
||||
fFadeOut = stream->ReadLEScalar();
|
||||
fBodyUsage = static_cast<BodyUsage>(stream->ReadByte());
|
||||
|
||||
}
|
||||
|
||||
// Write -----------------------------------------------
|
||||
// ------
|
||||
void plEmoteAnim::Write(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plATCAnim::Write(stream, mgr);
|
||||
stream->WriteLEScalar(fFadeIn);
|
||||
stream->WriteLEScalar(fFadeOut);
|
||||
stream->WriteByte(static_cast<uint8_t>(fBodyUsage));
|
||||
}
|
||||
|
||||
// GetBodyUsage ----------------------------------------
|
||||
// -------------
|
||||
plEmoteAnim::BodyUsage plEmoteAnim::GetBodyUsage() const
|
||||
{
|
||||
return fBodyUsage;
|
||||
}
|
||||
|
||||
// GetFadeIn -----------------------
|
||||
// ----------
|
||||
float plEmoteAnim::GetFadeIn() const
|
||||
{
|
||||
return fFadeIn;
|
||||
}
|
||||
|
||||
// GetFadeOut -----------------------
|
||||
// -----------
|
||||
float plEmoteAnim::GetFadeOut() const
|
||||
{
|
||||
return fFadeOut;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// plAgeGlobalAnim
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ctor --------------------------
|
||||
// -----
|
||||
plAgeGlobalAnim::plAgeGlobalAnim()
|
||||
: plAGAnim()
|
||||
{
|
||||
}
|
||||
|
||||
// ctor --------------------------------------------------------------------
|
||||
// -----
|
||||
plAgeGlobalAnim::plAgeGlobalAnim(const plString &name, double start, double end)
|
||||
: plAGAnim(name, start, end)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// Read ---------------------------------------------------
|
||||
// -----
|
||||
void plAgeGlobalAnim::Read(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plAGAnim::Read(stream, mgr);
|
||||
|
||||
fGlobalVarName = stream->ReadSafeString();
|
||||
}
|
||||
|
||||
// Write ---------------------------------------------------
|
||||
// ------
|
||||
void plAgeGlobalAnim::Write(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plAGAnim::Write(stream, mgr);
|
||||
|
||||
stream->WriteSafeString(fGlobalVarName);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// UTILITIES
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// GetStartToEndTransform -----------------------------------------------
|
||||
bool GetStartToEndTransform(const plAGAnim *anim, hsMatrix44 *startToEnd,
|
||||
hsMatrix44 *endToStart, const plString &channelName)
|
||||
{
|
||||
double start = 0.0f; // assumed
|
||||
double end = anim->GetEnd();
|
||||
|
||||
GetRelativeTransform(anim, start, end, startToEnd, endToStart, channelName);
|
||||
return true;
|
||||
}
|
||||
|
||||
// GetRelativeTransform ---------------------------------------------------
|
||||
bool GetRelativeTransform(const plAGAnim *anim, double timeA, double timeB,
|
||||
hsMatrix44 *a2b, hsMatrix44 *b2a, const plString &channelName)
|
||||
{
|
||||
bool result = false;
|
||||
plAGChannel *maybeChannel = anim->GetChannel(channelName);
|
||||
hsAssert(maybeChannel, "Couldn't find channel with given name.");
|
||||
if(maybeChannel)
|
||||
{
|
||||
plMatrixChannel *channel = plMatrixChannel::ConvertNoRef(maybeChannel);
|
||||
hsAssert(channel, "Found channel, but it's not a matrix channel.");
|
||||
|
||||
if(channel)
|
||||
{
|
||||
hsMatrix44 matA;
|
||||
hsMatrix44 matB;
|
||||
|
||||
channel->Value(matA, timeA);
|
||||
channel->Value(matB, timeB);
|
||||
|
||||
if(a2b) // requested a transform from point A to point B
|
||||
{
|
||||
hsMatrix44 invA;
|
||||
matA.GetInverse(&invA);
|
||||
*a2b = invA * matB;
|
||||
}
|
||||
if(b2a) // requested a transform from point B to point A
|
||||
{
|
||||
hsMatrix44 invB;
|
||||
matB.GetInverse(&invB);
|
||||
*b2a = invB * matA;
|
||||
|
||||
if(a2b)
|
||||
{
|
||||
hsMatrix44 invB2;
|
||||
a2b->GetInverse(&invB2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
443
Sources/Plasma/PubUtilLib/plAnimation/plAGAnim.h
Normal file
443
Sources/Plasma/PubUtilLib/plAnimation/plAGAnim.h
Normal file
@ -0,0 +1,443 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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==*/
|
||||
#ifndef PLAGANIM_INC
|
||||
#define PLAGANIM_INC
|
||||
|
||||
/** \file plAGAnim.h
|
||||
\brief The animation class for the AniGraph animation system
|
||||
|
||||
\ingroup Avatar
|
||||
\ingroup AniGraph
|
||||
*/
|
||||
#pragma warning(disable: 4786) // don't care if mangled names are longer than 255 characters
|
||||
|
||||
#include <map>
|
||||
#include "pnNetCommon/plSynchedObject.h"
|
||||
|
||||
class plTMController;
|
||||
class hsAffineParts;
|
||||
class plAnimTimeConvert;
|
||||
struct hsMatrix44;
|
||||
class plEmoteAnim;
|
||||
class plAGApplicator;
|
||||
class plAGChannel;
|
||||
|
||||
/** \class plAGAnim
|
||||
This class holds reusable animation data. A single plAGAnim can be instanced
|
||||
any number of times simultaneously.
|
||||
In order to use a plAGAnim, you need a plAGMasterMod, which is a special type of
|
||||
modifier which can be attached to multiple scene objects. A master mod is typically
|
||||
applied to the root of a scene branch, but there is no requirement that all the scene
|
||||
objects animated be children.
|
||||
Each plAGAnim has a number of channels, each of which can animate a single parameter
|
||||
of a single object. Channels are parametric, i.e. they can carry any data type.
|
||||
A plAGAnim carries a name for the animation, and each channel is named as well.
|
||||
Instancing a plAGAnim is done via a plAGAnimInstance.
|
||||
\sa plAGAnimInstance plAGMasterMod plAGModifier
|
||||
*/
|
||||
class plAGAnim : public plSynchedObject
|
||||
{
|
||||
public:
|
||||
/** How much of the body does this emote use? This is handy information for
|
||||
figuring out whether you can, say, wave while sitting down. */
|
||||
enum BodyUsage {
|
||||
kBodyUnknown,
|
||||
kBodyUpper,
|
||||
kBodyFull,
|
||||
kBodyLower,
|
||||
kBodyMax,
|
||||
kForceSize = 0xff
|
||||
};
|
||||
|
||||
plAGAnim();
|
||||
/** Construct with name, start time, and end time (within the max note track)
|
||||
*/
|
||||
plAGAnim(const plString &name, double begin, double end);
|
||||
/** Destruct, freeing the underlying animation data. */
|
||||
virtual ~plAGAnim();
|
||||
|
||||
/** Return the total of number of channels supplied by this animation.
|
||||
An object being animated by this animation does not have to have this
|
||||
many channels; any which are not available will be ignored.
|
||||
This is syntactic sugar: GetApplicatorCount will return the exact
|
||||
same number, but some code is only interested in the channels and not
|
||||
the applicators. */
|
||||
int GetChannelCount() const;
|
||||
|
||||
/** Return the ith channel of the animation. Ordering is arbitrary but consistent.
|
||||
It's currently breadth first base on the export algorithm, but don't count on this
|
||||
remaining true. */
|
||||
plAGChannel * GetChannel(int i) const;
|
||||
|
||||
/** Get the name of the channel having the given index. Useful for talking to an
|
||||
an animation before it is applied and finding out what channels it's going to
|
||||
affect. */
|
||||
virtual plString GetChannelName(int index);
|
||||
|
||||
/** Get channel by name. This corresponds to the name of the scene object this channel
|
||||
will be attached to when the animation is applied.
|
||||
This function is fairly slow and shouldn't be used often. */
|
||||
plAGChannel * GetChannel(const plString &name) const;
|
||||
|
||||
/** Return the number of applicators held by this animation. An applicator is used
|
||||
to attach a channel to a sceneobject. */
|
||||
int GetApplicatorCount() const;
|
||||
|
||||
/** Return the ith applicator in the channel.
|
||||
Order is arbitrary but consistent, corresponding to processing order in the exporter. */
|
||||
plAGApplicator * GetApplicator(int i) const; // get applicator by index
|
||||
|
||||
/** Add an applicator -- which must have a channel behind it.
|
||||
Applicators are translator object which take the output of a
|
||||
channel and apply it to a scene object. */
|
||||
int AddApplicator(plAGApplicator * app);
|
||||
|
||||
/** Remove the ith applicator and its associated channel. Existing applicators
|
||||
will be renumbered. */
|
||||
bool RemoveApplicator(int appNum);
|
||||
|
||||
/** The name of the animation. This name is used in the avatar manager to reference
|
||||
animations. Animations are generally indexed by name when they are loaded
|
||||
by the avatar or from script, but most of the functions which take an animation
|
||||
name (such as AttachAnimation on the plAGMasterMod) will also take an pointer
|
||||
to a plAGAnim. */
|
||||
virtual plString GetName() const { return fName; }
|
||||
|
||||
/** Return the length of the animation; end - start. */
|
||||
virtual float GetLength() const { return fEnd - fStart; }
|
||||
|
||||
/** Hacky function to extend the length of the animation to some minimum
|
||||
length. Does nothing if the animation is already longer than this. */
|
||||
void ExtendToLength(float length);
|
||||
|
||||
/** Return the start time for the beginning of the animation. The animation
|
||||
contains no data prior to this time.
|
||||
In practice, this always returns 0.0f and this function may be deprecated. */
|
||||
virtual float GetStart() const { return fStart; }
|
||||
void SetStart(float start) { fStart = start; }
|
||||
|
||||
/** Return the end time of the animation. Since start is typically 0, this usually
|
||||
serves as the length of the animation as well. */
|
||||
virtual float GetEnd() const { return fEnd; }
|
||||
void SetEnd(float end) { fEnd = end; }
|
||||
|
||||
|
||||
/** Returns true if any applicator on the arg anim tries to use the
|
||||
same pin (on the same object) as we do. */
|
||||
bool SharesPinsWith(const plAGAnim *anim) const;
|
||||
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
// rtti
|
||||
CLASSNAME_REGISTER( plAGAnim );
|
||||
GETINTERFACE_ANY( plAGAnim, plSynchedObject );
|
||||
|
||||
// *** temp hack to manage animation instances
|
||||
/** Add the animation by name to a global static registry.
|
||||
This functionality will possibly be added to the resource
|
||||
manager. */
|
||||
static void AddAnim(const plString & name, plAGAnim *anim);
|
||||
/** See if there is an animation with the given name in the
|
||||
global animation registry. */
|
||||
static plAGAnim *FindAnim(const plString &name);
|
||||
/** Remove the given animation from the registry. */
|
||||
static bool RemoveAnim(const plString &name);
|
||||
/** Clear the animation cache. Used when resetting the client
|
||||
to a vanilla state, as when clearing the scene while
|
||||
exporting. */
|
||||
static void ClearAnimationRegistry();
|
||||
/** Debugging utility. Prints out a list of all the animations
|
||||
in the registry */
|
||||
static void DumpAnimationRegistry();
|
||||
|
||||
// persistance
|
||||
virtual void Read(hsStream* stream, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* stream, hsResMgr* mgr);
|
||||
|
||||
protected:
|
||||
typedef std::vector<plAGApplicator*> ApplicatorVec;
|
||||
ApplicatorVec fApps; /// our animation channels
|
||||
float fBlend; /// requested blend factor
|
||||
|
||||
float fStart; /// the start time of the beginning of the animation (usually 0)
|
||||
float fEnd; /// the end time of the animation
|
||||
|
||||
plString fName; /// the name of our animation
|
||||
|
||||
// ??? Can this be moved to the resource manager? If it can manage an efficient
|
||||
// string-based namespace per class, we could get rid of this.
|
||||
typedef std::map<plString, plAGAnim *, plString::less_i> plAnimMap; //
|
||||
static plAnimMap fAllAnims; /// map of animation names to animations
|
||||
|
||||
typedef std::map<plString, plEmoteAnim *, plString::less_i> plEmoteMap;
|
||||
static plEmoteMap fAllEmotes;
|
||||
};
|
||||
|
||||
///////////////
|
||||
// PLATCANIM
|
||||
///////////////
|
||||
|
||||
/** \class plATCAnim
|
||||
The most common subclass of plAGAnim.
|
||||
Represents an animation with a standard AnimTimeConvert
|
||||
(i.e. stop/start/loop/etc animation)
|
||||
*/
|
||||
class plATCAnim : public plAGAnim
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
plATCAnim();
|
||||
/** Construct with name, start time, and end time (within the max note track)
|
||||
Default is to start automatically, not loop, with no ease curves. */
|
||||
plATCAnim(const plString &name, double begin, double end);
|
||||
/** Destruct, freeing the underlying animation data. */
|
||||
virtual ~plATCAnim();
|
||||
|
||||
/** Returns the initial position of the "playback head" for this animation.
|
||||
Animations are not required to start at their actual beginning but can,
|
||||
for instance, start in the middle, play to the end, and then loop to the
|
||||
beginning or to their loop start point. */
|
||||
virtual float GetInitial() const { return fInitial; }
|
||||
void SetInitial(float initial) { fInitial = initial; }
|
||||
|
||||
/** Does this animation start automatically when it's applied? */
|
||||
virtual bool GetAutoStart() const { return fAutoStart; }
|
||||
void SetAutoStart(bool start) { fAutoStart = (start != 0); }
|
||||
|
||||
/** If the animation loops, this is where it will restart the loop. Note that
|
||||
loops do not have to start at the beginning of the animation. */
|
||||
virtual float GetLoopStart() const { return fLoopStart; }
|
||||
void SetLoopStart(float start) { fLoopStart = start; }
|
||||
|
||||
/** If the animation loops, this is the end point of the loop. After passing
|
||||
this point, the animation will cycle around to GetLoopStart */
|
||||
virtual float GetLoopEnd() const { return fLoopEnd; }
|
||||
void SetLoopEnd(float end) { fLoopEnd = end; }
|
||||
|
||||
/** Does this animation loop?. Note that there may be multiple loop segments defined
|
||||
within a given animation. */
|
||||
virtual bool GetLoop() const { return fLoop; }
|
||||
void SetLoop(bool loop) { fLoop = (loop != 0); }
|
||||
|
||||
/** Set the curve type for easing in. Easing is an optional feature which allows you
|
||||
to make an animation slow down gradually when you stop it.
|
||||
The types are defined in plAnimEaseTypes.h
|
||||
*/
|
||||
virtual uint8_t GetEaseInType() const { return fEaseInType; }
|
||||
void SetEaseInType(uint8_t type) { fEaseInType = type; }
|
||||
|
||||
/** Set the length of time the ease-in should take. */
|
||||
virtual float GetEaseInLength() const { return fEaseInLength; }
|
||||
/** Set the length of time the ease-in should take. */
|
||||
void SetEaseInLength(float length) { fEaseInLength = length; }
|
||||
|
||||
/** The minimum value used at the start of the ease in. */
|
||||
virtual float GetEaseInMin() const { return fEaseInMin; }
|
||||
/** The minimum value used at the start of the ease in. */
|
||||
void SetEaseInMin(float length) { fEaseInMin = length; }
|
||||
|
||||
/** The maximum value reached at the end of the ease in. */
|
||||
virtual float GetEaseInMax() const { return fEaseInMax; }
|
||||
/** The maximum value reached at the end of the ease in. */
|
||||
void SetEaseInMax(float length) { fEaseInMax = length; }
|
||||
|
||||
/** The curve type for the ease out. */
|
||||
virtual uint8_t GetEaseOutType() const { return fEaseOutType; }
|
||||
/** The curve type for the ease out. */
|
||||
void SetEaseOutType(uint8_t type) { fEaseOutType = type; }
|
||||
|
||||
/** The length of time for the ease out. */
|
||||
virtual float GetEaseOutLength() const { return fEaseOutLength; }
|
||||
/** The length of time for the ease out. */
|
||||
void SetEaseOutLength(float length) { fEaseOutLength = length; }
|
||||
|
||||
/** Minimum value reached in ease-out */
|
||||
virtual float GetEaseOutMin() const { return fEaseOutMin; }
|
||||
/** Minimum value reached in ease-out */
|
||||
void SetEaseOutMin(float length) { fEaseOutMin = length; }
|
||||
|
||||
/** Maximum value reached in ease-in */
|
||||
virtual float GetEaseOutMax() const { return fEaseOutMax; }
|
||||
/** Maximum value reached in ease-in */
|
||||
void SetEaseOutMax(float length) { fEaseOutMax = length; }
|
||||
|
||||
/** Animations can have multiple defined loop segments; these
|
||||
are selected using animation control messages.
|
||||
Each loop segment is named using markers in the notetrack. */
|
||||
void AddLoop(const plString &name, float start, float end);
|
||||
/** Get the loop having the given name.
|
||||
\param start will return the start time of the loop.
|
||||
\param end will hold the end time of the loop */
|
||||
bool GetLoop(const plString &name, float &start, float &end) const;
|
||||
/** Lets you get a loop by index instead of name. */
|
||||
bool GetLoop(uint32_t num, float &start, float &end) const;
|
||||
/** Returns the number of loops defined on this anim. */
|
||||
uint32_t GetNumLoops() const;
|
||||
|
||||
/** Add a marker to the animation. Markers can be used
|
||||
for callbacks or for goto comands. A marker is a simple
|
||||
name/time tuple. */
|
||||
void AddMarker(const plString &name, float time);
|
||||
/** Returns the time value of the marker named by name. */
|
||||
float GetMarker(const plString &name) const;
|
||||
void CopyMarkerNames(std::vector<plString> &out);
|
||||
/** Add a stop point to the animation. A stop point is a
|
||||
"detent" for playback - if the animation is stopping
|
||||
near a stop point and fading out, the stop point will
|
||||
override the fade, so that the animation stops precisely
|
||||
at the defined time. */
|
||||
void AddStopPoint(float time);
|
||||
/** Return the number of stop points defined for this animation. */
|
||||
uint32_t NumStopPoints();
|
||||
/** Get the time corresponding to the given stop point. Stop points
|
||||
are numbered in the order they were added. */
|
||||
float GetStopPoint(uint32_t i);
|
||||
/** Function to check for a zero-length loop, and set it to
|
||||
the anim's start/end instead */
|
||||
void CheckLoop();
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
// rtti
|
||||
CLASSNAME_REGISTER( plATCAnim );
|
||||
GETINTERFACE_ANY( plATCAnim, plAGAnim );
|
||||
|
||||
// persistance
|
||||
virtual void Read(hsStream* stream, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* stream, hsResMgr* mgr);
|
||||
|
||||
protected:
|
||||
float fInitial; /// the position of the playback head
|
||||
bool fAutoStart; /// does the animation start automatically?
|
||||
float fLoopStart; /// when wrapping a loop, start here
|
||||
float fLoopEnd; /// when you reach this point, loop back
|
||||
bool fLoop; /// do we loop?
|
||||
|
||||
uint8_t fEaseInType; /// the type (none/linear/spline) of our ease-in curve, if any
|
||||
uint8_t fEaseOutType; /// the type (none/linear/spline) of our ease-out curve, if any
|
||||
float fEaseInLength; /// the length of time our ease-in curve takes
|
||||
float fEaseInMin; /// minimum (initial) value of our ease-in
|
||||
float fEaseInMax; /// maximum (final) value of our ease-in
|
||||
float fEaseOutLength; /// the length of time our ease-out curve takes
|
||||
float fEaseOutMin; /// minimum (final) value of our ease-out
|
||||
float fEaseOutMax; /// maximum (initial) value of our ease-out
|
||||
|
||||
// a map from segment names to times
|
||||
typedef std::map<plString, float> MarkerMap;
|
||||
MarkerMap fMarkers;
|
||||
|
||||
typedef std::map<plString, std::pair<float,float> > LoopMap;
|
||||
LoopMap fLoops;
|
||||
|
||||
typedef std::vector<float> ScalarMap;
|
||||
ScalarMap fStopPoints; /// vector of stop points
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** \class plEmoteAnim
|
||||
An animation to be used for emotes.
|
||||
Automatically registers so that it can be played from the chat field.
|
||||
*/
|
||||
class plEmoteAnim : public plATCAnim
|
||||
{
|
||||
public:
|
||||
|
||||
plEmoteAnim();
|
||||
plEmoteAnim(const plString &animName, double begin, double end, float fadeIn, float fadeOut, BodyUsage bodyUsage);
|
||||
|
||||
BodyUsage GetBodyUsage() const;
|
||||
float GetFadeIn() const;
|
||||
float GetFadeOut() const;
|
||||
|
||||
CLASSNAME_REGISTER( plEmoteAnim );
|
||||
GETINTERFACE_ANY( plEmoteAnim, plATCAnim );
|
||||
|
||||
virtual void Read(hsStream *stream, hsResMgr *mgr);
|
||||
virtual void Write(hsStream *stream, hsResMgr *mgr);
|
||||
|
||||
protected:
|
||||
BodyUsage fBodyUsage; // how much of the body is used by this emote?
|
||||
float fFadeIn; // how fast to fade in the emote
|
||||
float fFadeOut; // how fast to fade out the emote
|
||||
};
|
||||
|
||||
//////////////////
|
||||
// PLAGEGLOBALANIM
|
||||
//////////////////
|
||||
|
||||
/** \class plAgeGlobalAnim
|
||||
An animation that bases its current position on a variable that global to the age,
|
||||
like weather, time of day, etc.
|
||||
*/
|
||||
|
||||
class plAgeGlobalAnim : public plAGAnim
|
||||
{
|
||||
public:
|
||||
plAgeGlobalAnim();
|
||||
/** Construct with name, start time, and end time (within the max note track)
|
||||
*/
|
||||
plAgeGlobalAnim(const plString &name, double begin, double end);
|
||||
|
||||
plString GetGlobalVarName() const { return fGlobalVarName; }
|
||||
void SetGlobalVarName(const plString &name) { fGlobalVarName = name; }
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
// rtti
|
||||
CLASSNAME_REGISTER( plAgeGlobalAnim );
|
||||
GETINTERFACE_ANY( plAgeGlobalAnim, plAGAnim );
|
||||
|
||||
// persistance
|
||||
virtual void Read(hsStream* stream, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* stream, hsResMgr* mgr);
|
||||
|
||||
protected:
|
||||
plString fGlobalVarName; // Name of the SDL variable we animate on.
|
||||
};
|
||||
|
||||
// USEFUL HELPER FUNCTIONS
|
||||
bool GetStartToEndTransform(const plAGAnim *anim, hsMatrix44 *startToEnd, hsMatrix44 *endToStart, const plString &channelName);
|
||||
bool GetRelativeTransform(const plAGAnim *anim, double timeA, double timeB, hsMatrix44 *a2b, hsMatrix44 *b2a, const plString &channelName);
|
||||
|
||||
|
||||
|
||||
#endif
|
681
Sources/Plasma/PubUtilLib/plAnimation/plAGAnimInstance.cpp
Normal file
681
Sources/Plasma/PubUtilLib/plAnimation/plAGAnimInstance.cpp
Normal file
@ -0,0 +1,681 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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==*/
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDES
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// singular
|
||||
#include "plAGAnimInstance.h"
|
||||
|
||||
// local
|
||||
#include "plAGAnim.h"
|
||||
#include "plAGModifier.h"
|
||||
#include "plAGMasterMod.h"
|
||||
|
||||
// global
|
||||
#include "hsTimer.h" // just when debugging for GetSysSeconds
|
||||
|
||||
// other
|
||||
#include "pnNetCommon/plSDLTypes.h"
|
||||
#include "plMessage/plAnimCmdMsg.h"
|
||||
#include "plMessage/plOneShotCallbacks.h"
|
||||
#include "plModifier/plSDLModifier.h"
|
||||
#include "plSDL/plSDL.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// FLAGS
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// enable this to show blend trees before and after attaches and detaches
|
||||
// #define SHOW_AG_CHANGES
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// STATIC
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
#ifdef TRACK_AG_ALLOCS
|
||||
plString gGlobalAnimName;
|
||||
plString gGlobalChannelName;
|
||||
#endif // TRACK_AG_ALLOCS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// plAGAnimInstance
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ctor -------------------------------------------------------------------
|
||||
// -----
|
||||
plAGAnimInstance::plAGAnimInstance(plAGAnim * anim, plAGMasterMod * master,
|
||||
float blend, uint16_t blendPriority, bool cache,
|
||||
bool useAmplitude)
|
||||
: fAnimation(anim),
|
||||
fMaster(master),
|
||||
fBlend(blend),
|
||||
fAmplitude(useAmplitude ? 1.0f : -1.0f)
|
||||
{
|
||||
int i;
|
||||
fTimeConvert = nil;
|
||||
plScalarChannel *timeChan = nil;
|
||||
#ifdef TRACK_AG_ALLOCS
|
||||
gGlobalAnimName = anim->GetName(); // for debug tracking...
|
||||
#endif // TRACK_AG_ALLOCS
|
||||
|
||||
plATCAnim *atcAnim = plATCAnim::ConvertNoRef(anim);
|
||||
if (atcAnim)
|
||||
{
|
||||
fTimeConvert = new plAnimTimeConvert();
|
||||
IInitAnimTimeConvert(fTimeConvert, atcAnim, master);
|
||||
//fTimeConvert->Init(atcAnim, this, master);
|
||||
timeChan = new plATCChannel(fTimeConvert);
|
||||
}
|
||||
else
|
||||
{
|
||||
timeChan = new plScalarSDLChannel(anim->GetLength());
|
||||
fSDLChannels.push_back((plScalarSDLChannel *)timeChan);
|
||||
}
|
||||
|
||||
int nInChannels = anim->GetChannelCount();
|
||||
|
||||
fCleanupChannels.push_back(timeChan);
|
||||
|
||||
#ifdef SHOW_AG_CHANGES
|
||||
hsStatusMessageF("\nAbout to Attach anim <%s>", GetName().c_str());
|
||||
fMaster->DumpAniGraph("bone_pelvis", false, hsTimer::GetSysSeconds());
|
||||
#endif
|
||||
|
||||
for (i = 0; i < nInChannels; i++)
|
||||
{
|
||||
plAGApplicator * app = fAnimation->GetApplicator(i);
|
||||
plAGChannel * inChannel = app->GetChannel();
|
||||
plString channelName = app->GetChannelName();
|
||||
plAGModifier * channelMod = master->GetChannelMod(channelName);
|
||||
|
||||
if(channelMod) {
|
||||
#ifdef TRACK_AG_ALLOCS
|
||||
gGlobalChannelName = channelName;
|
||||
#endif // TRACK_AG_ALLOCS
|
||||
|
||||
// we're going to be accumulating a chain of channels.
|
||||
// curChannel will always point to the top one...
|
||||
plAGChannel *topNode = inChannel;
|
||||
|
||||
if(cache)
|
||||
{
|
||||
topNode = topNode->MakeCacheChannel(fTimeConvert);
|
||||
IRegisterDetach(channelName, topNode);
|
||||
}
|
||||
|
||||
if(useAmplitude)
|
||||
{
|
||||
// amplitude is rarely used and expensive, so only alloc if asked
|
||||
// first build a static copy of the incoming channel...
|
||||
plAGChannel *zeroState = inChannel->MakeZeroState();
|
||||
IRegisterDetach(channelName, zeroState);
|
||||
|
||||
// now make a blend node to blend the anim with its static copy
|
||||
topNode = zeroState->MakeBlend(topNode, &fAmplitude, -1);
|
||||
}
|
||||
|
||||
// make a time scaler to localize time for this instance
|
||||
topNode = topNode->MakeTimeScale(timeChan);
|
||||
IRegisterDetach(channelName, topNode);
|
||||
|
||||
channelMod->MergeChannel(app, topNode, &fBlend, this, blendPriority);
|
||||
}
|
||||
else
|
||||
hsAssert(false, "Adding an animation with an invalid channel.");
|
||||
}
|
||||
fFadeBlend = fFadeAmp = false;
|
||||
|
||||
#ifdef TRACK_AG_ALLOCS
|
||||
gGlobalAnimName = "";
|
||||
#endif // TRACK_AG_ALLOCS
|
||||
}
|
||||
|
||||
// dtor -----------------------------
|
||||
// -----
|
||||
plAGAnimInstance::~plAGAnimInstance()
|
||||
{
|
||||
delete fTimeConvert;
|
||||
}
|
||||
|
||||
|
||||
void plAGAnimInstance::IInitAnimTimeConvert(plAnimTimeConvert* atc, plATCAnim* anim, plAGMasterMod* master)
|
||||
{
|
||||
// Set up our eval callbacks
|
||||
plAGInstanceCallbackMsg* instMsg;
|
||||
|
||||
instMsg = new plAGInstanceCallbackMsg(master->GetKey(), kStart);
|
||||
instMsg->fInstance = this;
|
||||
atc->AddCallback(instMsg);
|
||||
hsRefCnt_SafeUnRef(instMsg);
|
||||
|
||||
instMsg = new plAGInstanceCallbackMsg(master->GetKey(), kStop);
|
||||
instMsg->fInstance = this;
|
||||
atc->AddCallback(instMsg);
|
||||
hsRefCnt_SafeUnRef(instMsg);
|
||||
|
||||
instMsg = new plAGInstanceCallbackMsg(master->GetKey(), kSingleFrameAdjust);
|
||||
instMsg->fInstance = this;
|
||||
atc->AddCallback(instMsg);
|
||||
hsRefCnt_SafeUnRef(instMsg);
|
||||
|
||||
atc->SetOwner(master);
|
||||
atc->ClearFlags();
|
||||
|
||||
for (size_t i = 0; i < anim->NumStopPoints(); i++)
|
||||
{
|
||||
atc->GetStopPoints().Append(anim->GetStopPoint(i));
|
||||
}
|
||||
|
||||
atc->SetBegin(anim->GetStart());
|
||||
atc->SetEnd(anim->GetEnd());
|
||||
atc->SetInitialBegin(atc->GetBegin());
|
||||
atc->SetInitialEnd(atc->GetEnd());
|
||||
|
||||
if (anim->GetInitial() != -1)
|
||||
{
|
||||
atc->SetCurrentAnimTime(anim->GetInitial());
|
||||
}
|
||||
else
|
||||
{
|
||||
atc->SetCurrentAnimTime(anim->GetStart());
|
||||
}
|
||||
|
||||
atc->SetLoopPoints(anim->GetLoopStart(), anim->GetLoopEnd());
|
||||
atc->Loop(anim->GetLoop());
|
||||
atc->SetSpeed(1.f);
|
||||
|
||||
atc->SetEase(true, anim->GetEaseInType(), anim->GetEaseInMin(),
|
||||
anim->GetEaseInMax(), anim->GetEaseInLength());
|
||||
|
||||
atc->SetEase(false, anim->GetEaseOutType(), anim->GetEaseOutMin(),
|
||||
anim->GetEaseOutMax(), anim->GetEaseOutLength());
|
||||
|
||||
|
||||
// set up our time converter based on the animation's specs...
|
||||
// ... after we've set all of its other state values.
|
||||
if (anim->GetAutoStart())
|
||||
{
|
||||
plSynchEnabler ps(true); // enable dirty tracking so that autostart will send out a state update
|
||||
atc->Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
atc->InitStop();
|
||||
}
|
||||
}
|
||||
|
||||
// SearchForGlobals ---------------------
|
||||
// -----------------
|
||||
void plAGAnimInstance::SearchForGlobals()
|
||||
{
|
||||
const plAgeGlobalAnim *ageAnim = plAgeGlobalAnim::ConvertNoRef(fAnimation);
|
||||
if (ageAnim != nil && fSDLChannels.size() > 0)
|
||||
{
|
||||
extern const plSDLModifier *ExternFindAgeSDL();
|
||||
const plSDLModifier *sdlMod = ExternFindAgeSDL();
|
||||
if (!sdlMod)
|
||||
return;
|
||||
|
||||
plSimpleStateVariable *var = sdlMod->GetStateCache()->FindVar(ageAnim->GetGlobalVarName());
|
||||
if (!var)
|
||||
return;
|
||||
|
||||
sdlMod->AddNotifyForVar(fMaster->GetKey(), ageAnim->GetGlobalVarName(), 0);
|
||||
int i;
|
||||
for (i = 0; i < fSDLChannels.size(); i++)
|
||||
fSDLChannels[i]->SetVar(var);
|
||||
}
|
||||
}
|
||||
|
||||
void plAGAnimInstance::IRegisterDetach(const plString &channelName, plAGChannel *channel)
|
||||
{
|
||||
plDetachMap::value_type newPair(channelName, channel);
|
||||
fManualDetachChannels.insert(newPair);
|
||||
}
|
||||
|
||||
// SetCurrentTime ---------------------------------------------------------------
|
||||
// ---------------
|
||||
void plAGAnimInstance::SetCurrentTime(float localT, bool jump /* = false */)
|
||||
{
|
||||
if (fTimeConvert)
|
||||
fTimeConvert->SetCurrentAnimTime(localT, jump);
|
||||
}
|
||||
|
||||
// SeekRelative ------------------------------------
|
||||
// -------------
|
||||
void plAGAnimInstance::SeekRelative (float delta, bool jump)
|
||||
{
|
||||
if(fTimeConvert)
|
||||
{
|
||||
float now = fTimeConvert->CurrentAnimTime();
|
||||
fTimeConvert->SetCurrentAnimTime (now + delta, jump);
|
||||
}
|
||||
}
|
||||
|
||||
// Detach ---------------------
|
||||
// -------
|
||||
void plAGAnimInstance::Detach()
|
||||
{
|
||||
fMaster->DetachAnimation(this);
|
||||
}
|
||||
|
||||
// DetachChannels ---------------------
|
||||
// ---------------
|
||||
void plAGAnimInstance::DetachChannels()
|
||||
{
|
||||
#ifdef SHOW_AG_CHANGES
|
||||
hsStatusMessageF("\nAbout to DETACH anim <%s>", GetName().c_str());
|
||||
fMaster->DumpAniGraph("bone_pelvis", false, hsTimer::GetSysSeconds());
|
||||
#endif
|
||||
plDetachMap::iterator i = fManualDetachChannels.begin();
|
||||
|
||||
while(i != fManualDetachChannels.end())
|
||||
{
|
||||
plString channelName = (*i).first;
|
||||
plAGModifier *channelMod = fMaster->GetChannelMod(channelName, true);
|
||||
|
||||
if(channelMod)
|
||||
{
|
||||
do {
|
||||
plAGChannel *channel = (*i).second;
|
||||
channelMod->DetachChannel(channel);
|
||||
} while (++i != fManualDetachChannels.end() && i->first == channelName);
|
||||
} else {
|
||||
do {
|
||||
} while (++i != fManualDetachChannels.end() && i->first == channelName);
|
||||
}
|
||||
}
|
||||
|
||||
int cleanCount = fCleanupChannels.size();
|
||||
hsAssert(cleanCount, "No time controls when deleting animation");
|
||||
for (int j = 0; j < cleanCount; j++)
|
||||
{
|
||||
delete fCleanupChannels[j];
|
||||
}
|
||||
fCleanupChannels.clear();
|
||||
|
||||
#ifdef SHOW_AG_CHANGES
|
||||
hsStatusMessageF("\nFinished DETACHING anim <%s>", GetName().c_str());
|
||||
fMaster->DumpAniGraph("bone_pelvis", false, hsTimer::GetSysSeconds());
|
||||
#endif
|
||||
}
|
||||
|
||||
// SetBlend ---------------------------------------
|
||||
// ---------
|
||||
float plAGAnimInstance::SetBlend(float blend)
|
||||
{
|
||||
float oldBlend = fBlend.Value(0.0, true);
|
||||
if(oldBlend != blend &&
|
||||
(oldBlend == 0.0f ||
|
||||
blend == 0.0f ||
|
||||
oldBlend == 1.0f ||
|
||||
blend == 1.0f))
|
||||
{
|
||||
fMaster->SetNeedCompile(true);
|
||||
}
|
||||
fBlend.Set(blend);
|
||||
return blend;
|
||||
}
|
||||
|
||||
// GetBlend -------------------------
|
||||
// ---------
|
||||
float plAGAnimInstance::GetBlend()
|
||||
{
|
||||
return fBlend.Value(0);
|
||||
}
|
||||
|
||||
// SetAmplitude -------------------------------------
|
||||
// -------------
|
||||
float plAGAnimInstance::SetAmplitude(float amp)
|
||||
{
|
||||
if(fAmplitude.Get() != -1.0f)
|
||||
{
|
||||
fAmplitude.Set(amp);
|
||||
}
|
||||
return amp;
|
||||
}
|
||||
|
||||
// GetAmplitude -------------------------
|
||||
// -------------
|
||||
float plAGAnimInstance::GetAmplitude()
|
||||
{
|
||||
return fAmplitude.Value(0);
|
||||
}
|
||||
|
||||
// GetName -----------------------------
|
||||
// --------
|
||||
plString plAGAnimInstance::GetName()
|
||||
{
|
||||
if(fAnimation)
|
||||
return fAnimation->GetName();
|
||||
else
|
||||
return plString::Null;
|
||||
}
|
||||
|
||||
// SetLoop ----------------------------------
|
||||
// --------
|
||||
void plAGAnimInstance::SetLoop(bool status)
|
||||
{
|
||||
if (fTimeConvert)
|
||||
fTimeConvert->Loop(status);
|
||||
}
|
||||
|
||||
// HandleCmd ----------------------------------------
|
||||
// ----------
|
||||
bool plAGAnimInstance::HandleCmd(plAnimCmdMsg *msg)
|
||||
{
|
||||
if (fTimeConvert)
|
||||
return fTimeConvert->HandleCmd(msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
// IsFinished -----------------------
|
||||
// -----------
|
||||
bool plAGAnimInstance::IsFinished()
|
||||
{
|
||||
if (fTimeConvert)
|
||||
return fTimeConvert->IsStopped();
|
||||
return false;
|
||||
}
|
||||
|
||||
// IsAtEnd -----------------------
|
||||
// --------
|
||||
bool plAGAnimInstance::IsAtEnd()
|
||||
{
|
||||
if(fTimeConvert)
|
||||
{
|
||||
return fTimeConvert->CurrentAnimTime() == fTimeConvert->GetEnd();
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start -----------------------------------
|
||||
// ------
|
||||
void plAGAnimInstance::Start(double timeNow)
|
||||
{
|
||||
if (fTimeConvert)
|
||||
{
|
||||
if (timeNow < 0)
|
||||
fTimeConvert->Start();
|
||||
else
|
||||
fTimeConvert->Start(timeNow);
|
||||
}
|
||||
}
|
||||
|
||||
// Stop ---------------------
|
||||
// -----
|
||||
void plAGAnimInstance::Stop()
|
||||
{
|
||||
if (fTimeConvert)
|
||||
fTimeConvert->Stop();
|
||||
}
|
||||
|
||||
// AttachCallbacks --------------------------------------------------
|
||||
// ----------------
|
||||
void plAGAnimInstance::AttachCallbacks(plOneShotCallbacks *callbacks)
|
||||
{
|
||||
const plATCAnim *anim = plATCAnim::ConvertNoRef(fAnimation);
|
||||
if (callbacks && anim)
|
||||
{
|
||||
plAnimCmdMsg animMsg;
|
||||
animMsg.SetCmd(plAnimCmdMsg::kAddCallbacks);
|
||||
|
||||
for (int i = 0; i < callbacks->GetNumCallbacks(); i++)
|
||||
{
|
||||
plOneShotCallbacks::plOneShotCallback& cb = callbacks->GetCallback(i);
|
||||
|
||||
plEventCallbackMsg *eventMsg = new plEventCallbackMsg;
|
||||
eventMsg->AddReceiver(cb.fReceiver);
|
||||
eventMsg->fRepeats = 0;
|
||||
eventMsg->fUser = cb.fUser;
|
||||
|
||||
if (!cb.fMarker.IsNull())
|
||||
{
|
||||
float marker = anim->GetMarker(cb.fMarker);
|
||||
hsAssert(marker != -1, "Bad marker name");
|
||||
eventMsg->fEventTime = marker;
|
||||
eventMsg->fEvent = kTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
eventMsg->fEvent = kStop;
|
||||
}
|
||||
|
||||
animMsg.AddCallback(eventMsg);
|
||||
hsRefCnt_SafeUnRef(eventMsg);
|
||||
}
|
||||
|
||||
fTimeConvert->HandleCmd(&animMsg);
|
||||
}
|
||||
}
|
||||
|
||||
// ProcessFade -------------------------------------
|
||||
// ------------
|
||||
void plAGAnimInstance::ProcessFade(float elapsed)
|
||||
{
|
||||
if (fFadeBlend) {
|
||||
float newBlend = ICalcFade(fFadeBlend, GetBlend(), fFadeBlendGoal, fFadeBlendRate, elapsed);
|
||||
SetBlend(newBlend);
|
||||
if(fFadeDetach && (newBlend == fFadeBlendGoal) && (fFadeBlendGoal == 0.0f) )
|
||||
{
|
||||
fMaster->DetachAnimation(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (fFadeAmp && fAmplitude.Get() != -1.0f) {
|
||||
float curAmp = GetAmplitude();
|
||||
float newAmp = ICalcFade(fFadeAmp, curAmp, fFadeAmpGoal, fFadeAmpRate, elapsed);
|
||||
SetAmplitude(newAmp);
|
||||
}
|
||||
}
|
||||
|
||||
// ICalcFade ---------------------------------------------------------------------
|
||||
// ----------
|
||||
float plAGAnimInstance::ICalcFade(bool &fade, float curVal, float goal,
|
||||
float rate, float elapsed)
|
||||
{
|
||||
float newVal;
|
||||
float curStep = rate * elapsed;
|
||||
if(rate > 0) {
|
||||
newVal = std::min(goal, curVal + curStep);
|
||||
} else {
|
||||
newVal = std::max(goal, curVal + curStep);
|
||||
}
|
||||
|
||||
if(newVal == goal)
|
||||
{
|
||||
fade = false;
|
||||
fMaster->DirtySynchState(kSDLAGMaster, 0); // send SDL state update to server
|
||||
}
|
||||
return newVal;
|
||||
}
|
||||
|
||||
// FadeAndDetach -------------------------------------------------
|
||||
// --------------
|
||||
void plAGAnimInstance::FadeAndDetach(float goal, float rate)
|
||||
{
|
||||
ISetupFade(goal, rate, true, kFadeBlend);
|
||||
}
|
||||
|
||||
// Fade --------------------------------------------------------------------------------
|
||||
// -----
|
||||
void plAGAnimInstance::Fade(float goal, float rate, uint8_t type /* = kFadeBlend */)
|
||||
{
|
||||
ISetupFade(goal, rate, false, type);
|
||||
}
|
||||
|
||||
// ISetupFade --------------------------------------------------------------------------
|
||||
// -----------
|
||||
void plAGAnimInstance::ISetupFade(float goal, float rate, bool detach, uint8_t type)
|
||||
{
|
||||
if (rate == 0)
|
||||
{
|
||||
if (type == kFadeBlend)
|
||||
{
|
||||
SetBlend(goal);
|
||||
fFadeBlend = false;
|
||||
if(detach) {
|
||||
fMaster->DetachAnimation(this);
|
||||
}
|
||||
}
|
||||
else if (type == kFadeAmp)
|
||||
{
|
||||
SetAmplitude(goal);
|
||||
fFadeAmp = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
rate = (rate > 0 ? rate : -rate); // For old code that sends negative values
|
||||
|
||||
float curVal = 0;
|
||||
switch (type)
|
||||
{
|
||||
case kFadeBlend:
|
||||
curVal = GetBlend();
|
||||
break;
|
||||
case kFadeAmp:
|
||||
curVal = GetAmplitude();
|
||||
break;
|
||||
}
|
||||
if (curVal > goal)
|
||||
rate = -rate;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case kFadeBlend:
|
||||
fFadeBlend = true;
|
||||
fFadeBlendGoal = goal;
|
||||
fFadeBlendRate = rate;
|
||||
fFadeDetach = detach;
|
||||
break;
|
||||
case kFadeAmp:
|
||||
fFadeAmp = true;
|
||||
fFadeAmpGoal = goal;
|
||||
fFadeAmpRate = rate;
|
||||
fFadeDetach = false; // only detach on blend fades, for the moment.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
class agAlloc
|
||||
{
|
||||
public:
|
||||
agAlloc(plAGChannel *object, const char *chanName, const char *animName, uint16_t classIndex)
|
||||
: fObject(object),
|
||||
fClassIndex(classIndex)
|
||||
{
|
||||
fChannelName = hsStrcpy(chanName);
|
||||
fAnimName = hsStrcpy(animName);
|
||||
}
|
||||
|
||||
~agAlloc()
|
||||
{
|
||||
delete[] fChannelName;
|
||||
delete[] fAnimName;
|
||||
}
|
||||
|
||||
plAGChannel *fObject;
|
||||
char *fChannelName;
|
||||
char *fAnimName;
|
||||
uint16_t fClassIndex;
|
||||
};
|
||||
|
||||
typedef std::map<plAGChannel *, agAlloc *> agAllocMap;
|
||||
static agAllocMap gAGAllocs;
|
||||
|
||||
void RegisterAGAlloc(plAGChannel *object, const char *chanName, const char *animName, uint16_t classIndex)
|
||||
{
|
||||
gAGAllocs[object] = new agAlloc(object, chanName, animName, classIndex);
|
||||
}
|
||||
|
||||
void DumpAGAllocs()
|
||||
{
|
||||
agAllocMap::iterator i = gAGAllocs.begin();
|
||||
agAllocMap::iterator theEnd = gAGAllocs.end();
|
||||
|
||||
hsStatusMessage("DUMPING AG ALLOCATIONS ================================================");
|
||||
|
||||
for ( ; i != theEnd; i++)
|
||||
{
|
||||
agAlloc * al = (*i).second;
|
||||
|
||||
uint16_t realClassIndex = al->fObject->ClassIndex();
|
||||
|
||||
hsStatusMessageF("agAlloc: an: %s ch: %s, cl: %s", al->fAnimName, al->fChannelName, plFactory::GetNameOfClass(realClassIndex));
|
||||
|
||||
}
|
||||
// it's not fast but it's safe and simple..
|
||||
i = gAGAllocs.begin();
|
||||
while(i != gAGAllocs.end())
|
||||
{
|
||||
agAlloc * al = (*i).second;
|
||||
delete al;
|
||||
|
||||
gAGAllocs.erase(i++);
|
||||
}
|
||||
hsStatusMessage("FINISHED DUMPING AG ALLOCATIONS *********************************************");
|
||||
}
|
||||
|
||||
void UnRegisterAGAlloc(plAGChannel *object)
|
||||
{
|
||||
agAllocMap::iterator i = gAGAllocs.find(object);
|
||||
if(i != gAGAllocs.end())
|
||||
{
|
||||
agAlloc * al = (*i).second;
|
||||
|
||||
gAGAllocs.erase(i);
|
||||
delete al;
|
||||
}
|
||||
}
|
274
Sources/Plasma/PubUtilLib/plAnimation/plAGAnimInstance.h
Normal file
274
Sources/Plasma/PubUtilLib/plAnimation/plAGAnimInstance.h
Normal file
@ -0,0 +1,274 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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==*/
|
||||
/** \file plAGAnimInstance.h
|
||||
\brief The animation class for the AniGraph animation system
|
||||
|
||||
\ingroup Avatar
|
||||
\ingroup AniGraph
|
||||
*/
|
||||
|
||||
#ifndef PLAGANIMINSTANCE_INC
|
||||
#define PLAGANIMINSTANCE_INC
|
||||
|
||||
// disable warning C4503: dcorated name length exceeded, name was truncated
|
||||
// disable warning C4786: symbol greater than 255 characters,
|
||||
#pragma warning(disable: 4503 4786)
|
||||
|
||||
#include "HeadSpin.h"
|
||||
#include <map>
|
||||
|
||||
// local
|
||||
#include "plScalarChannel.h"
|
||||
|
||||
// other
|
||||
#include "plInterp/plAnimTimeConvert.h"
|
||||
|
||||
// declarations
|
||||
class plAGChannel;
|
||||
class plAGAnim;
|
||||
class plAGMasterMod;
|
||||
class plAGChannelApplicator;
|
||||
class plOneShotCallbacks;
|
||||
|
||||
/////////////////
|
||||
// PLAGANIMINSTANCE
|
||||
/////////////////
|
||||
/** \class plAGAnimInstance
|
||||
Whenever we attach an animation to a scene object hierarchy, we
|
||||
create an activation record -- a plAGAnimInstance -- that remembers
|
||||
all the ephemeral state associated with animation
|
||||
Since animations have many channels and may involve blend operations,
|
||||
one of the primary responsibilities of this class is to keep track of
|
||||
all the animation node graphs that were created by the invocation of
|
||||
this animation.
|
||||
*/
|
||||
class plAGAnimInstance {
|
||||
public:
|
||||
/** Used for the fade commands to select what to fade. */
|
||||
enum
|
||||
{
|
||||
kFadeBlend, /// Fade the blend strength
|
||||
kFadeAmp, /// Fade the amplitude
|
||||
} FadeType;
|
||||
|
||||
/** Default constructor. */
|
||||
plAGAnimInstance();
|
||||
|
||||
/** Construct from an animation and a master modifier.
|
||||
This attaches the animation channels to the channels of
|
||||
the master modifier and creates all the bookkeeping structures
|
||||
necessary to undo it later. */
|
||||
plAGAnimInstance(plAGAnim * anim, plAGMasterMod * master, float blend, uint16_t blendPriority, bool cache, bool useAmplitude);
|
||||
|
||||
/** Destructor. Removes the animation from the scene objects it's attached to. */
|
||||
virtual ~plAGAnimInstance();
|
||||
|
||||
/** Returns the animation that this instance mediates. */
|
||||
const plAGAnim * GetAnimation() { return fAnimation; };
|
||||
|
||||
/** Returns the timeconvert object that controls the progress of time
|
||||
in this animation. */
|
||||
plAnimTimeConvert *GetTimeConvert() { return fTimeConvert; }
|
||||
|
||||
/** Set the speed of the animation. This is expressed as a fraction of
|
||||
the speed with which the animation was defined. */
|
||||
void SetSpeed(float speed) { if (fTimeConvert) fTimeConvert->SetSpeed(speed); };
|
||||
|
||||
// \{
|
||||
/**
|
||||
The current blend factor of the animation. This indicates the
|
||||
priority of this animation as opposed to other animations which
|
||||
were attached before it. Conceptually it may help to think of this
|
||||
as a layer in an stack of animations, where the blend value is the
|
||||
'opacity' of this animation relative to the ones below it.
|
||||
1.0 represents full strength.
|
||||
You may use values higher than 1.0, but this has not
|
||||
yet been seen to have any practical utility whatsoever. Note that
|
||||
even if an animation has a blend strength of 1.0, it may have another
|
||||
animation on top/downstream from it that is masking it completely. */
|
||||
float SetBlend(float blend);
|
||||
float GetBlend();
|
||||
// \}
|
||||
|
||||
/** Set the strength of the animation with respect to its 0th frame.
|
||||
This can be used to dampen the motion of the animation.
|
||||
Animations must be designed to use this: frame 0 of the animation
|
||||
must be a reasonable "default pose" as it will be blended with the
|
||||
current frame of the animation to produce the result. */
|
||||
float SetAmplitude(float amp);
|
||||
/** Get the current strength of the animation. */
|
||||
float GetAmplitude();
|
||||
|
||||
/** Make this animation loop (or not.) Note that the instance can loop
|
||||
or not without regard to whether the plAGAnim it is based on loops. */
|
||||
void SetLoop(bool status);
|
||||
|
||||
/** Interpret and respond to an animation command message. /sa plAnimCmdMsg */
|
||||
bool HandleCmd(plAnimCmdMsg *msg);
|
||||
|
||||
/** Start playback of the animation. You may optionally provide the a world
|
||||
time, which is needed for synchronizing the animation's timeline
|
||||
with the global timeline. If timeNow is -1 (the default,) the system
|
||||
time will be polled */
|
||||
void Start(double worldTimeNow = -1);
|
||||
|
||||
/** Stop playback of the animation. */
|
||||
void Stop();
|
||||
|
||||
/** Move the playback head of the animation to a specific time.
|
||||
Note that this time is in animation local time, not global time.
|
||||
The "jump" parameter specifies whether or not to fire callbacks
|
||||
that occur between the current time and the target time. */
|
||||
void SetCurrentTime(float newLocalTime, bool jump = false);
|
||||
|
||||
/** Move the playback head by the specified relative amount within
|
||||
the animation. This may cause looping. If the beginning or end
|
||||
of the animation is reached an looping is not on, the movement
|
||||
will pin.
|
||||
\param jump if true, don't look for callbacks between old time and TRACKED_NEW */
|
||||
void SeekRelative(float delta, bool jump);
|
||||
|
||||
/** Gradually fade the blend strength or amplitude of the animation.
|
||||
\param goal is the desired blend strength
|
||||
\param rate is in blend units per second
|
||||
\type is either kFadeBlend or kFadeAmp */
|
||||
void Fade(float goal, float rate, uint8_t type = kFadeBlend);
|
||||
|
||||
/** Fade the animation and detach it after the fade is complete.
|
||||
Extremely useful for situations where the controlling logic
|
||||
is terminating immediately but you want the animation to fade
|
||||
out gradually.
|
||||
\deprecated
|
||||
*/
|
||||
void FadeAndDetach(float goal, float rate);
|
||||
|
||||
/** Has the animation terminated of natural causes?
|
||||
Primarily used to see if an animation has played all the
|
||||
way to the end, but will also return true if the animation
|
||||
was stopped with a stop command */
|
||||
bool IsFinished();
|
||||
|
||||
/** Is the animation playback head positioned at the end. */
|
||||
bool IsAtEnd();
|
||||
|
||||
/** Get the name of the underlying animation. */
|
||||
plString GetName();
|
||||
|
||||
/** Remove all channels from the master mode and remove us from
|
||||
our master modifier.
|
||||
Destructs the object! */
|
||||
void Detach();
|
||||
|
||||
/** Remove all the instance's channels from the modifiers they're attached to.
|
||||
Typically called by the master mod prior to destructing the instance. */
|
||||
void DetachChannels();
|
||||
|
||||
/** Prune any unused branches out of the animation graph; add any
|
||||
newly active branches back in. */
|
||||
void Optimize();
|
||||
|
||||
/** Convert the given world time to local animation time.
|
||||
May include the effects of looping or wraparound.
|
||||
If the local time passes the end of the animation, the returned
|
||||
time will be pinned appropriately. */
|
||||
double WorldToAnimTime(double foo) { return (fTimeConvert ? fTimeConvert->WorldToAnimTimeNoUpdate(foo) : 0); };
|
||||
|
||||
/** Attach a sequence of callback messages to the animation instance.
|
||||
Messages are each associated with a specific (local) time
|
||||
in the animation and will be sent when playback passes that time. */
|
||||
void AttachCallbacks(plOneShotCallbacks *callbacks);
|
||||
|
||||
void ProcessFade(float elapsed); // process any outstanding fades
|
||||
void SearchForGlobals(); // Util function to setup SDL channels
|
||||
protected:
|
||||
/** Set up bookkeeping for a fade. */
|
||||
void ISetupFade(float goal, float rate, bool detach, uint8_t type);
|
||||
|
||||
void IRegisterDetach(const plString &channelName, plAGChannel *channel);
|
||||
|
||||
void IInitAnimTimeConvert(plAnimTimeConvert* atc, plATCAnim* anim, plAGMasterMod* master);
|
||||
|
||||
const plAGAnim * fAnimation;
|
||||
plAGMasterMod * fMaster;
|
||||
|
||||
std::map<plString, plAGChannelApplicator *, plString::less_i> fChannels;
|
||||
|
||||
typedef std::multimap<plString, plAGChannel *> plDetachMap;
|
||||
plDetachMap fManualDetachChannels;
|
||||
|
||||
std::vector<plAGChannel*> fCleanupChannels;
|
||||
std::vector<plScalarSDLChannel*> fSDLChannels;
|
||||
|
||||
plScalarConstant fBlend; // blend factor vs. previous animations
|
||||
plScalarConstant fAmplitude; // for animation scaling
|
||||
|
||||
// Each activation gets its own timeline.
|
||||
plAnimTimeConvert *fTimeConvert;
|
||||
|
||||
bool fFadeBlend; /// we are fading the blend
|
||||
float fFadeBlendGoal; /// what blend level we're trying to reach
|
||||
float fFadeBlendRate; /// how fast are we fading in blend units per second (1 blend unit = full)
|
||||
bool fFadeDetach; /// detach after fade is finished? (only used for blend fades)
|
||||
|
||||
bool fFadeAmp; /// we are fading the amplitude
|
||||
float fFadeAmpGoal; /// amplitude we're trying to reach
|
||||
float fFadeAmpRate; /// how faster we're fading in blend units per second
|
||||
|
||||
float ICalcFade(bool &fade, float curVal, float goal, float rate, float elapsed);
|
||||
|
||||
};
|
||||
|
||||
//#ifdef _DEBUG
|
||||
//#define TRACK_AG_ALLOCS // for now, automatically track AG allocations in debug
|
||||
//#endif
|
||||
#ifdef TRACK_AG_ALLOCS
|
||||
|
||||
extern plString gGlobalAnimName;
|
||||
extern plString gGlobalChannelName;
|
||||
|
||||
void RegisterAGAlloc(plAGChannel *object, const char *chanName, const char *animName, uint16_t classIndex);
|
||||
void UnRegisterAGAlloc(plAGChannel *object);
|
||||
void DumpAGAllocs();
|
||||
|
||||
#endif // TRACK_AG_ALLOCS
|
||||
|
||||
#endif // PLAGANIMINSTANCE_INC
|
178
Sources/Plasma/PubUtilLib/plAnimation/plAGApplicator.cpp
Normal file
178
Sources/Plasma/PubUtilLib/plAnimation/plAGApplicator.cpp
Normal file
@ -0,0 +1,178 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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 "plAGApplicator.h"
|
||||
#include "plAGModifier.h"
|
||||
#include "hsResMgr.h"
|
||||
|
||||
|
||||
// ctor --------
|
||||
// -----
|
||||
plAGApplicator::plAGApplicator()
|
||||
: fChannel(nil),
|
||||
fEnabled(true)
|
||||
{
|
||||
};
|
||||
|
||||
// ctor -------------------------------
|
||||
// -----
|
||||
plAGApplicator::plAGApplicator(const plString &channelName)
|
||||
: fChannel(nil),
|
||||
fEnabled(true),
|
||||
fChannelName(channelName)
|
||||
{
|
||||
};
|
||||
|
||||
plAGApplicator::~plAGApplicator()
|
||||
{
|
||||
}
|
||||
|
||||
void plAGApplicator::Apply(const plAGModifier *mod, double time, bool force)
|
||||
{
|
||||
if (fEnabled || force)
|
||||
IApply(mod, time);
|
||||
}
|
||||
|
||||
void plAGApplicator::SetChannelName(const plString &name)
|
||||
{
|
||||
if(!name.IsNull())
|
||||
fChannelName = name;
|
||||
};
|
||||
|
||||
|
||||
plString plAGApplicator::GetChannelName()
|
||||
{
|
||||
return fChannelName;
|
||||
};
|
||||
|
||||
plAGChannel *plAGApplicator::MergeChannel(plAGApplicator *app, plAGChannel *channel,
|
||||
plScalarChannel *blend, int blendPriority)
|
||||
{
|
||||
plAGChannel *result = nil;
|
||||
if(fChannel)
|
||||
{
|
||||
if (CanCombine(app))
|
||||
result = fChannel->MakeCombine(channel);
|
||||
else if (CanBlend(app))
|
||||
result = fChannel->MakeBlend(channel, blend, blendPriority);
|
||||
} else {
|
||||
result = channel;
|
||||
}
|
||||
|
||||
if (result && result != fChannel)
|
||||
SetChannel(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
plAGApplicator *plAGApplicator::CloneWithChannel(plAGChannel *channel)
|
||||
{
|
||||
plAGApplicator *app = plAGApplicator::ConvertNoRef(plFactory::Create(ClassIndex()));
|
||||
app->SetChannel(channel);
|
||||
app->Enable(fEnabled);
|
||||
app->SetChannelName(fChannelName);
|
||||
return app;
|
||||
}
|
||||
|
||||
bool plAGApplicator::CanBlend(plAGApplicator *app)
|
||||
{
|
||||
uint16_t ourClass = ClassIndex();
|
||||
uint16_t theirClass = app->ClassIndex();
|
||||
|
||||
return(ourClass == theirClass);
|
||||
|
||||
// return(this->HasBaseClass(theirClass)
|
||||
// || app->HasBaseClass(ourClass));
|
||||
}
|
||||
|
||||
|
||||
void plAGApplicator::Write(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plCreatable::Write(stream, mgr);
|
||||
|
||||
stream->WriteBool(fEnabled);
|
||||
stream->WriteSafeString(fChannelName);
|
||||
}
|
||||
|
||||
void plAGApplicator::Read(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plCreatable::Read(stream, mgr);
|
||||
|
||||
fEnabled = stream->ReadBool();
|
||||
fChannel = nil; // Whatever is reading this applicator in should know what channel to assign it
|
||||
fChannelName = stream->ReadSafeString();
|
||||
}
|
||||
|
||||
// IGETxI
|
||||
// Gain access to of our modifier's target's interfaces.
|
||||
// This is technically in violation of the principle that only modifiers can get non-const
|
||||
// reference to their target's interfaces,
|
||||
// BUT since the plAGApplicator architecture is wholly "owned" by the AGModifier, this
|
||||
// seemed the most graceful way to do it without const_cast or modifying plModifier or plSceneObject
|
||||
|
||||
// IGETAI
|
||||
plAudioInterface * plAGApplicator::IGetAI(const plAGModifier *modifier) const
|
||||
{
|
||||
return modifier->LeakAI();
|
||||
}
|
||||
|
||||
// IGETCI
|
||||
plCoordinateInterface * plAGApplicator::IGetCI(const plAGModifier* modifier) const
|
||||
{
|
||||
return modifier->LeakCI();
|
||||
}
|
||||
|
||||
// IGETDI
|
||||
plDrawInterface * plAGApplicator::IGetDI(const plAGModifier * modifier) const
|
||||
{
|
||||
return modifier->LeakDI();
|
||||
}
|
||||
|
||||
// IGETSI
|
||||
plSimulationInterface * plAGApplicator::IGetSI(const plAGModifier * modifier) const
|
||||
{
|
||||
return modifier->LeakSI();
|
||||
}
|
||||
|
||||
plObjInterface * plAGApplicator::IGetGI(const plAGModifier * modifier, uint16_t classIdx) const
|
||||
{
|
||||
return modifier->LeakGI(classIdx);
|
||||
}
|
174
Sources/Plasma/PubUtilLib/plAnimation/plAGApplicator.h
Normal file
174
Sources/Plasma/PubUtilLib/plAnimation/plAGApplicator.h
Normal file
@ -0,0 +1,174 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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==*/
|
||||
#ifndef plAGApplicator_h
|
||||
#define plAGApplicator_h
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// FORWARDS
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class plAudioInterface;
|
||||
class plCoordinateInterface;
|
||||
class plDrawInterface;
|
||||
class plSimulationInterface;
|
||||
class plObjInterface;
|
||||
class plAGModifier;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDES
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
#include "pnFactory/plCreatable.h"
|
||||
#include "plAGDefs.h"
|
||||
#include "plString.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDES
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
class plAGChannel;
|
||||
class plScalarChannel;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DEFINITIONS
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/** \class plAGApplicator
|
||||
Takes the end of a channel tree and applies it to a scene object.
|
||||
A transform applicator takes a matrix-typed-tree and applies it to
|
||||
the transform of the scene object.
|
||||
Other applicators might take floats and use them to animate alpha channels,
|
||||
etc. */
|
||||
class plAGApplicator : public plCreatable
|
||||
{
|
||||
public:
|
||||
// -- methods --
|
||||
/** Base constructor. */
|
||||
plAGApplicator();
|
||||
plAGApplicator(const plString &channelName);
|
||||
virtual ~plAGApplicator();
|
||||
|
||||
/** Return our single input channel. Applicators only ever
|
||||
have a single input channel; you can always use blend
|
||||
or combine nodes to merge channels before routing
|
||||
them into the applicator. */
|
||||
plAGChannel *GetChannel() { return fChannel; }
|
||||
|
||||
/** Set our input channel. Does not free the previous input channel. */
|
||||
void SetChannel(plAGChannel *channel) { fChannel = channel; }
|
||||
|
||||
void SetChannelName(const plString &name);
|
||||
plString GetChannelName();
|
||||
|
||||
/** Optionally suppress the action of this applicator.
|
||||
The applicator can still be forced to apply using the force
|
||||
paramater of the Apply function. */
|
||||
void Enable(bool on) { fEnabled = on; }
|
||||
|
||||
/** Make a shallow copy of the applicator. Keep the same input channel
|
||||
but do not clone the input channel. */
|
||||
virtual plAGApplicator *CloneWithChannel(plAGChannel *channel);
|
||||
|
||||
/** What animation type do we have? Used to determine whether two
|
||||
applicators are trying to animate the same thing or whether they
|
||||
can coexist peacefully. */
|
||||
virtual plAGPinType GetPinType() { return kAGPinUnknown; }
|
||||
|
||||
// Join the incoming channel (if possible) to ours
|
||||
|
||||
|
||||
/** Determine whether the given applicator can be blended to ours. If so, this
|
||||
would be effected by pulling the input channel from the other applicator,
|
||||
blending it with our input channel via a new blend node, attaching that blend
|
||||
node as our new input, and throwing the other applicator away. */
|
||||
virtual bool CanBlend(plAGApplicator *app);
|
||||
/** Combine the two applicators if possible. \sa CanBlend */
|
||||
virtual plAGChannel * MergeChannel(plAGApplicator *app, plAGChannel *channel,
|
||||
plScalarChannel *blend, int blendPriority);
|
||||
|
||||
/** \bug It makes no sense for an applicator to combine because combination always
|
||||
results in a different data type, which would require a different applicator. */
|
||||
virtual bool CanCombine(plAGApplicator *app) { return false; }
|
||||
|
||||
/** Apply our channel's data to the scene object, via the modifier.
|
||||
This is the only function that actually changes perceivable scene state. */
|
||||
void Apply(const plAGModifier *mod, double time, bool force = false); // Apply our channel's data to the modifier
|
||||
|
||||
// this is pretty much a HACK to support applicators that want to stick around when
|
||||
// their channel is gone so they can operate on the next channel that comes in
|
||||
// the RIGHT way to do this is to make applicators support the Detach() protocol just
|
||||
// like channels...
|
||||
virtual bool AutoDelete() { return true; } // should we remove it when its input channel is gone?
|
||||
|
||||
// PlOP
|
||||
CLASSNAME_REGISTER( plAGApplicator );
|
||||
GETINTERFACE_ANY( plAGApplicator, plCreatable );
|
||||
|
||||
virtual void Write(hsStream *stream, hsResMgr *mgr);
|
||||
virtual void Read(hsStream *s, hsResMgr *mgr);
|
||||
|
||||
protected:
|
||||
// -- methods --
|
||||
virtual void IApply(const plAGModifier *mod, double time) = 0;
|
||||
|
||||
// give derived classes access to the object interfaces
|
||||
plAudioInterface * IGetAI(const plAGModifier *modifier) const;
|
||||
plCoordinateInterface * IGetCI(const plAGModifier *modifier) const;
|
||||
plDrawInterface * IGetDI(const plAGModifier *modifier) const;
|
||||
plSimulationInterface * IGetSI(const plAGModifier *modifier) const;
|
||||
plObjInterface * IGetGI(const plAGModifier *modifier, uint16_t classIdx) const;
|
||||
|
||||
// Allow plAGModifier to declare IGet?? as friends
|
||||
friend class plAGModifier;
|
||||
|
||||
// -- members --
|
||||
plAGChannel *fChannel;
|
||||
bool fEnabled;
|
||||
plString fChannelName;
|
||||
};
|
||||
|
||||
#endif
|
126
Sources/Plasma/PubUtilLib/plAnimation/plAGChannel.cpp
Normal file
126
Sources/Plasma/PubUtilLib/plAnimation/plAGChannel.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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==*/
|
||||
// singular
|
||||
#include "plAGChannel.h"
|
||||
|
||||
// local
|
||||
#include "plAGModifier.h"
|
||||
|
||||
// global
|
||||
#include "HeadSpin.h"
|
||||
#include "hsResMgr.h"
|
||||
|
||||
#include "plAGAnimInstance.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// plAGChannel
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plAGChannel::plAGChannel()
|
||||
{
|
||||
#ifdef TRACK_AG_ALLOCS
|
||||
fName = gGlobalAnimName;
|
||||
RegisterAGAlloc(this, gGlobalChannelName.c_str(), gGlobalAnimName.c_str(), this->ClassIndex());
|
||||
#endif // TRACK_AG_ALLOCS
|
||||
}
|
||||
|
||||
// DTOR
|
||||
plAGChannel::~plAGChannel()
|
||||
{
|
||||
// we do not own the "fName" string, so don't delete it!
|
||||
#ifdef TRACK_AG_ALLOCS
|
||||
UnRegisterAGAlloc(this);
|
||||
#endif // TRACK_AG_ALLOCS
|
||||
}
|
||||
|
||||
// MAKECOMBINE
|
||||
plAGChannel * plAGChannel::MakeCombine(plAGChannel *channelA)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
// MAKEBLEND
|
||||
plAGChannel * plAGChannel::MakeBlend(plAGChannel *channelA, plScalarChannel *blend, int blendPriority)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
// DETACH
|
||||
// If the channel being detached is us, let our caller know to replace us
|
||||
// by return NIL.
|
||||
plAGChannel * plAGChannel::Detach(plAGChannel *channel)
|
||||
{
|
||||
if (this == channel)
|
||||
{
|
||||
return nil;
|
||||
} else {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
// OPTIMIZE
|
||||
plAGChannel * plAGChannel::Optimize(double time)
|
||||
{
|
||||
// the basic channel can't optimize...
|
||||
return this;
|
||||
}
|
||||
|
||||
// WRITE
|
||||
void plAGChannel::Write(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plCreatable::Write(stream, mgr);
|
||||
|
||||
stream->WriteSafeString(fName);
|
||||
}
|
||||
|
||||
// READ
|
||||
void plAGChannel::Read(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plCreatable::Read(stream, mgr);
|
||||
|
||||
fName = stream->ReadSafeString();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
199
Sources/Plasma/PubUtilLib/plAnimation/plAGChannel.h
Normal file
199
Sources/Plasma/PubUtilLib/plAnimation/plAGChannel.h
Normal file
@ -0,0 +1,199 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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==*/
|
||||
/** \file plAGChannel.h
|
||||
\brief The animation class for the AniGraph animation system
|
||||
WHAT'S AG STAND FOR?
|
||||
AG stands for animation graph. It's a directed acyclic graph of animation data sources and operations.
|
||||
|
||||
WHAT'S A CHANNEL?
|
||||
A channel is a stream of animation data.
|
||||
A channel is a node in an animation graph.
|
||||
Animation data can come from anything; keyframes, IK, physics, etc.
|
||||
Channels are often grouped together using blending nodes.
|
||||
Blending nodes are also a type of channel.
|
||||
See where I'm going with this?
|
||||
|
||||
HOW IS THIS DIFFERENT FROM PLCONTROLLER?
|
||||
It's very similar, but it's designed to be extremely lightweight; animation graphs are set up and torn down
|
||||
quickly and with great frequency. They are not persistent, and their only state (besides cache)
|
||||
is their interconnectedness.
|
||||
|
||||
HOW DO THEY GET SAVED?
|
||||
Their client must recreate them at read/load time. Since they are stateless, all information necessary
|
||||
to recreate them is necessarily held by the client.
|
||||
|
||||
ARE THEY REFERENCE COUNTED?
|
||||
No. The entire graph is owned by the creator.
|
||||
Deleting the top node of a graph deletes the entire graph.
|
||||
If we decide we want to share subgraphs, we'll add reference counting -- easy since cycles are illegal
|
||||
|
||||
HOW DO THEY INTEGRATE WITH PLCONTROLLERS?
|
||||
Once we decide the animation graph approach is workable and effective, we'll combine the plController
|
||||
concept with the plAGChannel concept.
|
||||
Until then, there will be a handful of channel types that adapt controllers into animation graphs.
|
||||
|
||||
WHAT DOES "COMBINE" MEAN?
|
||||
Merging more than one types of animation data into a single output that preserves the value
|
||||
of both.
|
||||
|
||||
WHAT DOES "BLEND" MEAN?
|
||||
Merging two similar types of animation data using a weight to "fade" from one to the other
|
||||
|
||||
WHAT IS ZEROSTATE?
|
||||
This is a static channel that always returns the value at time zero. It is used as a reference for animation
|
||||
scaling (amplitude).
|
||||
|
||||
WHAT'S AN APPLICATOR?
|
||||
In order to cut down on the number of derived channel classes for different Value() and Apply() behaviors,
|
||||
applicators were created. At the end of each graph is an applicator, which specifies what should be done
|
||||
with the result of a call to Value().
|
||||
|
||||
\ingroup Avatar
|
||||
\ingroup AniGraph
|
||||
*/
|
||||
|
||||
#ifndef PLAGCHANNEL_H
|
||||
#define PLAGCHANNEL_H
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDES
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "pnFactory/plCreatable.h"
|
||||
#include "plString.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// FORWARDS
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class plAGModifier;
|
||||
class plAnimTimeConvert;
|
||||
class plAGChannel;
|
||||
class plScalarChannel;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DEFINITIONS
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** \class plAGChannel
|
||||
An object that emits data of a specific type. Fundamental building
|
||||
block of the animation graph. */
|
||||
class plAGChannel : public plCreatable
|
||||
{
|
||||
public:
|
||||
|
||||
// -- methods --
|
||||
/** Default constructor for the base class. */
|
||||
plAGChannel();
|
||||
|
||||
/** Free an allocated name. Does not release any upstream nodes. */
|
||||
virtual ~plAGChannel();
|
||||
|
||||
// AG PROTOCOL
|
||||
/** Combine the given channel with this channel, allocating and returning
|
||||
a new node which does the combination. It's up to the caller to
|
||||
manage the lifetime of the new node. */
|
||||
virtual plAGChannel * MakeCombine(plAGChannel * channelB);
|
||||
|
||||
/** Blend the given channel with this channel, using a third channel (which
|
||||
must output a float/scalar value) to crossfade between the two.
|
||||
As the blendChannel varies, the blend will vary. */
|
||||
virtual plAGChannel * MakeBlend(plAGChannel * channelB, plScalarChannel * blendChannel, int blendPriority);
|
||||
|
||||
/** Create a "static clone" of this channel which always returns this channel's
|
||||
value at time zero. */
|
||||
virtual plAGChannel * MakeZeroState() = 0;
|
||||
|
||||
/** If we're potentially sharing this channel with other plAGMasterMods, we'll
|
||||
want to insert a channel in the graph for cache info. This function returns
|
||||
either the cache channel (replacing us) or ourself. */
|
||||
virtual plAGChannel * MakeCacheChannel(plAnimTimeConvert *atc) { return this; }
|
||||
|
||||
/** Create a new channel which converts global time to local time
|
||||
and attach it downstream from this channel. This allows you to
|
||||
convert an animation from one timespace to another - critical for
|
||||
blending.
|
||||
local-time-animation <-- timescale <-- world-time-animation */
|
||||
virtual plAGChannel * MakeTimeScale(plScalarChannel *timeSource) = 0;
|
||||
|
||||
/** Is the animation moving at the given world time? Takes into account
|
||||
start/stop messages that haven't been applied yet, ease curves, etc. */
|
||||
virtual bool IsStoppedAt(double wSecs) { return true; }
|
||||
|
||||
/** Detach the given channel from our graph. If this is the channel in
|
||||
question, returns any upstream channels so they can be reattached.
|
||||
If this is not the channel in question, passes the request upstream
|
||||
and does any reattachment necessary. */
|
||||
virtual plAGChannel * Detach(plAGChannel * channel);
|
||||
|
||||
/** Return the optimized version of this channel. May be a completely
|
||||
different channel; will collapse out inactive subgraphs. */
|
||||
virtual plAGChannel * Optimize(double time);
|
||||
|
||||
// \{
|
||||
/** The name of the channel is used to dynamically attach to sub-parts of an
|
||||
object. */
|
||||
virtual plString GetName() { return fName; };
|
||||
virtual void SetName(const plString & name) { fName = name; };
|
||||
// \}
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
// rtti
|
||||
CLASSNAME_REGISTER( plAGChannel );
|
||||
GETINTERFACE_ANY( plAGChannel, plCreatable );
|
||||
|
||||
// persistence
|
||||
virtual void Write(hsStream *stream, hsResMgr *mgr);
|
||||
virtual void Read(hsStream *s, hsResMgr *mgr);
|
||||
|
||||
protected:
|
||||
plString fName;
|
||||
|
||||
};
|
||||
|
||||
#endif //PLAGCHANNEL_H
|
63
Sources/Plasma/PubUtilLib/plAnimation/plAGDefs.h
Normal file
63
Sources/Plasma/PubUtilLib/plAnimation/plAGDefs.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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==*/
|
||||
#ifndef plAGDefs_h
|
||||
#define plAGDefs_h
|
||||
|
||||
/** \enum PinType
|
||||
Tells us what category of animation this channel affects.
|
||||
Primarly used to determine if two channels are competing,
|
||||
which you can't tell strictly from the type of data the
|
||||
channel handles. */
|
||||
enum plAGPinType
|
||||
{
|
||||
kAGPinUnknown, // this applicator hasn't decided its pin type
|
||||
kAGPinTransform, // this applicator munches the entire transform
|
||||
kNumPinTypes
|
||||
};
|
||||
|
||||
#define kAGMaxBlendPriority 0x0fffffff
|
||||
#define kAGMinBlendPriority 0x00000000
|
||||
#define kAGMedBlendPriority 0x0000ffff
|
||||
|
||||
|
||||
#endif
|
||||
|
823
Sources/Plasma/PubUtilLib/plAnimation/plAGMasterMod.cpp
Normal file
823
Sources/Plasma/PubUtilLib/plAnimation/plAGMasterMod.cpp
Normal file
@ -0,0 +1,823 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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==*/
|
||||
// singular
|
||||
#include "plAGMasterMod.h"
|
||||
|
||||
// local
|
||||
#include "plAGAnim.h"
|
||||
#include "plAGAnimInstance.h"
|
||||
#include "plAGModifier.h"
|
||||
// #include "plAvatarAnim.h"
|
||||
#include "plModifier/plAGMasterSDLModifier.h"
|
||||
#include "plMatrixChannel.h"
|
||||
|
||||
// global
|
||||
#include "hsResMgr.h"
|
||||
#include "plgDispatch.h"
|
||||
|
||||
// other
|
||||
#include "plInterp/plAnimEaseTypes.h"
|
||||
#include "plMessage/plAnimCmdMsg.h"
|
||||
#include "pnMessage/plSDLModifierMsg.h"
|
||||
#include "pnMessage/plSDLNotificationMsg.h"
|
||||
#include "pnMessage/plTimeMsg.h"
|
||||
#include "pnSceneObject/plSceneObject.h"
|
||||
#include "pnSceneObject/plCoordinateInterface.h"
|
||||
|
||||
////////////////
|
||||
// PLAGMASTERMOD
|
||||
////////////////
|
||||
// Coordinates the activities of a bunch of plAGModifiers
|
||||
// std::map<char *, plAGMasterMod *, stringISorter> plAGMasterMod::fInstances;
|
||||
|
||||
// CTOR
|
||||
plAGMasterMod::plAGMasterMod()
|
||||
: fTarget(nil),
|
||||
fNeedEval(false),
|
||||
fFirstEval(true),
|
||||
fAGMasterSDLMod(nil),
|
||||
fNeedCompile(false),
|
||||
fIsGrouped(false),
|
||||
fIsGroupMaster(false),
|
||||
fMsgForwarder(nil)
|
||||
{
|
||||
}
|
||||
|
||||
// DTOR
|
||||
plAGMasterMod::~plAGMasterMod()
|
||||
{
|
||||
}
|
||||
|
||||
void plAGMasterMod::Write(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plModifier::Write(stream, mgr);
|
||||
|
||||
int length = 0;
|
||||
stream->WriteLE32(length); // backwards compatability. Nuke on next format change.
|
||||
stream->WriteLE32(fPrivateAnims.size());
|
||||
int i;
|
||||
for (i = 0; i < fPrivateAnims.size(); i++)
|
||||
{
|
||||
mgr->WriteKey(stream, fPrivateAnims[i]->GetKey());
|
||||
}
|
||||
stream->WriteBool(fIsGrouped);
|
||||
stream->WriteBool(fIsGroupMaster);
|
||||
if (fIsGroupMaster)
|
||||
mgr->WriteKey(stream, fMsgForwarder->GetKey());
|
||||
|
||||
// maybe later... WriteCachedMessages(stream, mgr);
|
||||
}
|
||||
|
||||
void plAGMasterMod::Read(hsStream * stream, hsResMgr *mgr)
|
||||
{
|
||||
plModifier::Read(stream, mgr);
|
||||
|
||||
//////////////////////////////////////////
|
||||
int nameLength = stream->ReadLE32(); // Unused. Nuke next format change.
|
||||
char *junk = new char[nameLength+1]; //
|
||||
stream->Read(nameLength, junk); //
|
||||
junk[nameLength] = 0; //
|
||||
delete [] junk; //
|
||||
//////////////////////////////////////////
|
||||
|
||||
int numPrivateAnims = stream->ReadLE32();
|
||||
fPrivateAnims.reserve(numPrivateAnims); // pre-allocate for performance
|
||||
int i;
|
||||
for (i = 0; i < numPrivateAnims; i++)
|
||||
{
|
||||
plGenRefMsg* msg = new plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kPrivateAnim);
|
||||
mgr->ReadKeyNotifyMe(stream, msg, plRefFlags::kActiveRef);
|
||||
}
|
||||
fIsGrouped = stream->ReadBool();
|
||||
fIsGroupMaster = stream->ReadBool();
|
||||
if (fIsGroupMaster)
|
||||
{
|
||||
plGenRefMsg* msg = new plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, 0);
|
||||
mgr->ReadKeyNotifyMe(stream, msg, plRefFlags::kActiveRef);
|
||||
}
|
||||
|
||||
// maybe later... ReadCachedMessages(stream, mgr);
|
||||
}
|
||||
|
||||
// ADDTARGET
|
||||
// Collect all the plAGModifiers from our children and attach private anims.
|
||||
void plAGMasterMod::AddTarget(plSceneObject * object)
|
||||
{
|
||||
plSynchEnabler p(false); // turn off dirty tracking while in this function
|
||||
|
||||
fTarget = object;
|
||||
int autoIdx = -1;
|
||||
int initialIdx = -1;
|
||||
int timeIdx = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < fPrivateAnims.size(); i++)
|
||||
{
|
||||
plATCAnim *atcAnim = plATCAnim::ConvertNoRef(fPrivateAnims[i]);
|
||||
if (!atcAnim)
|
||||
continue;
|
||||
|
||||
if (atcAnim->GetAutoStart())
|
||||
autoIdx = i;
|
||||
if (atcAnim->GetInitial() != -1)
|
||||
initialIdx = i;
|
||||
if (atcAnim->GetStart() < fPrivateAnims[timeIdx]->GetStart())
|
||||
timeIdx = i;
|
||||
}
|
||||
|
||||
int masterIdx;
|
||||
if (autoIdx != -1)
|
||||
masterIdx = autoIdx; // If something autostarts, it wins.
|
||||
else if (initialIdx != -1)
|
||||
masterIdx = initialIdx; // Otherwise, the fellow with the @initial point wins
|
||||
else
|
||||
masterIdx = timeIdx; // Default case: the earliest anim wins
|
||||
|
||||
for (i = 0; i < fPrivateAnims.size(); i++)
|
||||
{
|
||||
AttachAnimationBlended(fPrivateAnims[i], i == masterIdx ? 1.f : 0.f);
|
||||
}
|
||||
|
||||
// Force one eval after we init
|
||||
plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey());
|
||||
|
||||
if (!fIsGrouped || fIsGroupMaster)
|
||||
{
|
||||
// add sdl modifier
|
||||
delete fAGMasterSDLMod;
|
||||
fAGMasterSDLMod = new plAGMasterSDLModifier;
|
||||
object->AddModifier(fAGMasterSDLMod);
|
||||
}
|
||||
}
|
||||
|
||||
void plAGMasterMod::RemoveTarget(plSceneObject* o)
|
||||
{
|
||||
hsAssert(o == fTarget, "Removing target I don't have");
|
||||
|
||||
DetachAllAnimations();
|
||||
|
||||
// remove sdl modifier
|
||||
if (o)
|
||||
{
|
||||
if (fAGMasterSDLMod)
|
||||
o->RemoveModifier(fAGMasterSDLMod);
|
||||
}
|
||||
delete fAGMasterSDLMod;
|
||||
fAGMasterSDLMod=nil;
|
||||
|
||||
fTarget = nil;
|
||||
}
|
||||
|
||||
#include "plProfile.h"
|
||||
|
||||
plProfile_CreateTimer("ApplyAnimation", "Animation", ApplyAnimation);
|
||||
plProfile_CreateTimer(" AffineValue", "Animation", AffineValue);
|
||||
plProfile_CreateTimer(" AffineInterp", "Animation", AffineInterp);
|
||||
plProfile_CreateTimer(" AffineBlend", "Animation", AffineBlend);
|
||||
plProfile_CreateTimer(" AffineCompose", "Animation", AffineCompose);
|
||||
plProfile_CreateTimer(" AffineApplicator", "Animation", MatrixApplicator);
|
||||
plProfile_CreateTimer("AnimatingPhysicals", "Animation", AnimatingPhysicals);
|
||||
plProfile_CreateTimer("StoppedAnimPhysicals", "Animation", StoppedAnimPhysicals);
|
||||
|
||||
// IEVAL
|
||||
bool plAGMasterMod::IEval(double secs, float del, uint32_t dirty)
|
||||
{
|
||||
if (fFirstEval)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < fAnimInstances.size(); i++)
|
||||
fAnimInstances[i]->SearchForGlobals();
|
||||
|
||||
fFirstEval = false;
|
||||
}
|
||||
ApplyAnimations(secs, del);
|
||||
|
||||
// We might get registered for just a single eval. If we don't need to eval anymore, unregister
|
||||
if (!fNeedEval)
|
||||
plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey());
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// APPLYANIMATIONS
|
||||
void plAGMasterMod::ApplyAnimations(double time, float elapsed)
|
||||
{
|
||||
plProfile_BeginLap(ApplyAnimation, this->GetKey()->GetUoid().GetObjectName().c_str());
|
||||
|
||||
// update any fades
|
||||
for (int i = 0; i < fAnimInstances.size(); i++)
|
||||
{
|
||||
fAnimInstances[i]->ProcessFade(elapsed);
|
||||
}
|
||||
|
||||
AdvanceAnimsToTime(time);
|
||||
|
||||
plProfile_EndLap(ApplyAnimation,this->GetKey()->GetUoid().GetObjectName().c_str());
|
||||
}
|
||||
|
||||
void plAGMasterMod::AdvanceAnimsToTime(double time)
|
||||
{
|
||||
if(fNeedCompile)
|
||||
Compile(time);
|
||||
|
||||
for(plChannelModMap::iterator j = fChannelMods.begin(); j != fChannelMods.end(); j++)
|
||||
{
|
||||
plAGModifier *mod = (*j).second;
|
||||
mod->Apply(time);
|
||||
}
|
||||
}
|
||||
|
||||
void plAGMasterMod::SetNeedCompile(bool needCompile)
|
||||
{
|
||||
fNeedCompile = true;
|
||||
}
|
||||
|
||||
void plAGMasterMod::Compile(double time)
|
||||
{
|
||||
plChannelModMap::iterator end = fChannelMods.end();
|
||||
fNeedCompile = false;
|
||||
|
||||
for(plChannelModMap::iterator j = fChannelMods.begin(); j != end; j++)
|
||||
{
|
||||
plAGModifier *mod = (*j).second;
|
||||
plAGApplicator *app = mod->GetApplicator(kAGPinTransform);
|
||||
|
||||
if(app) {
|
||||
plAGChannel *channel = app->GetChannel();
|
||||
if(channel)
|
||||
{
|
||||
plMatrixChannel *topChannel = plMatrixChannel::ConvertNoRef(channel);
|
||||
if(topChannel)
|
||||
topChannel->Optimize(time);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void plAGMasterMod::DumpAniGraph(const char *justThisChannel, bool optimized, double time)
|
||||
{
|
||||
plChannelModMap::iterator end = fChannelMods.end();
|
||||
fNeedCompile = false;
|
||||
|
||||
for(plChannelModMap::iterator j = fChannelMods.begin(); j != end; j++)
|
||||
{
|
||||
plAGModifier *mod = (*j).second;
|
||||
if(!justThisChannel || mod->GetChannelName().Compare(justThisChannel, plString::kCaseInsensitive) == 0)
|
||||
{
|
||||
plAGApplicator *app = mod->GetApplicator(kAGPinTransform);
|
||||
|
||||
if(app) {
|
||||
plAGChannel *channel = app->GetChannel();
|
||||
if(channel)
|
||||
{
|
||||
plMatrixChannel *topChannel = plMatrixChannel::ConvertNoRef(channel);
|
||||
if(topChannel)
|
||||
{
|
||||
hsStatusMessageF("AGModifier: <%s>", mod->GetChannelName().c_str());
|
||||
topChannel->Dump(1, optimized, time);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(justThisChannel)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GETCHANNELMOD(name)
|
||||
// Get the modifier that controls the channel with the given name
|
||||
plAGModifier * plAGMasterMod::GetChannelMod(const plString & name, bool dontCache ) const
|
||||
{
|
||||
plAGModifier * result = nil;
|
||||
std::map<plString, plAGModifier *>::const_iterator i = fChannelMods.find(name);
|
||||
|
||||
if (i != fChannelMods.end()) {
|
||||
result = (*i).second;
|
||||
} else {
|
||||
plSceneObject *SO = GetTarget(0);
|
||||
if(SO) {
|
||||
result = IFindChannelMod(SO, name);
|
||||
if(result && !dontCache) {
|
||||
ICacheChannelMod(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// CACHECHANNELMOD
|
||||
plAGModifier * plAGMasterMod::ICacheChannelMod(plAGModifier *mod) const
|
||||
{
|
||||
plGenRefMsg* msg = new plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, 0);
|
||||
hsgResMgr::ResMgr()->SendRef(mod, msg, plRefFlags::kActiveRef);
|
||||
|
||||
return mod;
|
||||
}
|
||||
|
||||
// IFINDAGMOD (sceneObject)
|
||||
// See if there's an ag modifier on this sceneobject.
|
||||
// Doesn't check for multiples; just returns the first one.
|
||||
plAGModifier * plAGMasterMod::IFindChannelMod(const plSceneObject *SO, const plString &name) const
|
||||
{
|
||||
const plCoordinateInterface * CI = SO->GetCoordinateInterface();
|
||||
|
||||
const plAGModifier * constMod = static_cast<const plAGModifier *>(FindModifierByClass(SO, plAGModifier::Index()));
|
||||
plAGModifier * mod = const_cast<plAGModifier *>(constMod);
|
||||
|
||||
if(mod)
|
||||
{
|
||||
plString modName = mod->GetChannelName();
|
||||
if(modName.Compare(name, plString::kCaseInsensitive) == 0)
|
||||
return mod;
|
||||
}
|
||||
|
||||
if(CI)
|
||||
{
|
||||
int childCount = CI->GetNumChildren();
|
||||
for (int i = 0; i < childCount; i++)
|
||||
{
|
||||
const plSceneObject * subChild = CI->GetChild(i)->GetOwner();
|
||||
plAGModifier * mod = IFindChannelMod(subChild, name);
|
||||
|
||||
if(mod)
|
||||
return mod;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
// ATTACHANIMATIONBLENDED(anim, blend)
|
||||
plAGAnimInstance * plAGMasterMod::AttachAnimationBlended(plAGAnim *anim,
|
||||
float blendFactor /* = 0 */,
|
||||
uint16_t blendPriority /* plAGMedBlendPriority */,
|
||||
bool cache /* = false */)
|
||||
{
|
||||
plAGAnimInstance *instance = nil;
|
||||
plAnimVector::iterator i;
|
||||
if(anim)
|
||||
{
|
||||
fNeedCompile = true; // need to recompile the graph since we're editing it...
|
||||
for (i = fPrivateAnims.begin(); i != fPrivateAnims.end(); i++)
|
||||
{
|
||||
if (*i == anim)
|
||||
break;
|
||||
}
|
||||
if (i == fPrivateAnims.end()) // Didn't find it. Ref it!
|
||||
{
|
||||
plGenRefMsg* msg = new plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kPublicAnim);
|
||||
hsgResMgr::ResMgr()->SendRef(anim, msg, plRefFlags::kActiveRef);
|
||||
}
|
||||
instance = new plAGAnimInstance(anim, this, blendFactor, blendPriority, cache, false);
|
||||
fAnimInstances.push_back(instance);
|
||||
|
||||
plATCAnim *atcAnim = plATCAnim::ConvertNoRef(anim);
|
||||
if (atcAnim)
|
||||
{
|
||||
fATCAnimInstances.push_back(instance);
|
||||
ISetupMarkerCallbacks(atcAnim, instance->GetTimeConvert());
|
||||
}
|
||||
IRegForEval(HasRunningAnims());
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
// ATTACHANIMATIONBLENDED(name, blend)
|
||||
plAGAnimInstance * plAGMasterMod::AttachAnimationBlended(const plString &name, float blendFactor /* = 0 */, uint16_t blendPriority, bool cache /* = false */)
|
||||
{
|
||||
plAGAnimInstance *instance = nil;
|
||||
plAGAnim *anim = plAGAnim::FindAnim(name);
|
||||
|
||||
if(anim)
|
||||
{
|
||||
instance = AttachAnimationBlended(anim, blendFactor, blendPriority, cache);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
void plAGMasterMod::PlaySimpleAnim(const plString &name)
|
||||
{
|
||||
plATCAnim *anim = plATCAnim::ConvertNoRef(plAGAnim::FindAnim(name));
|
||||
plAGAnimInstance *instance = nil;
|
||||
if (anim)
|
||||
{
|
||||
if (FindAnimInstance(name))
|
||||
return;
|
||||
|
||||
instance = AttachAnimationBlended(anim, 1.f, (uint16_t)kAGMaxBlendPriority, false);
|
||||
}
|
||||
|
||||
if (instance)
|
||||
{
|
||||
instance->SetLoop(false);
|
||||
instance->Start();
|
||||
|
||||
plAGDetachCallbackMsg *msg = new plAGDetachCallbackMsg(GetKey(), kStop);
|
||||
msg->SetAnimName(name);
|
||||
instance->GetTimeConvert()->AddCallback(msg);
|
||||
hsRefCnt_SafeUnRef(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// FINDANIMINSTANCE
|
||||
// Look for an animation instance of the given name on the modifier.
|
||||
// If we need this to be fast, should make it a map rather than a vector
|
||||
plAGAnimInstance * plAGMasterMod::FindAnimInstance(const plString &name)
|
||||
{
|
||||
plAGAnimInstance *result = nil;
|
||||
|
||||
if (!name.IsNull())
|
||||
{
|
||||
for (int i = 0; i < fAnimInstances.size(); i++)
|
||||
{
|
||||
plAGAnimInstance *act = fAnimInstances[i];
|
||||
plString eachName = act->GetName();
|
||||
|
||||
if( eachName.Compare(name, plString::kCaseInsensitive) == 0)
|
||||
{
|
||||
result = act;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// FINDORATTACHINSTANCE
|
||||
plAGAnimInstance * plAGMasterMod::FindOrAttachInstance(const plString &name, float blendFactor)
|
||||
{
|
||||
plAGAnimInstance *result = FindAnimInstance(name);
|
||||
if(result)
|
||||
{
|
||||
// if it's already attached, we need to set the blend
|
||||
result->SetBlend(blendFactor);
|
||||
} else {
|
||||
result = AttachAnimationBlended(name, blendFactor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// GETANIMINSTANCE
|
||||
plAGAnimInstance * plAGMasterMod::GetAnimInstance(int i)
|
||||
{
|
||||
return fAnimInstances[i];
|
||||
}
|
||||
|
||||
// GETNUMANIMATIONS
|
||||
int plAGMasterMod::GetNumAnimations()
|
||||
{
|
||||
return fAnimInstances.size();
|
||||
}
|
||||
|
||||
// GETNUMPRIVATEANIMATIONS
|
||||
int plAGMasterMod::GetNumPrivateAnimations()
|
||||
{
|
||||
return fPrivateAnims.size();
|
||||
}
|
||||
|
||||
int plAGMasterMod::GetNumATCAnimations()
|
||||
{
|
||||
return fATCAnimInstances.size();
|
||||
}
|
||||
|
||||
plAGAnimInstance *plAGMasterMod::GetATCAnimInstance(int i)
|
||||
{
|
||||
return fATCAnimInstances[i];
|
||||
}
|
||||
|
||||
void plAGMasterMod::DetachAllAnimations()
|
||||
{
|
||||
int nInstances = fAnimInstances.size();
|
||||
|
||||
for (int i = nInstances - 1; i >= 0; i--)
|
||||
{
|
||||
plAGAnimInstance * instance = fAnimInstances[i];
|
||||
if(instance)
|
||||
{
|
||||
DetachAnimation(instance);
|
||||
// delete instance;
|
||||
}
|
||||
}
|
||||
fAnimInstances.clear();
|
||||
fPrivateAnims.clear();
|
||||
fATCAnimInstances.clear();
|
||||
}
|
||||
|
||||
// DETACHANIMATION(plAGAnimInstance *)
|
||||
void plAGMasterMod::DetachAnimation(plAGAnimInstance *anim)
|
||||
{
|
||||
plInstanceVector::iterator i;
|
||||
plAnimVector::iterator j;
|
||||
|
||||
fNeedCompile = true; // need to recompile the graph since we're editing it...
|
||||
|
||||
for ( i = fAnimInstances.begin(); i != fAnimInstances.end(); i++)
|
||||
{
|
||||
plAGAnimInstance *instance = *i;
|
||||
|
||||
if(instance == anim)
|
||||
{
|
||||
// DetachAnimation(instance);
|
||||
instance->DetachChannels();
|
||||
|
||||
// Need to release it if it's not a private anim
|
||||
const plAGAnim *agAnim = instance->GetAnimation();
|
||||
for (j = fPrivateAnims.begin(); j != fPrivateAnims.end(); j++)
|
||||
{
|
||||
if (*j == agAnim)
|
||||
break;
|
||||
}
|
||||
if (j == fPrivateAnims.end()) // We didn't find it
|
||||
GetKey()->Release(agAnim->GetKey());
|
||||
|
||||
delete instance;
|
||||
i = fAnimInstances.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for ( i = fATCAnimInstances.begin(); i != fATCAnimInstances.end(); i++)
|
||||
{
|
||||
plAGAnimInstance *instance = *i;
|
||||
|
||||
if(instance == anim)
|
||||
{
|
||||
i = fATCAnimInstances.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DETACHANIMATION(name)
|
||||
void plAGMasterMod::DetachAnimation(const plString &name)
|
||||
{
|
||||
plAGAnimInstance *anim = FindAnimInstance(name);
|
||||
if(anim) {
|
||||
DetachAnimation(anim);
|
||||
}
|
||||
}
|
||||
|
||||
void plAGMasterMod::DumpCurrentAnims(const char *header)
|
||||
{
|
||||
if(header)
|
||||
hsStatusMessageF("Dumping Armature Anim Stack: %s", header);
|
||||
int nAnims = fAnimInstances.size();
|
||||
for(int i = nAnims - 1; i >= 0; i--)
|
||||
{
|
||||
plAGAnimInstance *inst = fAnimInstances[i];
|
||||
plString name = inst->GetName();
|
||||
float blend = inst->GetBlend();
|
||||
|
||||
hsStatusMessageF("%d: %s with blend of %f\n", i, name.c_str(), blend);
|
||||
}
|
||||
}
|
||||
|
||||
// MSGRECEIVE
|
||||
// receive trigger messages
|
||||
bool plAGMasterMod::MsgReceive(plMessage* msg)
|
||||
{
|
||||
plSDLNotificationMsg* nMsg = plSDLNotificationMsg::ConvertNoRef(msg);
|
||||
if (nMsg)
|
||||
{
|
||||
// Force a single eval
|
||||
plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey());
|
||||
return true;
|
||||
}
|
||||
|
||||
plAnimCmdMsg* cmdMsg = plAnimCmdMsg::ConvertNoRef(msg);
|
||||
if (cmdMsg)
|
||||
{
|
||||
plString targetName = cmdMsg->GetAnimName();
|
||||
|
||||
if (targetName.IsNull())
|
||||
targetName = ENTIRE_ANIMATION_NAME;
|
||||
|
||||
plAGAnimInstance *inst = FindAnimInstance(targetName);
|
||||
if (inst != nil)
|
||||
{
|
||||
if (cmdMsg->CmdChangesAnimTime())
|
||||
{
|
||||
for (int i = 0; i < GetNumAnimations(); i++)
|
||||
{
|
||||
plAGAnimInstance *currInst = GetAnimInstance(i);
|
||||
if (currInst != inst && currInst->GetAnimation()->SharesPinsWith(inst->GetAnimation()))
|
||||
currInst->SetBlend(0);
|
||||
}
|
||||
inst->SetBlend(1);
|
||||
}
|
||||
|
||||
inst->HandleCmd(cmdMsg);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
plAGCmdMsg* agMsg = plAGCmdMsg::ConvertNoRef(msg);
|
||||
if (agMsg)
|
||||
{
|
||||
if (agMsg->Cmd(plAGCmdMsg::kSetAnimTime))
|
||||
{
|
||||
for (int i = 0; i < fAnimInstances.size(); i++)
|
||||
{
|
||||
plAGAnimInstance *inst = fAnimInstances[i];
|
||||
inst->SetCurrentTime(agMsg->fAnimTime, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
plAGAnimInstance *inst = FindAnimInstance(agMsg->GetAnimName());
|
||||
if (inst != nil)
|
||||
{
|
||||
if (agMsg->Cmd(plAGCmdMsg::kSetBlend))
|
||||
inst->Fade(agMsg->fBlend, agMsg->fBlendRate, plAGAnimInstance::kFadeBlend);
|
||||
if (agMsg->Cmd(plAGCmdMsg::kSetAmp))
|
||||
inst->Fade(agMsg->fAmp, agMsg->fAmpRate, plAGAnimInstance::kFadeAmp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
plAGInstanceCallbackMsg *agicMsg = plAGInstanceCallbackMsg::ConvertNoRef(msg);
|
||||
if (agicMsg)
|
||||
{
|
||||
if (agicMsg->fEvent == kStart)
|
||||
{
|
||||
IRegForEval(true);
|
||||
}
|
||||
else if (agicMsg->fEvent == kStop)
|
||||
{
|
||||
if (!HasRunningAnims())
|
||||
IRegForEval(false);
|
||||
}
|
||||
else // Just force a single eval
|
||||
{
|
||||
plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
plAGDetachCallbackMsg *detachMsg = plAGDetachCallbackMsg::ConvertNoRef(msg);
|
||||
if (detachMsg)
|
||||
{
|
||||
DetachAnimation(detachMsg->GetAnimName());
|
||||
}
|
||||
|
||||
plGenRefMsg *genRefMsg = plGenRefMsg::ConvertNoRef(msg);
|
||||
if (genRefMsg)
|
||||
{
|
||||
plAGAnim *anim = plAGAnim::ConvertNoRef(genRefMsg->GetRef());
|
||||
if (anim)
|
||||
{
|
||||
if (genRefMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest))
|
||||
{
|
||||
if (genRefMsg->fType == kPrivateAnim)
|
||||
fPrivateAnims.push_back(anim);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (genRefMsg->fType == kPrivateAnim)
|
||||
{
|
||||
plAnimVector::iterator i = fPrivateAnims.begin();
|
||||
for ( ; i != fPrivateAnims.end(); i++)
|
||||
{
|
||||
plAGAnim *currAnim = *i;
|
||||
|
||||
if(currAnim == anim)
|
||||
{
|
||||
i = fPrivateAnims.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
plAGModifier *agmod = plAGModifier::ConvertNoRef(genRefMsg->GetRef());
|
||||
if (agmod)
|
||||
{
|
||||
if (genRefMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest))
|
||||
fChannelMods[agmod->GetChannelName()] = agmod;
|
||||
else
|
||||
fChannelMods.erase(agmod->GetChannelName());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
plMsgForwarder *msgfwd = plMsgForwarder::ConvertNoRef(genRefMsg->GetRef());
|
||||
if (msgfwd)
|
||||
{
|
||||
if (genRefMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest))
|
||||
fMsgForwarder = msgfwd;
|
||||
else
|
||||
fMsgForwarder = nil;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
plRefMsg* refMsg = plRefMsg::ConvertNoRef(msg);
|
||||
if (refMsg)
|
||||
{
|
||||
if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace) )
|
||||
AddTarget(plSceneObject::ConvertNoRef(refMsg->GetRef()));
|
||||
else
|
||||
RemoveTarget(plSceneObject::ConvertNoRef(refMsg->GetRef()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return plModifier::MsgReceive(msg);
|
||||
}
|
||||
|
||||
void plAGMasterMod::IRegForEval(bool val)
|
||||
{
|
||||
if (fNeedEval == val)
|
||||
return;
|
||||
|
||||
fNeedEval = val;
|
||||
if (val)
|
||||
plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey());
|
||||
else
|
||||
plgDispatch::Dispatch()->UnRegisterForExactType(plEvalMsg::Index(), GetKey());
|
||||
}
|
||||
|
||||
bool plAGMasterMod::HasRunningAnims()
|
||||
{
|
||||
int i;
|
||||
bool needEval = false;
|
||||
for (i = 0; i < fAnimInstances.size(); i++)
|
||||
{
|
||||
if (!fAnimInstances[i]->IsFinished())
|
||||
{
|
||||
needEval = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return needEval;
|
||||
}
|
||||
|
||||
//
|
||||
// Send SDL sendState msg to object's plAGMasterSDLModifier
|
||||
//
|
||||
bool plAGMasterMod::DirtySynchState(const plString& SDLStateName, uint32_t synchFlags)
|
||||
{
|
||||
if(GetNumTargets() > 0 && (!fIsGrouped || fIsGroupMaster))
|
||||
{
|
||||
plSceneObject *sObj = GetTarget(0);
|
||||
if(sObj)
|
||||
return sObj->DirtySynchState(SDLStateName, synchFlags);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void plAGMasterMod::SetIsGroupMaster(bool master, plMsgForwarder* msgForwarder)
|
||||
{
|
||||
fIsGroupMaster = master;
|
||||
fMsgForwarder = msgForwarder;
|
||||
}
|
||||
|
||||
void plAGMasterMod::SetIsGrouped(bool grouped)
|
||||
{
|
||||
fIsGrouped = true;
|
||||
}
|
263
Sources/Plasma/PubUtilLib/plAnimation/plAGMasterMod.h
Normal file
263
Sources/Plasma/PubUtilLib/plAnimation/plAGMasterMod.h
Normal file
@ -0,0 +1,263 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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==*/
|
||||
/** \file plAGMasterMod.h
|
||||
\brief The animation class for the AniGraph animation system
|
||||
|
||||
\ingroup Avatar
|
||||
\ingroup AniGraph
|
||||
*/
|
||||
#ifndef PLAGMASTERMOD_INC
|
||||
#define PLAGMASTERMOD_INC
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDES
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
#include "pnModifier/plModifier.h"
|
||||
#include "plAGChannel.h"
|
||||
#include "plAGDefs.h"
|
||||
#include "pnKeyedObject/plMsgForwarder.h"
|
||||
|
||||
|
||||
class plAGModifier;
|
||||
class plAGAnimInstance;
|
||||
class plAGAnim;
|
||||
class plATCAnim;
|
||||
class plAGMasterSDLModifier;
|
||||
|
||||
////////////////
|
||||
//
|
||||
// PLAGMASTERMOD
|
||||
//
|
||||
////////////////
|
||||
/** \class plAGMasterMod
|
||||
A modifier which can apply animations to scene objects.
|
||||
Works together with a plAGModifier, which can apply animation to a
|
||||
single scene object. A master modifier hooks up to a family of
|
||||
ag modifiers to do its job.
|
||||
An animation (plAGAnim) can have many different channels, but the
|
||||
user can just pass it to a single master mod to apply it to all the
|
||||
channels owned by that master. The master will take care of hooking
|
||||
each channel up to an ag modifier.
|
||||
The goal is to make an animation a conceptually (and practically) simple
|
||||
object to work with, whether or not it has multiple channels.
|
||||
|
||||
\sa plAGAnim, plAGAnimInstance, plAGModifier
|
||||
*/
|
||||
class plAGMasterMod : public plModifier
|
||||
{
|
||||
friend class plAGMasterSDLModifier;
|
||||
public:
|
||||
/** Default constructor. Primarily for use by the class factory. */
|
||||
plAGMasterMod();
|
||||
/** Free the name and any other miscellany. */
|
||||
virtual ~plAGMasterMod();
|
||||
|
||||
/** Find an individual plAGModifier of the given name under our control. */
|
||||
plAGModifier * GetChannelMod(const plString & name, bool dontCache = false) const;
|
||||
|
||||
/** \name Managing Animations */
|
||||
// \{
|
||||
// AGANIM PROTOCOL
|
||||
/** Attach the given animation object with the given blend factor.
|
||||
If there's no animation already attached to blend with, the
|
||||
animation will be attached at full strength. */
|
||||
plAGAnimInstance *AttachAnimationBlended(plAGAnim *anim, float blendFactor = 0,
|
||||
uint16_t blendPriority = kAGMedBlendPriority,
|
||||
bool cache = false);
|
||||
|
||||
/** Look up the given animation by name and attach it
|
||||
with the given blend factor. */
|
||||
plAGAnimInstance *AttachAnimationBlended(const plString &name, float blendFactor = 0,
|
||||
uint16_t blendPriority = kAGMedBlendPriority,
|
||||
bool cache = false);
|
||||
|
||||
/** Play a simple anim (one that doesn't affect root) once and auto detach.
|
||||
Intended for Zandi's facial animations that run seperate from the behaviors. */
|
||||
void PlaySimpleAnim(const plString &name);
|
||||
|
||||
/** Detach the given animation instance. Does nothing
|
||||
if the instance is not managed by this master mod. */
|
||||
void DetachAnimation(plAGAnimInstance *instance);
|
||||
void DetachAllAnimations();
|
||||
|
||||
/** Detach the given animation by name. Searches for
|
||||
any instances derived from animations with the
|
||||
given name and removes them. */
|
||||
void DetachAnimation(const plString &name);
|
||||
// \}
|
||||
|
||||
/** Print the current animation stack to the console.
|
||||
Will list all the animations and their blend strengths.
|
||||
Animations later in the list will mask animations earlier
|
||||
in the list. */
|
||||
void DumpCurrentAnims(const char *header);
|
||||
|
||||
/** Find and return any animation instances with the
|
||||
given name on this master modifer. */
|
||||
plAGAnimInstance *FindAnimInstance(const plString &name);
|
||||
|
||||
/** Return the Ith animation instance, based on blend
|
||||
order. Of dubious utility, but, y'know. */
|
||||
plAGAnimInstance *GetAnimInstance(int i);
|
||||
|
||||
/** Attach the animation if it's not already attached. If
|
||||
it is attached, return the instance.
|
||||
Note that if it's attached by this function, it
|
||||
will be on top of the stack, but if it was already
|
||||
attached, it could be anywhere, including buried under
|
||||
a bunch of other animations. If it's important that it be
|
||||
on top of the stack, you may need to detach it first. */
|
||||
plAGAnimInstance *FindOrAttachInstance(const plString &name, float blendFactor);
|
||||
|
||||
/** Return the number of animations available. */
|
||||
int GetNumAnimations();
|
||||
/** Return the number of animations that are privately
|
||||
owned by this modifier.
|
||||
Animations may be either shared in a general pool,
|
||||
or privately owned by a mastermod. */
|
||||
int GetNumPrivateAnimations();
|
||||
|
||||
int GetNumATCAnimations();
|
||||
plAGAnimInstance *GetATCAnimInstance(int i);
|
||||
|
||||
/** Apply all our animations to all our parts.
|
||||
\param timeNow is the current world time
|
||||
\param elapsed is the time since the previous frame */
|
||||
void ApplyAnimations(double timeNow, float elapsed);
|
||||
|
||||
/** Runs through our anims and applies them, without
|
||||
processing fades. This is used when we load in anim
|
||||
state from the server, and need to advance it to a
|
||||
certain point before enabling callbacks */
|
||||
void AdvanceAnimsToTime(double time);
|
||||
|
||||
/** Change the connectivity in the graph so that inactive animations are bypassed.
|
||||
The original connectivity information is kept, so if the activity of different
|
||||
animations is changed (such as by changing blend biases or adding new animations,
|
||||
the graph can be compiled again to the correct state. */
|
||||
void Compile(double time);
|
||||
|
||||
/** We've done something that invalidates the cached connectivity in the graph.
|
||||
Mark this for fixup. */
|
||||
void SetNeedCompile(bool needCompile);
|
||||
|
||||
/** List the animationg graph to stdOut, with a ASCII representation of the tree
|
||||
structure. Done by recursively dumping the graph; some types of nodes will have
|
||||
more output information than others.
|
||||
*/
|
||||
void DumpAniGraph(const char *channel, bool optimized, double time);
|
||||
|
||||
/** Set whether or not this is the "group master" so grouped animations will only have
|
||||
one member getting/setting sdl animation state in order to synch the anims
|
||||
*/
|
||||
void SetIsGrouped(bool grouped);
|
||||
void SetIsGroupMaster(bool master, plMsgForwarder* msgForwarder);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
virtual int GetNumTargets() const { return fTarget ? 1 : 0; }
|
||||
virtual plSceneObject* GetTarget(int w) const { /* hsAssert(w < GetNumTargets(), "Bad target"); */ return fTarget; }
|
||||
virtual void AddTarget(plSceneObject * object);
|
||||
virtual void RemoveTarget(plSceneObject * object);
|
||||
|
||||
bool MsgReceive(plMessage* msg);
|
||||
|
||||
virtual void Write(hsStream *stream, hsResMgr *mgr);
|
||||
virtual void Read(hsStream * stream, hsResMgr *mgr);
|
||||
|
||||
bool HasRunningAnims();
|
||||
bool DirtySynchState(const plString& SDLStateName, uint32_t synchFlags);
|
||||
|
||||
CLASSNAME_REGISTER( plAGMasterMod );
|
||||
GETINTERFACE_ANY( plAGMasterMod, plModifier );
|
||||
|
||||
protected:
|
||||
// -- methods --
|
||||
plAGModifier * ICacheChannelMod(plAGModifier *mod) const;
|
||||
plAGModifier * IFindChannelMod(const plSceneObject *obj, const plString &name) const;
|
||||
|
||||
virtual bool IEval(double secs, float del, uint32_t dirty);
|
||||
|
||||
virtual void IApplyDynamic() {}; // dummy function required by base class
|
||||
|
||||
// Find markers in an anim for environment effects (footsteps)
|
||||
virtual void ISetupMarkerCallbacks(plATCAnim *anim, plAnimTimeConvert *atc) {}
|
||||
|
||||
// -- members
|
||||
plSceneObject* fTarget;
|
||||
|
||||
// a map from channel names to ag modifiers within our domain
|
||||
typedef std::map<plString, plAGModifier*> plChannelModMap;
|
||||
plChannelModMap fChannelMods;
|
||||
|
||||
// instances which are currently attached to this master
|
||||
typedef std::vector<plAGAnimInstance*> plInstanceVector;
|
||||
plInstanceVector fAnimInstances; // animation instances
|
||||
|
||||
// animations which are owned exclusively by this master
|
||||
typedef std::vector<plAGAnim*> plAnimVector;
|
||||
plAnimVector fPrivateAnims;
|
||||
|
||||
// animations that require AnimTimeConvert state to be synched
|
||||
plInstanceVector fATCAnimInstances;
|
||||
|
||||
bool fFirstEval;
|
||||
bool fNeedEval;
|
||||
void IRegForEval(bool val);
|
||||
|
||||
// SDL modifier which sends/recvs dynamics state
|
||||
plAGMasterSDLModifier *fAGMasterSDLMod;
|
||||
|
||||
bool fNeedCompile;
|
||||
|
||||
bool fIsGrouped;
|
||||
bool fIsGroupMaster;
|
||||
plMsgForwarder* fMsgForwarder;
|
||||
|
||||
enum {
|
||||
kPrivateAnim,
|
||||
kPublicAnim,
|
||||
};
|
||||
};
|
||||
|
||||
#endif // PLAGMASTERMOD_INC
|
313
Sources/Plasma/PubUtilLib/plAnimation/plAGModifier.cpp
Normal file
313
Sources/Plasma/PubUtilLib/plAnimation/plAGModifier.cpp
Normal file
@ -0,0 +1,313 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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()
|
||||
{
|
||||
fAutoApply = true;
|
||||
fEnabled = true;
|
||||
}
|
||||
|
||||
// CTOR(name)
|
||||
plAGModifier::plAGModifier(const plString &name, bool autoApply)
|
||||
: plSingleModifier(), fAutoApply(autoApply)
|
||||
{
|
||||
fChannelName = name;
|
||||
fEnabled = true;
|
||||
}
|
||||
|
||||
// DTOR
|
||||
plAGModifier::~plAGModifier()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < fApps.size(); i++)
|
||||
{
|
||||
delete fApps[i];
|
||||
}
|
||||
}
|
||||
|
||||
// GETCHANNELNAME
|
||||
plString plAGModifier::GetChannelName() const
|
||||
{
|
||||
return fChannelName;
|
||||
}
|
||||
|
||||
// ENABLE
|
||||
void plAGModifier::Enable(bool val)
|
||||
{
|
||||
fEnabled = val;
|
||||
}
|
||||
|
||||
// SETCHANNELNAME
|
||||
void plAGModifier::SetChannelName(const plString & name)
|
||||
{
|
||||
fChannelName = 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
|
||||
bool plAGModifier::IEval(double time, float delta, uint32_t 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, "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
|
||||
bool 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;
|
||||
}
|
||||
|
166
Sources/Plasma/PubUtilLib/plAnimation/plAGModifier.h
Normal file
166
Sources/Plasma/PubUtilLib/plAnimation/plAGModifier.h
Normal file
@ -0,0 +1,166 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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==*/
|
||||
/** \file plAGMasterMod.h
|
||||
|
||||
\ingroup Avatar
|
||||
\ingroup AniGraph
|
||||
*/
|
||||
#ifndef PLAGMODIFIER_H
|
||||
#define PLAGMODIFIER_H
|
||||
|
||||
#include "HeadSpin.h" // need for plSingleModifier
|
||||
#include "pnModifier/plSingleModifier.h" // inherited
|
||||
|
||||
// local
|
||||
#include "plScalarChannel.h"
|
||||
|
||||
class plSceneObject;
|
||||
|
||||
class plAGAnimInstance;
|
||||
class plAGAnim;
|
||||
class plAvatarAnim;
|
||||
class plAnimCmdMsg;
|
||||
class plOneShotCallbacks;
|
||||
|
||||
///////////////
|
||||
//
|
||||
// PLAGMODIFIER
|
||||
//
|
||||
///////////////
|
||||
/** \class plAGModifier
|
||||
Animates a single scene object.
|
||||
May apply multiple animations to that scene object, animating
|
||||
the transform with one, colors with another, etc.
|
||||
The basic model is that the ag modifier holds an array of
|
||||
applicators, each of which is the root of a tree of animation
|
||||
operations, such as a blend tree, etc. Each frame it fires
|
||||
all its applicators, or (ideally) only those that need to be fired.
|
||||
*/
|
||||
class plAGModifier : public plSingleModifier
|
||||
{
|
||||
public:
|
||||
/** Default constructor, primarily for the class factory. */
|
||||
plAGModifier();
|
||||
|
||||
/** Construct given a name. This name will be used to match up
|
||||
incoming channels with this modifier. You may also supply an
|
||||
autoApply parameter, which indicates whether this modifier
|
||||
should apply itself every frame, or only when explicitly asked to. */
|
||||
plAGModifier(const plString &name, bool autoApply = true);
|
||||
|
||||
/** It's a destructor. Destroys the name passed into the constructor,
|
||||
and a bunch of other stuff you don't need to know anything about. */
|
||||
virtual ~plAGModifier();
|
||||
|
||||
/** Get the name of the channel controlled by this modifier. */
|
||||
plString GetChannelName() const;
|
||||
/** Change the channel name of the modifier. Will delete the previous
|
||||
name. Will NOT remove any channels that are already attached, so
|
||||
you could wind up with a modifier named "Fred" and a bunch of
|
||||
channels attached to it that were intended for "Lamont." */
|
||||
void SetChannelName(const plString & name);
|
||||
|
||||
/** Attach a new applicator to our modifier. Will arbitrate with existing
|
||||
modifiers if necessary, based on pin type. May destruct existing applicators. */
|
||||
plAGChannel *MergeChannel(plAGApplicator *app, plAGChannel *chan, plScalarChannel *blend,
|
||||
plAGAnimInstance *anim, int priority);
|
||||
/** Remove the given channel. Will also remove the channel's applicator. */
|
||||
bool DetachChannel(plAGChannel * channel);
|
||||
|
||||
/** Set the applicator for a modifier.
|
||||
\deprecated */
|
||||
void SetApplicator(plAGApplicator *app);
|
||||
/** Get the applicator for a given pintype. Note that an ag modifier can
|
||||
only have one applicator of a given pin type attached at a time.
|
||||
The exception is for the unknown pin type, which never conflicts
|
||||
with any other pin type, including itself. */
|
||||
plAGApplicator *GetApplicator(plAGPinType pin) const;
|
||||
|
||||
/** Apply the animation for our scene object. */
|
||||
void Apply(double time) const;
|
||||
|
||||
/** Get the channel tied to our ith applicator */
|
||||
plAGChannel * GetChannel(int i) { return fApps[i]->GetChannel(); }
|
||||
|
||||
void Enable(bool val);
|
||||
|
||||
// PERSISTENCE
|
||||
virtual void Read(hsStream *stream, hsResMgr *mgr);
|
||||
virtual void Write(hsStream *stream, hsResMgr *mgr);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plAGModifier );
|
||||
GETINTERFACE_ANY( plAGModifier, plSingleModifier );
|
||||
|
||||
protected:
|
||||
typedef std::vector<plAGApplicator*> plAppTable;
|
||||
plAppTable fApps; // the applicators (with respective channels) that we're applying to our scene object
|
||||
|
||||
plString fChannelName; // name used for matching animation channels to this modifier
|
||||
bool fAutoApply; // evaluate animation automatically during IEval call
|
||||
bool fEnabled; // if not enabled, we don't eval any of our anims
|
||||
|
||||
// APPLYING THE ANIMATION
|
||||
virtual bool IEval(double secs, float del, uint32_t dirty);
|
||||
|
||||
virtual bool IHandleCmd(plAnimCmdMsg* modMsg) { return false; } // only plAGMasterMod should handle these
|
||||
virtual void IApplyDynamic() {}; // dummy function required by base class
|
||||
|
||||
// INTERNAL ACCESSORS FOR SCENE OBJECT INTERFACES
|
||||
plAudioInterface * LeakAI() const { return IGetTargetAudioInterface(0); };
|
||||
plCoordinateInterface * LeakCI() const { return IGetTargetCoordinateInterface(0); };
|
||||
plDrawInterface * LeakDI() const { return IGetTargetDrawInterface(0); };
|
||||
plSimulationInterface * LeakSI() const { return IGetTargetSimulationInterface(0); };
|
||||
plObjInterface * LeakGI(uint32_t classIdx) const { return IGetTargetGenericInterface(0, classIdx); }
|
||||
|
||||
friend plAudioInterface * plAGApplicator::IGetAI(const plAGModifier * modifier) const;
|
||||
friend plCoordinateInterface * plAGApplicator::IGetCI(const plAGModifier * modifier) const;
|
||||
friend plDrawInterface * plAGApplicator::IGetDI(const plAGModifier * modifier) const;
|
||||
friend plSimulationInterface * plAGApplicator::IGetSI(const plAGModifier * modifier) const;
|
||||
friend plObjInterface * plAGApplicator::IGetGI(const plAGModifier * modifier, uint16_t classIdx) const;
|
||||
|
||||
};
|
||||
const plModifier * FindModifierByClass(const plSceneObject *obj, int classID);
|
||||
|
||||
|
||||
#endif
|
||||
|
132
Sources/Plasma/PubUtilLib/plAnimation/plAnimationCreatable.h
Normal file
132
Sources/Plasma/PubUtilLib/plAnimation/plAnimationCreatable.h
Normal file
@ -0,0 +1,132 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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==*/
|
||||
|
||||
#ifndef plAnimationCreatable_inc
|
||||
#define plAnimationCreatable_inc
|
||||
|
||||
#include "pnFactory/plCreator.h"
|
||||
|
||||
|
||||
#include "plAGAnim.h"
|
||||
|
||||
REGISTER_CREATABLE(plAGAnim);
|
||||
REGISTER_CREATABLE(plATCAnim);
|
||||
REGISTER_CREATABLE(plEmoteAnim);
|
||||
REGISTER_CREATABLE(plAgeGlobalAnim);
|
||||
|
||||
|
||||
#include "plAGChannel.h"
|
||||
|
||||
REGISTER_NONCREATABLE(plAGChannel);
|
||||
|
||||
|
||||
#include "plAGApplicator.h"
|
||||
|
||||
REGISTER_NONCREATABLE(plAGApplicator);
|
||||
|
||||
|
||||
#include "plMatrixChannel.h"
|
||||
|
||||
REGISTER_CREATABLE(plMatrixChannel);
|
||||
REGISTER_CREATABLE(plMatrixConstant);
|
||||
REGISTER_CREATABLE(plMatrixTimeScale);
|
||||
REGISTER_CREATABLE(plMatrixBlend);
|
||||
REGISTER_CREATABLE(plMatrixControllerChannel);
|
||||
REGISTER_CREATABLE(plMatrixControllerCacheChannel);
|
||||
REGISTER_CREATABLE(plQuatPointCombine);
|
||||
REGISTER_CREATABLE(plMatrixChannelApplicator);
|
||||
REGISTER_CREATABLE(plMatrixDelayedCorrectionApplicator);
|
||||
REGISTER_CREATABLE(plMatrixDifferenceApp);
|
||||
|
||||
|
||||
#include "plPointChannel.h"
|
||||
|
||||
REGISTER_CREATABLE(plPointChannel);
|
||||
REGISTER_CREATABLE(plPointConstant);
|
||||
REGISTER_CREATABLE(plPointBlend);
|
||||
REGISTER_CREATABLE(plPointTimeScale);
|
||||
REGISTER_CREATABLE(plPointControllerChannel);
|
||||
REGISTER_CREATABLE(plPointControllerCacheChannel);
|
||||
REGISTER_CREATABLE(plPointChannelApplicator);
|
||||
REGISTER_CREATABLE(plLightDiffuseApplicator);
|
||||
REGISTER_CREATABLE(plLightAmbientApplicator);
|
||||
REGISTER_CREATABLE(plLightSpecularApplicator);
|
||||
|
||||
|
||||
#include "plQuatChannel.h"
|
||||
|
||||
REGISTER_CREATABLE(plQuatChannel);
|
||||
REGISTER_CREATABLE(plQuatConstant);
|
||||
REGISTER_CREATABLE(plQuatBlend);
|
||||
REGISTER_CREATABLE(plQuatTimeScale);
|
||||
REGISTER_CREATABLE(plQuatChannelApplicator);
|
||||
|
||||
|
||||
#include "plScalarChannel.h"
|
||||
|
||||
REGISTER_CREATABLE(plScalarChannel);
|
||||
REGISTER_CREATABLE(plScalarConstant);
|
||||
REGISTER_CREATABLE(plScalarTimeScale);
|
||||
REGISTER_CREATABLE(plScalarBlend);
|
||||
REGISTER_CREATABLE(plScalarControllerChannel);
|
||||
REGISTER_CREATABLE(plScalarControllerCacheChannel);
|
||||
REGISTER_CREATABLE(plScalarChannelApplicator);
|
||||
REGISTER_CREATABLE(plSpotInnerApplicator);
|
||||
REGISTER_CREATABLE(plSpotOuterApplicator);
|
||||
REGISTER_CREATABLE(plATCChannel);
|
||||
REGISTER_CREATABLE(plScalarSDLChannel);
|
||||
REGISTER_CREATABLE(plOmniApplicator);
|
||||
REGISTER_CREATABLE(plOmniSqApplicator);
|
||||
REGISTER_CREATABLE(plOmniCutoffApplicator);
|
||||
|
||||
|
||||
#include "plAGModifier.h"
|
||||
|
||||
REGISTER_CREATABLE(plAGModifier);
|
||||
|
||||
|
||||
#include "plAGMasterMod.h"
|
||||
|
||||
REGISTER_CREATABLE(plAGMasterMod);
|
||||
|
||||
#endif // plAnimationCreatable_inc
|
||||
|
1017
Sources/Plasma/PubUtilLib/plAnimation/plMatrixChannel.cpp
Normal file
1017
Sources/Plasma/PubUtilLib/plAnimation/plMatrixChannel.cpp
Normal file
File diff suppressed because it is too large
Load Diff
384
Sources/Plasma/PubUtilLib/plAnimation/plMatrixChannel.h
Normal file
384
Sources/Plasma/PubUtilLib/plAnimation/plMatrixChannel.h
Normal file
@ -0,0 +1,384 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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==*/
|
||||
#ifndef PLMATRIXCHANNEL_INC
|
||||
#define PLMATRIXCHANNEL_INC
|
||||
|
||||
// local
|
||||
#include "plScalarChannel.h"
|
||||
|
||||
// global
|
||||
#include "HeadSpin.h" // you need types to include Matrix
|
||||
#include "hsMatrix44.h"
|
||||
#include "plTransform/hsAffineParts.h"
|
||||
|
||||
// local prototypes
|
||||
class plQuatChannel;
|
||||
class plPointChannel;
|
||||
|
||||
// external prototypes
|
||||
class plController;
|
||||
class hsAffineParts;
|
||||
class plAnimTimeConvert;
|
||||
class plMatrixChannelApplicator;
|
||||
class plControllerCacheInfo;
|
||||
|
||||
//////////////////
|
||||
// PLMATRIXCHANNEL
|
||||
//////////////////
|
||||
// an animation channel that outputs matrices
|
||||
class plMatrixChannel : public plAGChannel
|
||||
{
|
||||
protected:
|
||||
hsMatrix44 fResult;
|
||||
hsAffineParts fAP;
|
||||
|
||||
public:
|
||||
plMatrixChannel();
|
||||
virtual ~plMatrixChannel();
|
||||
|
||||
// AG PROTOCOL
|
||||
virtual const hsMatrix44 & Value(double time, bool peek = false);
|
||||
virtual void Value(hsMatrix44 &matrix, double time, bool peek = false);
|
||||
virtual const hsAffineParts & AffineValue(double time, bool peek = false);
|
||||
|
||||
// combine it (allocates combine object)
|
||||
virtual plAGChannel * MakeCombine(plAGChannel * channelB);
|
||||
|
||||
// blend it (allocates blend object)
|
||||
virtual plAGChannel * MakeBlend(plAGChannel * channelB, plScalarChannel * channelBias, int blendPriority);
|
||||
|
||||
// const eval at time zero
|
||||
virtual plAGChannel * MakeZeroState();
|
||||
// make a timeScale instance
|
||||
virtual plAGChannel * MakeTimeScale(plScalarChannel *timeSource);
|
||||
|
||||
virtual plAGPinType GetPinType() { return kAGPinTransform; };
|
||||
|
||||
virtual void Dump(int indent, bool optimized, double time);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plMatrixChannel );
|
||||
GETINTERFACE_ANY( plMatrixChannel, plAGChannel );
|
||||
};
|
||||
|
||||
///////////////////
|
||||
// PLMATRIXCONSTANT
|
||||
///////////////////
|
||||
// A matrix source that just keeps handing out the same value
|
||||
class plMatrixConstant : public plMatrixChannel
|
||||
{
|
||||
public:
|
||||
plMatrixConstant();
|
||||
plMatrixConstant(const hsMatrix44 &value);
|
||||
virtual ~plMatrixConstant();
|
||||
|
||||
void Set(const hsMatrix44 &value);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plMatrixConstant );
|
||||
GETINTERFACE_ANY( plMatrixConstant, plMatrixChannel );
|
||||
|
||||
virtual void Write(hsStream *stream, hsResMgr *mgr);
|
||||
virtual void Read(hsStream *s, hsResMgr *mgr);
|
||||
};
|
||||
|
||||
////////////////////
|
||||
// PLMATRIXTIMESCALE
|
||||
////////////////////
|
||||
// Adapts the time scale before passing it to the next channel in line.
|
||||
// Use to instance animations while allowing each instance to run at different speeds.
|
||||
class plMatrixTimeScale : public plMatrixChannel
|
||||
{
|
||||
protected:
|
||||
plScalarChannel *fTimeSource;
|
||||
plMatrixChannel *fChannelIn;
|
||||
|
||||
public:
|
||||
plMatrixTimeScale();
|
||||
plMatrixTimeScale(plMatrixChannel *channel, plScalarChannel *timeSource);
|
||||
virtual ~plMatrixTimeScale();
|
||||
|
||||
virtual bool IsStoppedAt(double time);
|
||||
virtual const hsMatrix44 & Value(double time, bool peek = false);
|
||||
virtual const hsAffineParts & AffineValue(double time, bool peek = false);
|
||||
|
||||
virtual plAGChannel * Detach(plAGChannel * channel);
|
||||
|
||||
virtual void Dump(int indent, bool optimized, double time);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plMatrixTimeScale );
|
||||
GETINTERFACE_ANY( plMatrixTimeScale, plMatrixChannel );
|
||||
};
|
||||
|
||||
////////////////
|
||||
// PLMATRIXBLEND
|
||||
////////////////
|
||||
// blends two matrices into one with weighting
|
||||
class plMatrixBlend : public plMatrixChannel
|
||||
{
|
||||
protected:
|
||||
plMatrixChannel * fChannelA;
|
||||
plMatrixChannel * fOptimizedA;
|
||||
plMatrixChannel * fChannelB;
|
||||
plMatrixChannel * fOptimizedB;
|
||||
plScalarChannel * fChannelBias;
|
||||
int fPriority;
|
||||
|
||||
public:
|
||||
// xTORs
|
||||
plMatrixBlend();
|
||||
plMatrixBlend(plMatrixChannel * channelA, plMatrixChannel * channelB, plScalarChannel * channelBias, int priority);
|
||||
virtual ~plMatrixBlend();
|
||||
|
||||
virtual plAGChannel * MakeBlend(plAGChannel *newChannel, plScalarChannel *channelBias, int blendPriority);
|
||||
|
||||
// you cannot blend on top of a channel that has higher priority than you do.
|
||||
virtual uint16_t GetPriority();
|
||||
|
||||
// SPECIFICS
|
||||
const plMatrixChannel * GetChannelA() const { return fChannelA; }
|
||||
void SetChannelA(plMatrixChannel * channel) { fChannelA = channel; }
|
||||
|
||||
const plMatrixChannel * GetChannelB() const { return fChannelB; }
|
||||
void SetChannelB(plMatrixChannel * channel) { fChannelB = channel; }
|
||||
|
||||
const plScalarChannel * GetChannelBias() const { return fChannelBias; }
|
||||
void SetChannelBias(plScalarChannel * channel) { fChannelBias = channel; }
|
||||
|
||||
//virtual void SetBlend(float blend) { fBlend = blend; };
|
||||
//virtual float GetBlend() { return fBlend; };
|
||||
|
||||
virtual bool IsStoppedAt(double time);
|
||||
|
||||
// AG PROTOCOL
|
||||
virtual const hsMatrix44 & Value(double time, bool peek = false);
|
||||
virtual const hsAffineParts & AffineValue(double time, bool peek = false);
|
||||
|
||||
// remove the specified channel from our graph
|
||||
virtual plAGChannel * Detach(plAGChannel * channel);
|
||||
virtual void Dump(int indent, bool optimized, double time);
|
||||
|
||||
plAGChannel* Optimize(double time);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plMatrixBlend );
|
||||
GETINTERFACE_ANY( plMatrixBlend, plMatrixChannel );
|
||||
};
|
||||
|
||||
/////////////////////
|
||||
// PLMATRIXCONTROLLER
|
||||
/////////////////////
|
||||
// converts a plController-style animation into a plMatrixChannel
|
||||
class plMatrixControllerChannel : public plMatrixChannel
|
||||
{
|
||||
protected:
|
||||
plController *fController;
|
||||
|
||||
public:
|
||||
// xTORs
|
||||
plMatrixControllerChannel();
|
||||
plMatrixControllerChannel(plController *controller, hsAffineParts *parts);
|
||||
virtual ~plMatrixControllerChannel();
|
||||
|
||||
// AG PROTOCOL
|
||||
virtual const hsAffineParts & AffineValue(double time, bool peek = false);
|
||||
virtual const hsAffineParts & AffineValue(double time, bool peek, plControllerCacheInfo *cache);
|
||||
virtual const hsMatrix44 & Value(double time, bool peek = false);
|
||||
virtual const hsMatrix44 & Value(double time, bool peek, plControllerCacheInfo *cache);
|
||||
|
||||
virtual plAGChannel * MakeCacheChannel(plAnimTimeConvert *atc);
|
||||
|
||||
virtual void Dump(int indent, bool optimized, double time);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
// rtti
|
||||
CLASSNAME_REGISTER( plMatrixControllerChannel );
|
||||
GETINTERFACE_ANY( plMatrixControllerChannel, plMatrixChannel );
|
||||
|
||||
// persistence
|
||||
virtual void Write(hsStream *stream, hsResMgr *mgr);
|
||||
virtual void Read(hsStream *s, hsResMgr *mgr);
|
||||
};
|
||||
|
||||
/////////////////////////////////
|
||||
// PLMATRIXCONTROLLERCACHECHANNEL
|
||||
/////////////////////////////////
|
||||
// Same as plMatrixController, but with caching info
|
||||
class plMatrixControllerCacheChannel : public plMatrixChannel
|
||||
{
|
||||
protected:
|
||||
plControllerCacheInfo *fCache;
|
||||
plMatrixControllerChannel *fControllerChannel;
|
||||
|
||||
public:
|
||||
plMatrixControllerCacheChannel();
|
||||
plMatrixControllerCacheChannel(plMatrixControllerChannel *channel, plControllerCacheInfo *cache);
|
||||
virtual ~plMatrixControllerCacheChannel();
|
||||
|
||||
virtual const hsMatrix44 & Value(double time, bool peek = false);
|
||||
virtual const hsAffineParts & AffineValue(double time, bool peek = false);
|
||||
|
||||
virtual plAGChannel * Detach(plAGChannel * channel);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plMatrixControllerCacheChannel );
|
||||
GETINTERFACE_ANY( plMatrixControllerCacheChannel, plMatrixChannel );
|
||||
|
||||
// Created at runtime only, so no Read/Write
|
||||
};
|
||||
|
||||
/////////////////////
|
||||
// PLQUATPOINTCOMBINE
|
||||
/////////////////////
|
||||
// combines a quaternion and a point into a matrix
|
||||
class plQuatPointCombine : public plMatrixChannel
|
||||
{
|
||||
protected:
|
||||
plQuatChannel *fQuatChannel;
|
||||
plPointChannel *fPointChannel;
|
||||
|
||||
public:
|
||||
// xTORs
|
||||
plQuatPointCombine();
|
||||
plQuatPointCombine(plQuatChannel *quatChannel, plPointChannel *pointChannel);
|
||||
virtual ~plQuatPointCombine();
|
||||
|
||||
// SPECIFICS
|
||||
const plQuatChannel * GetQuatChannel() const { return fQuatChannel; }
|
||||
void SetQuatChannel(plQuatChannel * channel) { fQuatChannel = channel; }
|
||||
|
||||
plPointChannel * GetPointChannel() const { return fPointChannel; }
|
||||
void SetPointChannel(plPointChannel * channel) { fPointChannel = channel; }
|
||||
|
||||
// AG PROTOCOL
|
||||
virtual const hsMatrix44 & Value(double time);
|
||||
virtual const hsAffineParts & AffineValue(double time);
|
||||
|
||||
// remove the specified channel from our graph
|
||||
virtual plAGChannel * Detach(plAGChannel * channel);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plQuatPointCombine );
|
||||
GETINTERFACE_ANY( plQuatPointCombine, plMatrixChannel );
|
||||
};
|
||||
|
||||
|
||||
/////////////////////
|
||||
//
|
||||
// Applicator classes
|
||||
|
||||
class plMatrixChannelApplicator : public plAGApplicator
|
||||
{
|
||||
protected:
|
||||
virtual void IApply(const plAGModifier *mod, double time);
|
||||
|
||||
public:
|
||||
CLASSNAME_REGISTER( plMatrixChannelApplicator );
|
||||
GETINTERFACE_ANY( plMatrixChannelApplicator, plAGApplicator );
|
||||
|
||||
virtual bool CanCombine(plAGApplicator *app) { return false; }
|
||||
virtual plAGPinType GetPinType() { return kAGPinTransform; }
|
||||
};
|
||||
|
||||
// PLMATRIXDELAYEDCORRECTIONAPPLICATOR
|
||||
// Used for blending in sudden location changes due to synch messages.
|
||||
// This app tacks on a correction to the l2p transform
|
||||
// (so l2p is set as animL2P*correction)
|
||||
// interpolating this to the identity matrix over time.
|
||||
class plMatrixDelayedCorrectionApplicator : public plMatrixChannelApplicator
|
||||
{
|
||||
protected:
|
||||
hsAffineParts fCorAP; // AP of the correction.
|
||||
double fDelayStart; // Start time of the delayed correction
|
||||
|
||||
// apply our animation * our correction to the node
|
||||
virtual void IApply(const plAGModifier *mod, double time);
|
||||
|
||||
public:
|
||||
plMatrixDelayedCorrectionApplicator() : fDelayStart(-1000.f), fIgnoreNextCorrection(true) { fCorAP.Reset(); }
|
||||
|
||||
CLASSNAME_REGISTER( plMatrixDelayedCorrectionApplicator );
|
||||
GETINTERFACE_ANY( plMatrixDelayedCorrectionApplicator, plMatrixChannelApplicator );
|
||||
|
||||
void SetCorrection(hsMatrix44 &correction);
|
||||
virtual bool AutoDelete() { return false; } // should we remove it when its input channel is gone?
|
||||
|
||||
// applicator arbitration...
|
||||
virtual plAGPinType GetPinType() { return kAGPinTransform; }
|
||||
virtual bool CanBlend(plAGApplicator *app);
|
||||
|
||||
bool fIgnoreNextCorrection;
|
||||
static const float fDelayLength; // static var for now.
|
||||
};
|
||||
|
||||
// PLMATRIXDIFFERENCEAPP
|
||||
// Each frame, this guy takes the difference between his current value
|
||||
// and his last value and applies that to the current world
|
||||
// transform of the target.
|
||||
// You could also call it the Temporal Matrix Difference Applicator,
|
||||
// but that sucks to type.
|
||||
class plMatrixDifferenceApp : public plMatrixChannelApplicator
|
||||
{
|
||||
public:
|
||||
/** Forget the previous cached transform and start again */
|
||||
void Reset(double time);
|
||||
|
||||
/** Should this applicator be automatically removed when its channel goes away? */
|
||||
virtual bool AutoDelete() { return false; }
|
||||
|
||||
// applicator arbitration
|
||||
virtual plAGPinType GetPinType() { return kAGPinTransform; }
|
||||
virtual bool CanBlend(plAGApplicator *app);
|
||||
|
||||
CLASSNAME_REGISTER(plMatrixDifferenceApp);
|
||||
GETINTERFACE_ANY(plMatrixDifferenceApp, plMatrixChannelApplicator);
|
||||
|
||||
protected:
|
||||
virtual void IApply(const plAGModifier *mod, double time);
|
||||
hsMatrix44 fLastL2A; // local to animation space
|
||||
hsMatrix44 fLastA2L; // animation space to local
|
||||
bool fNew; // true if we haven't cached anything yet
|
||||
};
|
||||
|
||||
|
||||
#endif
|
498
Sources/Plasma/PubUtilLib/plAnimation/plPointChannel.cpp
Normal file
498
Sources/Plasma/PubUtilLib/plAnimation/plPointChannel.cpp
Normal file
@ -0,0 +1,498 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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 "plPointChannel.h"
|
||||
#include "plScalarChannel.h"
|
||||
#include "hsResMgr.h"
|
||||
|
||||
#include "pnSceneObject/plDrawInterface.h"
|
||||
#include "pnSceneObject/plSimulationInterface.h"
|
||||
#include "pnSceneObject/plCoordinateInterface.h"
|
||||
#include "pnSceneObject/plAudioInterface.h"
|
||||
#include "plInterp/plController.h"
|
||||
#include "plInterp/plAnimTimeConvert.h"
|
||||
#include "plGLight/plLightInfo.h"
|
||||
|
||||
//////////////
|
||||
// PLPOINTSRCE
|
||||
//////////////
|
||||
|
||||
// CTOR
|
||||
plPointChannel::plPointChannel()
|
||||
: plAGChannel(), fResult(0, 0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
// DTOR
|
||||
plPointChannel::~plPointChannel()
|
||||
{
|
||||
}
|
||||
|
||||
// VALUE
|
||||
// default behaviour is just to return our result (constant value)
|
||||
const hsPoint3 & plPointChannel::Value(double time)
|
||||
{
|
||||
return fResult;
|
||||
}
|
||||
|
||||
// VALUE(point, time)
|
||||
void plPointChannel::Value(hsPoint3 &point, double time)
|
||||
{
|
||||
point = Value(time);
|
||||
}
|
||||
|
||||
// MAKECOMBINE
|
||||
plAGChannel * plPointChannel::MakeCombine(plAGChannel *channelA)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
// MAKEBLEND
|
||||
plAGChannel * plPointChannel::MakeBlend(plAGChannel * channelB, plScalarChannel * channelBias, int blendPriority)
|
||||
{
|
||||
return new plPointBlend(this, (plPointChannel *)channelB, channelBias);
|
||||
}
|
||||
|
||||
// MAKEZEROSTATE
|
||||
plAGChannel * plPointChannel::MakeZeroState()
|
||||
{
|
||||
return new plPointConstant(Value(0));
|
||||
}
|
||||
|
||||
// MAKETIMESCALE
|
||||
plAGChannel * plPointChannel::MakeTimeScale(plScalarChannel *timeSource)
|
||||
{
|
||||
return new plPointTimeScale(this, timeSource);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// plPointConstant
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ctor --------------------------
|
||||
// -----
|
||||
plPointConstant::plPointConstant()
|
||||
: plPointChannel()
|
||||
{
|
||||
}
|
||||
|
||||
// ctor -----------------------------------------------
|
||||
// -----
|
||||
plPointConstant::plPointConstant(const hsPoint3 &point)
|
||||
{
|
||||
fResult = point;
|
||||
}
|
||||
|
||||
// dtor ---------------------------
|
||||
// -----
|
||||
plPointConstant::~plPointConstant()
|
||||
{
|
||||
}
|
||||
|
||||
void plPointConstant::Read(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plPointChannel::Read(stream, mgr);
|
||||
fResult.Read(stream);
|
||||
}
|
||||
|
||||
void plPointConstant::Write(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plPointChannel::Write(stream, mgr);
|
||||
fResult.Write(stream);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PLPOINTTIMESCALE
|
||||
//
|
||||
// Insert into the graph when you need to change the speed or direction of time
|
||||
// Also serves as a handy instancing node, since it just passes its data through.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ctor ----------------------------
|
||||
// -----
|
||||
plPointTimeScale::plPointTimeScale()
|
||||
: fTimeSource(nil), fChannelIn(nil)
|
||||
{
|
||||
}
|
||||
|
||||
// ctor --------------------------------------------------------------------------------
|
||||
// -----
|
||||
plPointTimeScale::plPointTimeScale(plPointChannel *channel, plScalarChannel *timeSource)
|
||||
: fChannelIn(channel),
|
||||
fTimeSource(timeSource)
|
||||
{
|
||||
}
|
||||
|
||||
// dtor -----------------------------
|
||||
// -----
|
||||
plPointTimeScale::~plPointTimeScale()
|
||||
{
|
||||
}
|
||||
|
||||
// IsStoppedAt ---------------------------
|
||||
// ------------
|
||||
bool plPointTimeScale::IsStoppedAt(double time)
|
||||
{
|
||||
return fTimeSource->IsStoppedAt(time);
|
||||
}
|
||||
|
||||
// Value --------------------------------------------
|
||||
// ------
|
||||
const hsPoint3 & plPointTimeScale::Value(double time)
|
||||
{
|
||||
fResult = fChannelIn->Value(fTimeSource->Value(time));
|
||||
|
||||
return fResult;
|
||||
}
|
||||
|
||||
// Detach ---------------------------------------------------
|
||||
// -------
|
||||
plAGChannel * plPointTimeScale::Detach(plAGChannel * channel)
|
||||
{
|
||||
plAGChannel *result = this;
|
||||
|
||||
fChannelIn = plPointChannel::ConvertNoRef(fChannelIn->Detach(channel));
|
||||
|
||||
if(!fChannelIn || channel == this)
|
||||
result = nil;
|
||||
|
||||
if(result != this)
|
||||
delete this;
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// plPointBlend
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ctor --------------------
|
||||
// -----
|
||||
plPointBlend::plPointBlend()
|
||||
: fPointA(nullptr),
|
||||
fPointB(nullptr),
|
||||
fChannelBias(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
// ctor ---------------------------------------------------------------------------------
|
||||
// -----
|
||||
plPointBlend::plPointBlend(plPointChannel *channelA, plPointChannel *channelB,
|
||||
plScalarChannel *channelBias)
|
||||
: fPointA(channelA),
|
||||
fPointB(channelB),
|
||||
fChannelBias(channelBias)
|
||||
{
|
||||
}
|
||||
|
||||
// dtor ---------------------
|
||||
// -----
|
||||
plPointBlend::~plPointBlend()
|
||||
{
|
||||
fPointA = nil;
|
||||
fPointB = nil;
|
||||
fChannelBias = nil;
|
||||
}
|
||||
|
||||
// IsStoppedAt ------------------------------
|
||||
// ------------
|
||||
bool plPointBlend::IsStoppedAt(double time)
|
||||
{
|
||||
float blend = fChannelBias->Value(time);
|
||||
if (blend == 0)
|
||||
return fPointA->IsStoppedAt(time);
|
||||
if (blend == 1)
|
||||
return fPointB->IsStoppedAt(time);
|
||||
|
||||
return (fPointA->IsStoppedAt(time) && fPointB->IsStoppedAt(time));
|
||||
}
|
||||
|
||||
// Value ---------------------------------------
|
||||
// ------
|
||||
const hsPoint3 &plPointBlend::Value(double time)
|
||||
{
|
||||
if (fPointA && fPointB)
|
||||
{
|
||||
float curBlend = fChannelBias->Value(time);
|
||||
if(curBlend == 0) {
|
||||
fPointA->Value(fResult, time);
|
||||
} else {
|
||||
if(curBlend == 1) {
|
||||
fPointB->Value(fResult, time);
|
||||
} else {
|
||||
const hsPoint3 &pointA = fPointA->Value(time);
|
||||
const hsPoint3 &pointB = fPointB->Value(time);
|
||||
hsPoint3 difference = pointB - pointA;
|
||||
|
||||
difference *= curBlend;
|
||||
|
||||
fResult = pointA + difference;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (fPointA) {
|
||||
fResult = fPointA->Value(time);
|
||||
} else if (fPointB) {
|
||||
fResult = fPointB->Value(time);
|
||||
}
|
||||
}
|
||||
return fResult;
|
||||
}
|
||||
|
||||
// Detach ------------------------------------------------------
|
||||
// -------
|
||||
plAGChannel * plPointBlend::Detach(plAGChannel *remove)
|
||||
{
|
||||
plAGChannel *result = this;
|
||||
|
||||
if (remove == this)
|
||||
{
|
||||
result = nil;
|
||||
} else {
|
||||
// it's possible that the incoming channel could reside down *all* of our
|
||||
// branches (it's a graph, not a tree,) so we always pass down all limbs
|
||||
fChannelBias = plScalarChannel::ConvertNoRef(fChannelBias->Detach(remove));
|
||||
fPointA = plPointChannel::ConvertNoRef(fPointA->Detach(remove));
|
||||
fPointB = plPointChannel::ConvertNoRef(fPointB->Detach(remove));
|
||||
if (!fChannelBias)
|
||||
{
|
||||
// No more bias channel, assume it's zero from now on, (a.k.a. We just want channelA)
|
||||
result = fPointA;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!fChannelBias)
|
||||
result = fPointA;
|
||||
else if(fPointA && !fPointB)
|
||||
result = fPointA;
|
||||
else if(fPointB && !fPointA)
|
||||
result = fPointB;
|
||||
else if(!fPointA && !fPointB)
|
||||
result = nil;
|
||||
if(result != this)
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// PLPOINTCONTROLLERCHANNEL
|
||||
///////////////////////////
|
||||
|
||||
// CTOR
|
||||
plPointControllerChannel::plPointControllerChannel()
|
||||
: fController(nil)
|
||||
{
|
||||
}
|
||||
|
||||
// CTOR(name, controller)
|
||||
plPointControllerChannel::plPointControllerChannel(plController *controller)
|
||||
: fController(controller)
|
||||
{
|
||||
}
|
||||
|
||||
// ~DTOR()
|
||||
plPointControllerChannel::~plPointControllerChannel()
|
||||
{
|
||||
if(fController) {
|
||||
delete fController;
|
||||
fController = nil;
|
||||
}
|
||||
}
|
||||
|
||||
// VALUE(time)
|
||||
const hsPoint3 & plPointControllerChannel::Value(double time)
|
||||
{
|
||||
return Value(time, nil);
|
||||
}
|
||||
|
||||
// VALUE(time)
|
||||
const hsPoint3 & plPointControllerChannel::Value(double time, plControllerCacheInfo *cache)
|
||||
{
|
||||
fController->Interp((float)time, &fResult, cache);
|
||||
return fResult;
|
||||
}
|
||||
|
||||
plAGChannel *plPointControllerChannel::MakeCacheChannel(plAnimTimeConvert *atc)
|
||||
{
|
||||
plControllerCacheInfo *cache = fController->CreateCache();
|
||||
cache->SetATC(atc);
|
||||
return new plPointControllerCacheChannel(this, cache);
|
||||
}
|
||||
|
||||
// WRITE(stream, mgr)
|
||||
void plPointControllerChannel::Write(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plPointChannel::Write(stream, mgr);
|
||||
|
||||
hsAssert(fController, "Trying to write plPointControllerChannel with nil controller. File will not be importable.");
|
||||
mgr->WriteCreatable(stream, fController);
|
||||
}
|
||||
|
||||
// READ(stream, mgr)
|
||||
void plPointControllerChannel::Read(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plPointChannel::Read(stream, mgr);
|
||||
|
||||
fController = plController::ConvertNoRef(mgr->ReadCreatable(stream));
|
||||
}
|
||||
|
||||
/////////////////////////////////
|
||||
// PLPOINTCONTROLLERCACHECHANNEL
|
||||
/////////////////////////////////
|
||||
|
||||
// CTOR
|
||||
plPointControllerCacheChannel::plPointControllerCacheChannel()
|
||||
: fControllerChannel(nil),
|
||||
fCache(nil)
|
||||
{
|
||||
}
|
||||
|
||||
// CTOR(name, controller)
|
||||
plPointControllerCacheChannel::plPointControllerCacheChannel(plPointControllerChannel *controller, plControllerCacheInfo *cache)
|
||||
: fControllerChannel(controller),
|
||||
fCache(cache)
|
||||
{
|
||||
}
|
||||
|
||||
// ~DTOR()
|
||||
plPointControllerCacheChannel::~plPointControllerCacheChannel()
|
||||
{
|
||||
delete fCache;
|
||||
fControllerChannel = nil;
|
||||
}
|
||||
|
||||
// VALUE(time)
|
||||
const hsPoint3 & plPointControllerCacheChannel::Value(double time, bool peek)
|
||||
{
|
||||
return fControllerChannel->Value(time, fCache);
|
||||
}
|
||||
|
||||
// DETACH
|
||||
plAGChannel * plPointControllerCacheChannel::Detach(plAGChannel * channel)
|
||||
{
|
||||
if(channel == this)
|
||||
{
|
||||
return nil;
|
||||
} else {
|
||||
plAGChannel *result = fControllerChannel->Detach(channel);
|
||||
|
||||
if(result == fControllerChannel)
|
||||
{
|
||||
return this;
|
||||
} else {
|
||||
// if our controller channel has been detached, then detach ourselves as well.
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Channel applicators
|
||||
|
||||
void plPointChannelApplicator::IApply(const plAGModifier *modifier, double time)
|
||||
{
|
||||
plPointChannel *pointChan = plPointChannel::ConvertNoRef(fChannel);
|
||||
hsAssert(pointChan, "Invalid channel given to plPointChannelApplicator");
|
||||
|
||||
plCoordinateInterface *CI = IGetCI(modifier);
|
||||
|
||||
hsMatrix44 l2p = CI->GetLocalToParent();
|
||||
const hsPoint3 &point = pointChan->Value(time);
|
||||
|
||||
l2p.SetTranslate(&point);
|
||||
|
||||
hsMatrix44 p2l;
|
||||
l2p.GetInverse(&p2l);
|
||||
CI->SetLocalToParent(l2p, p2l);
|
||||
}
|
||||
|
||||
void plLightDiffuseApplicator::IApply(const plAGModifier *modifier, double time)
|
||||
{
|
||||
plPointChannel *pointChan = plPointChannel::ConvertNoRef(fChannel);
|
||||
hsAssert(pointChan, "Invalid channel given to plLightDiffuseApplicator");
|
||||
|
||||
plLightInfo *li = plLightInfo::ConvertNoRef(IGetGI(modifier, plLightInfo::Index()));
|
||||
|
||||
const hsPoint3 &point = pointChan->Value(time);
|
||||
hsColorRGBA color;
|
||||
color.Set(point.fX, point.fY, point.fZ, 1.0f);
|
||||
li->SetDiffuse(color);
|
||||
}
|
||||
|
||||
void plLightAmbientApplicator::IApply(const plAGModifier *modifier, double time)
|
||||
{
|
||||
plPointChannel *pointChan = plPointChannel::ConvertNoRef(fChannel);
|
||||
hsAssert(pointChan, "Invalid channel given to plLightAmbientApplicator");
|
||||
|
||||
plLightInfo *li = plLightInfo::ConvertNoRef(IGetGI(modifier, plLightInfo::Index()));
|
||||
|
||||
const hsPoint3 &point = pointChan->Value(time);
|
||||
hsColorRGBA color;
|
||||
color.Set(point.fX, point.fY, point.fZ, 1.0f);
|
||||
li->SetAmbient(color);
|
||||
}
|
||||
|
||||
void plLightSpecularApplicator::IApply(const plAGModifier *modifier, double time)
|
||||
{
|
||||
plPointChannel *pointChan = plPointChannel::ConvertNoRef(fChannel);
|
||||
hsAssert(pointChan, "Invalid channel given to plLightSpecularApplicator");
|
||||
|
||||
plLightInfo *li = plLightInfo::ConvertNoRef(IGetGI(modifier, plLightInfo::Index()));
|
||||
|
||||
const hsPoint3 &point = pointChan->Value(time);
|
||||
hsColorRGBA color;
|
||||
color.Set(point.fX, point.fY, point.fZ, 1.0f);
|
||||
li->SetSpecular(color);
|
||||
}
|
||||
|
||||
|
302
Sources/Plasma/PubUtilLib/plAnimation/plPointChannel.h
Normal file
302
Sources/Plasma/PubUtilLib/plAnimation/plPointChannel.h
Normal file
@ -0,0 +1,302 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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==*/
|
||||
#ifndef PLPOINTCHANNEL_H
|
||||
#define PLPOINTCHANNEL_H
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDES
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "plAGApplicator.h"
|
||||
#include "plAGChannel.h"
|
||||
|
||||
#include "hsGeometry3.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// FORWARDS
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class plController;
|
||||
class plControllerCacheInfo;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DEFINITIONS
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PLPOINTCHANNEL
|
||||
/////////////////
|
||||
// A source of animated hsPoint3 data
|
||||
class plPointChannel : public plAGChannel
|
||||
{
|
||||
protected:
|
||||
hsPoint3 fResult;
|
||||
|
||||
public:
|
||||
plPointChannel();
|
||||
virtual ~plPointChannel();
|
||||
|
||||
// AG PROTOCOL
|
||||
virtual const hsPoint3 & Value(double time);
|
||||
virtual void Value(hsPoint3 &point, double time);
|
||||
|
||||
// combine it (allocates combine object)
|
||||
virtual plAGChannel * MakeCombine(plAGChannel * channelB);
|
||||
|
||||
// blend it (allocates blend object)
|
||||
virtual plAGChannel * MakeBlend(plAGChannel * channelB, plScalarChannel * channelBias, int blendPriority);
|
||||
|
||||
// const eval at time zero
|
||||
virtual plAGChannel * MakeZeroState();
|
||||
// make a timeScale instance
|
||||
virtual plAGChannel * MakeTimeScale(plScalarChannel *timeSource);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plPointChannel );
|
||||
GETINTERFACE_ANY( plPointChannel, plAGChannel );
|
||||
};
|
||||
|
||||
//////////////////
|
||||
// PLPOINTCONSTANT
|
||||
//////////////////
|
||||
// A point source that just keeps handing out the same point
|
||||
class plPointConstant : public plPointChannel
|
||||
{
|
||||
public:
|
||||
plPointConstant();
|
||||
plPointConstant(const hsPoint3 &point);
|
||||
virtual ~plPointConstant();
|
||||
|
||||
void Set(const hsPoint3 &the_Point) { fResult = the_Point; }
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plPointConstant );
|
||||
GETINTERFACE_ANY( plPointConstant, plPointChannel );
|
||||
|
||||
void Read(hsStream *stream, hsResMgr *mgr);
|
||||
void Write(hsStream *stream, hsResMgr *mgr);
|
||||
};
|
||||
|
||||
////////////////////
|
||||
// PLPOINTTIMESCALE
|
||||
////////////////////
|
||||
// Adapts the time scale before passing it to the next channel in line.
|
||||
// Use to instance animations while allowing each instance to run at different speeds.
|
||||
class plPointTimeScale : public plPointChannel
|
||||
{
|
||||
protected:
|
||||
plScalarChannel *fTimeSource;
|
||||
plPointChannel *fChannelIn;
|
||||
|
||||
public:
|
||||
plPointTimeScale();
|
||||
plPointTimeScale(plPointChannel *channel, plScalarChannel *timeSource);
|
||||
virtual ~plPointTimeScale();
|
||||
|
||||
virtual bool IsStoppedAt(double time);
|
||||
virtual const hsPoint3 & Value(double time);
|
||||
|
||||
virtual plAGChannel * Detach(plAGChannel * channel);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plPointTimeScale );
|
||||
GETINTERFACE_ANY( plPointTimeScale, plPointChannel );
|
||||
};
|
||||
|
||||
// PLPOINTBLEND
|
||||
///////////////
|
||||
// Combines two point sources into one
|
||||
class plPointBlend : public plPointChannel
|
||||
{
|
||||
public:
|
||||
plPointBlend();
|
||||
plPointBlend(plPointChannel *channelA, plPointChannel *channelB, plScalarChannel *channelBias);
|
||||
virtual ~plPointBlend();
|
||||
|
||||
plAGChannel * Remove(plAGChannel *srceToRemove);
|
||||
|
||||
const plPointChannel * GetPointChannelA() const { return fPointA; }
|
||||
void SetPointChannelA(plPointChannel *the_PointA) { fPointA = the_PointA; }
|
||||
|
||||
const plPointChannel * GetPointChannelB() const { return fPointB; }
|
||||
void SetPointChannelB(plPointChannel *the_PointB) { fPointB = the_PointB; }
|
||||
|
||||
const plScalarChannel * GetChannelBias() const { return fChannelBias; }
|
||||
void SetChannelBias(plScalarChannel * channel) { fChannelBias = channel; }
|
||||
|
||||
//float GetBlend() const { return fBlend; }
|
||||
//void SetBlend(float the_blend) { fBlend = the_blend; }
|
||||
virtual bool IsStoppedAt(double time);
|
||||
|
||||
// AG PROTOCOL
|
||||
virtual const hsPoint3 &Value(double time);
|
||||
|
||||
// remove the specified channel from our graph
|
||||
virtual plAGChannel * Detach(plAGChannel * channel);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plPointBlend );
|
||||
GETINTERFACE_ANY( plPointBlend, plPointChannel );
|
||||
|
||||
protected:
|
||||
plPointChannel *fPointA;
|
||||
plPointChannel *fPointB;
|
||||
plScalarChannel *fChannelBias;
|
||||
};
|
||||
|
||||
// BLENDPOINTS
|
||||
// Handy little function to share with others.
|
||||
hsPoint3 BlendPoints(hsPoint3 &pointA, hsPoint3 &pointB, float blend);
|
||||
|
||||
|
||||
///////////////////////////
|
||||
// PLPOINTCONTROLLERCHANNEL
|
||||
///////////////////////////
|
||||
|
||||
// converts a plController-style animation into a plPointChannel
|
||||
class plPointControllerChannel : public plPointChannel
|
||||
{
|
||||
protected:
|
||||
plController *fController;
|
||||
|
||||
public:
|
||||
// xTORs
|
||||
plPointControllerChannel();
|
||||
plPointControllerChannel(plController *controller);
|
||||
virtual ~plPointControllerChannel();
|
||||
|
||||
// AG PROTOCOL
|
||||
virtual const hsPoint3 & Value(double time);
|
||||
virtual const hsPoint3 & Value(double time, plControllerCacheInfo *cache);
|
||||
|
||||
virtual plAGChannel * MakeCacheChannel(plAnimTimeConvert *atc);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
// rtti
|
||||
CLASSNAME_REGISTER( plPointControllerChannel );
|
||||
GETINTERFACE_ANY( plPointControllerChannel, plPointChannel );
|
||||
|
||||
// persistence
|
||||
virtual void Write(hsStream *stream, hsResMgr *mgr);
|
||||
virtual void Read(hsStream *s, hsResMgr *mgr);
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
// PLPOINTCONTROLLERCACHECHANNEL
|
||||
////////////////////////////////
|
||||
// Same as plPointController, but with caching info
|
||||
class plPointControllerCacheChannel : public plPointChannel
|
||||
{
|
||||
protected:
|
||||
plControllerCacheInfo *fCache;
|
||||
plPointControllerChannel *fControllerChannel;
|
||||
|
||||
public:
|
||||
plPointControllerCacheChannel();
|
||||
plPointControllerCacheChannel(plPointControllerChannel *channel, plControllerCacheInfo *cache);
|
||||
virtual ~plPointControllerCacheChannel();
|
||||
|
||||
virtual const hsPoint3 & Value(double time, bool peek = false);
|
||||
|
||||
virtual plAGChannel * Detach(plAGChannel * channel);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plPointControllerCacheChannel );
|
||||
GETINTERFACE_ANY( plPointControllerCacheChannel, plPointChannel );
|
||||
|
||||
// Created at runtime only, so no Read/Write
|
||||
};
|
||||
|
||||
////////////////////////////
|
||||
//
|
||||
// Channel Applicator classes
|
||||
|
||||
class plPointChannelApplicator : public plAGApplicator
|
||||
{
|
||||
protected:
|
||||
virtual void IApply(const plAGModifier *mod, double time);
|
||||
|
||||
public:
|
||||
CLASSNAME_REGISTER( plPointChannelApplicator );
|
||||
GETINTERFACE_ANY( plPointChannelApplicator, plAGApplicator );
|
||||
};
|
||||
|
||||
class plLightDiffuseApplicator : public plAGApplicator
|
||||
{
|
||||
protected:
|
||||
virtual void IApply(const plAGModifier *mod, double time);
|
||||
|
||||
public:
|
||||
CLASSNAME_REGISTER( plLightDiffuseApplicator );
|
||||
GETINTERFACE_ANY( plLightDiffuseApplicator, plAGApplicator );
|
||||
};
|
||||
|
||||
class plLightAmbientApplicator : public plAGApplicator
|
||||
{
|
||||
protected:
|
||||
virtual void IApply(const plAGModifier *mod, double time);
|
||||
|
||||
public:
|
||||
CLASSNAME_REGISTER( plLightAmbientApplicator );
|
||||
GETINTERFACE_ANY( plLightAmbientApplicator, plAGApplicator );
|
||||
};
|
||||
|
||||
class plLightSpecularApplicator : public plAGApplicator
|
||||
{
|
||||
protected:
|
||||
virtual void IApply(const plAGModifier *mod, double time);
|
||||
|
||||
public:
|
||||
CLASSNAME_REGISTER( plLightSpecularApplicator );
|
||||
GETINTERFACE_ANY( plLightSpecularApplicator, plAGApplicator );
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // PLPOINTCHANNEL_H
|
326
Sources/Plasma/PubUtilLib/plAnimation/plQuatChannel.cpp
Normal file
326
Sources/Plasma/PubUtilLib/plAnimation/plQuatChannel.cpp
Normal file
@ -0,0 +1,326 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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 "plQuatChannel.h"
|
||||
#include "plPointChannel.h"
|
||||
#include "plMatrixChannel.h"
|
||||
|
||||
#include "pnSceneObject/plDrawInterface.h"
|
||||
#include "pnSceneObject/plSimulationInterface.h"
|
||||
#include "pnSceneObject/plCoordinateInterface.h"
|
||||
#include "pnSceneObject/plAudioInterface.h"
|
||||
#include "plInterp/plAnimTimeConvert.h"
|
||||
|
||||
#include "hsMatrix44.h"
|
||||
|
||||
////////////////
|
||||
// PLQUATCHANNEL
|
||||
////////////////
|
||||
|
||||
// CTOR
|
||||
plQuatChannel::plQuatChannel()
|
||||
: plAGChannel()
|
||||
{
|
||||
fResult.Identity();
|
||||
}
|
||||
|
||||
// DTOR
|
||||
plQuatChannel::~plQuatChannel()
|
||||
{
|
||||
}
|
||||
|
||||
// VALUE (time)
|
||||
const hsQuat &plQuatChannel::Value(double time)
|
||||
{
|
||||
return fResult;
|
||||
}
|
||||
|
||||
// VALUE (quaternion, time)
|
||||
void plQuatChannel::Value(hsQuat &quat, double time)
|
||||
{
|
||||
quat = Value(time);
|
||||
}
|
||||
|
||||
// CANCOMBINE
|
||||
bool plQuatChannel::CanCombine(plAGChannel *channelA)
|
||||
{
|
||||
if(plPointChannel::ConvertNoRef(channelA))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
// MAKECOMBINE
|
||||
plAGChannel * plQuatChannel::MakeCombine(plAGChannel *channelA)
|
||||
{
|
||||
plPointChannel* channel = plPointChannel::ConvertNoRef(channelA);
|
||||
if(channel)
|
||||
return new plQuatPointCombine(this, channel);
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// MAKEBLEND
|
||||
plAGChannel *plQuatChannel::MakeBlend(plAGChannel *channelB, plScalarChannel *channelBias, int blendPriority)
|
||||
{
|
||||
plQuatChannel *chanB = plQuatChannel::ConvertNoRef(channelB);
|
||||
plScalarChannel *chanBias = plScalarChannel::ConvertNoRef(channelBias);
|
||||
if(chanB && chanBias)
|
||||
{
|
||||
return new plQuatBlend(this, chanB, chanBias);
|
||||
} else {
|
||||
hsStatusMessageF("Blend operation failed.");
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
// MAKEZEROSTATE
|
||||
plAGChannel * plQuatChannel::MakeZeroState()
|
||||
{
|
||||
return new plQuatConstant(Value(0));
|
||||
}
|
||||
|
||||
// MAKETIMESCALE
|
||||
plAGChannel * plQuatChannel::MakeTimeScale(plScalarChannel *timeSource)
|
||||
{
|
||||
return new plQuatTimeScale(this, timeSource);
|
||||
}
|
||||
|
||||
/////////////////
|
||||
// PLQUATCONSTANT
|
||||
/////////////////
|
||||
|
||||
// CTOR
|
||||
plQuatConstant::plQuatConstant()
|
||||
: plQuatChannel()
|
||||
{
|
||||
}
|
||||
|
||||
// CTOR(name, quaternion)
|
||||
plQuatConstant::plQuatConstant(const hsQuat &quaternion)
|
||||
{
|
||||
fResult = quaternion;
|
||||
}
|
||||
|
||||
// DTOR
|
||||
plQuatConstant::~plQuatConstant()
|
||||
{
|
||||
}
|
||||
|
||||
void plQuatConstant::Read(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plQuatChannel::Read(stream, mgr);
|
||||
fResult.Read(stream);
|
||||
}
|
||||
|
||||
void plQuatConstant::Write(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plQuatChannel::Write(stream, mgr);
|
||||
fResult.Write(stream);
|
||||
}
|
||||
|
||||
////////////////////
|
||||
// PLQUATTIMESCALE
|
||||
////////////////////
|
||||
// Insert into the graph when you need to change the speed or direction of time
|
||||
// Also serves as a handy instancing node, since it just passes its data through.
|
||||
|
||||
// CTOR
|
||||
plQuatTimeScale::plQuatTimeScale()
|
||||
: fTimeSource(nil),
|
||||
fChannelIn(nil)
|
||||
{
|
||||
}
|
||||
|
||||
// CTOR (channel, converter)
|
||||
plQuatTimeScale::plQuatTimeScale(plQuatChannel *channel, plScalarChannel *timeSource)
|
||||
: fChannelIn(channel),
|
||||
fTimeSource(timeSource)
|
||||
{
|
||||
}
|
||||
|
||||
// DTOR
|
||||
plQuatTimeScale::~plQuatTimeScale()
|
||||
{
|
||||
}
|
||||
|
||||
bool plQuatTimeScale::IsStoppedAt(double time)
|
||||
{
|
||||
return fTimeSource->IsStoppedAt(time);
|
||||
}
|
||||
|
||||
// VALUE
|
||||
const hsQuat & plQuatTimeScale::Value(double time)
|
||||
{
|
||||
fResult = fChannelIn->Value(fTimeSource->Value(time));
|
||||
|
||||
return fResult;
|
||||
}
|
||||
|
||||
// DETACH
|
||||
plAGChannel * plQuatTimeScale::Detach(plAGChannel * channel)
|
||||
{
|
||||
plAGChannel *result = this;
|
||||
|
||||
fChannelIn = plQuatChannel::ConvertNoRef(fChannelIn->Detach(channel));
|
||||
|
||||
if(!fChannelIn || channel == this)
|
||||
result = nil;
|
||||
|
||||
if (result != this)
|
||||
delete this;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//////////////
|
||||
// PLQUATBLEND
|
||||
//////////////
|
||||
|
||||
// CTOR
|
||||
plQuatBlend::plQuatBlend()
|
||||
: fQuatA(nil),
|
||||
fQuatB(nil),
|
||||
fChannelBias(nil)
|
||||
{
|
||||
}
|
||||
|
||||
// CTOR(channelA, channelB, blend)
|
||||
plQuatBlend::plQuatBlend(plQuatChannel *channelA, plQuatChannel *channelB, plScalarChannel *channelBias)
|
||||
: fQuatA(channelA),
|
||||
fQuatB(channelB),
|
||||
fChannelBias(channelBias)
|
||||
{
|
||||
}
|
||||
|
||||
// DTOR
|
||||
plQuatBlend::~plQuatBlend()
|
||||
{
|
||||
//if (fQuatA) delete fQuatA;
|
||||
//if (fQuatB) delete fQuatB;
|
||||
fQuatA = fQuatB = nil;
|
||||
fChannelBias = nil;
|
||||
}
|
||||
|
||||
bool plQuatBlend::IsStoppedAt(double time)
|
||||
{
|
||||
float blend = fChannelBias->Value(time);
|
||||
if (blend == 0)
|
||||
return fQuatA->IsStoppedAt(time);
|
||||
if (blend == 1)
|
||||
return fQuatB->IsStoppedAt(time);
|
||||
|
||||
return (fQuatA->IsStoppedAt(time) && fQuatB->IsStoppedAt(time));
|
||||
}
|
||||
|
||||
// VALUE(time)
|
||||
const hsQuat &plQuatBlend::Value(double time)
|
||||
{
|
||||
hsQuat quatA = fQuatA->Value(time);
|
||||
hsQuat quatB = fQuatB->Value(time);
|
||||
|
||||
fResult.SetFromSlerp(quatA, quatB, fChannelBias->Value(time));
|
||||
|
||||
return fResult;
|
||||
}
|
||||
|
||||
|
||||
// REMOVE
|
||||
// Remove the given channel wherever it may be in the graph (including this node)
|
||||
plAGChannel * plQuatBlend::Detach(plAGChannel *remove)
|
||||
{
|
||||
plAGChannel *result = this;
|
||||
|
||||
hsAssert(remove != this, "Cannot remove blenders explicitly. Remove blended source instead.");
|
||||
|
||||
if (remove != this)
|
||||
{
|
||||
fChannelBias = plScalarChannel::ConvertNoRef(fChannelBias->Detach(remove));
|
||||
if (!fChannelBias)
|
||||
{
|
||||
// No more bias channel, assume it's zero from now on, (a.k.a. We just want channelA)
|
||||
result = fQuatA;
|
||||
}
|
||||
else
|
||||
{
|
||||
fQuatA = (plQuatChannel *)fQuatA->Detach(remove);
|
||||
if(fQuatA)
|
||||
{
|
||||
// channel a still here(although children may be gone); try channel b
|
||||
fQuatB = (plQuatChannel *)fQuatB->Detach(remove);
|
||||
|
||||
if(!fQuatB)
|
||||
{
|
||||
result = fQuatA; // channel b is gone: return channel a as blender's replacement
|
||||
}
|
||||
} else {
|
||||
result = fQuatB; // channel a is gone: return channel b
|
||||
}
|
||||
|
||||
if (result != this)
|
||||
{
|
||||
delete this; // lost one of our channels: kill the blender.
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// Applicators
|
||||
|
||||
void plQuatChannelApplicator::IApply(const plAGModifier *mod, double time)
|
||||
{
|
||||
plQuatChannel *quatChan = plQuatChannel::ConvertNoRef(fChannel);
|
||||
hsAssert(quatChan, "Invalid channel in plQuatChannelApplicator");
|
||||
|
||||
const hsQuat &rotate = quatChan->Value(time);
|
||||
|
||||
plCoordinateInterface *CI = IGetCI(mod);
|
||||
|
||||
hsMatrix44 l2w;
|
||||
hsMatrix44 w2l;
|
||||
|
||||
rotate.MakeMatrix(&l2w);
|
||||
l2w.GetInverse(&w2l);
|
||||
|
||||
CI->SetLocalToParent(l2w, w2l);
|
||||
}
|
187
Sources/Plasma/PubUtilLib/plAnimation/plQuatChannel.h
Normal file
187
Sources/Plasma/PubUtilLib/plAnimation/plQuatChannel.h
Normal file
@ -0,0 +1,187 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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==*/
|
||||
#ifndef PLQUATCHANNEL_INC
|
||||
#define PLQUATCHANNEL_INC
|
||||
|
||||
#include "hsQuat.h"
|
||||
|
||||
#include "plAGChannel.h"
|
||||
#include "plAGApplicator.h"
|
||||
|
||||
// PLQUATCHANNEL
|
||||
/////////////
|
||||
// A source of animated hsQuat data
|
||||
class plQuatChannel : public plAGChannel
|
||||
{
|
||||
protected:
|
||||
hsQuat fResult;
|
||||
|
||||
public:
|
||||
plQuatChannel();
|
||||
virtual ~plQuatChannel();
|
||||
|
||||
// AG PROTOCOL
|
||||
virtual const hsQuat & Value(double time);
|
||||
virtual void Value(hsQuat &quaternion, double time);
|
||||
|
||||
// can this channel combine with the given channel?
|
||||
virtual bool CanCombine(plAGChannel * channelB);
|
||||
// combine it (allocates combine object)
|
||||
virtual plAGChannel * MakeCombine(plAGChannel * channelB);
|
||||
|
||||
// const eval at time zero
|
||||
virtual plAGChannel * MakeZeroState();
|
||||
// make a timeScale instance
|
||||
virtual plAGChannel * MakeTimeScale(plScalarChannel *timeSource);
|
||||
|
||||
// blend it (allocates blend object)
|
||||
virtual plAGChannel * MakeBlend(plAGChannel * channelB, plScalarChannel * channelBias, int blendPriority);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plQuatChannel );
|
||||
GETINTERFACE_ANY( plQuatChannel, plAGChannel );
|
||||
};
|
||||
|
||||
// PLQUATCONSTANT
|
||||
////////////
|
||||
// A quat channel that just keeps handing out the same quaternion
|
||||
class plQuatConstant : public plQuatChannel
|
||||
{
|
||||
public:
|
||||
plQuatConstant();
|
||||
plQuatConstant(const hsQuat &quaternion);
|
||||
virtual ~plQuatConstant();
|
||||
|
||||
void Set(const hsQuat &the_Quat) { fResult = the_Quat; }
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plQuatConstant );
|
||||
GETINTERFACE_ANY( plQuatConstant, plQuatChannel );
|
||||
|
||||
void Read(hsStream *stream, hsResMgr *mgr);
|
||||
void Write(hsStream *stream, hsResMgr *mgr);
|
||||
};
|
||||
|
||||
////////////////////
|
||||
// PLQUATTIMESCALE
|
||||
////////////////////
|
||||
// Adapts the time scale before passing it to the next channel in line.
|
||||
// Use to instance animations while allowing each instance to run at different speeds.
|
||||
class plQuatTimeScale : public plQuatChannel
|
||||
{
|
||||
protected:
|
||||
plScalarChannel *fTimeSource;
|
||||
plQuatChannel *fChannelIn;
|
||||
|
||||
public:
|
||||
plQuatTimeScale();
|
||||
plQuatTimeScale(plQuatChannel *channel, plScalarChannel *timeSource);
|
||||
virtual ~plQuatTimeScale();
|
||||
|
||||
virtual bool IsStoppedAt(double time);
|
||||
virtual const hsQuat & Value(double time);
|
||||
|
||||
virtual plAGChannel * Detach(plAGChannel * channel);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plQuatTimeScale );
|
||||
GETINTERFACE_ANY( plQuatTimeScale, plQuatChannel );
|
||||
};
|
||||
|
||||
// PLQUATBLEND
|
||||
//////////////
|
||||
// Combines two quaternion sources into one
|
||||
class plQuatBlend : public plQuatChannel
|
||||
{
|
||||
public:
|
||||
plQuatBlend();
|
||||
plQuatBlend(plQuatChannel *channelA, plQuatChannel *channelB, plScalarChannel *channelBias);
|
||||
virtual ~plQuatBlend();
|
||||
|
||||
// GETTERS AND SETTERS FOR CHANNELS
|
||||
const plQuatChannel * GetQuatA() const { return fQuatA; }
|
||||
void SetQuatA(plQuatChannel *the_QuatA) { fQuatA = the_QuatA; }
|
||||
|
||||
const plQuatChannel * GetQuatB() const { return fQuatB; }
|
||||
void SetQuatB(plQuatChannel *the_QuatB) { fQuatB = the_QuatB; }
|
||||
|
||||
const plScalarChannel * GetChannelBias() const { return fChannelBias; }
|
||||
void SetChannelBias(plScalarChannel *channel) { fChannelBias = channel; }
|
||||
|
||||
//float GetBlend() const { return fBlend; }
|
||||
//void SetBlend(float the_blend) { fBlend = the_blend; }
|
||||
virtual bool IsStoppedAt(double time);
|
||||
|
||||
// AG PROTOCOL
|
||||
virtual const hsQuat &Value(double time);
|
||||
|
||||
// remove the specified channel from our graph
|
||||
virtual plAGChannel * Detach(plAGChannel * channel);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plQuatBlend );
|
||||
GETINTERFACE_ANY( plQuatBlend, plQuatChannel );
|
||||
|
||||
protected:
|
||||
plQuatChannel *fQuatA;
|
||||
plQuatChannel *fQuatB;
|
||||
plScalarChannel *fChannelBias;
|
||||
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////
|
||||
//
|
||||
// Channel Applicator classes
|
||||
|
||||
class plQuatChannelApplicator : public plAGApplicator
|
||||
{
|
||||
protected:
|
||||
virtual void IApply(const plAGModifier *mod, double time);
|
||||
|
||||
public:
|
||||
CLASSNAME_REGISTER( plQuatChannelApplicator );
|
||||
GETINTERFACE_ANY( plQuatChannelApplicator, plAGApplicator );
|
||||
};
|
||||
|
||||
|
||||
#endif // PLQUATCHANNEL_INC
|
606
Sources/Plasma/PubUtilLib/plAnimation/plScalarChannel.cpp
Normal file
606
Sources/Plasma/PubUtilLib/plAnimation/plScalarChannel.cpp
Normal file
@ -0,0 +1,606 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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==*/
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDES
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// singular
|
||||
#include "plScalarChannel.h"
|
||||
|
||||
// global
|
||||
#include "hsResMgr.h"
|
||||
|
||||
// other
|
||||
#include "plGLight/plLightInfo.h"
|
||||
#include "plInterp/plController.h"
|
||||
#include "plInterp/plAnimTimeConvert.h"
|
||||
#include "plSDL/plSDL.h"
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// plScalarChannel
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ctor --------------------------
|
||||
// -----
|
||||
plScalarChannel::plScalarChannel()
|
||||
: plAGChannel()
|
||||
{
|
||||
}
|
||||
|
||||
// dtor ---------------------------
|
||||
// -----
|
||||
plScalarChannel::~plScalarChannel()
|
||||
{
|
||||
}
|
||||
|
||||
// value --------------------------------------------------------
|
||||
// ------
|
||||
const float & plScalarChannel::Value(double time, bool peek)
|
||||
{
|
||||
return fResult;
|
||||
}
|
||||
|
||||
// value --------------------------------------------------------------
|
||||
// ------
|
||||
void plScalarChannel::Value(float &scalar, double time, bool peek)
|
||||
{
|
||||
scalar = Value(time, peek);
|
||||
}
|
||||
|
||||
// MakeCombine -----------------------------------------------
|
||||
// ------------
|
||||
plAGChannel * plScalarChannel::MakeCombine(plAGChannel *other)
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
// MakeBlend ---------------------------------------------------
|
||||
// ----------
|
||||
plAGChannel * plScalarChannel::MakeBlend(plAGChannel * channelB,
|
||||
plScalarChannel * channelBias,
|
||||
int blendPriority)
|
||||
{
|
||||
plScalarChannel * chanB = plScalarChannel::ConvertNoRef(channelB);
|
||||
plScalarChannel * chanBias = plScalarChannel::ConvertNoRef(channelBias);
|
||||
plAGChannel * result = this;
|
||||
|
||||
if (chanB)
|
||||
{
|
||||
result = new plScalarBlend(this, chanB, chanBias);
|
||||
} else {
|
||||
hsStatusMessage("Blend operation failed.");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// MakeZeroState -----------------------------
|
||||
// --------------
|
||||
plAGChannel * plScalarChannel::MakeZeroState()
|
||||
{
|
||||
return new plScalarConstant(Value(0));
|
||||
}
|
||||
|
||||
// MakeTimeScale --------------------------------------------------------
|
||||
// --------------
|
||||
plAGChannel * plScalarChannel::MakeTimeScale(plScalarChannel *timeSource)
|
||||
{
|
||||
return new plScalarTimeScale(this, timeSource);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// plScalarConstant
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ctor ----------------------------
|
||||
// -----
|
||||
plScalarConstant::plScalarConstant()
|
||||
{
|
||||
}
|
||||
|
||||
// ctor ------------------------------------------
|
||||
// -----
|
||||
plScalarConstant::plScalarConstant(float value)
|
||||
{
|
||||
fResult = value;
|
||||
}
|
||||
|
||||
// dtor -----------------------------
|
||||
// -----
|
||||
plScalarConstant::~plScalarConstant()
|
||||
{
|
||||
}
|
||||
|
||||
void plScalarConstant::Read(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plScalarChannel::Read(stream, mgr);
|
||||
fResult = stream->ReadLEScalar();
|
||||
}
|
||||
|
||||
void plScalarConstant::Write(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plScalarChannel::Write(stream, mgr);
|
||||
stream->WriteLEScalar(fResult);
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////
|
||||
// PLSCALARTIMESCALE
|
||||
////////////////////
|
||||
// Insert into the graph when you need to change the speed or direction of time
|
||||
// Also serves as a handy instancing node, since it just passes its data through.
|
||||
|
||||
// CTOR
|
||||
plScalarTimeScale::plScalarTimeScale()
|
||||
: fTimeSource(nil),
|
||||
fChannelIn(nil)
|
||||
{
|
||||
}
|
||||
|
||||
// CTOR (channel, converter)
|
||||
plScalarTimeScale::plScalarTimeScale(plScalarChannel *channel, plScalarChannel *timeSource)
|
||||
: fChannelIn(channel),
|
||||
fTimeSource(timeSource)
|
||||
{
|
||||
}
|
||||
|
||||
// DTOR
|
||||
plScalarTimeScale::~plScalarTimeScale()
|
||||
{
|
||||
}
|
||||
|
||||
bool plScalarTimeScale::IsStoppedAt(double time)
|
||||
{
|
||||
return fTimeSource->IsStoppedAt(time);
|
||||
}
|
||||
|
||||
// VALUE
|
||||
const float & plScalarTimeScale::Value(double time, bool peek)
|
||||
{
|
||||
fResult = fChannelIn->Value(fTimeSource->Value(time, peek));
|
||||
|
||||
return fResult;
|
||||
}
|
||||
|
||||
// DETACH
|
||||
plAGChannel * plScalarTimeScale::Detach(plAGChannel * detach)
|
||||
{
|
||||
plAGChannel *result = this;
|
||||
|
||||
fChannelIn = plScalarChannel::ConvertNoRef(fChannelIn->Detach(detach));
|
||||
|
||||
if(!fChannelIn || detach == this)
|
||||
result = nil;
|
||||
|
||||
if(result != this)
|
||||
delete this;
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// plScalarBlend
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ctor ----------------------
|
||||
// -----
|
||||
plScalarBlend::plScalarBlend()
|
||||
: fChannelA(nil),
|
||||
fChannelB(nil),
|
||||
fChannelBias(nil)
|
||||
{
|
||||
}
|
||||
|
||||
// ctor ----------------------------------------------------------------------------
|
||||
// -----
|
||||
plScalarBlend::plScalarBlend(plScalarChannel * channelA, plScalarChannel * channelB,
|
||||
plScalarChannel * channelBias)
|
||||
: fChannelA(channelA),
|
||||
fChannelB(channelB),
|
||||
fChannelBias(channelBias)
|
||||
{
|
||||
}
|
||||
|
||||
// dtor -----------------------
|
||||
// -----
|
||||
plScalarBlend::~plScalarBlend()
|
||||
{
|
||||
fChannelA = nil;
|
||||
fChannelB = nil;
|
||||
fChannelBias = nil;
|
||||
}
|
||||
|
||||
// IsStoppedAt -------------------------------
|
||||
// ------------
|
||||
bool plScalarBlend::IsStoppedAt(double time)
|
||||
{
|
||||
float blend = fChannelBias->Value(time);
|
||||
if (blend == 0)
|
||||
return fChannelA->IsStoppedAt(time);
|
||||
if (blend == 1)
|
||||
return fChannelB->IsStoppedAt(time);
|
||||
|
||||
return (fChannelA->IsStoppedAt(time) && fChannelB->IsStoppedAt(time));
|
||||
}
|
||||
|
||||
// Value ------------------------------------------------------
|
||||
// ------
|
||||
const float & plScalarBlend::Value(double time, bool peek)
|
||||
{
|
||||
float curBlend = fChannelBias->Value(time, peek);
|
||||
if(curBlend == 0) {
|
||||
fChannelA->Value(fResult, time, peek);
|
||||
} else {
|
||||
if(curBlend == 1) {
|
||||
fChannelB->Value(fResult, time, peek);
|
||||
} else {
|
||||
const float &scalarA = fChannelA->Value(time, peek);
|
||||
const float &scalarB = fChannelB->Value(time, peek);
|
||||
fResult = scalarA + curBlend * (scalarB - scalarA);
|
||||
}
|
||||
}
|
||||
return fResult;
|
||||
}
|
||||
|
||||
|
||||
// Detach ----------------------------------------------
|
||||
// -------
|
||||
plAGChannel * plScalarBlend::Detach(plAGChannel *remove)
|
||||
{
|
||||
plAGChannel *result = this;
|
||||
|
||||
// it's possible that the incoming channel could reside down *all* of our
|
||||
// branches (it's a graph, not a tree,) so we always pass down all limbs
|
||||
fChannelBias = plScalarChannel::ConvertNoRef(fChannelBias->Detach(remove));
|
||||
fChannelA = plScalarChannel::ConvertNoRef(fChannelA->Detach(remove));
|
||||
fChannelB = plScalarChannel::ConvertNoRef(fChannelB->Detach(remove));
|
||||
|
||||
if(!fChannelBias)
|
||||
result = fChannelA;
|
||||
else if(fChannelA && !fChannelB)
|
||||
result = fChannelA;
|
||||
else if(fChannelB && !fChannelA)
|
||||
result = fChannelB;
|
||||
else if(!fChannelA && !fChannelB)
|
||||
result = nil;
|
||||
|
||||
if(result != this)
|
||||
delete this;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PLSCALARCONTROLLERCHANNEL
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ctor ----------------------------------------------
|
||||
// -----
|
||||
plScalarControllerChannel::plScalarControllerChannel()
|
||||
: fController(nil)
|
||||
{
|
||||
}
|
||||
|
||||
// ctor ----------------------------------------------------------------------------
|
||||
// -----
|
||||
plScalarControllerChannel::plScalarControllerChannel(plController *controller)
|
||||
: fController(controller)
|
||||
{
|
||||
}
|
||||
|
||||
// dtor -----------------------------------------------
|
||||
// -----
|
||||
plScalarControllerChannel::~plScalarControllerChannel()
|
||||
{
|
||||
if(fController) {
|
||||
delete fController;
|
||||
fController = nil;
|
||||
}
|
||||
}
|
||||
|
||||
// Value ------------------------------------------------------------------
|
||||
// ------
|
||||
const float & plScalarControllerChannel::Value(double time, bool peek)
|
||||
{
|
||||
return Value(time, peek, nil);
|
||||
}
|
||||
|
||||
// Value ------------------------------------------------------------------
|
||||
// ------
|
||||
const float & plScalarControllerChannel::Value(double time, bool peek,
|
||||
plControllerCacheInfo *cache)
|
||||
{
|
||||
fController->Interp((float)time, &fResult, cache);
|
||||
return fResult;
|
||||
}
|
||||
|
||||
// MakeCacheChannel ------------------------------------------------------------
|
||||
// -----------------
|
||||
plAGChannel *plScalarControllerChannel::MakeCacheChannel(plAnimTimeConvert *atc)
|
||||
{
|
||||
plControllerCacheInfo *cache = fController->CreateCache();
|
||||
cache->SetATC(atc);
|
||||
return new plScalarControllerCacheChannel(this, cache);
|
||||
}
|
||||
|
||||
// Write -------------------------------------------------------------
|
||||
// ------
|
||||
void plScalarControllerChannel::Write(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plScalarChannel::Write(stream, mgr);
|
||||
|
||||
hsAssert(fController, "Trying to write plScalarControllerChannel with nil controller. File will not be importable.");
|
||||
mgr->WriteCreatable(stream, fController);
|
||||
}
|
||||
|
||||
// Read -------------------------------------------------------------
|
||||
// -----
|
||||
void plScalarControllerChannel::Read(hsStream *stream, hsResMgr *mgr)
|
||||
{
|
||||
plScalarChannel::Read(stream, mgr);
|
||||
|
||||
fController = plController::ConvertNoRef(mgr->ReadCreatable(stream));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PLSCALARCONTROLLERCACHECHANNEL
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ctor --------------------------------------------------------
|
||||
// -----
|
||||
plScalarControllerCacheChannel::plScalarControllerCacheChannel()
|
||||
: fControllerChannel(nil),
|
||||
fCache(nil)
|
||||
{
|
||||
}
|
||||
|
||||
// ctor ---------------------------------------------------------------------------------------------
|
||||
// -----
|
||||
plScalarControllerCacheChannel::plScalarControllerCacheChannel(plScalarControllerChannel *controller,
|
||||
plControllerCacheInfo *cache)
|
||||
: fControllerChannel(controller),
|
||||
fCache(cache)
|
||||
{
|
||||
}
|
||||
|
||||
// dtor ---------------------------------------------------------
|
||||
// -----
|
||||
plScalarControllerCacheChannel::~plScalarControllerCacheChannel()
|
||||
{
|
||||
delete fCache;
|
||||
fControllerChannel = nil;
|
||||
}
|
||||
|
||||
// Value ---------------------------------------------------------------------
|
||||
// ------
|
||||
const float & plScalarControllerCacheChannel::Value(double time, bool peek)
|
||||
{
|
||||
return fControllerChannel->Value(time, peek, fCache);
|
||||
}
|
||||
|
||||
// Detach -----------------------------------------------------------------
|
||||
// -------
|
||||
plAGChannel * plScalarControllerCacheChannel::Detach(plAGChannel * channel)
|
||||
{
|
||||
plAGChannel *result = this;
|
||||
|
||||
if(channel == this)
|
||||
{
|
||||
result = nil;
|
||||
} else {
|
||||
fControllerChannel = plScalarControllerChannel::ConvertNoRef(fControllerChannel->Detach(channel));
|
||||
|
||||
if(!fControllerChannel)
|
||||
result = nil;
|
||||
}
|
||||
if(result != this)
|
||||
delete this;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PLATCCHANNEL
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ctor --------------------
|
||||
plATCChannel::plATCChannel()
|
||||
: fConvert(nil)
|
||||
{
|
||||
}
|
||||
|
||||
// ctor ----------------------------------------------
|
||||
plATCChannel::plATCChannel(plAnimTimeConvert *convert)
|
||||
: fConvert(convert)
|
||||
{
|
||||
}
|
||||
|
||||
// dtor ---------------------
|
||||
plATCChannel::~plATCChannel()
|
||||
{
|
||||
}
|
||||
|
||||
// IsStoppedAt ------------------------------
|
||||
// ------------
|
||||
bool plATCChannel::IsStoppedAt(double time)
|
||||
{
|
||||
return fConvert->IsStoppedAt(time);
|
||||
}
|
||||
|
||||
// Value -----------------------------------------------------
|
||||
// ------
|
||||
const float & plATCChannel::Value(double time, bool peek)
|
||||
{
|
||||
fResult = (peek ? fConvert->WorldToAnimTimeNoUpdate(time) : fConvert->WorldToAnimTime(time));
|
||||
return fResult;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PLSCALARSDLCHANNEL
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// ctor --------------------------------
|
||||
// -----
|
||||
plScalarSDLChannel::plScalarSDLChannel()
|
||||
: fLength(1), fVar(nil)
|
||||
{
|
||||
fResult = 0;
|
||||
}
|
||||
|
||||
plScalarSDLChannel::plScalarSDLChannel(float length)
|
||||
: fLength(length), fVar(nil)
|
||||
{
|
||||
fResult = 0;
|
||||
}
|
||||
|
||||
// dtor ---------------------------------
|
||||
plScalarSDLChannel::~plScalarSDLChannel()
|
||||
{
|
||||
}
|
||||
|
||||
// IsStoppedAt ------------------------------------
|
||||
// ------------
|
||||
bool plScalarSDLChannel::IsStoppedAt(double time)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Value -----------------------------------------------------------
|
||||
// ------
|
||||
const float & plScalarSDLChannel::Value(double time, bool peek)
|
||||
{
|
||||
if (fVar)
|
||||
fVar->Get(&fResult);
|
||||
|
||||
// the var will return a 0-1 value, scale to match our anim length.
|
||||
fResult *= fLength;
|
||||
return fResult;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// APPLICATORS
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// IApply ------------------------------------------------------------------
|
||||
// -------
|
||||
void plScalarChannelApplicator::IApply(const plAGModifier *mod, double time)
|
||||
{
|
||||
}
|
||||
|
||||
// IApply --------------------------------------------------------------
|
||||
// -------
|
||||
void plSpotInnerApplicator::IApply(const plAGModifier *mod, double time)
|
||||
{
|
||||
plScalarChannel *scalarChan = plScalarChannel::ConvertNoRef(fChannel);
|
||||
hsAssert(scalarChan, "Invalid channel given to plSpotInnerApplicator");
|
||||
|
||||
plSpotLightInfo *sli = plSpotLightInfo::ConvertNoRef(IGetGI(mod, plSpotLightInfo::Index()));
|
||||
|
||||
const float &scalar = scalarChan->Value(time);
|
||||
sli->SetSpotInner(hsDegreesToRadians(scalar)*0.5f);
|
||||
}
|
||||
|
||||
// IApply --------------------------------------------------------------
|
||||
// -------
|
||||
void plSpotOuterApplicator::IApply(const plAGModifier *mod, double time)
|
||||
{
|
||||
plScalarChannel *scalarChan = plScalarChannel::ConvertNoRef(fChannel);
|
||||
hsAssert(scalarChan, "Invalid channel given to plSpotInnerApplicator");
|
||||
|
||||
plSpotLightInfo *sli = plSpotLightInfo::ConvertNoRef(IGetGI(mod, plSpotLightInfo::Index()));
|
||||
|
||||
const float &scalar = scalarChan->Value(time);
|
||||
sli->SetSpotOuter(hsDegreesToRadians(scalar)*0.5f);
|
||||
}
|
||||
|
||||
|
||||
void plOmniApplicator::IApply(const plAGModifier *modifier, double time)
|
||||
{
|
||||
plScalarChannel *scalarChan = plScalarChannel::ConvertNoRef(fChannel);
|
||||
hsAssert(scalarChan, "Invalid channel given to plLightOmniApplicator");
|
||||
|
||||
plOmniLightInfo *oli = plOmniLightInfo::ConvertNoRef(IGetGI(modifier, plOmniLightInfo::Index()));
|
||||
|
||||
oli->SetLinearAttenuation(scalarChan->Value(time));
|
||||
}
|
||||
|
||||
void plOmniSqApplicator::IApply(const plAGModifier *modifier, double time)
|
||||
{
|
||||
plScalarChannel *scalarChan = plScalarChannel::ConvertNoRef(fChannel);
|
||||
hsAssert(scalarChan, "Invalid channel given to plLightOmniApplicator");
|
||||
|
||||
plOmniLightInfo *oli = plOmniLightInfo::ConvertNoRef(IGetGI(modifier, plOmniLightInfo::Index()));
|
||||
|
||||
oli->SetQuadraticAttenuation(scalarChan->Value(time));
|
||||
}
|
||||
|
||||
void plOmniCutoffApplicator::IApply(const plAGModifier *modifier, double time)
|
||||
{
|
||||
plScalarChannel *scalarChan = plScalarChannel::ConvertNoRef(fChannel);
|
||||
hsAssert(scalarChan, "Invalid channel given to plOmniCutoffApplicator");
|
||||
|
||||
plOmniLightInfo *oli = plOmniLightInfo::ConvertNoRef(IGetGI(modifier, plOmniLightInfo::Index()));
|
||||
|
||||
oli->SetCutoffAttenuation( scalarChan->Value( time ) );
|
||||
}
|
362
Sources/Plasma/PubUtilLib/plAnimation/plScalarChannel.h
Normal file
362
Sources/Plasma/PubUtilLib/plAnimation/plScalarChannel.h
Normal file
@ -0,0 +1,362 @@
|
||||
/*==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/>.
|
||||
|
||||
Additional permissions under GNU GPL version 3 section 7
|
||||
|
||||
If you modify this Program, or any covered work, by linking or
|
||||
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||||
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||||
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||||
(or a modified version of those libraries),
|
||||
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||||
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||||
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||||
licensors of this Program grant you additional
|
||||
permission to convey the resulting work. Corresponding Source for a
|
||||
non-source form of such a combination shall include the source code for
|
||||
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||||
work.
|
||||
|
||||
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==*/
|
||||
#ifndef PLSCALARCHANNEL_INC
|
||||
#define PLSCALARCHANNEL_INC
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// INCLUDES
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// base
|
||||
#include "plAGChannel.h"
|
||||
#include "plAGApplicator.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// FORWARDS
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
class plController;
|
||||
class plAnimTimeConvert;
|
||||
class plSimpleStateVariable;
|
||||
class plControllerCacheInfo;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DEFINITIONS
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//////////////////
|
||||
// PLSCALARCHANNEL
|
||||
//////////////////
|
||||
// an animation channel that outputs a scalar value
|
||||
class plScalarChannel : public plAGChannel
|
||||
{
|
||||
protected:
|
||||
float fResult;
|
||||
|
||||
public:
|
||||
plScalarChannel();
|
||||
virtual ~plScalarChannel();
|
||||
|
||||
// AG PROTOCOL
|
||||
virtual const float & Value(double time, bool peek = false);
|
||||
virtual void Value(float &result, double time, bool peek = false);
|
||||
|
||||
// combine it (allocates combine object)
|
||||
virtual plAGChannel * MakeCombine(plAGChannel * channelB);
|
||||
|
||||
// blend it (allocates blend object)
|
||||
virtual plAGChannel * MakeBlend(plAGChannel * channelB, plScalarChannel * channelBias, int blendPriority);
|
||||
|
||||
// const eval at time zero
|
||||
virtual plAGChannel * MakeZeroState();
|
||||
|
||||
// make a timeScale instance
|
||||
virtual plAGChannel * MakeTimeScale(plScalarChannel *timeSource);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plScalarChannel );
|
||||
GETINTERFACE_ANY( plScalarChannel, plAGChannel );
|
||||
};
|
||||
|
||||
///////////////////
|
||||
// PLSCALARCONSTANT
|
||||
///////////////////
|
||||
// A scalar source that just keeps handing out the same value
|
||||
class plScalarConstant : public plScalarChannel
|
||||
{
|
||||
public:
|
||||
plScalarConstant();
|
||||
plScalarConstant(float value);
|
||||
virtual ~plScalarConstant();
|
||||
|
||||
void Set(float value) { fResult = value; }
|
||||
float Get() { return fResult; }
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plScalarConstant );
|
||||
GETINTERFACE_ANY( plScalarConstant, plScalarChannel );
|
||||
|
||||
void Read(hsStream *stream, hsResMgr *mgr);
|
||||
void Write(hsStream *stream, hsResMgr *mgr);
|
||||
};
|
||||
|
||||
|
||||
////////////////////
|
||||
// PLSCALARTIMESCALE
|
||||
////////////////////
|
||||
// Adapts the time scale before passing it to the next channel in line.
|
||||
// Use to instance animations while allowing each instance to run at different speeds.
|
||||
class plScalarTimeScale : public plScalarChannel
|
||||
{
|
||||
protected:
|
||||
plScalarChannel *fTimeSource;
|
||||
plScalarChannel *fChannelIn;
|
||||
|
||||
public:
|
||||
plScalarTimeScale();
|
||||
plScalarTimeScale(plScalarChannel *channel, plScalarChannel *timeSource);
|
||||
virtual ~plScalarTimeScale();
|
||||
|
||||
virtual bool IsStoppedAt(double time);
|
||||
virtual const float & Value(double time, bool peek = false);
|
||||
virtual plAGChannel * Detach(plAGChannel * channel);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plScalarTimeScale );
|
||||
GETINTERFACE_ANY( plScalarTimeScale, plScalarChannel );
|
||||
};
|
||||
|
||||
////////////////
|
||||
// PLSCALARBLEND
|
||||
////////////////
|
||||
// blends two scalars into one with weighting
|
||||
class plScalarBlend : public plScalarChannel
|
||||
{
|
||||
protected:
|
||||
plScalarChannel * fChannelA;
|
||||
plScalarChannel * fChannelB;
|
||||
plScalarChannel * fChannelBias;
|
||||
|
||||
public:
|
||||
// xTORs
|
||||
plScalarBlend();
|
||||
plScalarBlend(plScalarChannel * channelA, plScalarChannel * channelB, plScalarChannel * channelBias);
|
||||
virtual ~plScalarBlend();
|
||||
|
||||
// SPECIFICS
|
||||
const plScalarChannel * GetChannelA() const { return fChannelA; }
|
||||
void SetChannelA(plScalarChannel * channel) { fChannelA = channel; }
|
||||
|
||||
const plScalarChannel * GetChannelB() const { return fChannelB; }
|
||||
void SetChannelB(plScalarChannel * channel) { fChannelB = channel; }
|
||||
|
||||
const plScalarChannel * GetChannelBias() const { return fChannelBias; }
|
||||
void SetChannelBias(plScalarChannel * channel) { fChannelBias = channel; }
|
||||
|
||||
virtual bool IsStoppedAt(double time);
|
||||
|
||||
// AG PROTOCOL
|
||||
virtual const float & Value(double time, bool peek = false);
|
||||
|
||||
// remove the specified channel from our graph
|
||||
virtual plAGChannel * Detach(plAGChannel * channel);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plScalarBlend );
|
||||
GETINTERFACE_ANY( plScalarBlend, plScalarChannel );
|
||||
};
|
||||
|
||||
////////////////////////////
|
||||
// PLSCALARCONTROLLERCHANNEL
|
||||
////////////////////////////
|
||||
// converts a plController-style animation into a plScalarChannel
|
||||
class plScalarControllerChannel : public plScalarChannel
|
||||
{
|
||||
protected:
|
||||
plController *fController;
|
||||
|
||||
public:
|
||||
// xTORs
|
||||
plScalarControllerChannel();
|
||||
plScalarControllerChannel(plController *controller);
|
||||
virtual ~plScalarControllerChannel();
|
||||
|
||||
// AG PROTOCOL
|
||||
virtual const float & Value(double time, bool peek = false);
|
||||
virtual const float & Value(double time, bool peek, plControllerCacheInfo *cache);
|
||||
|
||||
virtual plAGChannel *MakeCacheChannel(plAnimTimeConvert *atc);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
// rtti
|
||||
CLASSNAME_REGISTER( plScalarControllerChannel );
|
||||
GETINTERFACE_ANY( plScalarControllerChannel, plScalarChannel );
|
||||
|
||||
// persistence
|
||||
virtual void Write(hsStream *stream, hsResMgr *mgr);
|
||||
virtual void Read(hsStream *s, hsResMgr *mgr);
|
||||
};
|
||||
|
||||
/////////////////////////////////
|
||||
// PLSCALARCONTROLLERCACHECHANNEL
|
||||
/////////////////////////////////
|
||||
// Same as plScalarController, but with caching info
|
||||
class plScalarControllerCacheChannel : public plScalarChannel
|
||||
{
|
||||
protected:
|
||||
plControllerCacheInfo *fCache;
|
||||
plScalarControllerChannel *fControllerChannel;
|
||||
|
||||
public:
|
||||
plScalarControllerCacheChannel();
|
||||
plScalarControllerCacheChannel(plScalarControllerChannel *channel, plControllerCacheInfo *cache);
|
||||
virtual ~plScalarControllerCacheChannel();
|
||||
|
||||
virtual const float & Value(double time, bool peek = false);
|
||||
|
||||
virtual plAGChannel * Detach(plAGChannel * channel);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plScalarControllerCacheChannel );
|
||||
GETINTERFACE_ANY( plScalarControllerCacheChannel, plScalarChannel );
|
||||
|
||||
// Created at runtime only, so no Read/Write
|
||||
};
|
||||
|
||||
////////////////////
|
||||
// PLATCChannel
|
||||
////////////////////
|
||||
// Channel interface for a plAnimTimeConvert object
|
||||
class plATCChannel : public plScalarChannel
|
||||
{
|
||||
protected:
|
||||
plAnimTimeConvert *fConvert;
|
||||
|
||||
public:
|
||||
plATCChannel();
|
||||
plATCChannel(plAnimTimeConvert *convert);
|
||||
virtual ~plATCChannel();
|
||||
|
||||
virtual bool IsStoppedAt(double time);
|
||||
virtual const float & Value(double time, bool peek = false);
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plATCChannel );
|
||||
GETINTERFACE_ANY( plATCChannel, plScalarChannel );
|
||||
};
|
||||
|
||||
////////////////////
|
||||
// PLSCALARSDLCHANNEL
|
||||
////////////////////
|
||||
// Returns the value of an SDL scalar variable
|
||||
class plScalarSDLChannel : public plScalarChannel
|
||||
{
|
||||
protected:
|
||||
plSimpleStateVariable *fVar;
|
||||
float fLength;
|
||||
|
||||
public:
|
||||
plScalarSDLChannel();
|
||||
plScalarSDLChannel(float length);
|
||||
virtual ~plScalarSDLChannel();
|
||||
|
||||
virtual bool IsStoppedAt(double time);
|
||||
virtual const float & Value(double time, bool peek = false);
|
||||
|
||||
void SetVar(plSimpleStateVariable *var) { fVar = var; }
|
||||
|
||||
// PLASMA PROTOCOL
|
||||
CLASSNAME_REGISTER( plScalarSDLChannel );
|
||||
GETINTERFACE_ANY( plScalarSDLChannel, plScalarChannel );
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////
|
||||
//
|
||||
// Channel Applicator classes
|
||||
|
||||
class plScalarChannelApplicator : public plAGApplicator
|
||||
{
|
||||
protected:
|
||||
virtual void IApply(const plAGModifier *mod, double time);
|
||||
|
||||
public:
|
||||
CLASSNAME_REGISTER( plScalarChannelApplicator );
|
||||
GETINTERFACE_ANY( plScalarChannelApplicator, plAGApplicator );
|
||||
};
|
||||
|
||||
class plSpotInnerApplicator : public plAGApplicator
|
||||
{
|
||||
protected:
|
||||
virtual void IApply(const plAGModifier *mod, double time);
|
||||
|
||||
public:
|
||||
CLASSNAME_REGISTER( plSpotInnerApplicator );
|
||||
GETINTERFACE_ANY( plSpotInnerApplicator, plAGApplicator );
|
||||
};
|
||||
|
||||
class plSpotOuterApplicator : public plAGApplicator
|
||||
{
|
||||
protected:
|
||||
virtual void IApply(const plAGModifier *mod, double time);
|
||||
|
||||
public:
|
||||
CLASSNAME_REGISTER( plSpotOuterApplicator );
|
||||
GETINTERFACE_ANY( plSpotOuterApplicator, plAGApplicator );
|
||||
};
|
||||
|
||||
class plOmniApplicator : public plAGApplicator
|
||||
{
|
||||
protected:
|
||||
virtual void IApply(const plAGModifier *mod, double time);
|
||||
|
||||
public:
|
||||
CLASSNAME_REGISTER( plOmniApplicator );
|
||||
GETINTERFACE_ANY( plOmniApplicator, plAGApplicator );
|
||||
};
|
||||
|
||||
class plOmniSqApplicator : public plAGApplicator
|
||||
{
|
||||
protected:
|
||||
virtual void IApply(const plAGModifier *mod, double time);
|
||||
|
||||
public:
|
||||
CLASSNAME_REGISTER( plOmniSqApplicator );
|
||||
GETINTERFACE_ANY( plOmniSqApplicator, plAGApplicator );
|
||||
};
|
||||
|
||||
class plOmniCutoffApplicator : public plAGApplicator
|
||||
{
|
||||
protected:
|
||||
virtual void IApply(const plAGModifier *mod, double time);
|
||||
|
||||
public:
|
||||
CLASSNAME_REGISTER( plOmniCutoffApplicator );
|
||||
GETINTERFACE_ANY( plOmniCutoffApplicator, plAGApplicator );
|
||||
};
|
||||
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user