summaryrefslogtreecommitdiffstats
path: root/rwsdk/include/d3d8/rtslerp.h
blob: ec41752ca782bb464e738a9cff083a0e91422ee6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
/* 
 * 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
 * \ingroup rttool
 *
 * 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 */