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.
916 lines
27 KiB
916 lines
27 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/>. |
|
|
|
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 "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<hsScalar> &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<hsScalar> &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); |
|
} |
|
|
|
|