/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ ///////////////////////////////////////////////////////////////////////////////////////// // // 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(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& 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(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& 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& 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 &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(stream->ReadByte()); } // Write ----------------------------------------------- // ------ void plEmoteAnim::Write(hsStream *stream, hsResMgr *mgr) { plATCAnim::Write(stream, mgr); stream->WriteSwapScalar(fFadeIn); stream->WriteSwapScalar(fFadeOut); stream->WriteByte(static_cast(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; }