/*==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==*/ #include "plController.h" #include "hsInterp.h" #include "hsResMgr.h" #include "plTransform/hsEuler.h" #include "plAnimTimeConvert.h" ///////////////////////////////////////////// // Controller interp caching ///////////////////////////////////////////// static const char *kInvalidInterpString = "Invalid call to plController::Interp()"; plControllerCacheInfo::plControllerCacheInfo() : fNumSubControllers(0), fSubControllers(nil), fKeyIndex(0), fAtc(nil) {} plControllerCacheInfo::~plControllerCacheInfo() { int i; for (i = 0; i < fNumSubControllers; i++) delete fSubControllers[i]; delete [] fSubControllers; } void plControllerCacheInfo::SetATC(plAnimTimeConvert *atc) { fAtc = atc; int i; for (i = 0; i < fNumSubControllers; i++) if (fSubControllers[i]) fSubControllers[i]->SetATC(atc); } ////////////////////////////////////////////////////////////////////////////////////////// plLeafController::~plLeafController() { delete [] fKeys; } void plLeafController::Interp(hsScalar time, hsScalar* result, plControllerCacheInfo *cache) const { hsAssert(fType == hsKeyFrame::kScalarKeyFrame || fType == hsKeyFrame::kBezScalarKeyFrame, kInvalidInterpString); hsBool tryForward = (cache? cache->fAtc->IsForewards() : true); if (fType == hsKeyFrame::kScalarKeyFrame) { hsScalarKey *k1, *k2; hsScalar t; UInt32 *idxStore = (cache ? &cache->fKeyIndex : &fLastKeyIdx); hsInterp::GetBoundaryKeyFrames(time, fNumKeys, fKeys, sizeof(hsScalarKey), (hsKeyFrame**)&k1, (hsKeyFrame**)&k2, idxStore, &t, tryForward); hsInterp::LinInterp(k1->fValue, k2->fValue, t, result); } else { hsBezScalarKey *k1, *k2; hsScalar t; UInt32 *idxStore = (cache ? &cache->fKeyIndex : &fLastKeyIdx); hsInterp::GetBoundaryKeyFrames(time, fNumKeys, fKeys, sizeof(hsBezScalarKey), (hsKeyFrame**)&k1, (hsKeyFrame**)&k2, idxStore, &t, tryForward); hsInterp::BezInterp(k1, k2, t, result); } } void plLeafController::Interp(hsScalar time, hsScalarTriple* result, plControllerCacheInfo *cache) const { hsAssert(fType == hsKeyFrame::kPoint3KeyFrame || fType == hsKeyFrame::kBezPoint3KeyFrame, kInvalidInterpString); hsBool tryForward = (cache? cache->fAtc->IsForewards() : true); if (fType == hsKeyFrame::kPoint3KeyFrame) { hsPoint3Key *k1, *k2; hsScalar t; UInt32 *idxStore = (cache ? &cache->fKeyIndex : &fLastKeyIdx); hsInterp::GetBoundaryKeyFrames(time, fNumKeys, fKeys, sizeof(hsPoint3Key), (hsKeyFrame**)&k1, (hsKeyFrame**)&k2, idxStore, &t, tryForward); hsInterp::LinInterp(&k1->fValue, &k2->fValue, t, result); } else { hsBezPoint3Key *k1, *k2; hsScalar t; UInt32 *idxStore = (cache ? &cache->fKeyIndex : &fLastKeyIdx); hsInterp::GetBoundaryKeyFrames(time, fNumKeys, fKeys, sizeof(hsBezPoint3Key), (hsKeyFrame**)&k1, (hsKeyFrame**)&k2, idxStore, &t, tryForward); hsInterp::BezInterp(k1, k2, t, result); } } void plLeafController::Interp(hsScalar time, hsScaleValue* result, plControllerCacheInfo *cache) const { hsAssert(fType == hsKeyFrame::kScaleKeyFrame || fType == hsKeyFrame::kBezScaleKeyFrame, kInvalidInterpString); hsBool tryForward = (cache? cache->fAtc->IsForewards() : true); if (fType == hsKeyFrame::kScaleKeyFrame) { hsScaleKey *k1, *k2; hsScalar t; UInt32 *idxStore = (cache ? &cache->fKeyIndex : &fLastKeyIdx); hsInterp::GetBoundaryKeyFrames(time, fNumKeys, fKeys, sizeof(hsScaleKey), (hsKeyFrame**)&k1, (hsKeyFrame**)&k2, idxStore, &t, tryForward); hsInterp::LinInterp(&k1->fValue, &k2->fValue, t, result); } else { hsBezScaleKey *k1, *k2; hsScalar t; UInt32 *idxStore = (cache ? &cache->fKeyIndex : &fLastKeyIdx); hsInterp::GetBoundaryKeyFrames(time, fNumKeys, fKeys, sizeof(hsBezScaleKey), (hsKeyFrame**)&k1, (hsKeyFrame**)&k2, idxStore, &t, tryForward); hsInterp::BezInterp(k1, k2, t, result); } } void plLeafController::Interp(hsScalar time, hsQuat* result, plControllerCacheInfo *cache) const { hsAssert(fType == hsKeyFrame::kQuatKeyFrame || fType == hsKeyFrame::kCompressedQuatKeyFrame32 || fType == hsKeyFrame::kCompressedQuatKeyFrame64, kInvalidInterpString); hsBool tryForward = (cache? cache->fAtc->IsForewards() : true); if (fType == hsKeyFrame::kQuatKeyFrame) { hsQuatKey *k1, *k2; hsScalar t; UInt32 *idxStore = (cache ? &cache->fKeyIndex : &fLastKeyIdx); hsInterp::GetBoundaryKeyFrames(time, fNumKeys, fKeys, sizeof(hsQuatKey), (hsKeyFrame**)&k1, (hsKeyFrame**)&k2, idxStore, &t, tryForward); hsInterp::LinInterp(&k1->fValue, &k2->fValue, t, result); } else if (fType == hsKeyFrame::kCompressedQuatKeyFrame32) { hsCompressedQuatKey32 *k1, *k2; hsScalar t; UInt32 *idxStore = (cache ? &cache->fKeyIndex : &fLastKeyIdx); hsInterp::GetBoundaryKeyFrames(time, fNumKeys, fKeys, sizeof(hsCompressedQuatKey32), (hsKeyFrame**)&k1, (hsKeyFrame**)&k2, idxStore, &t, tryForward); hsQuat q1, q2; k1->GetQuat(q1); k2->GetQuat(q2); hsInterp::LinInterp(&q1, &q2, t, result); } else // (fType == hsKeyFrame::kCompressedQuatKeyFrame64) { hsCompressedQuatKey64 *k1, *k2; hsScalar t; UInt32 *idxStore = (cache ? &cache->fKeyIndex : &fLastKeyIdx); hsInterp::GetBoundaryKeyFrames(time, fNumKeys, fKeys, sizeof(hsCompressedQuatKey64), (hsKeyFrame**)&k1, (hsKeyFrame**)&k2, idxStore, &t, tryForward); hsQuat q1, q2; k1->GetQuat(q1); k2->GetQuat(q2); hsInterp::LinInterp(&q1, &q2, t, result); } } void plLeafController::Interp(hsScalar time, hsMatrix33* result, plControllerCacheInfo *cache) const { hsAssert(fType == hsKeyFrame::kMatrix33KeyFrame, kInvalidInterpString); hsBool tryForward = (cache? cache->fAtc->IsForewards() : true); hsMatrix33Key *k1, *k2; hsScalar t; UInt32 *idxStore = (cache ? &cache->fKeyIndex : &fLastKeyIdx); hsInterp::GetBoundaryKeyFrames(time, fNumKeys, fKeys, sizeof(hsMatrix33Key), (hsKeyFrame**)&k1, (hsKeyFrame**)&k2, idxStore, &t, tryForward); hsInterp::LinInterp(&k1->fValue, &k2->fValue, t, result); } void plLeafController::Interp(hsScalar time, hsMatrix44* result, plControllerCacheInfo *cache) const { hsAssert(fType == hsKeyFrame::kMatrix44KeyFrame, kInvalidInterpString); hsBool tryForward = (cache? cache->fAtc->IsForewards() : true); hsMatrix44Key *k1, *k2; hsScalar t; UInt32 *idxStore = (cache ? &cache->fKeyIndex : &fLastKeyIdx); hsInterp::GetBoundaryKeyFrames(time, fNumKeys, fKeys, sizeof(hsMatrix44Key), (hsKeyFrame**)&k1, (hsKeyFrame**)&k2, idxStore, &t, tryForward); hsInterp::LinInterp(&k1->fValue, &k2->fValue, t, result); } void plLeafController::Interp(hsScalar time, hsColorRGBA* result, plControllerCacheInfo *cache) const { hsPoint3 value; Interp(time, &value, cache); result->r = value.fX; result->g = value.fY; result->b = value.fZ; } plControllerCacheInfo *plLeafController::CreateCache() const { plControllerCacheInfo *cache = TRACKED_NEW plControllerCacheInfo; cache->fNumSubControllers = 0; return cache; } hsScalar plLeafController::GetLength() const { UInt32 stride = GetStride(); if (stride == 0 || fNumKeys == 0) return 0; UInt8 *ptr = (UInt8 *)fKeys; return ((hsKeyFrame *)(ptr + (fNumKeys - 1) * stride))->fFrame / MAX_FRAMES_PER_SEC; } UInt32 plLeafController::GetStride() const { switch (fType) { case hsKeyFrame::kPoint3KeyFrame: return sizeof(hsPoint3Key); case hsKeyFrame::kBezPoint3KeyFrame: return sizeof(hsBezPoint3Key); case hsKeyFrame::kScalarKeyFrame: return sizeof(hsScalarKey); case hsKeyFrame::kBezScalarKeyFrame: return sizeof(hsBezScalarKey); case hsKeyFrame::kScaleKeyFrame: return sizeof(hsScaleKey); case hsKeyFrame::kBezScaleKeyFrame: return sizeof(hsBezScaleKey); case hsKeyFrame::kQuatKeyFrame: return sizeof(hsQuatKey); case hsKeyFrame::kCompressedQuatKeyFrame32: return sizeof(hsCompressedQuatKey32); case hsKeyFrame::kCompressedQuatKeyFrame64: return sizeof(hsCompressedQuatKey64); case hsKeyFrame::k3dsMaxKeyFrame: return sizeof(hsG3DSMaxKeyFrame); case hsKeyFrame::kMatrix33KeyFrame: return sizeof(hsMatrix33Key); case hsKeyFrame::kMatrix44KeyFrame: return sizeof(hsMatrix44Key); case hsKeyFrame::kUnknownKeyFrame: default: return 0; } } hsPoint3Key *plLeafController::GetPoint3Key(UInt32 i) const { if (fType != hsKeyFrame::kPoint3KeyFrame) return nil; return (hsPoint3Key *)((UInt8 *)fKeys + i * sizeof(hsPoint3Key)); } hsBezPoint3Key *plLeafController::GetBezPoint3Key(UInt32 i) const { if (fType != hsKeyFrame::kBezPoint3KeyFrame) return nil; return (hsBezPoint3Key *)((UInt8 *)fKeys + i * sizeof(hsBezPoint3Key)); } hsScalarKey *plLeafController::GetScalarKey(UInt32 i) const { if (fType != hsKeyFrame::kScalarKeyFrame) return nil; return (hsScalarKey *)((UInt8 *)fKeys + i * sizeof(hsScalarKey)); } hsBezScalarKey *plLeafController::GetBezScalarKey(UInt32 i) const { if (fType != hsKeyFrame::kBezScalarKeyFrame) return nil; return (hsBezScalarKey *)((UInt8 *)fKeys + i * sizeof(hsBezScalarKey)); } hsScaleKey *plLeafController::GetScaleKey(UInt32 i) const { if (fType != hsKeyFrame::kScaleKeyFrame) return nil; return (hsScaleKey *)((UInt8 *)fKeys + i * sizeof(hsScaleKey)); } hsBezScaleKey *plLeafController::GetBezScaleKey(UInt32 i) const { if (fType != hsKeyFrame::kBezScaleKeyFrame) return nil; return (hsBezScaleKey *)((UInt8 *)fKeys + i * sizeof(hsBezScaleKey)); } hsQuatKey *plLeafController::GetQuatKey(UInt32 i) const { if (fType != hsKeyFrame::kQuatKeyFrame) return nil; return (hsQuatKey *)((UInt8 *)fKeys + i * sizeof(hsQuatKey)); } hsCompressedQuatKey32 *plLeafController::GetCompressedQuatKey32(UInt32 i) const { if (fType != hsKeyFrame::kCompressedQuatKeyFrame32) return nil; return (hsCompressedQuatKey32 *)((UInt8 *)fKeys + i * sizeof(hsCompressedQuatKey32)); } hsCompressedQuatKey64 *plLeafController::GetCompressedQuatKey64(UInt32 i) const { if (fType != hsKeyFrame::kCompressedQuatKeyFrame64) return nil; return (hsCompressedQuatKey64 *)((UInt8 *)fKeys + i * sizeof(hsCompressedQuatKey64)); } hsG3DSMaxKeyFrame *plLeafController::Get3DSMaxKey(UInt32 i) const { if (fType != hsKeyFrame::k3dsMaxKeyFrame) return nil; return (hsG3DSMaxKeyFrame *)((UInt8 *)fKeys + i * sizeof(hsG3DSMaxKeyFrame)); } hsMatrix33Key *plLeafController::GetMatrix33Key(UInt32 i) const { if (fType != hsKeyFrame::kMatrix33KeyFrame) return nil; return (hsMatrix33Key *)((UInt8 *)fKeys + i * sizeof(hsMatrix33Key)); } hsMatrix44Key *plLeafController::GetMatrix44Key(UInt32 i) const { if (fType != hsKeyFrame::kMatrix44KeyFrame) return nil; return (hsMatrix44Key *)((UInt8 *)fKeys + i * sizeof(hsMatrix44Key)); } void plLeafController::GetKeyTimes(hsTArray &keyTimes) const { int cIdx; int kIdx; UInt32 stride = GetStride(); UInt8 *keyPtr = (UInt8 *)fKeys; for (cIdx = 0, kIdx = 0; cIdx < fNumKeys, kIdx < keyTimes.GetCount();) { hsScalar kTime = keyTimes[kIdx]; hsScalar cTime = ((hsKeyFrame*)(keyPtr + cIdx * stride))->fFrame / MAX_FRAMES_PER_SEC; if (cTime < kTime) { keyTimes.InsertAtIndex(kIdx, cTime); cIdx++; kIdx++; } else if (cTime > kTime) { kIdx++; } else { kIdx++; cIdx++; } } // All remaining times in the controller are later than the original keyTimes set for (; cIdx < fNumKeys; cIdx++) { hsScalar cTime = ((hsKeyFrame*)(keyPtr + cIdx * stride))->fFrame / MAX_FRAMES_PER_SEC; keyTimes.Append(cTime); } } void plLeafController::AllocKeys(UInt32 numKeys, UInt8 type) { delete fKeys; fNumKeys = numKeys; fType = type; switch (fType) { case hsKeyFrame::kPoint3KeyFrame: fKeys = TRACKED_NEW hsPoint3Key[fNumKeys]; break; case hsKeyFrame::kBezPoint3KeyFrame: fKeys = TRACKED_NEW hsBezPoint3Key[fNumKeys]; break; case hsKeyFrame::kScalarKeyFrame: fKeys = TRACKED_NEW hsScalarKey[fNumKeys]; break; case hsKeyFrame::kBezScalarKeyFrame: fKeys = TRACKED_NEW hsBezScalarKey[fNumKeys]; break; case hsKeyFrame::kScaleKeyFrame: fKeys = TRACKED_NEW hsScaleKey[fNumKeys]; break; case hsKeyFrame::kBezScaleKeyFrame: fKeys = TRACKED_NEW hsBezScaleKey[fNumKeys]; break; case hsKeyFrame::kQuatKeyFrame: fKeys = TRACKED_NEW hsQuatKey[fNumKeys]; break; case hsKeyFrame::kCompressedQuatKeyFrame32: fKeys = TRACKED_NEW hsCompressedQuatKey32[fNumKeys]; break; case hsKeyFrame::kCompressedQuatKeyFrame64: fKeys = TRACKED_NEW hsCompressedQuatKey64[fNumKeys]; break; case hsKeyFrame::k3dsMaxKeyFrame: fKeys = TRACKED_NEW hsG3DSMaxKeyFrame[fNumKeys]; break; case hsKeyFrame::kMatrix33KeyFrame: fKeys = TRACKED_NEW hsMatrix33Key[fNumKeys]; break; case hsKeyFrame::kMatrix44KeyFrame: fKeys = TRACKED_NEW hsMatrix44Key[fNumKeys]; break; case hsKeyFrame::kUnknownKeyFrame: default: hsAssert(false, "Trying to allocate unknown keyframe type"); break; } } void plLeafController::QuickScalarController(int numKeys, hsScalar* times, hsScalar* values, UInt32 valueStrides) { AllocKeys(numKeys, hsKeyFrame::kScalarKeyFrame); int i; for( i = 0; i < numKeys; i++ ) { ((hsScalarKey*)fKeys)[i].fFrame = (UInt16)(*times++ * MAX_FRAMES_PER_SEC); ((hsScalarKey*)fKeys)[i].fValue = *values; values = (hsScalar *)((UInt8 *)values + valueStrides); } } // If all the keys are the same, this controller is pretty useless. // This situation actually comes up a lot because of the biped killer // trying to convert character studio animations. hsBool plLeafController::AllKeysMatch() const { if (fNumKeys <= 1) return true; int idx; for (idx = 1; idx < fNumKeys; idx++) { switch (fType) { case hsKeyFrame::kPoint3KeyFrame: { hsPoint3Key *k1 = GetPoint3Key(idx - 1); hsPoint3Key *k2 = GetPoint3Key(idx); if (!k1->CompareValue(k2)) return false; break; } case hsKeyFrame::kBezPoint3KeyFrame: { hsBezPoint3Key *k1 = GetBezPoint3Key(idx - 1); hsBezPoint3Key *k2 = GetBezPoint3Key(idx); if (!k1->CompareValue(k2)) return false; break; } case hsKeyFrame::kScalarKeyFrame: { hsScalarKey *k1 = GetScalarKey(idx - 1); hsScalarKey *k2 = GetScalarKey(idx); if (!k1->CompareValue(k2)) return false; break; } case hsKeyFrame::kBezScalarKeyFrame: { hsBezScalarKey *k1 = GetBezScalarKey(idx - 1); hsBezScalarKey *k2 = GetBezScalarKey(idx); if (!k1->CompareValue(k2)) return false; break; } case hsKeyFrame::kScaleKeyFrame: { hsScaleKey *k1 = GetScaleKey(idx - 1); hsScaleKey *k2 = GetScaleKey(idx); if (!k1->CompareValue(k2)) return false; break; } case hsKeyFrame::kBezScaleKeyFrame: { hsBezScaleKey *k1 = GetBezScaleKey(idx - 1); hsBezScaleKey *k2 = GetBezScaleKey(idx); if (!k1->CompareValue(k2)) return false; break; } case hsKeyFrame::kQuatKeyFrame: { hsQuatKey *k1 = GetQuatKey(idx - 1); hsQuatKey *k2 = GetQuatKey(idx); if (!k1->CompareValue(k2)) return false; break; } case hsKeyFrame::kCompressedQuatKeyFrame32: { hsCompressedQuatKey32 *k1 = GetCompressedQuatKey32(idx - 1); hsCompressedQuatKey32 *k2 = GetCompressedQuatKey32(idx); if (!k1->CompareValue(k2)) return false; break; } case hsKeyFrame::kCompressedQuatKeyFrame64: { hsCompressedQuatKey64 *k1 = GetCompressedQuatKey64(idx - 1); hsCompressedQuatKey64 *k2 = GetCompressedQuatKey64(idx); if (!k1->CompareValue(k2)) return false; break; } case hsKeyFrame::k3dsMaxKeyFrame: { hsG3DSMaxKeyFrame *k1 = Get3DSMaxKey(idx - 1); hsG3DSMaxKeyFrame *k2 = Get3DSMaxKey(idx); if (!k1->CompareValue(k2)) return false; break; } case hsKeyFrame::kMatrix33KeyFrame: { hsMatrix33Key *k1 = GetMatrix33Key(idx - 1); hsMatrix33Key *k2 = GetMatrix33Key(idx); if (!k1->CompareValue(k2)) return false; break; } case hsKeyFrame::kMatrix44KeyFrame: { hsMatrix44Key *k1 = GetMatrix44Key(idx - 1); hsMatrix44Key *k2 = GetMatrix44Key(idx); if (!k1->CompareValue(k2)) return false; break; } case hsKeyFrame::kUnknownKeyFrame: default: hsAssert(false, "Trying to compare unknown keyframe type"); return false; } } return true; } hsBool plLeafController::PurgeRedundantSubcontrollers() { return AllKeysMatch(); } void plLeafController::Read(hsStream* s, hsResMgr *mgr) { UInt8 type = s->ReadByte(); UInt32 numKeys = s->ReadSwap32(); AllocKeys(numKeys, type); int i; switch (fType) { case hsKeyFrame::kPoint3KeyFrame: for (i = 0; i < fNumKeys; i++) ((hsPoint3Key *)fKeys)[i].Read(s); break; case hsKeyFrame::kBezPoint3KeyFrame: for (i = 0; i < fNumKeys; i++) ((hsBezPoint3Key *)fKeys)[i].Read(s); break; case hsKeyFrame::kScalarKeyFrame: for (i = 0; i < fNumKeys; i++) ((hsScalarKey *)fKeys)[i].Read(s); break; case hsKeyFrame::kBezScalarKeyFrame: for (i = 0; i < fNumKeys; i++) ((hsBezScalarKey *)fKeys)[i].Read(s); break; case hsKeyFrame::kScaleKeyFrame: for (i = 0; i < fNumKeys; i++) ((hsScaleKey *)fKeys)[i].Read(s); break; case hsKeyFrame::kBezScaleKeyFrame: for (i = 0; i < fNumKeys; i++) ((hsBezScaleKey *)fKeys)[i].Read(s); break; case hsKeyFrame::kQuatKeyFrame: for (i = 0; i < fNumKeys; i++) ((hsQuatKey *)fKeys)[i].Read(s); break; case hsKeyFrame::kCompressedQuatKeyFrame32: for (i = 0; i < fNumKeys; i++) ((hsCompressedQuatKey32 *)fKeys)[i].Read(s); break; case hsKeyFrame::kCompressedQuatKeyFrame64: for (i = 0; i < fNumKeys; i++) ((hsCompressedQuatKey64 *)fKeys)[i].Read(s); break; case hsKeyFrame::k3dsMaxKeyFrame: for (i = 0; i < fNumKeys; i++) ((hsG3DSMaxKeyFrame *)fKeys)[i].Read(s); break; case hsKeyFrame::kMatrix33KeyFrame: for (i = 0; i < fNumKeys; i++) ((hsMatrix33Key *)fKeys)[i].Read(s); break; case hsKeyFrame::kMatrix44KeyFrame: for (i = 0; i < fNumKeys; i++) ((hsMatrix44Key *)fKeys)[i].Read(s); break; case hsKeyFrame::kUnknownKeyFrame: default: hsAssert(false, "Reading in controller with unknown key data"); break; } } void plLeafController::Write(hsStream* s, hsResMgr *mgr) { s->WriteByte(fType); s->WriteSwap32(fNumKeys); int i; switch (fType) { case hsKeyFrame::kPoint3KeyFrame: for (i = 0; i < fNumKeys; i++) ((hsPoint3Key *)fKeys)[i].Write(s); break; case hsKeyFrame::kBezPoint3KeyFrame: for (i = 0; i < fNumKeys; i++) ((hsBezPoint3Key *)fKeys)[i].Write(s); break; case hsKeyFrame::kScalarKeyFrame: for (i = 0; i < fNumKeys; i++) ((hsScalarKey *)fKeys)[i].Write(s); break; case hsKeyFrame::kBezScalarKeyFrame: for (i = 0; i < fNumKeys; i++) ((hsBezScalarKey *)fKeys)[i].Write(s); break; case hsKeyFrame::kScaleKeyFrame: for (i = 0; i < fNumKeys; i++) ((hsScaleKey *)fKeys)[i].Write(s); break; case hsKeyFrame::kBezScaleKeyFrame: for (i = 0; i < fNumKeys; i++) ((hsBezScaleKey *)fKeys)[i].Write(s); break; case hsKeyFrame::kQuatKeyFrame: for (i = 0; i < fNumKeys; i++) ((hsQuatKey *)fKeys)[i].Write(s); break; case hsKeyFrame::kCompressedQuatKeyFrame32: for (i = 0; i < fNumKeys; i++) ((hsCompressedQuatKey32 *)fKeys)[i].Write(s); break; case hsKeyFrame::kCompressedQuatKeyFrame64: for (i = 0; i < fNumKeys; i++) ((hsCompressedQuatKey64 *)fKeys)[i].Write(s); break; case hsKeyFrame::k3dsMaxKeyFrame: for (i = 0; i < fNumKeys; i++) ((hsG3DSMaxKeyFrame *)fKeys)[i].Write(s); break; case hsKeyFrame::kMatrix33KeyFrame: for (i = 0; i < fNumKeys; i++) ((hsMatrix33Key *)fKeys)[i].Write(s); break; case hsKeyFrame::kMatrix44KeyFrame: for (i = 0; i < fNumKeys; i++) ((hsMatrix44Key *)fKeys)[i].Write(s); break; case hsKeyFrame::kUnknownKeyFrame: default: hsAssert(false, "Writing controller with unknown key data"); break; } } ///////////////////////////////////////////////////////////////////////////////// plCompoundController::plCompoundController() : fXController(nil), fYController(nil), fZController(nil) {} plCompoundController::~plCompoundController() { delete fXController; delete fYController; delete fZController; } void plCompoundController::Interp(hsScalar time, hsScalarTriple* result, plControllerCacheInfo *cache) const { if (fXController) fXController->Interp(time, &result->fX, (cache ? cache->fSubControllers[0] : nil)); if (fYController) fYController->Interp(time, &result->fY, (cache ? cache->fSubControllers[1] : nil)); if (fZController) fZController->Interp(time, &result->fZ, (cache ? cache->fSubControllers[2] : nil)); } void plCompoundController::Interp(hsScalar time, hsQuat* result, plControllerCacheInfo *cache) const { hsEuler eul(0,0,0,EulOrdXYZs); fXController->Interp(time, &eul.fX, (cache ? cache->fSubControllers[0] : nil)); fYController->Interp(time, &eul.fY, (cache ? cache->fSubControllers[1] : nil)); fZController->Interp(time, &eul.fZ, (cache ? cache->fSubControllers[2] : nil)); eul.GetQuat(result); } void plCompoundController::Interp(hsScalar time, hsAffineParts* parts, plControllerCacheInfo *cache) const { if (fXController) fXController->Interp(time, &parts->fT, (cache ? cache->fSubControllers[0] : nil)); if (fYController) fYController->Interp(time, &parts->fQ, (cache ? cache->fSubControllers[1] : nil)); hsScaleValue sv; if (fZController) { fZController->Interp(time, &sv, (cache ? cache->fSubControllers[2] : nil)); parts->fU = sv.fQ; parts->fK = sv.fS; } } void plCompoundController::Interp(hsScalar time, hsColorRGBA* result, plControllerCacheInfo *cache) const { fXController->Interp(time, &result->r, (cache ? cache->fSubControllers[0] : nil)); fYController->Interp(time, &result->g, (cache ? cache->fSubControllers[1] : nil)); fZController->Interp(time, &result->b, (cache ? cache->fSubControllers[2] : nil)); } hsScalar plCompoundController::GetLength() const { hsScalar len=0; int i; for(i=0; i<3; i++) { if (GetController(i)) len = hsMaximum(len, GetController(i)->GetLength()); } return len; } void plCompoundController::GetKeyTimes(hsTArray &keyTimes) const { if (fXController) fXController->GetKeyTimes(keyTimes); if (fYController) fYController->GetKeyTimes(keyTimes); if (fZController) fZController->GetKeyTimes(keyTimes); } hsBool plCompoundController::AllKeysMatch() const { return (!fXController || fXController->AllKeysMatch()) && (!fYController || fYController->AllKeysMatch()) && (!fZController || fZController->AllKeysMatch()); } // Careful here... We might detect that one of our subcontrollers // has animation keys that all have the same value. That doesn't // mean they're all zero though. An avatar animation might have // elbow bend a constant 90 degrees through the entire anim, but // if we delete the controller and assume zero, we'll have problems. // Transform controller channels get around this by sampling the source // first and using that to fill in the missing subcontrollers. // // Note: that one of our subcontrollers could itself be a compound // controller. An example would be a controller for XYZ Euler angles // that's a sub of the pos/rot/scale transform controller. // It's possible that some of these sub-sub controllers could be // removed, but then we'd have to store the default values somewhere. // At the moment, this doesn't seem likely to save us enough space // to be worth the effort. (This is why this function doesn't // recursively call purge on its subcontrollers.) hsBool plCompoundController::PurgeRedundantSubcontrollers() { if (fXController && fXController->AllKeysMatch()) { delete fXController; fXController = nil; } if (fYController && fYController->AllKeysMatch()) { delete fYController; fYController = nil; } if (fZController && fZController->AllKeysMatch()) { delete fZController; fZController = nil; } return (!fXController && !fYController && !fZController); } plControllerCacheInfo* plCompoundController::CreateCache() const { plControllerCacheInfo* cache = TRACKED_NEW plControllerCacheInfo; cache->fNumSubControllers = 3; cache->fSubControllers = TRACKED_NEW plControllerCacheInfo*[cache->fNumSubControllers]; int i; for (i = 0; i < cache->fNumSubControllers; i++) cache->fSubControllers[i] = (GetController(i) ? GetController(i)->CreateCache() : nil); return cache; } plController* plCompoundController::GetController(Int32 i) const { return (i==0 ? fXController : (i==1 ? fYController : fZController)); } void plCompoundController::SetController(Int32 i, plController* c) { delete GetController(i); (i==0 ? fXController : (i==1 ? fYController : fZController)) = c; } void plCompoundController::Read(hsStream* stream, hsResMgr *mgr) { fXController = plController::ConvertNoRef(mgr->ReadCreatable(stream)); fYController = plController::ConvertNoRef(mgr->ReadCreatable(stream)); fZController = plController::ConvertNoRef(mgr->ReadCreatable(stream)); } void plCompoundController::Write(hsStream* stream, hsResMgr *mgr) { mgr->WriteCreatable(stream, fXController); mgr->WriteCreatable(stream, fYController); mgr->WriteCreatable(stream, fZController); }