You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

766 lines
19 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
/////////////////////////////////////////////////////////////////////////////////////////
//
// INCLUDES
//
/////////////////////////////////////////////////////////////////////////////////////////
// singular
#include "plAGAnim.h"
// local
#include "plMatrixChannel.h"
// global
#include "hsResMgr.h"
// other
#include "plMessage/plAnimCmdMsg.h"
/////////////////////////////////////////////////////////////////////////////////////////
//
// STATICS
//
/////////////////////////////////////////////////////////////////////////////////////////
plAGAnim::plAnimMap plAGAnim::fAllAnims;
/////////////////////////////////////////////////////////////////////////////////////////
//
// plAGAnim
//
/////////////////////////////////////////////////////////////////////////////////////////
// ctor ------------
// -----
plAGAnim::plAGAnim()
: plSynchedObject()
{
fName = nil;
}
// ctor ------------------------------------------------------
// -----
plAGAnim::plAGAnim(const char *name, double start, double end)
: fStart((hsScalar)start),
fEnd((hsScalar)end)
{
if (name == nil)
name = "";
fName = TRACKED_NEW char[strlen(name) + 1];
strcpy(fName, name);
}
// dtor -------------
// -----
plAGAnim::~plAGAnim()
{
if (fName)
{
RemoveAnim(fName);
delete[] fName;
fName = nil;
}
//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 char *name) const
{
int appCount = fApps.size();
for(int i = 0; i < appCount; i++)
{
plAGApplicator *app = fApps[i];
plAGChannel *channel = app->GetChannel();
const char *channelName = app->GetChannelName();
if(stricmp(name, channelName) == 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 ------------------------
// -----------------
hsBool 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(hsScalar length)
{
if (length > GetEnd())
SetEnd(length);
}
// GetChannelName ------------------------------
// ---------------
const char * 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 nil;
}
}
// 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->ReadSwapScalar();
fEnd = stream->ReadSwapScalar();
int numApps = stream->ReadSwap32();
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->WriteSwapScalar(fStart);
stream->WriteSwapScalar(fEnd);
int numApps = fApps.size();
stream->WriteSwap32(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 char * name, plAGAnim *anim)
{
// Only register the animation if it's got a "real" name. Unnamed animations
// all get the same standard name.
if(strcmp(name, ENTIRE_ANIMATION_NAME) != 0)
{
hsAssert(anim, "registering nil anim");
fAllAnims[name] = anim;
}
}
// FindAnim -----------------------------------
// ---------
plAGAnim * plAGAnim::FindAnim(const char *name)
{
plAnimMap::iterator i = fAllAnims.find(name);
if(i != fAllAnims.end())
{
return (*i).second;
} else {
return nil;
}
}
// RemoveAnim -------------------------------
// -----------
hsBool plAGAnim::RemoveAnim(const char *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;
const char *name = anim->GetName();
hsStatusMessageF("GLOBAL ANIMS [%d]: <%s>", j++, name);
} while(++i != fAllAnims.end());
}
// SharesPinsWith -----------------------------------------
// ---------------
hsBool 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 (!strcmp(fApps[i]->GetChannelName(), anim->fApps[j]->GetChannelName()) &&
fApps[i]->CanBlend(anim->fApps[j]))
{
return true;
}
}
}
return false;
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// plATCAnim
//
/////////////////////////////////////////////////////////////////////////////////////////
// ctor --------------
// -----
plATCAnim::plATCAnim()
: plAGAnim()
{
}
// ctor --------------------------------------------------------
// -----
plATCAnim::plATCAnim(const char *name, double start, double end)
: plAGAnim(name, start, end),
fInitial(-1),
fAutoStart(true),
fLoopStart((hsScalar)start),
fLoopEnd((hsScalar)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()
{
for (MarkerMap::iterator it = fMarkers.begin(); it != fMarkers.end(); it++)
delete [] (char*)it->first;
fMarkers.clear();
for( LoopMap::iterator it2 = fLoops.begin(); it2 != fLoops.end(); it2++ )
delete [] (char *)it2->first;
fLoops.clear();
fStopPoints.clear();
}
// Read ---------------------------------------------
// -----
void plATCAnim::Read(hsStream *stream, hsResMgr *mgr)
{
plAGAnim::Read(stream, mgr);
fInitial = stream->ReadSwapScalar();
fAutoStart = stream->Readbool();
fLoopStart = stream->ReadSwapScalar();
fLoopEnd = stream->ReadSwapScalar();
fLoop = stream->Readbool();
fEaseInType = stream->ReadByte();
fEaseInMin = stream->ReadSwapScalar();
fEaseInMax = stream->ReadSwapScalar();
fEaseInLength = stream->ReadSwapScalar();
fEaseOutType = stream->ReadByte();
fEaseOutMin = stream->ReadSwapScalar();
fEaseOutMax = stream->ReadSwapScalar();
fEaseOutLength = stream->ReadSwapScalar();
int i;
int numMarkers = stream->ReadSwap32();
for (i = 0; i < numMarkers; i++)
{
char *name = stream->ReadSafeString();
float time = stream->ReadSwapFloat();
fMarkers[name] = time;
}
int numLoops = stream->ReadSwap32();
for (i = 0; i < numLoops; i++)
{
char *name = stream->ReadSafeString();
float begin = stream->ReadSwapScalar();
float end = stream->ReadSwapScalar();
fLoops[name] = std::pair<float,float>(begin,end);
}
int numStops = stream->ReadSwap32();
for (i = 0; i < numStops; i++)
fStopPoints.push_back(stream->ReadSwapScalar());
}
// Write ---------------------------------------------
// ------
void plATCAnim::Write(hsStream *stream, hsResMgr *mgr)
{
plAGAnim::Write(stream, mgr);
stream->WriteSwapScalar(fInitial);
stream->Writebool(fAutoStart);
stream->WriteSwapScalar(fLoopStart);
stream->WriteSwapScalar(fLoopEnd);
stream->Writebool(fLoop);
stream->WriteByte(fEaseInType);
stream->WriteSwapScalar(fEaseInMin);
stream->WriteSwapScalar(fEaseInMax);
stream->WriteSwapScalar(fEaseInLength);
stream->WriteByte(fEaseOutType);
stream->WriteSwapScalar(fEaseOutMin);
stream->WriteSwapScalar(fEaseOutMax);
stream->WriteSwapScalar(fEaseOutLength);
stream->WriteSwap32(fMarkers.size());
for (MarkerMap::iterator it = fMarkers.begin(); it != fMarkers.end(); it++)
{
stream->WriteSafeString(it->first);
stream->WriteSwapFloat(it->second);
}
stream->WriteSwap32(fLoops.size());
for (LoopMap::iterator loopIt = fLoops.begin(); loopIt != fLoops.end(); loopIt++)
{
stream->WriteSafeString(loopIt->first);
std::pair<float,float>& loop = loopIt->second;
stream->WriteSwapFloat(loop.first);
stream->WriteSwapFloat(loop.second);
}
int i;
stream->WriteSwap32(fStopPoints.size());
for (i = 0; i < fStopPoints.size(); i++)
stream->WriteSwapScalar(fStopPoints[i]);
}
// CheckLoop --------------
// ----------
void plATCAnim::CheckLoop()
{
if (fLoopStart == fLoopEnd)
{
fLoopStart = fStart;
fLoopEnd = fEnd;
}
}
// AddLoop ------------------------------------------------------
// --------
void plATCAnim::AddLoop(const char *name, float start, float end)
{
char *nameCpy = hsStrcpy(name);
fLoops[nameCpy] = std::pair<float,float>(start, end);
}
// GetLoop --------------------------------------------------------------
// --------
bool plATCAnim::GetLoop(const char *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 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 plATCAnim::GetNumLoops() const
{
return fLoops.size();
}
// AddMarker ------------------------------------------
// ----------
void plATCAnim::AddMarker(const char *name, float time)
{
char *nameCpy = hsStrcpy(name);
fMarkers[nameCpy] = time;
}
// GetMarker -------------------------------------
// ----------
float plATCAnim::GetMarker(const char *name) const
{
if (fMarkers.find(name) != fMarkers.end())
return (*fMarkers.find(name)).second;
return -1;
}
// CopyMarkerNames -------------------------------------
// ----------------
void plATCAnim::CopyMarkerNames(std::vector<char*> &out)
{
MarkerMap::iterator it = fMarkers.begin();
for (; it != fMarkers.end(); it++)
{
out.push_back(hsStrcpy((*it).first));
}
}
// AddStopPoint ---------------------------
// -------------
void plATCAnim::AddStopPoint(hsScalar time)
{
fStopPoints.push_back(time);
}
// NumStopPoints ----------------
// --------------
UInt32 plATCAnim::NumStopPoints()
{
return fStopPoints.size();
}
// GetStopPoint --------------------------
// -------------
hsScalar plATCAnim::GetStopPoint(UInt32 i)
{
hsAssert(i < fStopPoints.size(), "Invalid index for GetStopPoint");
return fStopPoints[i];
}
/////////////////////////////////////////////////////////////////////////////////////////
//
// plEmoteAnim
//
/////////////////////////////////////////////////////////////////////////////////////////
// ctor ------------------
// -----
plEmoteAnim::plEmoteAnim()
: fBodyUsage(kBodyFull)
{
}
// ctor ------------------------------------------------------------------------------
// -----
plEmoteAnim::plEmoteAnim(const char *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->ReadSwapScalar();
fFadeOut = stream->ReadSwapScalar();
fBodyUsage = static_cast<BodyUsage>(stream->ReadByte());
}
// Write -----------------------------------------------
// ------
void plEmoteAnim::Write(hsStream *stream, hsResMgr *mgr)
{
plATCAnim::Write(stream, mgr);
stream->WriteSwapScalar(fFadeIn);
stream->WriteSwapScalar(fFadeOut);
stream->WriteByte(static_cast<UInt8>(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()
{
fGlobalVarName = nil;
}
// ctor --------------------------------------------------------------------
// -----
plAgeGlobalAnim::plAgeGlobalAnim(const char *name, double start, double end)
: plAGAnim(name, start, end),
fGlobalVarName(nil)
{
}
// dtor ---------------------------
// -----
plAgeGlobalAnim::~plAgeGlobalAnim()
{
delete [] fGlobalVarName;
}
void plAgeGlobalAnim::SetGlobalVarName(char *name)
{
delete [] fGlobalVarName;
fGlobalVarName = hsStrcpy(name);
}
// 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 char *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 char *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;
}