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
18 KiB
766 lines
18 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; |
|
} |