2019-05-18 10:39:39 +00:00
|
|
|
/*
|
|
|
|
* Data Structures for Slerps/Spherical Linear Interpolations
|
|
|
|
* See also GemsIII/quatspin.c in
|
|
|
|
* http://www.acm.org/pubs/tog/GraphicsGems/gemsiii.zip
|
|
|
|
* Copyright (c) Criterion Software Limited
|
|
|
|
*/
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
* *
|
|
|
|
* Module : rtslerp.h *
|
|
|
|
* *
|
|
|
|
* Purpose : Slerp functionality *
|
|
|
|
* *
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
#ifndef RTSLERP_H
|
|
|
|
#define RTSLERP_H
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \defgroup rtslerp RtSlerp
|
2020-07-18 10:30:51 +00:00
|
|
|
* \ingroup mathtools
|
2019-05-18 10:39:39 +00:00
|
|
|
*
|
|
|
|
* Slerp/Spherical Linear Interpolations Toolkit for RenderWare.
|
|
|
|
*
|
|
|
|
* See also http://www.cis.ohio-state.edu/~parent/book/Full.html
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "rwcore.h"
|
|
|
|
#include "rtquat.h"
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
Includes
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "rtslerp.rpe" /* automatically generated header file */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
Defines
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Masks for specifying which matrices to store by reference */
|
|
|
|
#define rtSLERPREFNONE 0x00
|
|
|
|
#define rtSLERPREFSTARTMAT 0x01
|
|
|
|
#define rtSLERPREFENDMAT 0x02
|
|
|
|
#define rtSLERPREFALL (~rtSLERPREFNONE)
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
Global Types
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct RtSlerp RtSlerp;
|
|
|
|
/**
|
|
|
|
* \ingroup rtslerp
|
|
|
|
* \struct RtSlerp
|
|
|
|
* structure describing a Slerps/Spherical Linear Interpolations.
|
|
|
|
* See also GemsIII/quatspin.c in
|
|
|
|
* http://www.acm.org/pubs/tog/GraphicsGems/gemsiii.zip
|
|
|
|
*/
|
|
|
|
struct RtSlerp
|
|
|
|
{
|
|
|
|
RwInt32 matRefMask; /**< Which matrices do we NOT own */
|
|
|
|
RwMatrix *startMat; /**< The start matrix */
|
|
|
|
RwMatrix *endMat; /**< The end matrix */
|
|
|
|
RwV3d axis; /**< The axis of rotation for the slerp */
|
|
|
|
RwReal angle; /**< The angle (in degrees) between src & dest */
|
|
|
|
|
|
|
|
/* Though a slerp may be a bad idea and opting for a lerp is better */
|
|
|
|
RwBool useLerp; /**< Do we want to use lerps? */
|
|
|
|
};
|
|
|
|
|
|
|
|
/* static frame sequence animation - contains no state */
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct RtQuatSlerpCache RtQuatSlerpCache;
|
|
|
|
/**
|
|
|
|
* \ingroup rtslerp
|
|
|
|
* \struct RtQuatSlerpCache
|
|
|
|
* structure describing a SlerpCache,
|
|
|
|
* which should be initialized with \ref RtQuatSetupSlerpCache.
|
|
|
|
*/
|
|
|
|
struct RtQuatSlerpCache
|
|
|
|
{
|
|
|
|
RtQuat raFrom; /**< Scaled initial quaternion */
|
|
|
|
RtQuat raTo; /**< Scaled final quaternion */
|
|
|
|
RwReal omega; /**< Angular displacement in radians */
|
|
|
|
RwBool nearlyZeroOm; /**< Flags near-zero angular
|
|
|
|
displacement*/
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct RtQuatSlerpArgandCache RtQuatSlerpArgandCache;
|
|
|
|
/**
|
|
|
|
* \ingroup rtslerp
|
|
|
|
* \struct RtQuatSlerpArgandCache
|
|
|
|
* a structure describing
|
|
|
|
* an Argand SlerpCache which should be
|
|
|
|
* initialized with \ref RtQuatSetupSlerpArgandCache.
|
|
|
|
* See http://www-groups.dcs.st-and.ac.uk/~history/Mathematicians/Argand.html
|
|
|
|
* Jean Argand was an accountant and amateur mathematician.
|
|
|
|
* He is famed for his geometrical interpretation of the complex numbers
|
|
|
|
* where i is interpreted as a rotation through 90.
|
|
|
|
*/
|
|
|
|
struct RtQuatSlerpArgandCache
|
|
|
|
{
|
|
|
|
RtQuat logTo; /**< field Logarithm of final quaternion */
|
|
|
|
RtQuat logBase; /**< Logarithm of initial relative to final quaternion */
|
|
|
|
};
|
|
|
|
|
|
|
|
#define RtQuatSlerpMacro(qpResult, qpFrom, qpTo, rT, sCache) \
|
|
|
|
MACRO_START \
|
|
|
|
{ \
|
|
|
|
if ((rT) <= ((RwReal) 0)) \
|
|
|
|
{ \
|
|
|
|
/* t is before start */ \
|
|
|
|
*(qpResult) = *(qpFrom); \
|
|
|
|
} \
|
|
|
|
else if (((RwReal) 1) <= (rT)) \
|
|
|
|
{ \
|
|
|
|
\
|
|
|
|
/* t is after end */ \
|
|
|
|
*(qpResult) = *(qpTo); \
|
|
|
|
} \
|
|
|
|
else \
|
|
|
|
{ \
|
|
|
|
/* ... so t must be in the interior then */ \
|
|
|
|
/* Calc coefficients rSclFrom, rSclTo */ \
|
|
|
|
RwReal rSclFrom = ((RwReal) 1) - (rT); \
|
|
|
|
RwReal rSclTo = (rT); \
|
|
|
|
\
|
|
|
|
if (!((sCache)->nearlyZeroOm)) \
|
|
|
|
{ \
|
|
|
|
/* Standard case: slerp */ \
|
|
|
|
/* SLERPMESSAGE(("Neither nearly ZERO nor nearly PI")); */ \
|
|
|
|
\
|
|
|
|
rSclFrom *= (sCache)->omega; \
|
|
|
|
RwSinMinusPiToPiMacro(rSclFrom, rSclFrom); \
|
|
|
|
rSclTo *= (sCache)->omega; \
|
|
|
|
RwSinMinusPiToPiMacro(rSclTo, rSclTo); \
|
|
|
|
} \
|
|
|
|
\
|
|
|
|
/* Calc final values */ \
|
|
|
|
RwV3dScaleMacro(&(qpResult)->imag, \
|
|
|
|
&(sCache)->raFrom.imag, rSclFrom); \
|
|
|
|
RwV3dIncrementScaledMacro(&(qpResult)->imag, \
|
|
|
|
&(sCache)->raTo.imag, rSclTo); \
|
|
|
|
(qpResult)->real = \
|
|
|
|
((sCache)->raFrom.real * rSclFrom) + \
|
|
|
|
((sCache)->raTo.real * rSclTo); \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
MACRO_STOP
|
|
|
|
|
|
|
|
#define RtQuatSlerpArgandMacro(qpResult, qpFrom, qpTo, rT, sArgandCache) \
|
|
|
|
MACRO_START \
|
|
|
|
{ \
|
|
|
|
if ((rT) <= ((RwReal) 0)) \
|
|
|
|
{ \
|
|
|
|
/* t is before start */ \
|
|
|
|
*(qpResult) = *(qpFrom); \
|
|
|
|
} \
|
|
|
|
else if (((RwReal) 1) <= (rT)) \
|
|
|
|
{ \
|
|
|
|
/* t is after end */ \
|
|
|
|
*(qpResult) = *(qpTo); \
|
|
|
|
} \
|
|
|
|
else \
|
|
|
|
{ \
|
|
|
|
RtQuat logBlend; \
|
|
|
|
\
|
|
|
|
/* ... so t must be in the interior then */ \
|
|
|
|
\
|
|
|
|
logBlend.imag.x = \
|
|
|
|
(sArgandCache)->logBase.imag.x + \
|
|
|
|
(rT) * (sArgandCache)->logTo.imag.x; \
|
|
|
|
logBlend.imag.y = \
|
|
|
|
(sArgandCache)->logBase.imag.y + \
|
|
|
|
(rT) * (sArgandCache)->logTo.imag.y; \
|
|
|
|
logBlend.imag.z = \
|
|
|
|
(sArgandCache)->logBase.imag.z + \
|
|
|
|
(rT) * (sArgandCache)->logTo.imag.z; \
|
|
|
|
logBlend.real = 0; \
|
|
|
|
\
|
|
|
|
RtQuatUnitExpMacro((qpResult), &logBlend); \
|
|
|
|
\
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
MACRO_STOP
|
|
|
|
|
|
|
|
#if (! ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) ))
|
|
|
|
|
|
|
|
#define RtQuatSlerp(qpResult, qpFrom, qpTo, rT, sCache) \
|
|
|
|
RtQuatSlerpMacro(qpResult, qpFrom, qpTo, rT, sCache)
|
|
|
|
|
|
|
|
#define RtQuatSlerpArgand(qpResult, qpFrom, qpTo, rT, sArgandCache) \
|
|
|
|
RtQuatSlerpArgandMacro(qpResult, qpFrom, qpTo, rT, sArgandCache)
|
|
|
|
|
|
|
|
#endif /* (! ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) )) */
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
Function prototypes
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C"
|
|
|
|
{
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
|
|
|
/* Creating and destroying slerps */
|
|
|
|
|
|
|
|
extern RtSlerp *RtSlerpCreate(RwInt32 nMatRefMask);
|
|
|
|
|
|
|
|
extern void RtSlerpDestroy(RtSlerp * spSlerp);
|
|
|
|
|
|
|
|
/* setting up a slerp */
|
|
|
|
extern RtSlerp *RtSlerpInitialize(RtSlerp * spSlerp,
|
|
|
|
RwMatrix * mpMat1,
|
|
|
|
RwMatrix * mpMat2);
|
|
|
|
|
|
|
|
/* Get a matrix */
|
|
|
|
extern RwMatrix *RtSlerpGetMatrix(RtSlerp * spSlerp,
|
|
|
|
RwMatrix * mpResultMat,
|
|
|
|
RwReal nDelta);
|
|
|
|
|
|
|
|
/* Set if lerp or slerp */
|
|
|
|
extern RtSlerp *RtSlerpSetLerp(RtSlerp * spSlerp,
|
|
|
|
RwBool bUseLerp);
|
|
|
|
|
|
|
|
extern void
|
|
|
|
RtQuatSetupSlerpCache(RtQuat * qpFrom,
|
|
|
|
RtQuat * qpTo,
|
|
|
|
RtQuatSlerpCache * sCache);
|
|
|
|
|
|
|
|
extern void
|
|
|
|
RtQuatSetupSlerpArgandCache(RtQuat * qpFrom,
|
|
|
|
RtQuat * qpTo,
|
|
|
|
RtQuatSlerpArgandCache * sArgandCache);
|
|
|
|
|
|
|
|
#if ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) )
|
|
|
|
|
|
|
|
extern void
|
|
|
|
RtQuatSlerp(RtQuat * qpResult,
|
|
|
|
RtQuat * qpFrom,
|
|
|
|
RtQuat * qpTo,
|
|
|
|
RwReal rT,
|
|
|
|
RtQuatSlerpCache * sCache);
|
|
|
|
|
|
|
|
extern void
|
|
|
|
RtQuatSlerpArgand(RtQuat * qpResult,
|
|
|
|
RtQuat * qpFrom,
|
|
|
|
RtQuat * qpTo,
|
|
|
|
RwReal rT,
|
|
|
|
RtQuatSlerpArgandCache * sArgandCache);
|
|
|
|
|
|
|
|
#endif /* ( defined(RWDEBUG) || defined(RWSUPPRESSINLINE) ) */
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif /* __cplusplus */
|
|
|
|
|
|
|
|
#endif /* RTSLERP_H */
|
|
|
|
|