mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-14 02:27:40 -04:00
CWE Directory Reorganization
Rearrange directory structure of CWE to be loosely equivalent to the H'uru Plasma repository. Part 1: Movement of directories and files.
This commit is contained in:
510
Sources/Plasma/PubUtilLib/plInterp/hsInterp.cpp
Normal file
510
Sources/Plasma/PubUtilLib/plInterp/hsInterp.cpp
Normal file
@ -0,0 +1,510 @@
|
||||
/*==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 "hsTypes.h"
|
||||
#include "hsInterp.h"
|
||||
#include "../plTransform/hsAffineParts.h"
|
||||
#include "hsColorRGBA.h"
|
||||
#include "hsPoint2.h"
|
||||
|
||||
//
|
||||
///////////////////////////////////////////////////////
|
||||
// linear interpolation
|
||||
///////////////////////////////////////////////////////
|
||||
//
|
||||
void hsInterp::LinInterp(hsScalar k1, hsScalar k2, hsScalar t, hsScalar* result)
|
||||
{
|
||||
*result = k1 + t * (k2 - k1);
|
||||
}
|
||||
|
||||
void hsInterp::LinInterp(const hsScalarTriple* k1, const hsScalarTriple* k2, hsScalar t,
|
||||
hsScalarTriple* result)
|
||||
{
|
||||
if (t==0.0)
|
||||
*result = *k1;
|
||||
else
|
||||
if (t==1.0)
|
||||
*result = *k2;
|
||||
else
|
||||
{
|
||||
LinInterp(k1->fX, k2->fX, t, &result->fX);
|
||||
LinInterp(k1->fY, k2->fY, t, &result->fY);
|
||||
LinInterp(k1->fZ, k2->fZ, t, &result->fZ);
|
||||
}
|
||||
}
|
||||
|
||||
void hsInterp::LinInterp(const hsColorRGBA* k1, const hsColorRGBA* k2, hsScalar t,
|
||||
hsColorRGBA* result, UInt32 flags)
|
||||
{
|
||||
if (t==0.0)
|
||||
{
|
||||
// copy
|
||||
result->r = k1->r;
|
||||
result->g = k1->g;
|
||||
result->b = k1->b;
|
||||
if (!(flags & kIgnoreAlpha))
|
||||
result->a = k1->a;
|
||||
return;
|
||||
}
|
||||
|
||||
if (t==1.0)
|
||||
{
|
||||
result->r = k2->r;
|
||||
result->g = k2->g;
|
||||
result->b = k2->b;
|
||||
if (!(flags & kIgnoreAlpha))
|
||||
result->a = k2->a;
|
||||
return;
|
||||
}
|
||||
|
||||
LinInterp(k1->r, k2->r, t, &result->r);
|
||||
LinInterp(k1->g, k2->g, t, &result->g);
|
||||
LinInterp(k1->b, k2->b, t, &result->b);
|
||||
if (!(flags & kIgnoreAlpha))
|
||||
LinInterp(k1->a, k2->a, t, &result->a);
|
||||
}
|
||||
|
||||
void hsInterp::LinInterp(const hsMatrix33* k1, const hsMatrix33* k2, hsScalar t,
|
||||
hsMatrix33* result, UInt32 flags)
|
||||
{
|
||||
if (t==0.0)
|
||||
{
|
||||
// copy
|
||||
result->fMap[0][0] = k1->fMap[0][0];
|
||||
result->fMap[0][1] = k1->fMap[0][1];
|
||||
result->fMap[0][2] = k1->fMap[0][2];
|
||||
|
||||
result->fMap[1][0] = k1->fMap[1][0];
|
||||
result->fMap[1][1] = k1->fMap[1][1];
|
||||
result->fMap[1][2] = k1->fMap[1][2];
|
||||
|
||||
if (!(flags & kIgnoreLastMatRow))
|
||||
{
|
||||
result->fMap[2][0] = k1->fMap[2][0];
|
||||
result->fMap[2][1] = k1->fMap[2][1];
|
||||
result->fMap[2][2] = k1->fMap[2][2];
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (t==1.0)
|
||||
{
|
||||
// copy
|
||||
result->fMap[0][0] = k2->fMap[0][0];
|
||||
result->fMap[0][1] = k2->fMap[0][1];
|
||||
result->fMap[0][2] = k2->fMap[0][2];
|
||||
|
||||
result->fMap[1][0] = k2->fMap[1][0];
|
||||
result->fMap[1][1] = k2->fMap[1][1];
|
||||
result->fMap[1][2] = k2->fMap[1][2];
|
||||
|
||||
if (!(flags & kIgnoreLastMatRow))
|
||||
{
|
||||
result->fMap[2][0] = k2->fMap[2][0];
|
||||
result->fMap[2][1] = k2->fMap[2][1];
|
||||
result->fMap[2][2] = k2->fMap[2][2];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
LinInterp(k1->fMap[0][0], k2->fMap[0][0], t, &result->fMap[0][0]);
|
||||
LinInterp(k1->fMap[0][1], k2->fMap[0][1], t, &result->fMap[0][1]);
|
||||
LinInterp(k1->fMap[0][2], k2->fMap[0][2], t, &result->fMap[0][2]);
|
||||
|
||||
LinInterp(k1->fMap[1][0], k2->fMap[1][0], t, &result->fMap[1][0]);
|
||||
LinInterp(k1->fMap[1][1], k2->fMap[1][1], t, &result->fMap[1][1]);
|
||||
LinInterp(k1->fMap[1][2], k2->fMap[1][2], t, &result->fMap[1][2]);
|
||||
|
||||
if (!(flags & kIgnoreLastMatRow))
|
||||
{
|
||||
LinInterp(k1->fMap[2][0], k2->fMap[2][0], t, &result->fMap[2][0]);
|
||||
LinInterp(k1->fMap[2][1], k2->fMap[2][1], t, &result->fMap[2][1]);
|
||||
LinInterp(k1->fMap[2][2], k2->fMap[2][2], t, &result->fMap[2][2]);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
void hsInterp::LinInterp(const hsMatrix44* mat1, const hsMatrix44* mat2, hsScalar t,
|
||||
hsMatrix44* out, UInt32 flags)
|
||||
{
|
||||
if (flags == 0)
|
||||
{
|
||||
if( 0 == t )
|
||||
{
|
||||
*out = *mat1;
|
||||
return;
|
||||
}
|
||||
|
||||
if( hsScalar1 == t )
|
||||
{
|
||||
*out = *mat2;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if( flags & kIgnorePartsScale )
|
||||
{
|
||||
if (!(flags & kIgnorePartsRot))
|
||||
{
|
||||
// interp rotation with quats
|
||||
hsQuat q1, q2, qOut;
|
||||
q1.SetFromMatrix(mat1);
|
||||
q2.SetFromMatrix(mat2);
|
||||
LinInterp(&q1, &q2, t, &qOut);
|
||||
|
||||
qOut.Normalize();
|
||||
qOut.MakeMatrix(out);
|
||||
}
|
||||
else
|
||||
out->Reset();
|
||||
#if 1
|
||||
hsAssert(mat2->fMap[3][0]==0 && mat2->fMap[3][1]==0 && mat2->fMap[3][2]==0 && mat2->fMap[3][3]==1,
|
||||
"matrix prob?");
|
||||
#else
|
||||
// copy
|
||||
for(int i=0; i<3; i++)
|
||||
out->fMap[3][i] = mat2->fMap[3][i];
|
||||
#endif
|
||||
|
||||
if (!(flags & kIgnorePartsPos))
|
||||
{
|
||||
// interp translation
|
||||
hsPoint3 p1,p2,pOut;
|
||||
mat1->GetTranslate(&p1);
|
||||
mat2->GetTranslate(&p2);
|
||||
LinInterp(&p1, &p2, t, &pOut);
|
||||
out->SetTranslate(&pOut);
|
||||
out->NotIdentity(); // in case no rot
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Complete decomp and parts interp
|
||||
|
||||
gemAffineParts gemParts1, gemParts2;
|
||||
hsAffineParts parts1, parts2, partsOut;
|
||||
|
||||
decomp_affine(mat1->fMap, &gemParts1);
|
||||
AP_SET(parts1, gemParts1);
|
||||
|
||||
decomp_affine(mat2->fMap, &gemParts2);
|
||||
AP_SET(parts2, gemParts2);
|
||||
|
||||
LinInterp(&parts1, &parts2, t, &partsOut, flags); // flags will be parsed here
|
||||
|
||||
partsOut.ComposeMatrix(out);
|
||||
}
|
||||
}
|
||||
|
||||
void hsInterp::LinInterp(const hsQuat* k1, const hsQuat* k2, hsScalar t, hsQuat* result)
|
||||
{
|
||||
if (t==0.0)
|
||||
*result = *k1;
|
||||
else
|
||||
if (t==1.0)
|
||||
*result = *k2;
|
||||
else
|
||||
{
|
||||
result->SetFromSlerp(*k1, *k2, t);
|
||||
}
|
||||
}
|
||||
|
||||
void hsInterp::LinInterp(const hsScaleValue* k1, const hsScaleValue* k2, hsScalar t,
|
||||
hsScaleValue* result)
|
||||
{
|
||||
LinInterp(&k1->fS, &k2->fS, t, &result->fS); // Stretch rotation
|
||||
LinInterp(&k1->fQ, &k2->fQ, t, &result->fQ); // Stretch factor
|
||||
}
|
||||
|
||||
void hsInterp::LinInterp(const hsAffineParts* k1, const hsAffineParts* k2, hsScalar t,
|
||||
hsAffineParts* result, UInt32 flags)
|
||||
{
|
||||
if (t==0.0)
|
||||
{
|
||||
// copy
|
||||
if (!(flags & kIgnorePartsPos))
|
||||
result->fT = k1->fT;
|
||||
if (!(flags & kIgnorePartsRot))
|
||||
result->fQ = k1->fQ;
|
||||
if (!(flags & kIgnorePartsScale))
|
||||
{
|
||||
// same as preserveScale
|
||||
result->fU = k1->fU;
|
||||
result->fK = k1->fK;
|
||||
}
|
||||
result->fF = k1->fF;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags & kPreservePartsScale)
|
||||
{
|
||||
result->fU = k1->fU; // just copy scale from 1st key
|
||||
result->fK = k1->fK;
|
||||
}
|
||||
|
||||
if (t==1.0)
|
||||
{
|
||||
// copy
|
||||
if (!(flags & kIgnorePartsPos))
|
||||
result->fT = k2->fT;
|
||||
if (!(flags & kIgnorePartsRot))
|
||||
result->fQ = k2->fQ;
|
||||
if (!(flags & (kIgnorePartsScale | kPreservePartsScale)))
|
||||
{
|
||||
result->fU = k2->fU;
|
||||
result->fK = k2->fK;
|
||||
}
|
||||
result->fF = k2->fF;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(k1->fF!=k2->fF)
|
||||
hsStatusMessageF("WARNING: Inequality in affine parts flip value.");
|
||||
|
||||
// hsAssert(k1->fF==k2->fF, "inequality in affine parts flip value");
|
||||
if (!(flags & kIgnorePartsPos))
|
||||
LinInterp(&k1->fT, &k2->fT, t, &result->fT); // Translation
|
||||
if (!(flags & kIgnorePartsRot))
|
||||
{
|
||||
LinInterp(&k1->fQ, &k2->fQ, t, &result->fQ); // Essential rotation
|
||||
}
|
||||
|
||||
if (!(flags & (kIgnorePartsScale | kPreservePartsScale)))
|
||||
{
|
||||
LinInterp(&k1->fU, &k2->fU, t, &result->fU); // Stretch rotation
|
||||
LinInterp(&k1->fK, &k2->fK, t, &result->fK); // Stretch factor
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!(flags & kIgnorePartsDet))
|
||||
LinInterp(k1->fF, k2->fF, t, &result->fF); // Flip rot var
|
||||
#else
|
||||
result->fF = k1->fF;
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
///////////////////////////////////////////////////////
|
||||
// Key interpolation
|
||||
///////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
void hsInterp::BezScalarEval(const hsScalar value1, const hsScalar outTan,
|
||||
const hsScalar value2, const hsScalar inTan,
|
||||
const hsScalar t, const hsScalar tanScale, hsScalar *result)
|
||||
{
|
||||
#if 0
|
||||
// If the tangents were what you'd expect them to be... Hermite splines, than this code
|
||||
// would make sense. But no, Max likes to store them in a scaled form based on the
|
||||
// time of each frame. If we ever optimize this further, we could do the scaling on export,
|
||||
// but I need this to work right now before all the artists hate me too much.
|
||||
const hsScalar t2 = t * t;
|
||||
const hsScalar t3 = t2 * t;
|
||||
|
||||
const hsScalar term1 = 2 * t3 - 3 * t2;
|
||||
|
||||
*result = ((term1 + 1) * value1) +
|
||||
(-term1 * value2) +
|
||||
((t3 - 2 * t2 + 1) * outTan) +
|
||||
((t3 - t2) * inTan);
|
||||
#else
|
||||
const hsScalar oneMinusT = (1.0f - t);
|
||||
const hsScalar tSq = t * t;
|
||||
const hsScalar oneMinusTSq = oneMinusT * oneMinusT;
|
||||
|
||||
*result = (oneMinusT * oneMinusTSq * value1) +
|
||||
(3.f * t * oneMinusTSq * (value1 + outTan * tanScale)) +
|
||||
(3.f * tSq * oneMinusT * (value2 + inTan * tanScale)) +
|
||||
(tSq * t * value2);
|
||||
#endif
|
||||
}
|
||||
|
||||
void hsInterp::BezInterp(const hsBezPoint3Key* k1, const hsBezPoint3Key* k2, const hsScalar t, hsScalarTriple* result)
|
||||
{
|
||||
hsScalar scale = (k2->fFrame - k1->fFrame) * MAX_TICKS_PER_FRAME / 3.f;
|
||||
BezScalarEval(k1->fValue.fX, k1->fOutTan.fX, k2->fValue.fX, k2->fInTan.fX, t, scale, &result->fX);
|
||||
BezScalarEval(k1->fValue.fY, k1->fOutTan.fY, k2->fValue.fY, k2->fInTan.fY, t, scale, &result->fY);
|
||||
BezScalarEval(k1->fValue.fZ, k1->fOutTan.fZ, k2->fValue.fZ, k2->fInTan.fZ, t, scale, &result->fZ);
|
||||
}
|
||||
|
||||
void hsInterp::BezInterp(const hsBezScalarKey* k1, const hsBezScalarKey* k2, const hsScalar t, hsScalar* result)
|
||||
{
|
||||
hsScalar scale = (k2->fFrame - k1->fFrame) * MAX_TICKS_PER_FRAME / 3.f;
|
||||
BezScalarEval(k1->fValue, k1->fOutTan, k2->fValue, k2->fInTan, t, scale, result);
|
||||
}
|
||||
|
||||
void hsInterp::BezInterp(const hsBezScaleKey* k1, const hsBezScaleKey* k2, const hsScalar t, hsScaleValue* result)
|
||||
{
|
||||
hsScalar scale = (k2->fFrame - k1->fFrame) * MAX_TICKS_PER_FRAME / 3.f;
|
||||
BezScalarEval(k1->fValue.fS.fX, k1->fOutTan.fX, k2->fValue.fS.fX, k2->fInTan.fX, t, scale, &result->fS.fX);
|
||||
BezScalarEval(k1->fValue.fS.fY, k1->fOutTan.fY, k2->fValue.fS.fY, k2->fInTan.fY, t, scale, &result->fS.fY);
|
||||
BezScalarEval(k1->fValue.fS.fZ, k1->fOutTan.fZ, k2->fValue.fS.fZ, k2->fInTan.fZ, t, scale, &result->fS.fZ);
|
||||
|
||||
// Slerp scale axis
|
||||
LinInterp(&k1->fValue.fQ, &k2->fValue.fQ, t, &result->fQ);
|
||||
}
|
||||
|
||||
//
|
||||
// Get an element from an array of unknown type
|
||||
//
|
||||
static inline hsKeyFrame* GetKey(Int32 i, void *keys, Int32 size)
|
||||
{
|
||||
return (hsKeyFrame*) ((char*)keys + size * i);
|
||||
}
|
||||
|
||||
//
|
||||
// STATIC
|
||||
// Given a list of keys, and a time, fills in the 2 boundary keys and
|
||||
// a fraction (p=0-1) indicating where the time falls between them.
|
||||
// Returns the index of the first key which can be passed in as a hint (lastKeyIdx)
|
||||
// for the next search.
|
||||
//
|
||||
void hsInterp::GetBoundaryKeyFrames(hsScalar time, UInt32 numKeys, void *keys, UInt32 size,
|
||||
hsKeyFrame **kF1, hsKeyFrame **kF2, UInt32 *lastKeyIdx, hsScalar *p, hsBool forwards)
|
||||
{
|
||||
hsAssert(numKeys>1, "Must have more than 1 keyframe");
|
||||
int k1, k2;
|
||||
UInt16 frame = (UInt16)(time * MAX_FRAMES_PER_SEC);
|
||||
|
||||
// boundary case, past end
|
||||
if (frame > GetKey(numKeys-1, keys, size)->fFrame)
|
||||
{
|
||||
k1=k2=numKeys-1;
|
||||
(*kF2) = GetKey(k1, keys, size);
|
||||
(*kF1) = (*kF2);
|
||||
*p = 0.0;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
hsKeyFrame *key1, *key2;
|
||||
// boundary case, before start
|
||||
if (frame < (key1=GetKey(0, keys, size))->fFrame)
|
||||
{
|
||||
k1=k2=0;
|
||||
(*kF1) = GetKey(k1, keys, size);
|
||||
(*kF2) = (*kF1);
|
||||
*p = 0.0;
|
||||
goto ret;
|
||||
}
|
||||
|
||||
// prime loop
|
||||
int i;
|
||||
i = 1;
|
||||
if (*lastKeyIdx > 0 && *lastKeyIdx < numKeys - 1)
|
||||
{
|
||||
// new starting point for search
|
||||
if (forwards)
|
||||
key1 = GetKey(*lastKeyIdx, keys, size);
|
||||
else
|
||||
key2 = GetKey(*lastKeyIdx + 1, keys, size);
|
||||
|
||||
i = *lastKeyIdx + 1;
|
||||
}
|
||||
else if (!forwards)
|
||||
{
|
||||
key2 = GetKey(1, keys, size);
|
||||
}
|
||||
|
||||
// search pairs of keys
|
||||
int count;
|
||||
if (forwards)
|
||||
{
|
||||
for (count = 1; count <= numKeys; count++, i++)
|
||||
{
|
||||
if (i >= numKeys)
|
||||
{
|
||||
key1 = GetKey(0, keys, size);
|
||||
i = 1;
|
||||
count++;
|
||||
}
|
||||
|
||||
key2 = GetKey(i, keys, size);
|
||||
if (frame <= key2->fFrame && frame >= key1->fFrame)
|
||||
{
|
||||
k2=i;
|
||||
k1=i-1;
|
||||
(*kF2) = key2;
|
||||
(*kF1) = key1;
|
||||
*p = (time - (*kF1)->fFrame / MAX_FRAMES_PER_SEC) / (((*kF2)->fFrame - (*kF1)->fFrame) / MAX_FRAMES_PER_SEC);
|
||||
goto ret;
|
||||
}
|
||||
key1=key2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (count = 1; count <= numKeys; count++, i--)
|
||||
{
|
||||
if (i < 1)
|
||||
{
|
||||
i = numKeys - 1;
|
||||
key2 = GetKey(i, keys, size);
|
||||
count++;
|
||||
}
|
||||
|
||||
key1 = GetKey(i - 1, keys, size);
|
||||
if (frame <= key2->fFrame && frame >= key1->fFrame)
|
||||
{
|
||||
k2 = i;
|
||||
k1 = i - 1;
|
||||
(*kF2) = key2;
|
||||
(*kF1) = key1;
|
||||
*p = (time - (*kF1)->fFrame / MAX_FRAMES_PER_SEC) / (((*kF2)->fFrame - (*kF1)->fFrame) / MAX_FRAMES_PER_SEC);
|
||||
goto ret;
|
||||
}
|
||||
key2=key1;
|
||||
}
|
||||
}
|
||||
|
||||
ret:
|
||||
;
|
||||
|
||||
#if 0
|
||||
char str[128];
|
||||
sprintf(str, "k1=%d, k2=%d, p=%f\n", k1, k2, *p);
|
||||
OutputDebugString(str);
|
||||
#endif
|
||||
*lastKeyIdx = k1;
|
||||
}
|
||||
|
||||
|
98
Sources/Plasma/PubUtilLib/plInterp/hsInterp.h
Normal file
98
Sources/Plasma/PubUtilLib/plInterp/hsInterp.h
Normal file
@ -0,0 +1,98 @@
|
||||
/*==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==*/
|
||||
#ifndef HSINTERP_inc
|
||||
#define HSINTERP_inc
|
||||
|
||||
#include "HeadSpin.h"
|
||||
#include "hsKeys.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
// Performs interpolation of keyframes & values.
|
||||
// t param should be 0-1
|
||||
//
|
||||
struct hsColorRGBA;
|
||||
class hsAffineParts;
|
||||
class hsInterp
|
||||
{
|
||||
public:
|
||||
enum IgnoreFlags
|
||||
{
|
||||
kIgnoreAlpha = 0x1,
|
||||
kIgnoreLastMatRow = 0x2,
|
||||
kIgnorePartsPos = 0x4,
|
||||
kIgnorePartsRot = 0x8,
|
||||
kIgnorePartsScale = 0x10, // result gets no scale
|
||||
kIgnorePartsDet = 0x20,
|
||||
kPreservePartsScale = 0x40 // result gets the scale of key1
|
||||
};
|
||||
|
||||
static void BezScalarEval(const hsScalar value1, const hsScalar outTan,
|
||||
const hsScalar value2, const hsScalar inTan,
|
||||
const hsScalar t, const hsScalar scale, hsScalar *result);
|
||||
static void BezInterp(const hsBezPoint3Key *k1, const hsBezPoint3Key *k2, const hsScalar t, hsScalarTriple *result);
|
||||
static void BezInterp(const hsBezScalarKey *k1, const hsBezScalarKey *k2, const hsScalar t, hsScalar *result);
|
||||
static void BezInterp(const hsBezScaleKey *k1, const hsBezScaleKey *k2, const hsScalar t, hsScaleValue *result);
|
||||
|
||||
// simple linear interpolation
|
||||
static void LinInterp(const hsScalar k1, const hsScalar k2, const hsScalar t, hsScalar *result);
|
||||
static void LinInterp(const hsScalarTriple *k1, const hsScalarTriple *k2, const hsScalar t, hsScalarTriple *result);
|
||||
static void LinInterp(const hsColorRGBA *k1, const hsColorRGBA *k2, const hsScalar t, hsColorRGBA *result, UInt32 ignoreFlags=0);
|
||||
static void LinInterp(const hsMatrix33 *k1, const hsMatrix33 *k2, const hsScalar t, hsMatrix33 *result, UInt32 ignoreFlags=0);
|
||||
static void LinInterp(const hsMatrix44 *mat1, const hsMatrix44 *mat2, const hsScalar t, hsMatrix44 *out, UInt32 ignoreFlags=0);
|
||||
static void LinInterp(const hsQuat *k1, const hsQuat *k2, const hsScalar t, hsQuat *result);
|
||||
static void LinInterp(const hsScaleValue *k1, const hsScaleValue *k2, const hsScalar t, hsScaleValue *result);
|
||||
static void LinInterp(const hsAffineParts *k1, const hsAffineParts *k2, const hsScalar t, hsAffineParts *result, UInt32 ignoreFlags=0);
|
||||
|
||||
// Given a time value, find the enclosing keyframes and normalize time (0-1)
|
||||
static void GetBoundaryKeyFrames(hsScalar time, UInt32 numKeys, void *keys,
|
||||
UInt32 keySize, hsKeyFrame **kF1, hsKeyFrame **kF2, UInt32 *lastKeyIdx, hsScalar *p, hsBool forwards);
|
||||
|
||||
};
|
||||
|
||||
#define MAX_FRAMES_PER_SEC 30.0f
|
||||
#define MAX_TICKS_PER_FRAME 160.0f
|
||||
#define MAX_TICKS_PER_SEC (MAX_TICKS_PER_FRAME*MAX_FRAMES_PER_SEC)
|
||||
|
||||
#endif // #ifndef HSINTERP_inc
|
570
Sources/Plasma/PubUtilLib/plInterp/hsKeys.cpp
Normal file
570
Sources/Plasma/PubUtilLib/plInterp/hsKeys.cpp
Normal file
@ -0,0 +1,570 @@
|
||||
/*==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 "hsKeys.h"
|
||||
#include "hsStream.h"
|
||||
|
||||
const int hsKeyFrame::kMaxFrameNumber = 65535;
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
void hsPoint3Key::Read(hsStream *stream)
|
||||
{
|
||||
fFrame = stream->ReadSwap16();
|
||||
fValue.Read(stream);
|
||||
}
|
||||
|
||||
void hsPoint3Key::Write(hsStream *stream)
|
||||
{
|
||||
stream->WriteSwap16(fFrame);
|
||||
fValue.Write(stream);
|
||||
}
|
||||
|
||||
hsBool hsPoint3Key::CompareValue(hsPoint3Key *key)
|
||||
{
|
||||
return hsABS(fValue.fX - key->fValue.fX) < .01 &&
|
||||
hsABS(fValue.fY - key->fValue.fY) < .01 &&
|
||||
hsABS(fValue.fZ - key->fValue.fZ) < .01;
|
||||
}
|
||||
|
||||
void hsBezPoint3Key::Read(hsStream *stream)
|
||||
{
|
||||
fFrame = stream->ReadSwap16();
|
||||
fInTan.Read(stream);
|
||||
fOutTan.Read(stream);
|
||||
fValue.Read(stream);
|
||||
}
|
||||
|
||||
void hsBezPoint3Key::Write(hsStream *stream)
|
||||
{
|
||||
stream->WriteSwap16(fFrame);
|
||||
fInTan.Write(stream);
|
||||
fOutTan.Write(stream);
|
||||
fValue.Write(stream);
|
||||
}
|
||||
|
||||
hsBool hsBezPoint3Key::CompareValue(hsBezPoint3Key *key)
|
||||
{
|
||||
return hsABS(fValue.fX - key->fValue.fX) < .01 &&
|
||||
hsABS(fValue.fY - key->fValue.fY) < .01 &&
|
||||
hsABS(fValue.fZ - key->fValue.fZ) < .01;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
void hsScalarKey::Read(hsStream *stream)
|
||||
{
|
||||
fFrame = stream->ReadSwap16();
|
||||
fValue = stream->ReadSwapScalar();
|
||||
}
|
||||
|
||||
void hsScalarKey::Write(hsStream *stream)
|
||||
{
|
||||
stream->WriteSwap16(fFrame);
|
||||
stream->WriteSwapScalar(fValue);
|
||||
}
|
||||
|
||||
hsBool hsScalarKey::CompareValue(hsScalarKey *key)
|
||||
{
|
||||
return fValue == key->fValue;
|
||||
}
|
||||
|
||||
void hsBezScalarKey::Read(hsStream *stream)
|
||||
{
|
||||
fFrame = stream->ReadSwap16();
|
||||
fInTan = stream->ReadSwapScalar();
|
||||
fOutTan = stream->ReadSwapScalar();
|
||||
fValue = stream->ReadSwapScalar();
|
||||
}
|
||||
|
||||
void hsBezScalarKey::Write(hsStream *stream)
|
||||
{
|
||||
stream->WriteSwap16(fFrame);
|
||||
stream->WriteSwapScalar(fInTan);
|
||||
stream->WriteSwapScalar(fOutTan);
|
||||
stream->WriteSwapScalar(fValue);
|
||||
}
|
||||
|
||||
hsBool hsBezScalarKey::CompareValue(hsBezScalarKey *key)
|
||||
{
|
||||
return fValue == key->fValue;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
void hsQuatKey::Read(hsStream *stream)
|
||||
{
|
||||
fFrame = stream->ReadSwap16();
|
||||
fValue.Read(stream);
|
||||
}
|
||||
|
||||
void hsQuatKey::Write(hsStream *stream)
|
||||
{
|
||||
stream->WriteSwap16(fFrame);
|
||||
fValue.Write(stream);
|
||||
}
|
||||
|
||||
hsBool hsQuatKey::CompareValue(hsQuatKey *key)
|
||||
{
|
||||
return fValue == key->fValue;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const hsScalar hsCompressedQuatKey32::kOneOverRootTwo = 0.70710678;
|
||||
const hsScalar hsCompressedQuatKey32::k10BitScaleRange = 1023 / (2 * kOneOverRootTwo);
|
||||
|
||||
void hsCompressedQuatKey32::Read(hsStream *stream)
|
||||
{
|
||||
fFrame = stream->ReadSwap16();
|
||||
fData = stream->ReadSwap32();
|
||||
}
|
||||
|
||||
void hsCompressedQuatKey32::Write(hsStream *stream)
|
||||
{
|
||||
stream->WriteSwap16(fFrame);
|
||||
stream->WriteSwap32(fData);
|
||||
}
|
||||
|
||||
hsBool hsCompressedQuatKey32::CompareValue(hsCompressedQuatKey32 *key)
|
||||
{
|
||||
return fData == key->fData;
|
||||
}
|
||||
|
||||
// To store a quat in 32 bits, we find which element is the largest and use 2 bits to
|
||||
// store which one it is. We now know the other 3 elements fall in the range
|
||||
// of [-kOneOverRootTwo, kOneOverRootTwo]. We scale that range across 10 bits
|
||||
// and store each. When extracting, we use the fact that the quat was normalized
|
||||
// to compute the 4th element.
|
||||
void hsCompressedQuatKey32::SetQuat(hsQuat &q)
|
||||
{
|
||||
q.Normalize();
|
||||
UInt32 maxElement = kCompQuatNukeX;
|
||||
hsScalar maxVal = hsABS(q.fX);
|
||||
if (hsABS(q.fY) > maxVal)
|
||||
{
|
||||
maxElement = kCompQuatNukeY;
|
||||
maxVal = hsABS(q.fY);
|
||||
}
|
||||
if (hsABS(q.fZ) > maxVal)
|
||||
{
|
||||
maxElement = kCompQuatNukeZ;
|
||||
maxVal = hsABS(q.fZ);
|
||||
}
|
||||
if (hsABS(q.fW) > maxVal)
|
||||
{
|
||||
maxElement = kCompQuatNukeW;
|
||||
maxVal = hsABS(q.fW);
|
||||
}
|
||||
switch (maxElement)
|
||||
{
|
||||
case kCompQuatNukeX:
|
||||
{
|
||||
// Invert the quat so that the largest element is positive.
|
||||
// We need to do this so that later we know to use the positive root.
|
||||
if (q.fX < 0)
|
||||
q = -q;
|
||||
|
||||
fData = (maxElement << 30) |
|
||||
(((UInt32)(k10BitScaleRange * (q.fY + kOneOverRootTwo))) << 20) |
|
||||
(((UInt32)(k10BitScaleRange * (q.fZ + kOneOverRootTwo))) << 10) |
|
||||
(((UInt32)(k10BitScaleRange * (q.fW + kOneOverRootTwo))));
|
||||
break;
|
||||
}
|
||||
case kCompQuatNukeY:
|
||||
{
|
||||
if (q.fY < 0)
|
||||
q = -q;
|
||||
|
||||
fData = (maxElement << 30) |
|
||||
(((UInt32)(k10BitScaleRange * (q.fX + kOneOverRootTwo))) << 20) |
|
||||
(((UInt32)(k10BitScaleRange * (q.fZ + kOneOverRootTwo))) << 10) |
|
||||
(((UInt32)(k10BitScaleRange * (q.fW + kOneOverRootTwo))));
|
||||
break;
|
||||
}
|
||||
case kCompQuatNukeZ:
|
||||
{
|
||||
if (q.fZ < 0)
|
||||
q = -q;
|
||||
|
||||
fData = (maxElement << 30) |
|
||||
(((UInt32)(k10BitScaleRange * (q.fX + kOneOverRootTwo))) << 20) |
|
||||
(((UInt32)(k10BitScaleRange * (q.fY + kOneOverRootTwo))) << 10) |
|
||||
(((UInt32)(k10BitScaleRange * (q.fW + kOneOverRootTwo))));
|
||||
break;
|
||||
}
|
||||
case kCompQuatNukeW:
|
||||
default:
|
||||
{
|
||||
if (q.fW < 0)
|
||||
q = -q;
|
||||
|
||||
fData = (maxElement << 30) |
|
||||
(((UInt32)(k10BitScaleRange * (q.fX + kOneOverRootTwo))) << 20) |
|
||||
(((UInt32)(k10BitScaleRange * (q.fY + kOneOverRootTwo))) << 10) |
|
||||
(((UInt32)(k10BitScaleRange * (q.fZ + kOneOverRootTwo))));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hsCompressedQuatKey32::GetQuat(hsQuat &q)
|
||||
{
|
||||
UInt32 maxElement = fData >> 30;
|
||||
switch (maxElement)
|
||||
{
|
||||
case kCompQuatNukeX:
|
||||
{
|
||||
q.fY = (fData >> 20 & 0x000003ff) / k10BitScaleRange - kOneOverRootTwo;
|
||||
q.fZ = (fData >> 10 & 0x000003ff) / k10BitScaleRange - kOneOverRootTwo;
|
||||
q.fW = (fData & 0x000003ff) / k10BitScaleRange - kOneOverRootTwo;
|
||||
q.fX = hsSquareRoot(1 - q.fY * q.fY - q.fZ * q.fZ - q.fW *q.fW);
|
||||
break;
|
||||
}
|
||||
case kCompQuatNukeY:
|
||||
{
|
||||
q.fX = (fData >> 20 & 0x000003ff) / k10BitScaleRange - kOneOverRootTwo;
|
||||
q.fZ = (fData >> 10 & 0x000003ff) / k10BitScaleRange - kOneOverRootTwo;
|
||||
q.fW = (fData & 0x000003ff) / k10BitScaleRange - kOneOverRootTwo;
|
||||
q.fY = hsSquareRoot(1 - q.fX * q.fX - q.fZ * q.fZ - q.fW *q.fW);
|
||||
break;
|
||||
}
|
||||
case kCompQuatNukeZ:
|
||||
{
|
||||
q.fX = (fData >> 20 & 0x000003ff) / k10BitScaleRange - kOneOverRootTwo;
|
||||
q.fY = (fData >> 10 & 0x000003ff) / k10BitScaleRange - kOneOverRootTwo;
|
||||
q.fW = (fData & 0x000003ff) / k10BitScaleRange - kOneOverRootTwo;
|
||||
q.fZ = hsSquareRoot(1 - q.fX * q.fX - q.fY * q.fY - q.fW *q.fW);
|
||||
break;
|
||||
}
|
||||
case kCompQuatNukeW:
|
||||
default:
|
||||
{
|
||||
q.fX = (fData >> 20 & 0x000003ff) / k10BitScaleRange - kOneOverRootTwo;
|
||||
q.fY = (fData >> 10 & 0x000003ff) / k10BitScaleRange - kOneOverRootTwo;
|
||||
q.fZ = (fData & 0x000003ff) / k10BitScaleRange - kOneOverRootTwo;
|
||||
q.fW = hsSquareRoot(1 - q.fX * q.fX - q.fY * q.fY - q.fZ * q.fZ);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const hsScalar hsCompressedQuatKey64::kOneOverRootTwo = 0.70710678;
|
||||
const hsScalar hsCompressedQuatKey64::k20BitScaleRange = 1048575 / (2 * kOneOverRootTwo);
|
||||
const hsScalar hsCompressedQuatKey64::k21BitScaleRange = 2097151 / (2 * kOneOverRootTwo);
|
||||
|
||||
void hsCompressedQuatKey64::Read(hsStream *stream)
|
||||
{
|
||||
fFrame = stream->ReadSwap16();
|
||||
fData[0] = stream->ReadSwap32();
|
||||
fData[1] = stream->ReadSwap32();
|
||||
}
|
||||
|
||||
void hsCompressedQuatKey64::Write(hsStream *stream)
|
||||
{
|
||||
stream->WriteSwap16(fFrame);
|
||||
stream->WriteSwap32(fData[0]);
|
||||
stream->WriteSwap32(fData[1]);
|
||||
}
|
||||
|
||||
hsBool hsCompressedQuatKey64::CompareValue(hsCompressedQuatKey64 *key)
|
||||
{
|
||||
return (fData[0] == key->fData[0]) && (fData[1] == key->fData[1]);
|
||||
}
|
||||
|
||||
// To store a quat in 64 bits, we find which element is the largest and use 2 bits to
|
||||
// store which one it is. We now know the other 3 elements fall in the range
|
||||
// of [-kOneOverRootTwo, kOneOverRootTwo]. We scale that range across 20/21/21 bits
|
||||
// and store each. When extracting, we use the fact that the quat was normalized
|
||||
// to compute the 4th element.
|
||||
void hsCompressedQuatKey64::SetQuat(hsQuat &q)
|
||||
{
|
||||
q.Normalize();
|
||||
UInt32 maxElement = kCompQuatNukeX;
|
||||
hsScalar maxVal = hsABS(q.fX);
|
||||
if (hsABS(q.fY) > maxVal)
|
||||
{
|
||||
maxElement = kCompQuatNukeY;
|
||||
maxVal = hsABS(q.fY);
|
||||
}
|
||||
if (hsABS(q.fZ) > maxVal)
|
||||
{
|
||||
maxElement = kCompQuatNukeZ;
|
||||
maxVal = hsABS(q.fZ);
|
||||
}
|
||||
if (hsABS(q.fW) > maxVal)
|
||||
{
|
||||
maxElement = kCompQuatNukeW;
|
||||
maxVal = hsABS(q.fW);
|
||||
}
|
||||
switch (maxElement)
|
||||
{
|
||||
case kCompQuatNukeX:
|
||||
{
|
||||
// Invert the quat so that the largest element is positive.
|
||||
// We need to do this so that later we know to use the positive root.
|
||||
if (q.fX < 0)
|
||||
q = -q;
|
||||
|
||||
fData[0] = (maxElement << 30) |
|
||||
(((UInt32)(k20BitScaleRange * (q.fY + kOneOverRootTwo))) << 10) |
|
||||
(((UInt32)(k21BitScaleRange * (q.fZ + kOneOverRootTwo))) >> 11);
|
||||
fData[1] =
|
||||
(((UInt32)(k21BitScaleRange * (q.fZ + kOneOverRootTwo))) << 21) |
|
||||
(((UInt32)(k21BitScaleRange * (q.fW + kOneOverRootTwo))));
|
||||
break;
|
||||
}
|
||||
case kCompQuatNukeY:
|
||||
{
|
||||
if (q.fY < 0)
|
||||
q = -q;
|
||||
|
||||
fData[0] = (maxElement << 30) |
|
||||
(((UInt32)(k20BitScaleRange * (q.fX + kOneOverRootTwo))) << 10) |
|
||||
(((UInt32)(k21BitScaleRange * (q.fZ + kOneOverRootTwo))) >> 11);
|
||||
fData[1] =
|
||||
(((UInt32)(k21BitScaleRange * (q.fZ + kOneOverRootTwo))) << 21) |
|
||||
(((UInt32)(k21BitScaleRange * (q.fW + kOneOverRootTwo))));
|
||||
break;
|
||||
}
|
||||
case kCompQuatNukeZ:
|
||||
{
|
||||
if (q.fZ < 0)
|
||||
q = -q;
|
||||
|
||||
fData[0] = (maxElement << 30) |
|
||||
(((UInt32)(k20BitScaleRange * (q.fX + kOneOverRootTwo))) << 10) |
|
||||
(((UInt32)(k21BitScaleRange * (q.fY + kOneOverRootTwo))) >> 11);
|
||||
fData[1] =
|
||||
(((UInt32)(k21BitScaleRange * (q.fY + kOneOverRootTwo))) << 21) |
|
||||
(((UInt32)(k21BitScaleRange * (q.fW + kOneOverRootTwo))));
|
||||
break;
|
||||
}
|
||||
case kCompQuatNukeW:
|
||||
default:
|
||||
{
|
||||
if (q.fW < 0)
|
||||
q = -q;
|
||||
|
||||
fData[0] = (maxElement << 30) |
|
||||
(((UInt32)(k20BitScaleRange * (q.fX + kOneOverRootTwo))) << 10) |
|
||||
(((UInt32)(k21BitScaleRange * (q.fY + kOneOverRootTwo))) >> 11);
|
||||
fData[1] =
|
||||
(((UInt32)(k21BitScaleRange * (q.fY + kOneOverRootTwo))) << 21) |
|
||||
(((UInt32)(k21BitScaleRange * (q.fZ + kOneOverRootTwo))));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hsCompressedQuatKey64::GetQuat(hsQuat &q)
|
||||
{
|
||||
UInt32 maxElement = fData[0] >> 30;
|
||||
switch (maxElement)
|
||||
{
|
||||
case kCompQuatNukeX:
|
||||
{
|
||||
q.fY = ((fData[0] >> 10) & 0x000fffff) / k20BitScaleRange - kOneOverRootTwo;
|
||||
q.fZ = (((fData[0] & 0x000003ff) << 11) | (fData[1] >> 21)) / k21BitScaleRange - kOneOverRootTwo;
|
||||
q.fW = (fData[1] & 0x001fffff) / k21BitScaleRange - kOneOverRootTwo;
|
||||
q.fX = hsSquareRoot(1 - q.fY * q.fY - q.fZ * q.fZ - q.fW *q.fW);
|
||||
break;
|
||||
}
|
||||
case kCompQuatNukeY:
|
||||
{
|
||||
q.fX = ((fData[0] >> 10) & 0x000fffff) / k20BitScaleRange - kOneOverRootTwo;
|
||||
q.fZ = (((fData[0] & 0x000003ff) << 11) | (fData[1] >> 21)) / k21BitScaleRange - kOneOverRootTwo;
|
||||
q.fW = (fData[1] & 0x001fffff) / k21BitScaleRange - kOneOverRootTwo;
|
||||
q.fY = hsSquareRoot(1 - q.fX * q.fX - q.fZ * q.fZ - q.fW *q.fW);
|
||||
break;
|
||||
}
|
||||
case kCompQuatNukeZ:
|
||||
{
|
||||
q.fX = ((fData[0] >> 10) & 0x000fffff) / k20BitScaleRange - kOneOverRootTwo;
|
||||
q.fY = (((fData[0] & 0x000003ff) << 11) | (fData[1] >> 21)) / k21BitScaleRange - kOneOverRootTwo;
|
||||
q.fW = (fData[1] & 0x001fffff) / k21BitScaleRange - kOneOverRootTwo;
|
||||
q.fZ = hsSquareRoot(1 - q.fX * q.fX - q.fY * q.fY - q.fW *q.fW);
|
||||
break;
|
||||
}
|
||||
case kCompQuatNukeW:
|
||||
default:
|
||||
{
|
||||
q.fX = ((fData[0] >> 10) & 0x000fffff) / k20BitScaleRange - kOneOverRootTwo;
|
||||
q.fY = (((fData[0] & 0x000003ff) << 11) | (fData[1] >> 21)) / k21BitScaleRange - kOneOverRootTwo;
|
||||
q.fZ = (fData[1] & 0x001fffff) / k21BitScaleRange - kOneOverRootTwo;
|
||||
q.fW = hsSquareRoot(1 - q.fX * q.fX - q.fY * q.fY - q.fZ * q.fZ);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Not a key
|
||||
//
|
||||
void hsScaleValue::Read(hsStream *stream)
|
||||
{
|
||||
fS.Read(stream);
|
||||
fQ.Read(stream);
|
||||
}
|
||||
|
||||
void hsScaleValue::Write(hsStream *stream)
|
||||
{
|
||||
fS.Write(stream);
|
||||
fQ.Write(stream);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
void hsScaleKey::Read(hsStream *stream)
|
||||
{
|
||||
fFrame = stream->ReadSwap16();
|
||||
fValue.Read(stream);
|
||||
}
|
||||
|
||||
void hsScaleKey::Write(hsStream *stream)
|
||||
{
|
||||
stream->WriteSwap16(fFrame);
|
||||
fValue.Write(stream);
|
||||
}
|
||||
|
||||
hsBool hsScaleKey::CompareValue(hsScaleKey *key)
|
||||
{
|
||||
return fValue == key->fValue;
|
||||
}
|
||||
|
||||
void hsBezScaleKey::Read(hsStream *stream)
|
||||
{
|
||||
fFrame = stream->ReadSwap16();
|
||||
fInTan.Read(stream);
|
||||
fOutTan.Read(stream);
|
||||
fValue.Read(stream);
|
||||
}
|
||||
|
||||
void hsBezScaleKey::Write(hsStream *stream)
|
||||
{
|
||||
stream->WriteSwap16(fFrame);
|
||||
fInTan.Write(stream);
|
||||
fOutTan.Write(stream);
|
||||
fValue.Write(stream);
|
||||
}
|
||||
|
||||
hsBool hsBezScaleKey::CompareValue(hsBezScaleKey *key)
|
||||
{
|
||||
return fValue == key->fValue;
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
|
||||
void hsG3DSMaxKeyFrame::Set(hsMatrix44 *mat, UInt16 frame)
|
||||
{
|
||||
fFrame = frame;
|
||||
gemAffineParts parts;
|
||||
decomp_affine(mat->fMap, &parts);
|
||||
AP_SET(fParts, parts);
|
||||
}
|
||||
|
||||
void hsG3DSMaxKeyFrame::Set(const hsAffineParts &parts, UInt16 frame)
|
||||
{
|
||||
fFrame = frame;
|
||||
fParts = parts;
|
||||
}
|
||||
|
||||
void hsG3DSMaxKeyFrame::Read(hsStream *stream)
|
||||
{
|
||||
fFrame = stream->ReadSwap16();
|
||||
fParts.Read(stream);
|
||||
}
|
||||
|
||||
void hsG3DSMaxKeyFrame::Write(hsStream *stream)
|
||||
{
|
||||
stream->WriteSwap16(fFrame);
|
||||
fParts.Write(stream);
|
||||
}
|
||||
|
||||
hsBool hsG3DSMaxKeyFrame::CompareValue(hsG3DSMaxKeyFrame *key)
|
||||
{
|
||||
return fParts == key->fParts;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
void hsMatrix33Key::Read(hsStream *stream)
|
||||
{
|
||||
fFrame = stream->ReadSwap16();
|
||||
Int32 i,j;
|
||||
for(i=0;i<3;i++)
|
||||
for(j=0;j<3;j++)
|
||||
fValue.fMap[j][i] = stream->ReadSwapScalar();
|
||||
}
|
||||
|
||||
void hsMatrix33Key::Write(hsStream *stream)
|
||||
{
|
||||
stream->WriteSwap16(fFrame);
|
||||
Int32 i,j;
|
||||
for(i=0;i<3;i++)
|
||||
for(j=0;j<3;j++)
|
||||
stream->WriteSwapScalar(fValue.fMap[j][i]);
|
||||
}
|
||||
|
||||
hsBool hsMatrix33Key::CompareValue(hsMatrix33Key *key)
|
||||
{
|
||||
return fValue == key->fValue;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
|
||||
void hsMatrix44Key::Read(hsStream *stream)
|
||||
{
|
||||
fFrame = stream->ReadSwap16();
|
||||
fValue.Read(stream);
|
||||
}
|
||||
|
||||
void hsMatrix44Key::Write(hsStream *stream)
|
||||
{
|
||||
stream->WriteSwap16(fFrame);
|
||||
fValue.Write(stream);
|
||||
}
|
||||
|
||||
hsBool hsMatrix44Key::CompareValue(hsMatrix44Key *key)
|
||||
{
|
||||
return fValue == key->fValue;
|
||||
}
|
255
Sources/Plasma/PubUtilLib/plInterp/hsKeys.h
Normal file
255
Sources/Plasma/PubUtilLib/plInterp/hsKeys.h
Normal file
@ -0,0 +1,255 @@
|
||||
/*==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==*/
|
||||
#ifndef HSKEYS_inc
|
||||
#define HSKEYS_inc
|
||||
|
||||
#include "HeadSpin.h"
|
||||
#include "hsGeometry3.h"
|
||||
#include "hsQuat.h"
|
||||
#include "../plTransform/hsAffineParts.h"
|
||||
#include "hsMatrix33.h"
|
||||
#include "hsMatrix44.h"
|
||||
|
||||
// No virtuals. Keep these nice and lean.
|
||||
struct hsKeyFrame
|
||||
{
|
||||
// Used by plController to specify which keys it has.
|
||||
enum
|
||||
{
|
||||
kUnknownKeyFrame,
|
||||
kPoint3KeyFrame,
|
||||
kBezPoint3KeyFrame,
|
||||
kScalarKeyFrame,
|
||||
kBezScalarKeyFrame,
|
||||
kScaleKeyFrame,
|
||||
kBezScaleKeyFrame,
|
||||
kQuatKeyFrame,
|
||||
kCompressedQuatKeyFrame32,
|
||||
kCompressedQuatKeyFrame64,
|
||||
k3dsMaxKeyFrame,
|
||||
kMatrix33KeyFrame,
|
||||
kMatrix44KeyFrame,
|
||||
};
|
||||
|
||||
UInt16 fFrame;
|
||||
static const int kMaxFrameNumber;
|
||||
};
|
||||
|
||||
struct hsPoint3Key : public hsKeyFrame
|
||||
{
|
||||
hsPoint3 fValue;
|
||||
|
||||
void Read(hsStream *stream);
|
||||
void Write(hsStream *stream);
|
||||
|
||||
hsBool CompareValue(hsPoint3Key *key);
|
||||
};
|
||||
|
||||
struct hsBezPoint3Key : public hsKeyFrame
|
||||
{
|
||||
hsPoint3 fInTan;
|
||||
hsPoint3 fOutTan;
|
||||
hsPoint3 fValue;
|
||||
|
||||
void Read(hsStream *stream);
|
||||
void Write(hsStream *stream);
|
||||
|
||||
hsBool CompareValue(hsBezPoint3Key *key);
|
||||
};
|
||||
|
||||
struct hsScalarKey : public hsKeyFrame
|
||||
{
|
||||
hsScalar fValue;
|
||||
|
||||
void Read(hsStream *stream);
|
||||
void Write(hsStream *stream);
|
||||
|
||||
hsBool CompareValue(hsScalarKey *key);
|
||||
};
|
||||
|
||||
struct hsBezScalarKey : public hsKeyFrame
|
||||
{
|
||||
hsScalar fInTan;
|
||||
hsScalar fOutTan;
|
||||
hsScalar fValue;
|
||||
|
||||
void Read(hsStream *stream);
|
||||
void Write(hsStream *stream);
|
||||
|
||||
hsBool CompareValue(hsBezScalarKey *key);
|
||||
};
|
||||
|
||||
struct hsQuatKey : public hsKeyFrame
|
||||
{
|
||||
hsQuat fValue;
|
||||
|
||||
void Read(hsStream *stream);
|
||||
void Write(hsStream *stream);
|
||||
|
||||
hsBool CompareValue(hsQuatKey *key);
|
||||
};
|
||||
|
||||
struct hsCompressedQuatKey32 : public hsKeyFrame
|
||||
{
|
||||
enum
|
||||
{
|
||||
kCompQuatNukeX,
|
||||
kCompQuatNukeY,
|
||||
kCompQuatNukeZ,
|
||||
kCompQuatNukeW,
|
||||
};
|
||||
|
||||
static const hsScalar kOneOverRootTwo;
|
||||
static const hsScalar k10BitScaleRange;
|
||||
|
||||
void SetQuat(hsQuat &q);
|
||||
void GetQuat(hsQuat &q);
|
||||
|
||||
void Read(hsStream *stream);
|
||||
void Write(hsStream *stream);
|
||||
|
||||
hsBool CompareValue(hsCompressedQuatKey32 *key);
|
||||
|
||||
protected:
|
||||
UInt32 fData;
|
||||
};
|
||||
|
||||
struct hsCompressedQuatKey64 : public hsKeyFrame
|
||||
{
|
||||
enum
|
||||
{
|
||||
kCompQuatNukeX,
|
||||
kCompQuatNukeY,
|
||||
kCompQuatNukeZ,
|
||||
kCompQuatNukeW,
|
||||
};
|
||||
|
||||
static const hsScalar kOneOverRootTwo;
|
||||
static const hsScalar k20BitScaleRange;
|
||||
static const hsScalar k21BitScaleRange;
|
||||
|
||||
void SetQuat(hsQuat &q);
|
||||
void GetQuat(hsQuat &q);
|
||||
|
||||
void Read(hsStream *stream);
|
||||
void Write(hsStream *stream);
|
||||
|
||||
hsBool CompareValue(hsCompressedQuatKey64 *key);
|
||||
|
||||
protected:
|
||||
UInt32 fData[2];
|
||||
};
|
||||
|
||||
struct hsScaleValue : public hsKeyFrame
|
||||
{
|
||||
hsVector3 fS; /* Scale components for x,y,z */
|
||||
hsQuat fQ; /* The axis along which the scale is applied */
|
||||
|
||||
void Read(hsStream *stream);
|
||||
void Write(hsStream *stream);
|
||||
|
||||
int operator==(const hsScaleValue& a) const { return (fS == a.fS && fQ == a.fQ); }
|
||||
};
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
struct hsScaleKey : public hsKeyFrame
|
||||
{
|
||||
hsScaleValue fValue;
|
||||
|
||||
void Read(hsStream *stream);
|
||||
void Write(hsStream *stream);
|
||||
|
||||
hsBool CompareValue(hsScaleKey *key);
|
||||
};
|
||||
|
||||
struct hsBezScaleKey : public hsKeyFrame
|
||||
{
|
||||
hsPoint3 fInTan;
|
||||
hsPoint3 fOutTan;
|
||||
hsScaleValue fValue;
|
||||
|
||||
void Read(hsStream *stream);
|
||||
void Write(hsStream *stream);
|
||||
|
||||
hsBool CompareValue(hsBezScaleKey *key);
|
||||
};
|
||||
|
||||
struct hsG3DSMaxKeyFrame : public hsKeyFrame
|
||||
{
|
||||
hsAffineParts fParts;
|
||||
|
||||
void Reset() { fParts.Reset(); } // Make parts identity
|
||||
|
||||
void Set(hsMatrix44 *mat, UInt16 frame);
|
||||
void Set(const hsAffineParts &parts, UInt16 frame);
|
||||
|
||||
hsMatrix44* GetMatrix44(hsMatrix44 *mat) { fParts.ComposeMatrix(mat); return mat; }
|
||||
|
||||
void Read(hsStream *stream);
|
||||
void Write(hsStream *stream);
|
||||
|
||||
hsBool CompareValue(hsG3DSMaxKeyFrame *key);
|
||||
};
|
||||
|
||||
struct hsMatrix33Key : public hsKeyFrame
|
||||
{
|
||||
hsMatrix33 fValue;
|
||||
|
||||
void Read(hsStream *stream);
|
||||
void Write(hsStream *stream);
|
||||
|
||||
hsBool CompareValue(hsMatrix33Key *key);
|
||||
};
|
||||
|
||||
struct hsMatrix44Key : public hsKeyFrame
|
||||
{
|
||||
hsMatrix44 fValue;
|
||||
|
||||
void Read(hsStream *stream);
|
||||
void Write(hsStream *stream);
|
||||
|
||||
hsBool CompareValue(hsMatrix44Key *key);
|
||||
};
|
||||
|
||||
#endif
|
236
Sources/Plasma/PubUtilLib/plInterp/hsTimedValue.h
Normal file
236
Sources/Plasma/PubUtilLib/plInterp/hsTimedValue.h
Normal file
@ -0,0 +1,236 @@
|
||||
/*==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==*/
|
||||
|
||||
#ifndef hsTimedValue_inc
|
||||
#define hsTimedValue_inc
|
||||
|
||||
#include "hsStream.h"
|
||||
|
||||
template <class T>
|
||||
class hsTimedValue {
|
||||
public:
|
||||
enum {
|
||||
kIdle = 0x1,
|
||||
kInstant = 0x2
|
||||
};
|
||||
protected:
|
||||
UInt32 fFlags;
|
||||
hsScalar fDuration;
|
||||
hsScalar fStartTime;
|
||||
|
||||
T fValue;
|
||||
T fGoal;
|
||||
T fFrom;
|
||||
|
||||
public:
|
||||
hsTimedValue() : fFlags(kIdle|kInstant), fDuration(0) {}
|
||||
hsTimedValue(const T& v) : fFlags(kIdle|kInstant), fDuration(0) { SetValue(v); }
|
||||
|
||||
UInt32 GetFlags() { return fFlags; }
|
||||
|
||||
void SetDuration(hsScalar duration);
|
||||
hsScalar GetDuration() const { return fDuration; }
|
||||
|
||||
hsBool32 operator==(const hsTimedValue<T>& v);
|
||||
hsTimedValue<T>& operator=(const T& v) { SetValue(v); return *this; }
|
||||
hsTimedValue<T>& operator+=(const T& v) { SetValue(v + fValue); return *this; }
|
||||
|
||||
void SetTempValue(const T& v) { fValue = v; }
|
||||
void SetValue(const T& v) { fFrom = fGoal = fValue = v; fFlags |= kIdle; }
|
||||
const T& GetValue() const { return fValue; }
|
||||
|
||||
void SetGoal(const T& g) { fGoal = g; }
|
||||
const T& GetGoal() const { return fGoal; }
|
||||
|
||||
void Reset() { fFlags |= (kIdle | kInstant); }
|
||||
|
||||
void StartClock(hsScalar s);
|
||||
hsScalar GetStartTime() const { return fStartTime; }
|
||||
|
||||
const T& GetFrom() const { return fFrom; }
|
||||
|
||||
void Update(hsScalar s);
|
||||
|
||||
void WriteScalar(hsStream* s, hsScalar currSecs);
|
||||
void Write(hsStream* s, hsScalar currSecs);
|
||||
|
||||
void ReadScalar(hsStream* s, hsScalar currSecs);
|
||||
void Read(hsStream* s, hsScalar currSecs);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void hsTimedValue<T>::WriteScalar(hsStream* s, hsScalar currSecs)
|
||||
{
|
||||
s->WriteSwap32(fFlags);
|
||||
|
||||
s->WriteSwapScalar(fValue);
|
||||
|
||||
if( !(fFlags & kIdle) )
|
||||
{
|
||||
s->WriteSwapScalar(fDuration);
|
||||
s->WriteSwapScalar(currSecs - fStartTime);
|
||||
|
||||
s->WriteSwapScalar(fGoal);
|
||||
s->WriteSwapScalar(fFrom);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hsTimedValue<T>::Write(hsStream* s, hsScalar currSecs)
|
||||
{
|
||||
s->WriteSwap32(fFlags);
|
||||
|
||||
fValue.Write(s);
|
||||
|
||||
if( !(fFlags & kIdle) )
|
||||
{
|
||||
s->WriteSwapScalar(fDuration);
|
||||
s->WriteSwapScalar(currSecs - fStartTime);
|
||||
|
||||
fGoal.Write(s);
|
||||
fFrom.Write(s);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hsTimedValue<T>::ReadScalar(hsStream* s, hsScalar currSecs)
|
||||
{
|
||||
fFlags = s->ReadSwap32();
|
||||
|
||||
fValue = s->ReadSwapScalar();
|
||||
|
||||
if( !(fFlags & kIdle) )
|
||||
{
|
||||
fDuration = s->ReadSwapScalar();
|
||||
fStartTime = currSecs - s->ReadSwapScalar();
|
||||
|
||||
fGoal = s->ReadSwapScalar();
|
||||
fFrom = s->ReadSwapScalar();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hsTimedValue<T>::Read(hsStream* s, hsScalar currSecs)
|
||||
{
|
||||
fFlags = s->ReadSwap32();
|
||||
|
||||
fValue.Read(s);
|
||||
|
||||
if( !(fFlags & kIdle) )
|
||||
{
|
||||
fDuration = s->ReadSwapScalar();
|
||||
fStartTime = currSecs - s->ReadSwapScalar();
|
||||
|
||||
fGoal.Read(s);
|
||||
fFrom.Read(s);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hsTimedValue<T>::SetDuration(hsScalar duration)
|
||||
{
|
||||
fDuration = duration;
|
||||
if( fDuration > 0 )
|
||||
fFlags &= ~kInstant;
|
||||
else
|
||||
fFlags |= kInstant;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
hsBool32 hsTimedValue<T>::operator==(const hsTimedValue<T>& v)
|
||||
{
|
||||
if ((fFlags == v.fFlags) &&
|
||||
(fDuration == v.fDuration) &&
|
||||
(fStartTime == v.fStartTime) &&
|
||||
(fValue == v.fValue) &&
|
||||
(fGoal == v.fGoal) &&
|
||||
(fFrom == v.fFrom))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hsTimedValue<T>::StartClock(hsScalar s)
|
||||
{
|
||||
fStartTime = s;
|
||||
|
||||
if( fFlags & kInstant )
|
||||
{
|
||||
fFlags |= kIdle;
|
||||
fValue = fGoal;
|
||||
return;
|
||||
}
|
||||
|
||||
fFlags &= ~kIdle;
|
||||
|
||||
if( fValue == fGoal )
|
||||
fFlags |= kIdle;
|
||||
|
||||
fFrom = fValue;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void hsTimedValue<T>::Update(hsScalar s)
|
||||
{
|
||||
if( fFlags & kIdle )
|
||||
return;
|
||||
|
||||
hsAssert(fDuration > 0, "Instant should always be idle");
|
||||
|
||||
hsScalar interp = (s - fStartTime) / fDuration;
|
||||
|
||||
if( interp >= hsScalar1 )
|
||||
{
|
||||
fValue = fGoal;
|
||||
interp = hsScalar1;
|
||||
fFlags |= kIdle;
|
||||
}
|
||||
else
|
||||
fValue = fFrom + (fGoal - fFrom) * interp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // hsTimedValue_inc
|
363
Sources/Plasma/PubUtilLib/plInterp/plATCEaseCurves.cpp
Normal file
363
Sources/Plasma/PubUtilLib/plInterp/plATCEaseCurves.cpp
Normal file
@ -0,0 +1,363 @@
|
||||
/*==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 "plAnimEaseTypes.h"
|
||||
#include "plAnimTimeConvert.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plATCEaseCurve *plATCEaseCurve::CreateEaseCurve(UInt8 type, hsScalar minLength, hsScalar maxLength, hsScalar length,
|
||||
hsScalar startSpeed, hsScalar goalSpeed)
|
||||
{
|
||||
if (type == plAnimEaseTypes::kConstAccel)
|
||||
return TRACKED_NEW plConstAccelEaseCurve(minLength, maxLength, length, startSpeed, goalSpeed);
|
||||
if (type == plAnimEaseTypes::kSpline)
|
||||
return TRACKED_NEW plSplineEaseCurve(minLength, maxLength, length, startSpeed, goalSpeed);
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
void plATCEaseCurve::RecalcToSpeed(hsScalar startSpeed, hsScalar goalSpeed, hsBool preserveRate /* = false */)
|
||||
{
|
||||
hsScalar rate = 1;
|
||||
|
||||
if (fSpeed == goalSpeed && fStartSpeed == startSpeed) // already there, no need to do anything
|
||||
return;
|
||||
|
||||
if (preserveRate)
|
||||
rate = (fSpeed - fStartSpeed) / fLength;
|
||||
|
||||
fStartSpeed = startSpeed;
|
||||
fSpeed = goalSpeed;
|
||||
|
||||
if (preserveRate)
|
||||
SetLengthOnRate(rate);
|
||||
}
|
||||
|
||||
void plATCEaseCurve::SetLengthOnRate(hsScalar rate)
|
||||
{
|
||||
fLength = (fSpeed - fStartSpeed) / rate;
|
||||
if (fLength < 0)
|
||||
fLength = -fLength;
|
||||
}
|
||||
|
||||
hsScalar plATCEaseCurve::GetMinDistance()
|
||||
{
|
||||
if (fMinLength == 0)
|
||||
return 0;
|
||||
|
||||
hsScalar oldLength = fLength;
|
||||
fLength = fMinLength;
|
||||
hsScalar result = PositionGivenTime(fMinLength);
|
||||
fLength = oldLength;
|
||||
return result;
|
||||
}
|
||||
|
||||
hsScalar plATCEaseCurve::GetMaxDistance()
|
||||
{
|
||||
if (fMaxLength == 0)
|
||||
return 0;
|
||||
|
||||
hsScalar oldLength = fLength;
|
||||
fLength = fMaxLength;
|
||||
hsScalar result = PositionGivenTime(fMaxLength);
|
||||
fLength = oldLength;
|
||||
return result;
|
||||
}
|
||||
|
||||
hsScalar plATCEaseCurve::GetNormDistance()
|
||||
{
|
||||
if (fNormLength == 0)
|
||||
return 0;
|
||||
|
||||
hsScalar oldLength = fLength;
|
||||
fLength = fNormLength;
|
||||
hsScalar result = PositionGivenTime(fNormLength);
|
||||
fLength = oldLength;
|
||||
return result;
|
||||
}
|
||||
|
||||
void plATCEaseCurve::Read(hsStream *s, hsResMgr *mgr)
|
||||
{
|
||||
plCreatable::Read(s, mgr);
|
||||
|
||||
fMinLength = s->ReadSwapScalar();
|
||||
fMaxLength = s->ReadSwapScalar();
|
||||
fNormLength = fLength = s->ReadSwapScalar();
|
||||
fStartSpeed = s->ReadSwapScalar();
|
||||
fSpeed = s->ReadSwapScalar();
|
||||
fBeginWorldTime = s->ReadSwapDouble();
|
||||
}
|
||||
|
||||
void plATCEaseCurve::Write(hsStream *s, hsResMgr *mgr)
|
||||
{
|
||||
plCreatable::Write(s, mgr);
|
||||
|
||||
s->WriteSwapScalar(fMinLength);
|
||||
s->WriteSwapScalar(fMaxLength);
|
||||
s->WriteSwapScalar(fNormLength);
|
||||
s->WriteSwapScalar(fStartSpeed);
|
||||
s->WriteSwapScalar(fSpeed);
|
||||
s->WriteSwapDouble(fBeginWorldTime);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plConstAccelEaseCurve::plConstAccelEaseCurve()
|
||||
{
|
||||
fMinLength = fMaxLength = fNormLength = fLength = 1;
|
||||
fBeginWorldTime = 0;
|
||||
|
||||
RecalcToSpeed(0, 1);
|
||||
}
|
||||
|
||||
plConstAccelEaseCurve::plConstAccelEaseCurve(hsScalar minLength, hsScalar maxLength, hsScalar length,
|
||||
hsScalar startSpeed, hsScalar goalSpeed)
|
||||
{
|
||||
fMinLength = minLength;
|
||||
fMaxLength = maxLength;
|
||||
fNormLength = fLength = length;
|
||||
fBeginWorldTime = 0;
|
||||
|
||||
RecalcToSpeed(startSpeed, goalSpeed);
|
||||
}
|
||||
|
||||
plATCEaseCurve *plConstAccelEaseCurve::Clone() const
|
||||
{
|
||||
plConstAccelEaseCurve *curve = TRACKED_NEW plConstAccelEaseCurve;
|
||||
curve->fStartSpeed = fStartSpeed;
|
||||
curve->fMinLength = fMinLength;
|
||||
curve->fMaxLength = fMaxLength;
|
||||
curve->fNormLength = fNormLength;
|
||||
curve->fBeginWorldTime = fBeginWorldTime;
|
||||
curve->fLength = fLength;
|
||||
curve->fSpeed = fSpeed;
|
||||
|
||||
return curve;
|
||||
}
|
||||
|
||||
void plConstAccelEaseCurve::SetLengthOnDistance(hsScalar dist)
|
||||
{
|
||||
fLength = 2 * dist / (fSpeed + fStartSpeed);
|
||||
}
|
||||
|
||||
hsScalar plConstAccelEaseCurve::PositionGivenTime(hsScalar time) const
|
||||
{
|
||||
return (hsScalar)(fStartSpeed * time + (0.5 * (fSpeed - fStartSpeed) / fLength) * time * time);
|
||||
}
|
||||
|
||||
hsScalar plConstAccelEaseCurve::VelocityGivenTime(hsScalar time) const
|
||||
{
|
||||
return fStartSpeed + ((fSpeed - fStartSpeed) / fLength) * time;
|
||||
}
|
||||
|
||||
hsScalar plConstAccelEaseCurve::TimeGivenVelocity(hsScalar velocity) const
|
||||
{
|
||||
return (velocity - fStartSpeed) / ((fSpeed - fStartSpeed) / fLength);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
plSplineEaseCurve::plSplineEaseCurve()
|
||||
{
|
||||
fMinLength = fMaxLength = fNormLength = fLength = 1;
|
||||
fBeginWorldTime = 0;
|
||||
|
||||
RecalcToSpeed(0, 1);
|
||||
}
|
||||
|
||||
plSplineEaseCurve::plSplineEaseCurve(hsScalar minLength, hsScalar maxLength, hsScalar length,
|
||||
hsScalar startSpeed, hsScalar goalSpeed)
|
||||
{
|
||||
fMinLength = minLength;
|
||||
fMaxLength = maxLength;
|
||||
fNormLength = fLength = length;
|
||||
fBeginWorldTime = 0;
|
||||
|
||||
RecalcToSpeed(startSpeed, goalSpeed);
|
||||
}
|
||||
|
||||
plATCEaseCurve *plSplineEaseCurve::Clone() const
|
||||
{
|
||||
plSplineEaseCurve *curve = TRACKED_NEW plSplineEaseCurve;
|
||||
curve->fStartSpeed = fStartSpeed;
|
||||
curve->fMinLength = fMinLength;
|
||||
curve->fMaxLength = fMaxLength;
|
||||
curve->fNormLength = fNormLength;
|
||||
curve->fBeginWorldTime = fBeginWorldTime;
|
||||
curve->fLength = fLength;
|
||||
curve->fSpeed = fSpeed;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 4; i++)
|
||||
curve->fCoef[i] = fCoef[i];
|
||||
|
||||
return curve;
|
||||
}
|
||||
|
||||
void plSplineEaseCurve::RecalcToSpeed(hsScalar startSpeed, hsScalar goalSpeed, hsBool preserveRate /* = false */)
|
||||
{
|
||||
plATCEaseCurve::RecalcToSpeed(startSpeed, goalSpeed, preserveRate);
|
||||
|
||||
// These are greatly simplified because the in/out tangents are always zero
|
||||
// Note: "b" is always zero for the ease splines we're currently doing (and will remain that way
|
||||
// so long as the initial acceleration is zero. Can optimize a bit of the eval math to take
|
||||
// advantage of this.
|
||||
hsScalar a, b, c, d;
|
||||
|
||||
a = fStartSpeed;
|
||||
b = 0;
|
||||
c = -3 * fStartSpeed + 3 * fSpeed;
|
||||
d = 2 * fStartSpeed - 2 * fSpeed;
|
||||
|
||||
fCoef[0] = a;
|
||||
fCoef[1] = b;
|
||||
fCoef[2] = c;
|
||||
fCoef[3] = d;
|
||||
}
|
||||
|
||||
void plSplineEaseCurve::SetLengthOnDistance(hsScalar dist)
|
||||
{
|
||||
hsScalar curDist = PositionGivenTime(fLength);
|
||||
|
||||
fLength = fLength * dist / curDist;
|
||||
}
|
||||
|
||||
hsScalar plSplineEaseCurve::PositionGivenTime(hsScalar time) const
|
||||
{
|
||||
hsScalar t1, t2, t3, t4;
|
||||
t1 = time / fLength;
|
||||
t2 = t1 * t1;
|
||||
t3 = t2 * t1;
|
||||
t4 = t3 * t1;
|
||||
|
||||
return fLength * (fCoef[0] * t1 + fCoef[1] * t2 / 2 + fCoef[2] * t3 / 3 + fCoef[3] * t4 / 4);
|
||||
}
|
||||
|
||||
hsScalar plSplineEaseCurve::VelocityGivenTime(hsScalar time) const
|
||||
{
|
||||
hsScalar t1, t2, t3;
|
||||
t1 = time / fLength;
|
||||
t2 = t1 * t1;
|
||||
t3 = t2 * t1;
|
||||
return fCoef[0] + fCoef[1] * t1 + fCoef[2] * t2 + fCoef[3] * t3;
|
||||
}
|
||||
|
||||
hsScalar plSplineEaseCurve::TimeGivenVelocity(hsScalar velocity) const
|
||||
{
|
||||
// Code based off of Graphics Gems V, pp 11-12 and
|
||||
// http://www.worldserver.com/turk/opensource/FindCubicRoots.c.txt
|
||||
|
||||
// Solving the equation: fCoef[0] + fCoef[1] * t + fCoef[2] * t^2 + fCoef[3] * t^3 - velocity = 0
|
||||
|
||||
hsScalar root;
|
||||
hsScalar a = (fCoef[0] - velocity) / fCoef[3];
|
||||
hsScalar b = fCoef[1] / fCoef[3];
|
||||
hsScalar c = fCoef[2] / fCoef[3];
|
||||
|
||||
hsScalar Q = (c * c - 3 * b) / 9;
|
||||
hsScalar R = (2 * c * c * c - 9 * c * b + 27 * a) / 54;
|
||||
hsScalar Q3 = Q * Q * Q;
|
||||
hsScalar D = Q3 - R * R;
|
||||
|
||||
if (D >= 0)
|
||||
{
|
||||
// 3 roots, find the one in the range [0, 1]
|
||||
const hsScalar pi = 3.14159;
|
||||
double theta = acos(R / sqrt(Q3));
|
||||
double sqrtQ = sqrt(Q);
|
||||
|
||||
root = (hsScalar)(-2 * sqrtQ * cos((theta + 4 * pi) / 3) - c / 3); // Middle root, most likely to match
|
||||
if (root < 0.f || root > 1.f)
|
||||
{
|
||||
root = (hsScalar)(-2 * sqrtQ * cos((theta + 2 * pi) / 3) - c / 3); // Lower root
|
||||
if (root < 0.f || root > 1.f)
|
||||
{
|
||||
root = (hsScalar)(-2 * sqrtQ * cos(theta / 3) - c / 3); // Upper root
|
||||
}
|
||||
}
|
||||
}
|
||||
else // One root to the equation (I don't expect this to happen for ease splines, but JIC)
|
||||
{
|
||||
double E = sqrt(-D) + pow(fabs(R), 1.f / 3.f);
|
||||
root = (hsScalar)((E + Q / E) - c / 3);
|
||||
if (R > 0)
|
||||
root = -root;
|
||||
}
|
||||
|
||||
if (root < 0.f || root > 1.f)
|
||||
{
|
||||
hsAssert(false, "No valid root found while solving animation spline");
|
||||
// Either a bug, or a rare case of floating-point inaccuracy. Either way, guess
|
||||
// the proper root as either the start or end of the curve based on the velocity.
|
||||
hsScalar dStart = velocity - fStartSpeed;
|
||||
if (dStart < 0)
|
||||
dStart = -dStart;
|
||||
hsScalar dEnd = velocity - fSpeed;
|
||||
if (dEnd < 0)
|
||||
dEnd = -dEnd;
|
||||
|
||||
root = (dStart < dEnd ? 0.f : 1.f);
|
||||
}
|
||||
|
||||
return root * fLength;
|
||||
}
|
||||
|
||||
void plSplineEaseCurve::Read(hsStream *s, hsResMgr *mgr)
|
||||
{
|
||||
plATCEaseCurve::Read(s, mgr);
|
||||
|
||||
fCoef[0] = s->ReadSwapScalar();
|
||||
fCoef[1] = s->ReadSwapScalar();
|
||||
fCoef[2] = s->ReadSwapScalar();
|
||||
fCoef[3] = s->ReadSwapScalar();
|
||||
}
|
||||
|
||||
void plSplineEaseCurve::Write(hsStream *s, hsResMgr *mgr)
|
||||
{
|
||||
plATCEaseCurve::Write(s, mgr);
|
||||
|
||||
s->WriteSwapScalar(fCoef[0]);
|
||||
s->WriteSwapScalar(fCoef[1]);
|
||||
s->WriteSwapScalar(fCoef[2]);
|
||||
s->WriteSwapScalar(fCoef[3]);
|
||||
}
|
||||
|
59
Sources/Plasma/PubUtilLib/plInterp/plAnimEaseTypes.h
Normal file
59
Sources/Plasma/PubUtilLib/plInterp/plAnimEaseTypes.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*==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==*/
|
||||
#ifndef PL_ANIM_EASE_TYPES
|
||||
#define PL_ANIM_EASE_TYPES
|
||||
|
||||
// Silly little header so that both export and runtime code can use these
|
||||
// constants without including tons of unneccessary stuff
|
||||
|
||||
namespace plAnimEaseTypes
|
||||
{
|
||||
enum {
|
||||
kNoEase,
|
||||
kConstAccel,
|
||||
kSpline,
|
||||
};
|
||||
};
|
||||
|
||||
#define ENTIRE_ANIMATION_NAME "(Entire Animation)"
|
||||
|
||||
#endif
|
809
Sources/Plasma/PubUtilLib/plInterp/plAnimPath.cpp
Normal file
809
Sources/Plasma/PubUtilLib/plInterp/plAnimPath.cpp
Normal file
@ -0,0 +1,809 @@
|
||||
/*==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 "hsTypes.h"
|
||||
#include "plAnimPath.h"
|
||||
#include "plController.h"
|
||||
#include "hsFastMath.h"
|
||||
#include "hsResMgr.h"
|
||||
|
||||
const hsScalar kSmallDelTime = 1.e-2f;
|
||||
const hsScalar kInvSmallDelTime = 1.f / kSmallDelTime;
|
||||
const hsScalar kTerminateDelTime = 1.e-3f;
|
||||
const hsScalar kTerminateDelDistSq = .1f;
|
||||
|
||||
plAnimPath::plAnimPath()
|
||||
: fController(nil), fLength(0), fMinDistSq(0),
|
||||
fAnimPathFlags(0)
|
||||
{
|
||||
fLocalToWorld.Reset();
|
||||
fWorldToLocal.Reset();
|
||||
Reset();
|
||||
}
|
||||
|
||||
plAnimPath::~plAnimPath()
|
||||
{
|
||||
delete fController;
|
||||
}
|
||||
|
||||
void plAnimPath::Reset()
|
||||
{
|
||||
SetCurTime(0);
|
||||
}
|
||||
|
||||
void plAnimPath::SetCurTime(hsScalar t, UInt32 calcFlags)
|
||||
{
|
||||
fTime = t;
|
||||
if( !fController )
|
||||
{
|
||||
fPos.Set(0,0,0);
|
||||
fXform.Reset();
|
||||
fVel.Set(0,0,0);
|
||||
fAccel.Set(0,0,0);
|
||||
return;
|
||||
}
|
||||
|
||||
hsScalar t0, t1, t2;
|
||||
|
||||
if( t < kSmallDelTime )
|
||||
{
|
||||
t0 = t;
|
||||
t1 = t + kSmallDelTime;
|
||||
t2 = t + 2 * kSmallDelTime;
|
||||
}
|
||||
else if( t > fLength - kSmallDelTime )
|
||||
{
|
||||
t0 = t - 2 * kSmallDelTime;
|
||||
t1 = t - kSmallDelTime;
|
||||
t2 = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
t0 = t - kSmallDelTime;
|
||||
t1 = t;
|
||||
t2 = t + kSmallDelTime;
|
||||
}
|
||||
|
||||
|
||||
if (!(calcFlags & kCalcPosOnly))
|
||||
{
|
||||
hsPoint3 pos[3];
|
||||
|
||||
fController->Interp(t0, &fParts);
|
||||
pos[0].Set(fParts.fT.fX, fParts.fT.fY, fParts.fT.fZ);
|
||||
|
||||
fController->Interp(t1, &fParts);
|
||||
pos[1].Set(fParts.fT.fX, fParts.fT.fY, fParts.fT.fZ);
|
||||
|
||||
fController->Interp(t2, &fParts);
|
||||
pos[2].Set(fParts.fT.fX, fParts.fT.fY, fParts.fT.fZ);
|
||||
|
||||
fVel.Set(pos+1, pos+0);
|
||||
fVel *= kInvSmallDelTime;
|
||||
fVel = fLocalToWorld * fVel;
|
||||
fAccel.Set(&(pos[2] - pos[1]), &(pos[1] - pos[0]));
|
||||
fAccel *= kInvSmallDelTime * kInvSmallDelTime;
|
||||
fAccel = fLocalToWorld * fAccel;
|
||||
}
|
||||
|
||||
fController->Interp(t, &fParts);
|
||||
fParts.ComposeMatrix(&fXform);
|
||||
fXform = fLocalToWorld * fXform;
|
||||
fXform.GetTranslate(&fPos);
|
||||
|
||||
}
|
||||
|
||||
void plAnimPath::ICalcBounds()
|
||||
{
|
||||
if( !fController )
|
||||
return;
|
||||
|
||||
plController* pc = fController->GetPosController();
|
||||
|
||||
int i;
|
||||
hsPoint3 pos;
|
||||
hsTArray<hsScalar> keyTimes;
|
||||
pc->GetKeyTimes(keyTimes);
|
||||
fCenter.Set(0,0,0);
|
||||
for( i = 0; i < keyTimes.GetCount() ; i++ )
|
||||
{
|
||||
pc->Interp(keyTimes[i], &pos);
|
||||
fCenter += pos;
|
||||
}
|
||||
fCenter *= hsScalarInvert((hsScalar)keyTimes.GetCount());
|
||||
|
||||
fRadius = 0;
|
||||
for( i = 0; i < keyTimes.GetCount(); i++ )
|
||||
{
|
||||
pc->Interp(keyTimes[i], &pos);
|
||||
hsScalar rad = (pos - fCenter).Magnitude();
|
||||
if( rad > fRadius )
|
||||
fRadius = rad;
|
||||
}
|
||||
}
|
||||
|
||||
hsScalar plAnimPath::ICalcTotalLength()
|
||||
{
|
||||
if( !(fController && fController->GetPosController()) )
|
||||
return 0;
|
||||
|
||||
fLength = fController->GetPosController()->GetLength();
|
||||
|
||||
return fLength;
|
||||
}
|
||||
|
||||
void plAnimPath::SetController(plCompoundController* tmc)
|
||||
{
|
||||
hsAssert(tmc, "Bad (nil) controller for AnimPath");
|
||||
hsAssert(tmc->GetPosController(), "Bad controller for AnimPath");
|
||||
fController = tmc;
|
||||
ICalcTotalLength();
|
||||
ICalcBounds();
|
||||
}
|
||||
|
||||
void plAnimPath::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
|
||||
{
|
||||
fLocalToWorld = l2w;
|
||||
fWorldToLocal = w2l;
|
||||
}
|
||||
|
||||
void plAnimPath::Read(hsStream* stream, hsResMgr* mgr)
|
||||
{
|
||||
fAnimPathFlags=stream->ReadSwap32();
|
||||
|
||||
delete fController;
|
||||
fController = plCompoundController::ConvertNoRef(mgr->ReadCreatable(stream));
|
||||
|
||||
ICalcBounds();
|
||||
|
||||
fParts.Read(stream);
|
||||
|
||||
fLocalToWorld.Read(stream);
|
||||
fWorldToLocal.Read(stream);
|
||||
|
||||
fLength = stream->ReadSwapScalar();
|
||||
fMinDistSq = stream->ReadSwapScalar();
|
||||
|
||||
Reset();
|
||||
}
|
||||
|
||||
void plAnimPath::Write(hsStream* stream, hsResMgr* mgr)
|
||||
{
|
||||
stream->WriteSwap32(fAnimPathFlags);
|
||||
|
||||
mgr->WriteCreatable(stream, fController);
|
||||
|
||||
fParts.Write(stream);
|
||||
|
||||
fLocalToWorld.Write(stream);
|
||||
fWorldToLocal.Write(stream);
|
||||
|
||||
stream->WriteSwapScalar(fLength);
|
||||
stream->WriteSwapScalar(fMinDistSq);
|
||||
}
|
||||
|
||||
hsBool plAnimPath::OutOfRange(hsPoint3 &worldPt, hsScalar range) const
|
||||
{
|
||||
hsPoint3 pt = fWorldToLocal * worldPt;
|
||||
|
||||
hsScalar radius = (pt - fCenter).Magnitude() - fRadius;
|
||||
return( radius > range );
|
||||
}
|
||||
|
||||
hsScalar plAnimPath::GetExtremePoint(hsPoint3 &worldPt) const
|
||||
{
|
||||
if( !fController )
|
||||
return 0;
|
||||
|
||||
hsPoint3 pt = fWorldToLocal * worldPt;
|
||||
|
||||
plController *pc = fController->GetPosController();
|
||||
|
||||
hsScalar minDistSq = 1.e33f;
|
||||
hsScalar minTime = 0, delTime = 0;
|
||||
// start search by using the time of the closest ctrl point
|
||||
int i;
|
||||
hsTArray<hsScalar> keyTimes;
|
||||
pc->GetKeyTimes(keyTimes);
|
||||
for( i = 0; i < keyTimes.GetCount(); i++ )
|
||||
{
|
||||
hsScalar t = keyTimes[i];
|
||||
hsPoint3 pos;
|
||||
pc->Interp(t, &pos); // handles easing
|
||||
hsScalar distSq = (pt - pos).MagnitudeSquared();
|
||||
if( distSq < minDistSq )
|
||||
{
|
||||
minDistSq = distSq;
|
||||
minTime = t;
|
||||
if( 0 == i )
|
||||
delTime = keyTimes[i+1] - t;
|
||||
else if( keyTimes.GetCount() - 1 == i )
|
||||
delTime = t - keyTimes[i - 1];
|
||||
else
|
||||
{
|
||||
hsScalar fore = keyTimes[i + 1] - t;
|
||||
hsScalar back = t - keyTimes[i - 1];
|
||||
delTime = hsMaximum(fore, back);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GetExtremePoint(minTime, delTime, worldPt);
|
||||
}
|
||||
|
||||
hsScalar plAnimPath::GetExtremePoint(hsScalar lastTime, hsScalar delTime, hsPoint3 &worldPt) const
|
||||
{
|
||||
if( !fController )
|
||||
return 0;
|
||||
|
||||
hsPoint3 pt = fWorldToLocal * worldPt;
|
||||
|
||||
IInitInterval(lastTime, delTime, pt);
|
||||
return ICheckInterval(pt);
|
||||
}
|
||||
|
||||
hsScalar plAnimPath::ICheckInterval(hsPoint3 &pt) const
|
||||
{
|
||||
if( fDelTime <= kTerminateDelTime &&
|
||||
hsVector3(&fCurPos, &fPrevPos).MagnitudeSquared() < kTerminateDelDistSq)
|
||||
{
|
||||
return IBestTime();
|
||||
}
|
||||
|
||||
if( fThisTime < 0 )
|
||||
return 0;
|
||||
|
||||
if( fThisTime > fLength )
|
||||
return fLength;
|
||||
|
||||
if( GetFarthest() )
|
||||
{
|
||||
if( (fLastDistSq > fThisDistSq)&&(fLastDistSq >= fNextDistSq) )
|
||||
return IShiftBack(pt);
|
||||
|
||||
if( (fNextDistSq > fThisDistSq)&&(fNextDistSq >= fLastDistSq) )
|
||||
return IShiftFore(pt);
|
||||
|
||||
if( (fThisDistSq >= fLastDistSq)&&(fLastDistSq >= fNextDistSq) )
|
||||
return ISubDivBack(pt);
|
||||
|
||||
if( (fThisDistSq >= fNextDistSq)&&(fNextDistSq >= fLastDistSq) )
|
||||
return ISubDivFore(pt);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (fLastDistSq < fThisDistSq)&&(fLastDistSq <= fNextDistSq) )
|
||||
return IShiftBack(pt);
|
||||
|
||||
if( (fNextDistSq < fThisDistSq)&&(fNextDistSq <= fLastDistSq) )
|
||||
return IShiftFore(pt);
|
||||
|
||||
if( (fThisDistSq <= fLastDistSq)&&(fLastDistSq <= fNextDistSq) )
|
||||
return ISubDivBack(pt);
|
||||
|
||||
if( (fThisDistSq <= fNextDistSq)&&(fNextDistSq <= fLastDistSq) )
|
||||
return ISubDivFore(pt);
|
||||
}
|
||||
|
||||
hsAssert(false, "Shouldn't have gotten here");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void plAnimPath::IInitInterval(hsScalar time, hsScalar delTime, hsPoint3 &pt) const
|
||||
{
|
||||
plController* pc = fController->GetPosController();
|
||||
|
||||
hsPoint3 pos;
|
||||
|
||||
fDelTime = delTime;
|
||||
if( fDelTime <= kTerminateDelTime )
|
||||
fDelTime = kTerminateDelTime * 2;
|
||||
else
|
||||
if( fDelTime > fLength * 0.5f )
|
||||
fDelTime = fLength * 0.5f;
|
||||
|
||||
fThisTime = time;
|
||||
if( fThisTime < fDelTime )
|
||||
fThisTime = fDelTime;
|
||||
else if( fThisTime > fLength - fDelTime )
|
||||
fThisTime = fLength - fDelTime;
|
||||
pc->Interp(fThisTime, &pos);
|
||||
fPrevPos=fCurPos=pos;
|
||||
fThisDistSq = (pos - pt).MagnitudeSquared();
|
||||
|
||||
fNextTime = fThisTime + delTime;
|
||||
if( fNextTime > fLength )
|
||||
fNextTime = fLength;
|
||||
if (!(GetAnimPathFlags() & kFavorBwdSearch))
|
||||
{
|
||||
pc->Interp(fNextTime, &pos);
|
||||
fNextDistSq = (pos - pt).MagnitudeSquared();
|
||||
}
|
||||
else
|
||||
{
|
||||
fNextDistSq = 1.e33f;
|
||||
}
|
||||
|
||||
fLastTime = fThisTime - delTime;
|
||||
if( fLastTime < 0 )
|
||||
fLastTime = 0;
|
||||
if (!(GetAnimPathFlags() & kFavorFwdSearch))
|
||||
{
|
||||
pc->Interp(fLastTime, &pos);
|
||||
fLastDistSq = (pos - pt).MagnitudeSquared();
|
||||
}
|
||||
else
|
||||
{
|
||||
fLastDistSq = 1.e33f;
|
||||
}
|
||||
|
||||
if( fMinDistSq != 0 )
|
||||
{
|
||||
fThisDistSq -= fMinDistSq;
|
||||
if( fThisDistSq < 0 )
|
||||
fThisDistSq = -fThisDistSq;
|
||||
|
||||
fNextDistSq -= fMinDistSq;
|
||||
if( fNextDistSq < 0 )
|
||||
fNextDistSq = -fNextDistSq;
|
||||
|
||||
fLastDistSq -= fMinDistSq;
|
||||
if( fLastDistSq < 0 )
|
||||
fLastDistSq = -fLastDistSq;
|
||||
}
|
||||
}
|
||||
|
||||
hsScalar plAnimPath::ISubDivBack(hsPoint3 &pt) const
|
||||
{
|
||||
fNextTime = fThisTime;
|
||||
fNextDistSq = fThisDistSq;
|
||||
|
||||
fDelTime *= 0.5f;
|
||||
|
||||
fThisTime -= fDelTime;
|
||||
if (fThisTime<0)
|
||||
fThisTime = GetWrap() ? fLength + fThisTime : 0;
|
||||
|
||||
plController* pc = fController->GetPosController();
|
||||
hsPoint3 pos;
|
||||
pc->Interp(fThisTime, &pos);
|
||||
fThisDistSq = (pos - pt).MagnitudeSquared() - fMinDistSq;
|
||||
if( fThisDistSq < 0 )
|
||||
fThisDistSq = -fThisDistSq;
|
||||
|
||||
fPrevPos=fCurPos;
|
||||
fCurPos=pos;
|
||||
|
||||
return ICheckInterval(pt);
|
||||
}
|
||||
|
||||
hsScalar plAnimPath::ISubDivFore(hsPoint3 &pt) const
|
||||
{
|
||||
fLastTime = fThisTime;
|
||||
fLastDistSq = fThisDistSq;
|
||||
|
||||
fDelTime *= 0.5f;
|
||||
|
||||
fThisTime += fDelTime;
|
||||
if (fThisTime>fLength)
|
||||
fThisTime = GetWrap() ? fThisTime-fLength : fLength;
|
||||
|
||||
plController* pc = fController->GetPosController();
|
||||
hsPoint3 pos;
|
||||
pc->Interp(fThisTime, &pos);
|
||||
fThisDistSq = (pos - pt).MagnitudeSquared() - fMinDistSq;
|
||||
if( fThisDistSq < 0 )
|
||||
fThisDistSq = -fThisDistSq;
|
||||
|
||||
fPrevPos=fCurPos;
|
||||
fCurPos=pos;
|
||||
|
||||
return ICheckInterval(pt);
|
||||
}
|
||||
|
||||
hsScalar plAnimPath::IShiftBack(hsPoint3 &pt) const
|
||||
{
|
||||
if( !GetWrap() && (fLastTime <= 0) )
|
||||
return ISubDivBack(pt);
|
||||
|
||||
fNextTime = fThisTime;
|
||||
fNextDistSq = fThisDistSq;
|
||||
|
||||
fThisTime = fLastTime;
|
||||
fThisDistSq = fLastDistSq;
|
||||
|
||||
fLastTime -= fDelTime;
|
||||
if( fLastTime < 0 )
|
||||
fLastTime = GetWrap() ? fLength + fLastTime : 0;
|
||||
plController* pc = fController->GetPosController();
|
||||
hsPoint3 pos;
|
||||
pc->Interp(fLastTime, &pos);
|
||||
fLastDistSq = (pos - pt).MagnitudeSquared() - fMinDistSq;
|
||||
if( fLastDistSq < 0 )
|
||||
fLastDistSq = -fLastDistSq;
|
||||
|
||||
fPrevPos=fCurPos;
|
||||
fCurPos=pos;
|
||||
|
||||
return ICheckInterval(pt);
|
||||
}
|
||||
|
||||
hsScalar plAnimPath::IShiftFore(hsPoint3 &pt) const
|
||||
{
|
||||
if( !GetWrap() &&(fNextTime >= fLength) )
|
||||
return ISubDivFore(pt);
|
||||
|
||||
fLastTime = fThisTime;
|
||||
fLastDistSq = fThisDistSq;
|
||||
|
||||
fThisTime = fNextTime;
|
||||
fThisDistSq = fNextDistSq;
|
||||
|
||||
fNextTime += fDelTime;
|
||||
if( fNextTime > fLength )
|
||||
fNextTime = GetWrap() ? fNextTime - fLength : fLength;
|
||||
plController* pc = fController->GetPosController();
|
||||
hsPoint3 pos;
|
||||
pc->Interp(fNextTime, &pos);
|
||||
fNextDistSq = (pos - pt).MagnitudeSquared() - fMinDistSq;
|
||||
if( fNextDistSq < 0 )
|
||||
fNextDistSq = -fNextDistSq;
|
||||
|
||||
fPrevPos=fCurPos;
|
||||
fCurPos=pos;
|
||||
|
||||
return ICheckInterval(pt);
|
||||
}
|
||||
|
||||
//
|
||||
// wireframe debug draw method.
|
||||
// doesn't use any fancy subdivision or curvature measure when drawing.
|
||||
// Changes current time.
|
||||
//
|
||||
void plAnimPath::IMakeSegment(hsTArray<UInt16>& idx, hsTArray<hsPoint3>& pos,
|
||||
hsPoint3& p1, hsPoint3& p2)
|
||||
{
|
||||
hsVector3 del(&p2, &p1);
|
||||
hsVector3 up;
|
||||
up.Set(0,0,1.f);
|
||||
|
||||
const hsScalar kOutLength = 0.25f;
|
||||
|
||||
hsVector3 a = del % up;
|
||||
hsScalar magSq = a.MagnitudeSquared();
|
||||
if( magSq < 1.e-3f )
|
||||
{
|
||||
a.Set(kOutLength, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
a *= hsFastMath::InvSqrtAppr(magSq);
|
||||
a *= kOutLength;
|
||||
}
|
||||
|
||||
hsVector3 b = a % del;
|
||||
hsFastMath::Normalize(b);
|
||||
b *= kOutLength;
|
||||
|
||||
hsPoint3 p1out, p2out;
|
||||
|
||||
int baseIdx = pos.GetCount();
|
||||
|
||||
pos.Append(p1);
|
||||
pos.Append(p2);
|
||||
|
||||
p1out = p1;
|
||||
p1out += a;
|
||||
p2out = p2;
|
||||
p2out += a;
|
||||
|
||||
pos.Append(p1out);
|
||||
pos.Append(p2out);
|
||||
|
||||
p1out += -2.f * a;
|
||||
p2out += -2.f * a;
|
||||
|
||||
pos.Append(p1out);
|
||||
pos.Append(p2out);
|
||||
|
||||
p1out = p1;
|
||||
p1out += b;
|
||||
p2out = p2;
|
||||
p2out += b;
|
||||
|
||||
pos.Append(p1out);
|
||||
pos.Append(p2out);
|
||||
|
||||
p1out += -2.f * b;
|
||||
p2out += -2.f * b;
|
||||
|
||||
pos.Append(p1out);
|
||||
pos.Append(p2out);
|
||||
|
||||
int i;
|
||||
for( i = 0; i < 4; i++ )
|
||||
{
|
||||
int outIdx = baseIdx + 2 + i * 2;
|
||||
idx.Append(baseIdx);
|
||||
idx.Append(baseIdx + 1);
|
||||
idx.Append(baseIdx + outIdx);
|
||||
|
||||
idx.Append(baseIdx + outIdx);
|
||||
idx.Append(baseIdx + 1);
|
||||
idx.Append(baseIdx + outIdx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void plAnimPath::MakeDrawList(hsTArray<UInt16>& idx, hsTArray<hsPoint3>& pos)
|
||||
{
|
||||
hsMatrix44 resetL2W = GetLocalToWorld();
|
||||
hsMatrix44 resetW2L = GetWorldToLocal();
|
||||
|
||||
hsMatrix44 ident;
|
||||
ident.Reset();
|
||||
SetTransform(ident, ident);
|
||||
|
||||
hsScalar numSegs = fRadius; // crude estimate of arclength
|
||||
if (numSegs>100)
|
||||
numSegs=100;
|
||||
hsScalar animLen = GetLength();
|
||||
hsScalar timeInc = animLen/numSegs;
|
||||
hsScalar time=0;
|
||||
hsPoint3 p1, p2;
|
||||
|
||||
SetCurTime(0, kCalcPosOnly);
|
||||
GetPosition(&p1);
|
||||
|
||||
time += timeInc;
|
||||
hsBool quit=false;
|
||||
while(! quit && time < animLen+timeInc)
|
||||
{
|
||||
if (time > animLen)
|
||||
{
|
||||
time = animLen;
|
||||
quit=true;
|
||||
}
|
||||
|
||||
SetCurTime(time, kCalcPosOnly);
|
||||
GetPosition(&p2);
|
||||
|
||||
IMakeSegment(idx, pos, p1, p2);
|
||||
|
||||
time += timeInc;
|
||||
|
||||
p1 = p2;
|
||||
}
|
||||
|
||||
SetTransform(resetL2W, resetW2L);
|
||||
}
|
||||
|
||||
//
|
||||
// Precompute array of arclen deltas for lookahead ability.
|
||||
// Changes current time!
|
||||
//
|
||||
void plAnimPath::ComputeArcLenDeltas(Int32 numSamples)
|
||||
{
|
||||
if (fArcLenDeltas.GetCount() >= numSamples)
|
||||
return; // already computed enough samples
|
||||
|
||||
// compute arc len deltas
|
||||
fArcLenDeltas.Reset();
|
||||
fArcLenDeltas.SetCount(numSamples);
|
||||
hsScalar animLen = GetLength();
|
||||
hsScalar timeInc = animLen/(numSamples-1); // use num-1 since we'll create the zeroth entry by hand
|
||||
hsScalar time=0;
|
||||
hsPoint3 p1, p2;
|
||||
|
||||
Int32 cnt=0;
|
||||
|
||||
// prime initial point
|
||||
SetCurTime(0, kCalcPosOnly);
|
||||
GetPosition(&p1);
|
||||
ArcLenDeltaInfo aldi(time, 0);
|
||||
fArcLenDeltas[cnt++]=aldi;
|
||||
time += timeInc;
|
||||
|
||||
hsBool quit=false;
|
||||
while(!quit && time<animLen+timeInc)
|
||||
{
|
||||
if (time > animLen || cnt+1 == numSamples)
|
||||
{
|
||||
time = animLen;
|
||||
quit=true;
|
||||
}
|
||||
|
||||
SetCurTime(time, kCalcPosOnly);
|
||||
GetPosition(&p2);
|
||||
|
||||
ArcLenDeltaInfo aldi(time, hsVector3(&p2, &p1).Magnitude());
|
||||
fArcLenDeltas[cnt++]=aldi;
|
||||
|
||||
time += timeInc;
|
||||
p1 = p2;
|
||||
}
|
||||
hsAssert(fArcLenDeltas.GetCount()==numSamples, "arcLenArray size wrong?");
|
||||
hsAssert(cnt==numSamples, "arcLenArray size wrong?");
|
||||
}
|
||||
|
||||
//
|
||||
// Returns time of point (at least) arcLength units away from point at startTime.
|
||||
// Also sets strtSrchIdx for incremental searching.
|
||||
//
|
||||
hsScalar plAnimPath::GetLookAheadTime(hsScalar startTime, hsScalar arcLengthIn, hsBool bwd,
|
||||
Int32* startSrchIdx)
|
||||
{
|
||||
if (arcLengthIn==0)
|
||||
return startTime; // default is no look ahead
|
||||
|
||||
if (startTime==GetLength() && !bwd)
|
||||
return GetLength();
|
||||
|
||||
if (startTime==0 && bwd)
|
||||
return 0;
|
||||
|
||||
hsAssert(startSrchIdx, "nil var for startSrchIdx");
|
||||
|
||||
hsScalar oldTime=fTime;
|
||||
|
||||
ComputeArcLenDeltas(); // precompute first time only
|
||||
|
||||
// save and change time if necessary
|
||||
if (fTime!=startTime)
|
||||
SetCurTime(startTime, kCalcPosOnly);
|
||||
|
||||
// find nearest (forward) arcLen sample point, use starting srch index provided
|
||||
hsBool found=false;
|
||||
Int32 i;
|
||||
for(i=(*startSrchIdx); i<fArcLenDeltas.GetCount()-1; i++)
|
||||
{
|
||||
if (fArcLenDeltas[i].fT<=startTime && startTime<fArcLenDeltas[i+1].fT)
|
||||
{
|
||||
*startSrchIdx=i;
|
||||
found=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
// check if equal to last index
|
||||
if (startTime==fArcLenDeltas[fArcLenDeltas.GetCount()-1].fT)
|
||||
{
|
||||
*startSrchIdx=fArcLenDeltas.GetCount()-1;
|
||||
found=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(i=0; i<*startSrchIdx; i++)
|
||||
{
|
||||
if (fArcLenDeltas[i].fT<=startTime && startTime<fArcLenDeltas[i+1].fT)
|
||||
{
|
||||
*startSrchIdx=i;
|
||||
found=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find distance to nearest arcLen sample point
|
||||
Int32 nearestIdx = bwd ? *startSrchIdx : *startSrchIdx+1;
|
||||
hsAssert(found, "couldn't find arcLength sample");
|
||||
|
||||
hsPoint3 pos;
|
||||
GetPosition(&pos); // startTime position
|
||||
|
||||
hsPoint3 pos2;
|
||||
hsScalar endTime = fArcLenDeltas[nearestIdx].fT;
|
||||
SetCurTime(endTime, kCalcPosOnly);
|
||||
GetPosition(&pos2); // position at nearest sample point
|
||||
|
||||
hsScalar curArcLen = hsVector3(&pos2, &pos).Magnitude();
|
||||
hsScalar curTime=0;
|
||||
hsBool quit=false;
|
||||
hsScalar timeOut = 0;
|
||||
Int32 inc = bwd ? -1 : 1;
|
||||
// now sum distance deltas until we exceed the desired arcLen
|
||||
if (curArcLen<arcLengthIn)
|
||||
{
|
||||
for(i=bwd ? nearestIdx : nearestIdx+inc; i<fArcLenDeltas.GetCount() && i>=0; i+=inc)
|
||||
{
|
||||
if (curArcLen+fArcLenDeltas[i].fArcLenDelta>arcLengthIn)
|
||||
{
|
||||
// gone tooFar
|
||||
endTime = fArcLenDeltas[i].fT;
|
||||
curTime = fArcLenDeltas[i-1].fT;
|
||||
break;
|
||||
}
|
||||
curArcLen += fArcLenDeltas[i].fArcLenDelta;
|
||||
}
|
||||
|
||||
if ( (i==fArcLenDeltas.GetCount() && !bwd) || (i<0 && bwd) )
|
||||
{
|
||||
quit=true;
|
||||
timeOut = bwd ? 0 : GetLength();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
curArcLen = 0;
|
||||
curTime = startTime;
|
||||
}
|
||||
|
||||
if (!quit)
|
||||
{
|
||||
// interp remaining interval
|
||||
|
||||
// 1. compute necessary distToGoal
|
||||
hsScalar distToGoal = arcLengthIn-curArcLen;
|
||||
hsAssert(distToGoal, "0 length distToGoal?");
|
||||
|
||||
// 2. compute % of dist interval which gives distToGoal
|
||||
SetCurTime(curTime, kCalcPosOnly);
|
||||
GetPosition(&pos);
|
||||
|
||||
SetCurTime(endTime, kCalcPosOnly);
|
||||
GetPosition(&pos2);
|
||||
|
||||
hsScalar distInterval = hsVector3(&pos2, &pos).Magnitude();
|
||||
hsScalar percent = distToGoal/distInterval;
|
||||
hsAssert(percent>=0 && percent<=1, "illegal percent value");
|
||||
|
||||
// 3. compute interpolated time value using percent
|
||||
if (!bwd)
|
||||
timeOut = curTime + (endTime-curTime)*percent;
|
||||
else
|
||||
timeOut = endTime - (endTime-curTime)*percent;
|
||||
hsAssert((timeOut>=curTime && timeOut<=endTime), "illegal interpolated time value");
|
||||
// hsAssert(!bwd || (timeOut<=curTime && timeOut>=endTime), "bwd: illegal interpolated time value");
|
||||
}
|
||||
|
||||
// restore time
|
||||
if (fTime != oldTime)
|
||||
SetCurTime(oldTime);
|
||||
|
||||
hsAssert(bwd || (timeOut>startTime && timeOut<=GetLength()), "fwd: illegal look ahead time");
|
||||
hsAssert(!bwd || (timeOut<startTime && timeOut>=0), "bwd: illegal look ahead time");
|
||||
|
||||
return timeOut;
|
||||
}
|
||||
|
188
Sources/Plasma/PubUtilLib/plInterp/plAnimPath.h
Normal file
188
Sources/Plasma/PubUtilLib/plInterp/plAnimPath.h
Normal file
@ -0,0 +1,188 @@
|
||||
/*==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==*/
|
||||
|
||||
#ifndef plAnimPath_inc
|
||||
#define plAnimPath_inc
|
||||
|
||||
#include "hsTemplates.h"
|
||||
#include "hsGeometry3.h"
|
||||
#include "hsMatrix44.h"
|
||||
#include "../plTransform/hsAffineParts.h"
|
||||
#include "../pnFactory/plCreatable.h"
|
||||
|
||||
class plCompoundController;
|
||||
|
||||
class plAnimPath : public plCreatable
|
||||
{
|
||||
public:
|
||||
enum Flags
|
||||
{
|
||||
kNone = 0x0,
|
||||
kFavorFwdSearch = 0x1, // only move fwd on the curve when searching
|
||||
kFavorBwdSearch = 0x2, // only move bwd on the curve when searching
|
||||
kCalcPosOnly = 0x4, // only compute pos when calling SetCurTime()
|
||||
kFarthest = 0x8,
|
||||
kWrap = 0x10,
|
||||
kIncrement = 0x20, // find the nearest / farthest point, but increment toward it
|
||||
};
|
||||
protected:
|
||||
// The final product info
|
||||
hsMatrix44 fXform;
|
||||
hsPoint3 fPos;
|
||||
hsVector3 fVel;
|
||||
hsVector3 fAccel;
|
||||
hsScalar fTime; // presumably seconds
|
||||
|
||||
// The paramters (and options) for this curve.
|
||||
UInt32 fAnimPathFlags; // currently set at runtime only
|
||||
hsScalar fMinDistSq;
|
||||
hsScalar fLength; // presumably seconds
|
||||
|
||||
// Controller stuff only works in local space.
|
||||
hsMatrix44 fLocalToWorld;
|
||||
hsMatrix44 fWorldToLocal;
|
||||
|
||||
// Bounding sphere available for ignoring out of range
|
||||
hsPoint3 fCenter;
|
||||
hsScalar fRadius;
|
||||
|
||||
plCompoundController* fController;
|
||||
|
||||
hsAffineParts fParts;
|
||||
|
||||
// These are temps during a search. They're here to avoid recalc.
|
||||
mutable hsScalar fLastTime;
|
||||
mutable hsScalar fLastDistSq;
|
||||
mutable hsScalar fThisTime;
|
||||
mutable hsScalar fThisDistSq;
|
||||
mutable hsScalar fNextTime;
|
||||
mutable hsScalar fNextDistSq;
|
||||
mutable hsScalar fDelTime;
|
||||
mutable hsPoint3 fPrevPos, fCurPos;
|
||||
|
||||
void ICalcBounds();
|
||||
hsScalar ICalcTotalLength();
|
||||
hsScalar IShiftFore(hsPoint3 &pt) const;
|
||||
hsScalar IShiftBack(hsPoint3 &pt) const;
|
||||
hsScalar ISubDivFore(hsPoint3 &pt) const;
|
||||
hsScalar ISubDivBack(hsPoint3 &pt) const;
|
||||
void IInitInterval(hsScalar time, hsScalar delTime, hsPoint3 &pt) const;
|
||||
hsScalar ICheckInterval(hsPoint3 &pt) const;
|
||||
hsScalar IBestTime() const { return fLastDistSq < fThisDistSq
|
||||
? (fLastDistSq < fNextDistSq
|
||||
? fLastTime
|
||||
: fNextTime)
|
||||
: (fThisDistSq < fNextDistSq
|
||||
? fThisTime
|
||||
: fNextTime); }
|
||||
|
||||
// Visualization helper
|
||||
void IMakeSegment(hsTArray<UInt16>& idx, hsTArray<hsPoint3>& pos,
|
||||
hsPoint3& p1, hsPoint3& p2);
|
||||
|
||||
// For computing arclen
|
||||
struct ArcLenDeltaInfo
|
||||
{
|
||||
hsScalar fT;
|
||||
hsScalar fArcLenDelta; // arc len distance from prev sample point (array entry)
|
||||
ArcLenDeltaInfo(hsScalar t, hsScalar del) : fT(t),fArcLenDelta(del) {}
|
||||
ArcLenDeltaInfo() : fT(0),fArcLenDelta(0) {}
|
||||
};
|
||||
hsTArray<ArcLenDeltaInfo> fArcLenDeltas;
|
||||
public:
|
||||
plAnimPath();
|
||||
virtual ~plAnimPath();
|
||||
|
||||
CLASSNAME_REGISTER( plAnimPath );
|
||||
GETINTERFACE_ANY( plAnimPath, plCreatable );
|
||||
|
||||
void Reset();
|
||||
|
||||
void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
|
||||
const hsMatrix44& GetLocalToWorld() const { return fLocalToWorld; }
|
||||
const hsMatrix44& GetWorldToLocal() const { return fWorldToLocal; }
|
||||
|
||||
// Visualization helper
|
||||
void MakeDrawList(hsTArray<UInt16>& idx, hsTArray<hsPoint3>& pos);
|
||||
|
||||
void SetAnimPathFlags(UInt32 f) { fAnimPathFlags=f; }
|
||||
UInt32 GetAnimPathFlags() const { return fAnimPathFlags; }
|
||||
|
||||
void SetWrap(hsBool on) { if(on)fAnimPathFlags |= kWrap; else fAnimPathFlags &= ~kWrap; }
|
||||
hsBool GetWrap() const { return 0 != (fAnimPathFlags & kWrap); }
|
||||
|
||||
void SetFarthest(hsBool on) { if(on)fAnimPathFlags |= kFarthest; else fAnimPathFlags &= ~kFarthest; }
|
||||
hsBool GetFarthest() const { return 0 != (fAnimPathFlags & kFarthest); }
|
||||
|
||||
void SetCurTime(hsScalar t, UInt32 calcFlags=0);
|
||||
hsScalar GetCurTime() const { return fTime; }
|
||||
|
||||
void SetController(plCompoundController* tmc);
|
||||
plCompoundController* GetController() const { return fController; }
|
||||
hsScalar GetLength() const { return fLength; } // seconds
|
||||
|
||||
void SetMinDistance(hsScalar d) { fMinDistSq = d*d; }
|
||||
hsScalar GetMinDistance() const { return hsSquareRoot(fMinDistSq); }
|
||||
|
||||
hsMatrix44* GetMatrix44(hsMatrix44* xOut) const { *xOut = fXform; return xOut; }
|
||||
hsPoint3* GetPosition(hsPoint3* pOut) const { *pOut = fPos; return pOut; }
|
||||
hsVector3* GetVelocity(hsVector3* vOut) const { *vOut = fVel; return vOut; }
|
||||
hsVector3* GetDirection(hsVector3* dOut) const { dOut->Set(fXform.fMap[0][2], fXform.fMap[1][2], fXform.fMap[2][2]); return dOut; }
|
||||
hsVector3* GetUp(hsVector3* uOut) const { uOut->Set(fXform.fMap[0][1], fXform.fMap[1][1], fXform.fMap[2][1]); return uOut; }
|
||||
hsVector3* GetAcceleration(hsVector3* aOut) const { *aOut = fAccel; return aOut; }
|
||||
|
||||
hsBool OutOfRange(hsPoint3 &pt, hsScalar range) const;
|
||||
const hsAffineParts* Parts() const { return &fParts; }
|
||||
void InitParts(const hsAffineParts& p) { fParts = p; }
|
||||
|
||||
hsScalar GetExtremePoint(hsPoint3 &worldPt) const; // Exhaustive search
|
||||
hsScalar GetExtremePoint(hsScalar lastTime, hsScalar delTime, hsPoint3 &worldPt) const; // Incremental search
|
||||
|
||||
// for arclen usage
|
||||
void ComputeArcLenDeltas(Int32 numSamples=256);
|
||||
hsScalar GetLookAheadTime(hsScalar startTime, hsScalar arcLength, hsBool bwd, Int32* startSrchIdx);
|
||||
|
||||
virtual void Read(hsStream* s, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* s, hsResMgr* mgr);
|
||||
};
|
||||
|
||||
#endif plAnimPath_inc
|
1402
Sources/Plasma/PubUtilLib/plInterp/plAnimTimeConvert.cpp
Normal file
1402
Sources/Plasma/PubUtilLib/plInterp/plAnimTimeConvert.cpp
Normal file
File diff suppressed because it is too large
Load Diff
322
Sources/Plasma/PubUtilLib/plInterp/plAnimTimeConvert.h
Normal file
322
Sources/Plasma/PubUtilLib/plInterp/plAnimTimeConvert.h
Normal file
@ -0,0 +1,322 @@
|
||||
/*==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==*/
|
||||
#ifndef plAnimTimeConvert_inc
|
||||
#define plAnimTimeConvert_inc
|
||||
|
||||
#include "../pnFactory/plCreatable.h"
|
||||
#include "hsTemplates.h"
|
||||
#include "../pnNetCommon/plSynchedValue.h"
|
||||
|
||||
#pragma warning (disable: 4284)
|
||||
|
||||
class plSynchedObject;
|
||||
class plAnimCmdMsg;
|
||||
class plEventCallbackMsg;
|
||||
class plATCEaseCurve;
|
||||
class plATCState;
|
||||
class plATCAnim;
|
||||
class plAGMasterMod;
|
||||
|
||||
class plAnimTimeConvert : public plCreatable
|
||||
{
|
||||
friend class plAnimTimeConvertSDLModifier;
|
||||
friend class plAGAnimInstance;
|
||||
|
||||
protected:
|
||||
UInt16 fFlags;
|
||||
hsScalar fBegin;
|
||||
hsScalar fEnd;
|
||||
hsScalar fLoopEnd;
|
||||
hsScalar fLoopBegin;
|
||||
hsScalar fSpeed;
|
||||
hsScalar fCurrentAnimTime;
|
||||
hsScalar fWrapTime;
|
||||
double fLastEvalWorldTime;
|
||||
// Do not change fLastEvalWorldTime anywhere except WorldToAnimTime()
|
||||
|
||||
plSynchedObject* fOwner;
|
||||
double fLastStateChange;
|
||||
|
||||
typedef std::list<plATCState *> plATCStateList;
|
||||
plATCStateList fStates;
|
||||
|
||||
hsTArray<hsScalar> fStopPoints;
|
||||
hsTArray<plEventCallbackMsg*> fCallbackMsgs;
|
||||
|
||||
/////////////////////////
|
||||
// Ease In/Out stuff
|
||||
|
||||
plATCEaseCurve *fEaseInCurve;
|
||||
plATCEaseCurve *fEaseOutCurve;
|
||||
plATCEaseCurve *fSpeedEaseCurve;
|
||||
plATCEaseCurve *fCurrentEaseCurve; // One of the above, or nil
|
||||
|
||||
//
|
||||
/////////////////////////
|
||||
|
||||
hsScalar fInitialBegin;
|
||||
hsScalar fInitialEnd;
|
||||
|
||||
static hsScalar ICalcEaseTime(const plATCEaseCurve *curve, double start, double end);
|
||||
void IClearSpeedEase();
|
||||
|
||||
void ICheckTimeCallbacks(hsScalar frameStart, hsScalar frameStop);
|
||||
hsBool ITimeInFrame(hsScalar secs, hsScalar start, hsScalar stop);
|
||||
void ISendCallback(int i);
|
||||
|
||||
plAnimTimeConvert& IStop(double time, hsScalar animTime);
|
||||
hsBool IIsStoppedAt(const double &wSecs, const UInt32 &flags, const plATCEaseCurve *curve) const;
|
||||
plAnimTimeConvert& IProcessStateChange(double worldTime, hsScalar animTime = -1);
|
||||
void IFlushOldStates();
|
||||
void IClearAllStates();
|
||||
plATCState *IGetState(double wSecs) const;
|
||||
plATCState *IGetLatestState() const;
|
||||
|
||||
plAnimTimeConvert& SetFlag(UInt8 f, hsBool on) { if(on)fFlags |= f; else fFlags &= ~f; return *this; }
|
||||
|
||||
public:
|
||||
plAnimTimeConvert();
|
||||
virtual ~plAnimTimeConvert();
|
||||
|
||||
void Init(plATCAnim *anim, plAGAnimInstance *instance, plAGMasterMod *master);
|
||||
|
||||
CLASSNAME_REGISTER( plAnimTimeConvert );
|
||||
GETINTERFACE_ANY( plAnimTimeConvert, plCreatable );
|
||||
|
||||
void SetOwner(plSynchedObject* o);
|
||||
const plSynchedObject* GetOwner() const { return fOwner; }
|
||||
|
||||
// ALL WorldToAnimTime functions are only valid if called with a time >= fLastEvalWorldTime.
|
||||
hsBool IsStoppedAt(double wSecs) const;
|
||||
hsScalar WorldToAnimTime(double wSecs);
|
||||
hsScalar WorldToAnimTimeNoUpdate(double wSecs) const; // convert time but don't fire triggers or set state
|
||||
|
||||
protected:
|
||||
static hsScalar IWorldToAnimTimeNoUpdate(double wSecs, plATCState *state);
|
||||
hsScalar IWorldToAnimTimeBeforeState(double wSecs) const;
|
||||
|
||||
public:
|
||||
void SetBegin(hsScalar s) { fBegin = s; }
|
||||
void SetEnd(hsScalar s) { fEnd = s; }
|
||||
void SetSpeed(hsScalar goal, hsScalar rate = 0);
|
||||
void SetLoopPoints(hsScalar begin, hsScalar end) { SetLoopBegin(begin); SetLoopEnd(end); }
|
||||
void SetLoopBegin(hsScalar s) { fLoopBegin = s; }
|
||||
void SetLoopEnd(hsScalar s) { fLoopEnd = s; }
|
||||
void SetEase(hsBool easeIn, UInt8 inType, hsScalar minLength, hsScalar maxLength, hsScalar inLength);
|
||||
void SetCurrentEaseCurve(int x); // 0=nil, 1=easeIn, 2=easeOut, 3=speed
|
||||
|
||||
hsScalar GetBegin() const { return fBegin; }
|
||||
hsScalar GetEnd() const { return fEnd; }
|
||||
hsScalar GetLoopBegin() const { return fLoopBegin; }
|
||||
hsScalar GetLoopEnd() const { return fLoopEnd; }
|
||||
hsScalar GetSpeed() const { return fSpeed; }
|
||||
hsTArray<hsScalar> &GetStopPoints() { return fStopPoints; }
|
||||
hsScalar GetBestStopDist(hsScalar min, hsScalar max, hsScalar norm, hsScalar time) const;
|
||||
int GetCurrentEaseCurve() const; // returns 0=nil, 1=easeIn, 2=easeOut, 3=speed
|
||||
|
||||
void ResizeStates(int cnt);
|
||||
void ResetWrap();
|
||||
|
||||
plAnimTimeConvert& ClearFlags() { fFlags = kNone; return *this; }
|
||||
hsBool GetFlag(UInt8 f) const { return (fFlags & f) ? true : false; }
|
||||
|
||||
plAnimTimeConvert& InitStop(); // Called when initializing an anim that doesn't autostart
|
||||
plAnimTimeConvert& Stop(hsBool on);
|
||||
plAnimTimeConvert& Stop(double s = -1.0);
|
||||
plAnimTimeConvert& Start(double s = -1.0);
|
||||
plAnimTimeConvert& PlayToTime(hsScalar time);
|
||||
plAnimTimeConvert& PlayToPercentage(hsScalar percent); // zero to one.
|
||||
|
||||
plAnimTimeConvert& Loop(hsBool on);
|
||||
plAnimTimeConvert& Loop() { return Loop(true); }
|
||||
plAnimTimeConvert& NoLoop() { return Loop(false); }
|
||||
|
||||
plAnimTimeConvert& Backwards(hsBool on);
|
||||
plAnimTimeConvert& Backwards();
|
||||
plAnimTimeConvert& Forewards();
|
||||
|
||||
hsBool IsStopped() const { return 0 != (fFlags & kStopped); }
|
||||
hsBool IsLooped() const { return 0 != (fFlags & kLoop); }
|
||||
hsBool IsBackwards() const { return 0 != (fFlags & kBackwards); }
|
||||
hsBool IsForewards() const { return !(fFlags & kBackwards); }
|
||||
|
||||
double LastEvalWorldTime() const { return fLastEvalWorldTime; }
|
||||
hsScalar CurrentAnimTime() const { return fCurrentAnimTime; }
|
||||
void SetCurrentAnimTime(hsScalar s, hsBool jump = false);
|
||||
|
||||
virtual void Read(hsStream* s, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* s, hsResMgr* mgr);
|
||||
|
||||
hsBool HandleCmd(plAnimCmdMsg* msg);
|
||||
void AddCallback(plEventCallbackMsg* pMsg);
|
||||
void RemoveCallback(plEventCallbackMsg* pMsg);
|
||||
void ClearCallbacks();
|
||||
void EnableCallbacks(hsBool val);
|
||||
|
||||
enum plAnimTimeFlags {
|
||||
kNone = 0x0,
|
||||
kStopped = 0x1,
|
||||
kLoop = 0x2,
|
||||
kBackwards = 0x4,
|
||||
kWrap = 0x8,
|
||||
kNeedsReset = 0x10,
|
||||
kEasingIn = 0x20,
|
||||
kForcedMove = 0x40,
|
||||
kNoCallbacks = 0x80,
|
||||
|
||||
kFlagsMask = 0xff
|
||||
};
|
||||
|
||||
enum plEaseCurveType {
|
||||
kEaseNone,
|
||||
kEaseIn,
|
||||
kEaseOut,
|
||||
kEaseSpeed,
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
// Rules for happy ease curves:
|
||||
// 1. Any time value between 0 and fLength is kosher.
|
||||
// 2. Velocity values accepted/returned are in the range [fStartSpeed, fSpeed]
|
||||
// (some tolerance for values REALLY close to the limit, to account for floating-point inaccuracy)
|
||||
|
||||
class plATCEaseCurve : public plCreatable
|
||||
{
|
||||
protected:
|
||||
hsScalar fStartSpeed;
|
||||
hsScalar fMinLength;
|
||||
hsScalar fMaxLength;
|
||||
hsScalar fNormLength;
|
||||
|
||||
public:
|
||||
CLASSNAME_REGISTER( plATCEaseCurve );
|
||||
GETINTERFACE_ANY( plATCEaseCurve, plCreatable );
|
||||
|
||||
double fBeginWorldTime;
|
||||
hsScalar fLength;
|
||||
hsScalar fSpeed; // The anim's target ("full") speed.
|
||||
|
||||
static plATCEaseCurve *CreateEaseCurve(UInt8 type, hsScalar minLength, hsScalar maxLength, hsScalar normLength,
|
||||
hsScalar startSpeed, hsScalar goalSpeed);
|
||||
|
||||
double GetEndWorldTime() const { return fBeginWorldTime + fLength; }
|
||||
|
||||
virtual plATCEaseCurve *Clone() const = 0;
|
||||
virtual void Read(hsStream *s, hsResMgr *mgr);
|
||||
virtual void Write(hsStream *s, hsResMgr *mgr);
|
||||
|
||||
virtual void RecalcToSpeed(hsScalar startSpeed, hsScalar goalSpeed, hsBool preserveRate = false);
|
||||
virtual void SetLengthOnRate(hsScalar rate);
|
||||
virtual void SetLengthOnDistance(hsScalar dist) = 0;
|
||||
virtual hsScalar PositionGivenTime(hsScalar time) const = 0;
|
||||
virtual hsScalar VelocityGivenTime(hsScalar time) const = 0;
|
||||
virtual hsScalar TimeGivenVelocity(hsScalar velocity) const = 0;
|
||||
virtual hsScalar GetMinDistance();
|
||||
virtual hsScalar GetMaxDistance();
|
||||
virtual hsScalar GetNormDistance();
|
||||
};
|
||||
|
||||
class plConstAccelEaseCurve : public plATCEaseCurve
|
||||
{
|
||||
public:
|
||||
plConstAccelEaseCurve();
|
||||
plConstAccelEaseCurve(hsScalar minLength, hsScalar maxLength, hsScalar length,
|
||||
hsScalar startSpeed, hsScalar goalSpeed);
|
||||
|
||||
CLASSNAME_REGISTER( plConstAccelEaseCurve );
|
||||
GETINTERFACE_ANY( plConstAccelEaseCurve, plATCEaseCurve );
|
||||
|
||||
virtual plATCEaseCurve *Clone() const;
|
||||
virtual void SetLengthOnDistance(hsScalar dist);
|
||||
virtual hsScalar PositionGivenTime(hsScalar time) const;
|
||||
virtual hsScalar VelocityGivenTime(hsScalar time) const;
|
||||
virtual hsScalar TimeGivenVelocity(hsScalar velocity) const;
|
||||
};
|
||||
|
||||
class plSplineEaseCurve : public plATCEaseCurve
|
||||
{
|
||||
public:
|
||||
plSplineEaseCurve();
|
||||
plSplineEaseCurve(hsScalar minLength, hsScalar maxLength, hsScalar length,
|
||||
hsScalar startSpeed, hsScalar goalSpeed);
|
||||
|
||||
CLASSNAME_REGISTER( plSplineEaseCurve );
|
||||
GETINTERFACE_ANY( plSplineEaseCurve, plATCEaseCurve );
|
||||
|
||||
virtual void Read(hsStream *s, hsResMgr *mgr);
|
||||
virtual void Write(hsStream *s, hsResMgr *mgr);
|
||||
|
||||
virtual plATCEaseCurve *Clone() const;
|
||||
virtual void RecalcToSpeed(hsScalar startSpeed, hsScalar goalSpeed, hsBool preserveRate = false);
|
||||
virtual void SetLengthOnDistance(hsScalar dist);
|
||||
virtual hsScalar PositionGivenTime(hsScalar time) const;
|
||||
virtual hsScalar VelocityGivenTime(hsScalar time) const;
|
||||
virtual hsScalar TimeGivenVelocity(hsScalar velocity) const;
|
||||
|
||||
hsScalar fCoef[4];
|
||||
};
|
||||
|
||||
class plATCState
|
||||
{
|
||||
public:
|
||||
plATCState() : fEaseCurve(nil) {}
|
||||
~plATCState() { delete fEaseCurve; }
|
||||
|
||||
void Read(hsStream *s, hsResMgr *mgr);
|
||||
void Write(hsStream *s, hsResMgr *mgr);
|
||||
|
||||
double fStartWorldTime;
|
||||
hsScalar fStartAnimTime;
|
||||
|
||||
UInt8 fFlags;
|
||||
hsScalar fBegin;
|
||||
hsScalar fEnd;
|
||||
hsScalar fLoopBegin;
|
||||
hsScalar fLoopEnd;
|
||||
hsScalar fSpeed;
|
||||
hsScalar fWrapTime;
|
||||
plATCEaseCurve *fEaseCurve;
|
||||
};
|
||||
|
||||
|
||||
#endif // plAnimTimeConvert_inc
|
916
Sources/Plasma/PubUtilLib/plInterp/plController.cpp
Normal file
916
Sources/Plasma/PubUtilLib/plInterp/plController.cpp
Normal file
@ -0,0 +1,916 @@
|
||||
/*==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);
|
||||
}
|
||||
|
230
Sources/Plasma/PubUtilLib/plInterp/plController.h
Normal file
230
Sources/Plasma/PubUtilLib/plInterp/plController.h
Normal file
@ -0,0 +1,230 @@
|
||||
/*==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==*/
|
||||
#ifndef HSCONTROLLER_inc
|
||||
#define HSCONTROLLER_inc
|
||||
|
||||
#include "HeadSpin.h"
|
||||
#include "../pnFactory/plCreatable.h"
|
||||
#include "hsColorRGBA.h"
|
||||
#include "hsKeys.h"
|
||||
#include "hsTemplates.h"
|
||||
|
||||
class hsResMgr;
|
||||
|
||||
struct hsScaleValue;
|
||||
struct hsScalarKey;
|
||||
struct hsPoint3Key;
|
||||
struct hsScalarTriple;
|
||||
struct hsMatrix33;
|
||||
struct hsMatrix44;
|
||||
class hsQuat;
|
||||
class hsAffineParts;
|
||||
class plScalarCurve;
|
||||
class plAnimTimeConvert;
|
||||
class plCompoundController;
|
||||
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
// base controller class.
|
||||
// Controllers correspond to Max controllers.
|
||||
// Some are leaf controllers which actually have keys, these can also have
|
||||
// multiple ease and multiplier controllers.
|
||||
// Some are compound controllers, which just contain other (leaf) controllers.
|
||||
// Leaf controllers have lists of keys (or plCurves which are just wrappers for
|
||||
// the lists of keys).
|
||||
//
|
||||
|
||||
class plControllerCacheInfo
|
||||
{
|
||||
public:
|
||||
UInt8 fNumSubControllers;
|
||||
plControllerCacheInfo **fSubControllers;
|
||||
|
||||
UInt32 fKeyIndex;
|
||||
plAnimTimeConvert *fAtc;
|
||||
|
||||
plControllerCacheInfo();
|
||||
~plControllerCacheInfo();
|
||||
|
||||
void SetATC(plAnimTimeConvert *atc);
|
||||
};
|
||||
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
// defines base methods
|
||||
//
|
||||
class plController : public plCreatable
|
||||
{
|
||||
public:
|
||||
CLASSNAME_REGISTER( plController );
|
||||
GETINTERFACE_ANY( plController, plCreatable );
|
||||
|
||||
virtual void Interp(hsScalar time, hsScalar* result, plControllerCacheInfo *cache = nil) const {}
|
||||
virtual void Interp(hsScalar time, hsScalarTriple* result, plControllerCacheInfo *cache = nil) const {}
|
||||
virtual void Interp(hsScalar time, hsScaleValue* result, plControllerCacheInfo *cache = nil) const {}
|
||||
virtual void Interp(hsScalar time, hsQuat* result, plControllerCacheInfo *cache = nil) const {}
|
||||
virtual void Interp(hsScalar time, hsMatrix33* result, plControllerCacheInfo *cache = nil) const {}
|
||||
virtual void Interp(hsScalar time, hsMatrix44* result, plControllerCacheInfo *cache = nil) const {}
|
||||
virtual void Interp(hsScalar time, hsColorRGBA* result, plControllerCacheInfo *cache = nil) const {}
|
||||
virtual void Interp(hsScalar time, hsAffineParts* parts, plControllerCacheInfo *cache = nil) const {}
|
||||
|
||||
virtual plControllerCacheInfo* CreateCache() const { return nil; } // Caller must handle deleting the pointer.
|
||||
virtual hsScalar GetLength() const = 0;
|
||||
virtual void GetKeyTimes(hsTArray<hsScalar> &keyTimes) const = 0;
|
||||
virtual hsBool AllKeysMatch() const = 0;
|
||||
|
||||
// Checks each of our subcontrollers (if we have any) and deletes any that
|
||||
// are nothing but matching keys. Returns true if this controller itself
|
||||
// is redundant.
|
||||
virtual hsBool PurgeRedundantSubcontrollers() = 0;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
class plLeafController : public plController
|
||||
{
|
||||
friend class plCompoundController;
|
||||
|
||||
protected:
|
||||
UInt8 fType;
|
||||
void *fKeys; // Need to pay attend to fType to determine what these actually are
|
||||
UInt32 fNumKeys;
|
||||
mutable UInt32 fLastKeyIdx;
|
||||
|
||||
public:
|
||||
plLeafController() : fType(hsKeyFrame::kUnknownKeyFrame), fKeys(nil), fNumKeys(0), fLastKeyIdx(0) {}
|
||||
virtual ~plLeafController();
|
||||
|
||||
CLASSNAME_REGISTER( plLeafController );
|
||||
GETINTERFACE_ANY( plLeafController, plController );
|
||||
|
||||
void Interp(hsScalar time, hsScalar* result, plControllerCacheInfo *cache = nil) const;
|
||||
void Interp(hsScalar time, hsScalarTriple* result, plControllerCacheInfo *cache = nil) const;
|
||||
void Interp(hsScalar time, hsScaleValue* result, plControllerCacheInfo *cache = nil) const;
|
||||
void Interp(hsScalar time, hsQuat* result, plControllerCacheInfo *cache = nil) const;
|
||||
void Interp(hsScalar time, hsMatrix33* result, plControllerCacheInfo *cache = nil) const;
|
||||
void Interp(hsScalar time, hsMatrix44* result, plControllerCacheInfo *cache = nil) const;
|
||||
void Interp(hsScalar time, hsColorRGBA* result, plControllerCacheInfo *cache = nil) const;
|
||||
|
||||
virtual plControllerCacheInfo* CreateCache() const;
|
||||
hsScalar GetLength() const;
|
||||
UInt32 GetStride() const;
|
||||
|
||||
hsPoint3Key *GetPoint3Key(UInt32 i) const;
|
||||
hsBezPoint3Key *GetBezPoint3Key(UInt32 i) const;
|
||||
hsScalarKey *GetScalarKey(UInt32 i) const;
|
||||
hsBezScalarKey *GetBezScalarKey(UInt32 i) const;
|
||||
hsScaleKey *GetScaleKey(UInt32 i) const;
|
||||
hsBezScaleKey *GetBezScaleKey(UInt32 i) const;
|
||||
hsQuatKey *GetQuatKey(UInt32 i) const;
|
||||
hsCompressedQuatKey32 *GetCompressedQuatKey32(UInt32 i) const;
|
||||
hsCompressedQuatKey64 *GetCompressedQuatKey64(UInt32 i) const;
|
||||
hsG3DSMaxKeyFrame *Get3DSMaxKey(UInt32 i) const;
|
||||
hsMatrix33Key *GetMatrix33Key(UInt32 i) const;
|
||||
hsMatrix44Key *GetMatrix44Key(UInt32 i) const;
|
||||
|
||||
UInt8 GetType() const { return fType; }
|
||||
UInt32 GetNumKeys() const { return fNumKeys; }
|
||||
void *GetKeyBuffer() const { return fKeys; }
|
||||
void GetKeyTimes(hsTArray<hsScalar> &keyTimes) const;
|
||||
void AllocKeys(UInt32 n, UInt8 type);
|
||||
void QuickScalarController(int numKeys, hsScalar* times, hsScalar* values, UInt32 valueStrides);
|
||||
hsBool AllKeysMatch() const;
|
||||
hsBool PurgeRedundantSubcontrollers();
|
||||
|
||||
void Read(hsStream* s, hsResMgr* mgr);
|
||||
void Write(hsStream* s, hsResMgr* mgr);
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// NON-LEAF (container) CONTROLLERS
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
class plCompoundController : public plController
|
||||
{
|
||||
private:
|
||||
plController* fXController;
|
||||
plController* fYController;
|
||||
plController* fZController;
|
||||
|
||||
public:
|
||||
plCompoundController(); // allocs leaf controllers
|
||||
~plCompoundController();
|
||||
|
||||
CLASSNAME_REGISTER( plCompoundController );
|
||||
GETINTERFACE_ANY( plCompoundController, plController );
|
||||
|
||||
void Interp(hsScalar time, hsQuat* result, plControllerCacheInfo *cache = nil) const;
|
||||
void Interp(hsScalar time, hsScalarTriple* result, plControllerCacheInfo *cache = nil) const;
|
||||
void Interp(hsScalar time, hsAffineParts* parts, plControllerCacheInfo *cache = nil) const;
|
||||
void Interp(hsScalar time, hsColorRGBA* result, plControllerCacheInfo *cache = nil) const;
|
||||
|
||||
plControllerCacheInfo* CreateCache() const;
|
||||
plController *GetXController() const { return fXController; }
|
||||
plController *GetYController() const { return fYController; }
|
||||
plController *GetZController() const { return fZController; }
|
||||
plController *GetPosController() const { return fXController; }
|
||||
plController *GetRotController() const { return fYController; }
|
||||
plController *GetScaleController() const { return fZController; }
|
||||
plController *GetController(Int32 i) const;
|
||||
hsScalar GetLength() const;
|
||||
void GetKeyTimes(hsTArray<hsScalar> &keyTimes) const;
|
||||
hsBool AllKeysMatch() const;
|
||||
hsBool PurgeRedundantSubcontrollers();
|
||||
|
||||
void SetXController(plController *c) { delete fXController; fXController = c; }
|
||||
void SetYController(plController *c) { delete fYController; fYController = c; }
|
||||
void SetZController(plController *c) { delete fZController; fZController = c; }
|
||||
void SetPosController(plController *c) { delete fXController; fXController = c; }
|
||||
void SetRotController(plController *c) { delete fYController; fYController = c; }
|
||||
void SetScaleController(plController *c) { delete fZController; fZController = c; }
|
||||
void SetController(Int32 i, plController* c);
|
||||
|
||||
void Read(hsStream* s, hsResMgr* mgr);
|
||||
void Write(hsStream* s, hsResMgr* mgr);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
69
Sources/Plasma/PubUtilLib/plInterp/plInterpCreatable.h
Normal file
69
Sources/Plasma/PubUtilLib/plInterp/plInterpCreatable.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*==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==*/
|
||||
|
||||
#ifndef plInterpCreatable_inc
|
||||
#define plInterpCreatable_inc
|
||||
|
||||
#include "../pnFactory/plCreator.h"
|
||||
|
||||
#include "plController.h"
|
||||
|
||||
REGISTER_NONCREATABLE( plController );
|
||||
REGISTER_CREATABLE( plLeafController );
|
||||
REGISTER_CREATABLE( plCompoundController );
|
||||
|
||||
#include "plAnimTimeConvert.h"
|
||||
|
||||
REGISTER_CREATABLE( plAnimTimeConvert );
|
||||
REGISTER_NONCREATABLE( plATCEaseCurve );
|
||||
REGISTER_CREATABLE( plConstAccelEaseCurve );
|
||||
REGISTER_CREATABLE( plSplineEaseCurve );
|
||||
|
||||
#include "plAnimPath.h"
|
||||
|
||||
REGISTER_CREATABLE( plAnimPath );
|
||||
|
||||
#include "plModulator.h"
|
||||
|
||||
REGISTER_CREATABLE( plModulator );
|
||||
|
||||
#endif // plInterpCreatable_inc
|
123
Sources/Plasma/PubUtilLib/plInterp/plModulator.cpp
Normal file
123
Sources/Plasma/PubUtilLib/plInterp/plModulator.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
/*==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 "hsTypes.h"
|
||||
#include "plModulator.h"
|
||||
#include "hsResMgr.h"
|
||||
#include "hsStream.h"
|
||||
#include "hsGeometry3.h"
|
||||
#include "hsBounds.h"
|
||||
|
||||
#include "plController.h"
|
||||
|
||||
#include "../plIntersect/plVolumeIsect.h"
|
||||
|
||||
plModulator::plModulator()
|
||||
: fVolume(nil),
|
||||
fSoftDist(0)
|
||||
{
|
||||
}
|
||||
|
||||
plModulator::~plModulator()
|
||||
{
|
||||
delete fVolume;
|
||||
}
|
||||
|
||||
void plModulator::SetVolume(plVolumeIsect* vol)
|
||||
{
|
||||
delete fVolume;
|
||||
fVolume = vol;
|
||||
}
|
||||
|
||||
void plModulator::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
|
||||
{
|
||||
hsAssert(fVolume, "Modulator with no Volume is pretty useless");
|
||||
|
||||
fVolume->SetTransform(l2w, w2l);
|
||||
}
|
||||
|
||||
// Volume - Want to base this on the closest point on the bounds, instead of just the center.
|
||||
hsScalar plModulator::Modulation(const hsBounds3Ext& bnd) const
|
||||
{
|
||||
return Modulation(bnd.GetCenter());
|
||||
}
|
||||
|
||||
hsScalar plModulator::Modulation(const hsPoint3& pos) const
|
||||
{
|
||||
hsAssert(fVolume, "Modulator with no Volume is pretty useless");
|
||||
|
||||
hsScalar dist = fVolume->Test(pos);
|
||||
|
||||
hsScalar retVal;
|
||||
if( dist > 0 )
|
||||
{
|
||||
if( dist < fSoftDist )
|
||||
{
|
||||
dist /= fSoftDist;
|
||||
retVal = 1.f - dist;
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = 1.f;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
void plModulator::Read(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
fVolume = plVolumeIsect::ConvertNoRef(mgr->ReadCreatable(s));
|
||||
fSoftDist = s->ReadSwapScalar();
|
||||
}
|
||||
|
||||
void plModulator::Write(hsStream* s, hsResMgr* mgr)
|
||||
{
|
||||
mgr->WriteCreatable(s, fVolume);
|
||||
s->WriteSwapScalar(fSoftDist);
|
||||
}
|
||||
|
||||
|
81
Sources/Plasma/PubUtilLib/plInterp/plModulator.h
Normal file
81
Sources/Plasma/PubUtilLib/plInterp/plModulator.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*==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==*/
|
||||
|
||||
#ifndef plModulator_inc
|
||||
#define plModulator_inc
|
||||
|
||||
#include "../pnFactory/plCreatable.h"
|
||||
|
||||
struct hsMatrix44;
|
||||
struct hsPoint3;
|
||||
class plVolumeIsect;
|
||||
class hsBounds3Ext;
|
||||
|
||||
class plModulator : public plCreatable
|
||||
{
|
||||
protected:
|
||||
plVolumeIsect* fVolume;
|
||||
hsScalar fSoftDist;
|
||||
|
||||
public:
|
||||
plModulator();
|
||||
virtual ~plModulator();
|
||||
|
||||
CLASSNAME_REGISTER( plModulator );
|
||||
GETINTERFACE_ANY( plModulator, plCreatable );
|
||||
|
||||
const plVolumeIsect* GetVolume() const { return fVolume; }
|
||||
void SetVolume(plVolumeIsect* vol); // Takes ownership, so don't delete after handing it in.
|
||||
|
||||
hsScalar Modulation(const hsPoint3& pos) const;
|
||||
hsScalar Modulation(const hsBounds3Ext& bnd) const;
|
||||
|
||||
void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
|
||||
|
||||
hsScalar GetSoftDist() const { return fSoftDist; }
|
||||
void SetSoftDist(hsScalar s) { fSoftDist = s; }
|
||||
|
||||
virtual void Read(hsStream* s, hsResMgr* mgr);
|
||||
virtual void Write(hsStream* s, hsResMgr* mgr);
|
||||
};
|
||||
|
||||
#endif // plModulator_inc
|
Reference in New Issue
Block a user