1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/graphics/m3g/m3gcore11/src/m3g_keyframesequence.c Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1004 @@
1.4 +/*
1.5 +* Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
1.6 +* All rights reserved.
1.7 +* This component and the accompanying materials are made available
1.8 +* under the terms of the License "Eclipse Public License v1.0"
1.9 +* which accompanies this distribution, and is available
1.10 +* at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.11 +*
1.12 +* Initial Contributors:
1.13 +* Nokia Corporation - initial contribution.
1.14 +*
1.15 +* Contributors:
1.16 +*
1.17 +* Description: KeyframeSequence implementation
1.18 +*
1.19 +*/
1.20 +
1.21 +
1.22 +/*!
1.23 + * \internal
1.24 + * \file
1.25 + * \brief KeyframeSequence implementation
1.26 + */
1.27 +
1.28 +#ifndef M3G_CORE_INCLUDE
1.29 +# error included by m3g_core.c; do not compile separately.
1.30 +#endif
1.31 +
1.32 +#include "m3g_keyframesequence.h"
1.33 +#include "m3g_memory.h"
1.34 +
1.35 +/*----------------------------------------------------------------------
1.36 + * Internal functions
1.37 + *--------------------------------------------------------------------*/
1.38 +
1.39 +/*!
1.40 + * \internal
1.41 + * \brief Destroys this KeyframeSequence object.
1.42 + *
1.43 + * \param obj KeyframeSequence object
1.44 + */
1.45 +static void m3gDestroyKeyframeSequence(Object *obj)
1.46 +{
1.47 + KeyframeSequence *sequence = (KeyframeSequence *) obj;
1.48 + M3G_VALIDATE_OBJECT(sequence);
1.49 + {
1.50 + Interface *m3g = M3G_INTERFACE(sequence);
1.51 + m3gFree(m3g, sequence->keyframes);
1.52 + m3gFree(m3g, sequence->keyframeTimes);
1.53 + m3gFree(m3g, sequence->inTangents);
1.54 + m3gFree(m3g, sequence->outTangents);
1.55 + m3gFree(m3g, sequence->a);
1.56 + m3gFree(m3g, sequence->b);
1.57 + }
1.58 + m3gDestroyObject(&sequence->object);
1.59 +}
1.60 +
1.61 +/*!
1.62 + * \internal
1.63 + * \brief Overloaded Object3D method.
1.64 + *
1.65 + * \param originalObj original KeyframeSequence object
1.66 + * \param cloneObj pointer to cloned KeyframeSequence object
1.67 + * \param pairs array for all object-duplicate pairs
1.68 + * \param numPairs number of pairs
1.69 + */
1.70 +static M3Gbool m3gKeyframeSequenceDuplicate(const Object *originalObj,
1.71 + Object **cloneObj,
1.72 + Object **pairs,
1.73 + M3Gint *numPairs)
1.74 +{
1.75 + KeyframeSequence *original = (KeyframeSequence *)originalObj;
1.76 + KeyframeSequence *clone =
1.77 + (KeyframeSequence *)m3gCreateKeyframeSequence(originalObj->interface,
1.78 + original->numKeyframes,
1.79 + original->numComponents,
1.80 + original->interpolation);
1.81 + *cloneObj = (Object *)clone;
1.82 + if (*cloneObj == NULL) {
1.83 + return M3G_FALSE;
1.84 + }
1.85 +
1.86 + if(m3gObjectDuplicate(originalObj, cloneObj, pairs, numPairs)) {
1.87 + M3Gsizei n = original->numKeyframes * original->numComponents;
1.88 +
1.89 + m3gCopy(clone->keyframes, original->keyframes, n * sizeof(M3Gfloat));
1.90 + m3gCopy(clone->keyframeTimes, original->keyframeTimes, original->numKeyframes * sizeof(M3Gint));
1.91 + if (original->dirty == M3G_FALSE) {
1.92 + if (original->inTangents) {
1.93 + m3gCopy(clone->inTangents, original->inTangents, n * sizeof(M3Gfloat));
1.94 + m3gCopy(clone->outTangents, original->outTangents, n * sizeof(M3Gfloat));
1.95 + }
1.96 + if (original->a) {
1.97 + m3gCopy(clone->a, original->a, original->numKeyframes * sizeof(Quat));
1.98 + m3gCopy(clone->b, original->b, original->numKeyframes * sizeof(Quat));
1.99 + }
1.100 + }
1.101 + else {
1.102 + clone->dirty = M3G_TRUE;
1.103 + }
1.104 +
1.105 + clone->duration = original->duration;
1.106 + clone->closed = original->closed;
1.107 + clone->firstValid = original->firstValid;
1.108 + clone->lastValid = original->lastValid;
1.109 + return M3G_TRUE;
1.110 + }
1.111 + else {
1.112 + return M3G_FALSE;
1.113 + }
1.114 +}
1.115 +
1.116 +/*!
1.117 + * \internal
1.118 + * \brief Initializes a KeyframeSequence object. See specification
1.119 + * for default values.
1.120 + *
1.121 + * \param m3g M3G interface
1.122 + * \param sequence KeyframeSequence object
1.123 + * \param numKeyframes number of keyframes
1.124 + * \param numComponents number of components
1.125 + * \param interpolation interpolation type
1.126 + * \retval KeyframeSequence initialized KeyframeSequence object
1.127 + * \retval NULL initialization failed
1.128 + */
1.129 +static KeyframeSequence *m3gInitKeyframeSequence(Interface *m3g,
1.130 + KeyframeSequence *sequence,
1.131 + M3Gint numKeyframes,
1.132 + M3Gint numComponents,
1.133 + M3Gint interpolation)
1.134 +{
1.135 + m3gInitObject(&sequence->object, m3g, M3G_CLASS_KEYFRAME_SEQUENCE);
1.136 +
1.137 + /* Set keyframe parameters */
1.138 +
1.139 + sequence->numKeyframes = numKeyframes;
1.140 + sequence->numComponents = numComponents;
1.141 + sequence->interpolation = interpolation;
1.142 + sequence->lastValid = numKeyframes - 1; /* firstValid defaults to 0 */
1.143 +
1.144 + /* Allocate keyframe and tangent data */
1.145 + {
1.146 + M3Gsizei n = numKeyframes * numComponents;
1.147 +
1.148 + sequence->keyframes = (M3Gfloat *)m3gAllocZ(m3g, n * sizeof(M3Gfloat));
1.149 + if (sequence->keyframes == NULL) {
1.150 + goto AllocFailed;
1.151 + }
1.152 + sequence->keyframeTimes = (M3Gint *)m3gAllocZ(m3g, numKeyframes * sizeof(M3Gint));
1.153 + if (sequence->keyframeTimes == NULL) {
1.154 + goto AllocFailed;
1.155 + }
1.156 +
1.157 + if (interpolation == M3G_SPLINE) {
1.158 + sequence->inTangents = (M3Gfloat *)m3gAllocZ(m3g, n * sizeof(M3Gfloat));
1.159 + sequence->outTangents = (M3Gfloat *)m3gAllocZ(m3g, n * sizeof(M3Gfloat));
1.160 + if (sequence->inTangents == NULL || sequence->outTangents == NULL) {
1.161 + goto AllocFailed;
1.162 + }
1.163 + }
1.164 + else if (interpolation == M3G_SQUAD) {
1.165 + sequence->a = (Quat *)m3gAlloc(m3g, numKeyframes * sizeof(Quat));
1.166 + sequence->b = (Quat *)m3gAlloc(m3g, numKeyframes * sizeof(Quat));
1.167 + if (sequence->a == NULL || sequence->b == NULL) {
1.168 + goto AllocFailed;
1.169 + }
1.170 + }
1.171 +
1.172 + /* Success; just make a note that the data is not valid yet */
1.173 +
1.174 + sequence->dirty = M3G_TRUE;
1.175 + return sequence;
1.176 +
1.177 +AllocFailed:
1.178 + /* The destructor contains exactly the code we need for this,
1.179 + * so just call that */
1.180 +
1.181 + m3gDestroyKeyframeSequence((Object*) sequence);
1.182 + return NULL;
1.183 + }
1.184 +}
1.185 +
1.186 +/*!
1.187 + * \internal
1.188 + * \brief Checks the validity of keyframe timings
1.189 + *
1.190 + * \param sequence KeyframeSequence object
1.191 + * \retval M3G_TRUE sequence valid
1.192 + * \retval M3G_FALSE sequence invalid
1.193 + */
1.194 +static M3Gbool m3gValidSequence(const KeyframeSequence *sequence)
1.195 +{
1.196 + const M3Gint last = sequence->lastValid;
1.197 + M3Gint current = sequence->firstValid;
1.198 +
1.199 + while (current != last) {
1.200 + M3Gint next = (current < sequence->numKeyframes-1) ? current + 1 : 0;
1.201 + if (sequence->keyframeTimes[next] < sequence->keyframeTimes[current]) {
1.202 + return M3G_FALSE;
1.203 + }
1.204 + current = next;
1.205 + }
1.206 + return (sequence->keyframeTimes[last] <= sequence->duration);
1.207 +}
1.208 +
1.209 +
1.210 +/*!
1.211 + * \internal
1.212 + * \brief Get number of components
1.213 + *
1.214 + * \param sequence KeyframeSequence object
1.215 + * \return number of components
1.216 + */
1.217 +static M3Gint m3gGetNumComponents(const KeyframeSequence *sequence)
1.218 +{
1.219 + return sequence->numComponents;
1.220 +}
1.221 +
1.222 +/*!
1.223 + * \internal
1.224 + * \brief Get next keyframe index
1.225 + *
1.226 + * \param sequence KeyframeSequence object
1.227 + * \param ind current index
1.228 + * \return next index
1.229 + */
1.230 +static M3Gint m3gNextKeyframeIndex(const KeyframeSequence *sequence, M3Gint ind)
1.231 +{
1.232 + if (ind == sequence->lastValid) {
1.233 + return sequence->firstValid;
1.234 + }
1.235 + else if (ind == sequence->numKeyframes - 1) {
1.236 + return 0;
1.237 + }
1.238 + else {
1.239 + return (ind + 1);
1.240 + }
1.241 +}
1.242 +
1.243 +/*!
1.244 + * \internal
1.245 + * \brief Get previous keyframe index
1.246 + *
1.247 + * \param sequence KeyframeSequence object
1.248 + * \param ind current index
1.249 + * \return previous index
1.250 + */
1.251 +static M3Gint m3gPreviousKeyframeIndex(const KeyframeSequence *sequence, M3Gint ind)
1.252 +{
1.253 + if (ind == sequence->firstValid) {
1.254 + return sequence->lastValid;
1.255 + }
1.256 + else if (ind == 0) {
1.257 + return (sequence->numKeyframes - 1);
1.258 + }
1.259 + else {
1.260 + return (ind - 1);
1.261 + }
1.262 +}
1.263 +
1.264 +/*!
1.265 + * \internal
1.266 + * \brief Get keyframe at index
1.267 + *
1.268 + * \param seq KeyframeSequence object
1.269 + * \param idx keyframe index
1.270 + * \return keyframe value
1.271 + */
1.272 +static M3G_INLINE const M3Gfloat *m3gKeyframeAt(const KeyframeSequence *seq, M3Gint idx)
1.273 +{
1.274 + return seq->keyframes + idx * seq->numComponents;
1.275 +}
1.276 +
1.277 +/*!
1.278 + * \internal
1.279 + * \brief Get keyframe at index -1
1.280 + *
1.281 + * \param seq KeyframeSequence object
1.282 + * \param idx keyframe index
1.283 + * \return keyframe value
1.284 + */
1.285 +static M3G_INLINE const M3Gfloat *m3gKeyframeBefore(const KeyframeSequence *seq, M3Gint idx)
1.286 +{
1.287 + return m3gKeyframeAt(seq, m3gPreviousKeyframeIndex(seq, idx));
1.288 +}
1.289 +
1.290 +/*!
1.291 + * \internal
1.292 + * \brief Get keyframe at index + 1
1.293 + *
1.294 + * \param seq KeyframeSequence object
1.295 + * \param idx keyframe index
1.296 + * \return keyframe value
1.297 + */
1.298 +static M3G_INLINE const M3Gfloat *m3gKeyframeAfter(const KeyframeSequence *seq, M3Gint idx)
1.299 +{
1.300 + return m3gKeyframeAt(seq, m3gNextKeyframeIndex(seq, idx));
1.301 +}
1.302 +
1.303 +/*!
1.304 + * \internal
1.305 + * \brief Get tangent to index
1.306 + *
1.307 + * \param seq KeyframeSequence object
1.308 + * \param idx keyframe index
1.309 + * \return tangent value
1.310 + */
1.311 +static M3G_INLINE const M3Gfloat *m3gTangentTo(const KeyframeSequence *seq, M3Gint idx)
1.312 +{
1.313 + M3G_ASSERT(seq->inTangents != NULL);
1.314 + return seq->inTangents + idx * seq->numComponents;
1.315 +}
1.316 +
1.317 +/*!
1.318 + * \internal
1.319 + * \brief Get tangent from index
1.320 + *
1.321 + * \param seq KeyframeSequence object
1.322 + * \param idx keyframe index
1.323 + * \return tangent value
1.324 + */
1.325 +static M3G_INLINE const M3Gfloat *m3gTangentFrom(const KeyframeSequence *seq, M3Gint idx)
1.326 +{
1.327 + M3G_ASSERT(seq->outTangents != NULL);
1.328 + return seq->outTangents + idx * seq->numComponents;
1.329 +}
1.330 +
1.331 +/*!
1.332 + * \internal
1.333 + * \brief Get time delta
1.334 + *
1.335 + * \param sequence KeyframeSequence object
1.336 + * \param ind keyframe index
1.337 + * \return time delta
1.338 + */
1.339 +static M3Gint m3gTimeDelta(const KeyframeSequence *sequence, M3Gint ind)
1.340 +{
1.341 + if (ind == sequence->lastValid) {
1.342 + return
1.343 + (sequence->duration
1.344 + - sequence->keyframeTimes[sequence->lastValid])
1.345 + + sequence->keyframeTimes[sequence->firstValid];
1.346 + }
1.347 + return sequence->keyframeTimes[m3gNextKeyframeIndex(sequence, ind)]
1.348 + - sequence->keyframeTimes[ind];
1.349 +}
1.350 +
1.351 +/*!
1.352 + * \internal
1.353 + * \brief Get incoming tangent scale
1.354 + *
1.355 + * \param sequence KeyframeSequence object
1.356 + * \param ind keyframe index
1.357 + * \return tangent scale
1.358 + */
1.359 +static M3Gfloat m3gIncomingTangentScale(const KeyframeSequence *sequence,
1.360 + M3Gint ind)
1.361 +{
1.362 + if (!sequence->closed
1.363 + && (ind == sequence->firstValid || ind == sequence->lastValid)) {
1.364 + return 0;
1.365 + }
1.366 + else {
1.367 + M3Gint prevind = m3gPreviousKeyframeIndex(sequence, ind);
1.368 + return m3gDiv(m3gMul(2.0f, (M3Gfloat) m3gTimeDelta(sequence, prevind)),
1.369 + (M3Gfloat)(m3gTimeDelta(sequence, ind)
1.370 + + m3gTimeDelta(sequence, prevind)));
1.371 + }
1.372 +}
1.373 +
1.374 +/*!
1.375 + * \internal
1.376 + * \brief Get outgoing tangent scale
1.377 + *
1.378 + * \param sequence KeyframeSequence object
1.379 + * \param ind keyframe index
1.380 + * \return tangent scale
1.381 + */
1.382 +static M3Gfloat m3gOutgoingTangentScale(const KeyframeSequence *sequence,
1.383 + M3Gint ind)
1.384 +{
1.385 + if (!sequence->closed
1.386 + && (ind == sequence->firstValid || ind == sequence->lastValid)) {
1.387 + return 0;
1.388 + }
1.389 + else {
1.390 + M3Gint prevind = m3gPreviousKeyframeIndex(sequence, ind);
1.391 + return m3gDiv(m3gMul(2.0f, (M3Gfloat) m3gTimeDelta(sequence, ind)),
1.392 + (M3Gfloat)(m3gTimeDelta(sequence, ind)
1.393 + + m3gTimeDelta(sequence, prevind)));
1.394 + }
1.395 +}
1.396 +
1.397 +/*!
1.398 + * \internal
1.399 + * \brief Precalculate all tangents
1.400 + *
1.401 + * \param sequence KeyframeSequence object
1.402 + */
1.403 +static void m3gPrecalculateTangents(KeyframeSequence *sequence)
1.404 +{
1.405 + M3Gint i, kf = sequence->firstValid;
1.406 + do {
1.407 + const M3Gfloat *prev = m3gKeyframeBefore(sequence, kf);
1.408 + const M3Gfloat *next = m3gKeyframeAfter(sequence, kf);
1.409 + const M3Gfloat sIn = m3gIncomingTangentScale(sequence, kf);
1.410 + const M3Gfloat sOut = m3gOutgoingTangentScale(sequence, kf);
1.411 + M3Gfloat *in = (M3Gfloat *) m3gTangentTo(sequence, kf);
1.412 + M3Gfloat *out = (M3Gfloat *) m3gTangentFrom(sequence, kf);
1.413 +
1.414 + for (i = 0; i < sequence->numComponents; ++i) {
1.415 + in[i] = m3gMul(m3gMul(0.5f, (m3gSub(next[i], prev[i]))), sIn);
1.416 + out[i] = m3gMul(m3gMul(0.5f, (m3gSub(next[i], prev[i]))), sOut);
1.417 + }
1.418 +
1.419 + kf = m3gNextKeyframeIndex(sequence, kf);
1.420 + } while (kf != sequence->firstValid);
1.421 +}
1.422 +
1.423 +/*!
1.424 + * \internal
1.425 + * \brief Precalculate A and B
1.426 + *
1.427 + * \param sequence KeyframeSequence object
1.428 + */
1.429 +static void m3gPrecalculateAB(KeyframeSequence *sequence)
1.430 +{
1.431 + Quat start, end, prev, next;
1.432 + Vec3 tangent, cfd;
1.433 + M3Gfloat temp[4]; /* used for both quats and vectors */
1.434 +
1.435 + M3Gint kf = sequence->firstValid;
1.436 + do {
1.437 +
1.438 + m3gSetQuat(&prev, m3gKeyframeBefore(sequence, kf));
1.439 + m3gSetQuat(&start, m3gKeyframeAt(sequence, kf));
1.440 + m3gSetQuat(&end, m3gKeyframeAfter(sequence, kf));
1.441 + m3gSetQuat(&next, m3gKeyframeAfter(sequence, m3gNextKeyframeIndex(sequence, kf)));
1.442 +
1.443 + /* Compute the centered finite difference at this
1.444 + keyframe; note that this would be the tangent for basic
1.445 + Catmull-Rom interpolation. */
1.446 +
1.447 + m3gLogDiffQuat(&cfd, &start, &end);
1.448 + m3gLogDiffQuat((Vec3*)temp, &prev, &start);
1.449 + m3gAddVec3(&cfd, (Vec3*)temp);
1.450 + m3gScaleVec3(&cfd, 0.5f);
1.451 +
1.452 + /* Compute the outgoing tangent, scaled to compensate for
1.453 + keyframe timing, then compute the "A" intermediate
1.454 + quaternion. */
1.455 +
1.456 + tangent = cfd;
1.457 + m3gScaleVec3(&tangent, m3gOutgoingTangentScale(sequence, kf));
1.458 +
1.459 + m3gLogDiffQuat((Vec3*)temp, &start, &end);
1.460 + m3gSubVec3(&tangent, (Vec3*)temp);
1.461 + m3gScaleVec3(&tangent, 0.5f);
1.462 + m3gExpQuat((Quat*)temp, &tangent);
1.463 + sequence->a[kf] = start;
1.464 + m3gMulQuat(&(sequence->a[kf]), (Quat*)temp);
1.465 +
1.466 + /* Then repeat the same steps for the incoming tangent and
1.467 + the "B" intermediate quaternion. */
1.468 +
1.469 + tangent = cfd;
1.470 + m3gScaleVec3(&tangent, m3gIncomingTangentScale(sequence, kf));
1.471 +
1.472 + m3gLogDiffQuat((Vec3*)temp, &prev, &start);
1.473 + m3gSubVec3((Vec3*)temp, &tangent);
1.474 + m3gScaleVec3((Vec3*)temp, 0.5f);
1.475 + m3gExpQuat((Quat*)temp, (Vec3*)temp);
1.476 + sequence->b[kf] = start;
1.477 + m3gMulQuat(&(sequence->b[kf]), (Quat*)temp);
1.478 +
1.479 + kf = m3gNextKeyframeIndex(sequence, kf);
1.480 + } while (kf != sequence->firstValid);
1.481 +}
1.482 +
1.483 +/*!
1.484 + * \internal
1.485 + * \brief Update all tangents
1.486 + *
1.487 + * \param sequence KeyframeSequence object
1.488 + */
1.489 +static void m3gUpdateTangents(KeyframeSequence *sequence)
1.490 +{
1.491 + if (sequence->interpolation == M3G_SPLINE) {
1.492 + m3gPrecalculateTangents(sequence);
1.493 + }
1.494 + else if (sequence->interpolation == M3G_SQUAD) {
1.495 + m3gPrecalculateAB(sequence);
1.496 + }
1.497 +}
1.498 +
1.499 +/*!
1.500 + * \internal
1.501 + * \brief Linear interpolate
1.502 + *
1.503 + * \param sequence KeyframeSequence object
1.504 + * \param sample input samples
1.505 + * \param s speed
1.506 + * \param startIndex start index
1.507 + * \param endIndex end index
1.508 + */
1.509 +static M3G_INLINE void m3gLerpSample(const KeyframeSequence *sequence,
1.510 + M3Gfloat *sample,
1.511 + M3Gfloat s,
1.512 + M3Gint startIndex, M3Gint endIndex)
1.513 +{
1.514 + const M3Gfloat *start = m3gKeyframeAt(sequence, startIndex);
1.515 + const M3Gfloat *end = m3gKeyframeAt(sequence, endIndex);
1.516 +
1.517 + m3gLerp(sequence->numComponents, sample, s, start, end);
1.518 +}
1.519 +
1.520 +/*!
1.521 + * \internal
1.522 + * \brief Spline interpolate
1.523 + *
1.524 + * \param sequence KeyframeSequence object
1.525 + * \param sample input samples
1.526 + * \param s speed
1.527 + * \param startIndex start index
1.528 + * \param endIndex end index
1.529 + */
1.530 +static M3G_INLINE void m3gSplineSample(const KeyframeSequence *sequence,
1.531 + M3Gfloat *sample,
1.532 + M3Gfloat s,
1.533 + M3Gint startIndex, M3Gint endIndex)
1.534 +{
1.535 + const M3Gfloat *start, *end;
1.536 + const M3Gfloat *tStart, *tEnd;
1.537 +
1.538 + /* Get the required keyframe values and the (one-sided) tangents
1.539 + * at the ends of the segment. */
1.540 +
1.541 + start = m3gKeyframeAt(sequence, startIndex);
1.542 + end = m3gKeyframeAt(sequence, endIndex);
1.543 +
1.544 + tStart = m3gTangentFrom(sequence, startIndex);
1.545 + tEnd = m3gTangentTo(sequence, endIndex);
1.546 +
1.547 + /* Interpolate the final value using a Hermite spline. */
1.548 +
1.549 + m3gHermite(sequence->numComponents, sample, s, start, end, tStart, tEnd);
1.550 +}
1.551 +
1.552 +/*!
1.553 + * \internal
1.554 + * \brief Spherical linear interpolate
1.555 + *
1.556 + * \param sequence KeyframeSequence object
1.557 + * \param sample input samples
1.558 + * \param s speed
1.559 + * \param startIndex start index
1.560 + * \param endIndex end index
1.561 + */
1.562 +static M3G_INLINE void m3gSlerpSample(const KeyframeSequence *sequence,
1.563 + M3Gfloat *sample,
1.564 + M3Gfloat s,
1.565 + M3Gint startIndex, M3Gint endIndex)
1.566 +{
1.567 + if (sequence->numComponents != 4) {
1.568 + m3gRaiseError(M3G_INTERFACE(sequence), M3G_INVALID_VALUE);
1.569 + return;
1.570 + }
1.571 +
1.572 + m3gSlerpQuat((Quat *) sample,
1.573 + s,
1.574 + (const Quat *) m3gKeyframeAt(sequence, startIndex),
1.575 + (const Quat *) m3gKeyframeAt(sequence, endIndex));
1.576 +}
1.577 +
1.578 +/*!
1.579 + * \internal
1.580 + * \brief Spline interpolate quats
1.581 + *
1.582 + * \param sequence KeyframeSequence object
1.583 + * \param sample input samples
1.584 + * \param s speed
1.585 + * \param startIndex start index
1.586 + * \param endIndex end index
1.587 + */
1.588 +static M3G_INLINE void m3gSquadSample(const KeyframeSequence *sequence,
1.589 + M3Gfloat *sample,
1.590 + M3Gfloat s,
1.591 + M3Gint startIndex, M3Gint endIndex)
1.592 +{
1.593 + if (sequence->numComponents != 4) {
1.594 + m3gRaiseError(M3G_INTERFACE(sequence), M3G_INVALID_VALUE);
1.595 + return;
1.596 + }
1.597 +
1.598 + m3gSquadQuat((Quat *) sample,
1.599 + s,
1.600 + (const Quat *) m3gKeyframeAt(sequence, startIndex),
1.601 + &(sequence->a[startIndex]),
1.602 + &(sequence->b[endIndex]),
1.603 + (const Quat *) m3gKeyframeAt(sequence, endIndex));
1.604 +}
1.605 +
1.606 +/*!
1.607 + * \internal
1.608 + * \brief Get sample
1.609 + *
1.610 + * \param sequence KeyframeSequence object
1.611 + * \param time time
1.612 + * \param sample pointer to sample
1.613 + * \return sample validity
1.614 + */
1.615 +static M3Gint m3gGetSample(KeyframeSequence *sequence,
1.616 + M3Gint time,
1.617 + M3Gfloat *sample)
1.618 +{
1.619 + M3Gint start, end, i;
1.620 + const M3Gfloat *value;
1.621 + M3Gfloat s;
1.622 +
1.623 + M3G_VALIDATE_OBJECT(sequence);
1.624 +
1.625 + if (sequence->dirty == M3G_TRUE) {
1.626 + if (!m3gValidSequence(sequence)) {
1.627 + m3gRaiseError(M3G_INTERFACE(sequence), M3G_INVALID_OPERATION);
1.628 + return 0;
1.629 + }
1.630 + m3gUpdateTangents(sequence);
1.631 + sequence->dirty = M3G_FALSE;
1.632 + sequence->probablyNext = sequence->firstValid;
1.633 + }
1.634 +
1.635 + /* First, map the time to the valid range of a repeating
1.636 + sequence, or handle the special end cases of an open-ended
1.637 + sequence. */
1.638 +
1.639 + if (sequence->closed) {
1.640 + if (time < 0)
1.641 + time = (time % sequence->duration) + sequence->duration;
1.642 + else
1.643 + time = time % sequence->duration;
1.644 + if (time < sequence->keyframeTimes[sequence->firstValid]) {
1.645 + time += sequence->duration;
1.646 + }
1.647 + }
1.648 + else {
1.649 + if (time < sequence->keyframeTimes[sequence->firstValid]) {
1.650 + value = m3gKeyframeAt(sequence, sequence->firstValid);
1.651 + for (i = 0; i < sequence->numComponents; i++)
1.652 + sample[i] = value[i];
1.653 + return (sequence->keyframeTimes[sequence->firstValid] - time);
1.654 + }
1.655 + else if (time >= sequence->keyframeTimes[sequence->lastValid]) {
1.656 + value = m3gKeyframeAt(sequence, sequence->lastValid);
1.657 + for (i = 0; i < sequence->numComponents; i++)
1.658 + sample[i] = value[i];
1.659 + /* \ define a meaningful constant */
1.660 + return 0x7FFFFFFF;
1.661 + }
1.662 + }
1.663 +
1.664 + /* Search for the starting keyframe of the segment to
1.665 + interpolate. Starting the search from the previously
1.666 + used keyframe, we are very likely to find the match
1.667 + sooner than if we'd start from the first keyframe. */
1.668 +
1.669 + start = sequence->probablyNext;
1.670 + if (sequence->keyframeTimes[start] > time)
1.671 + start = sequence->firstValid;
1.672 + while (start != sequence->lastValid &&
1.673 + sequence->keyframeTimes[m3gNextKeyframeIndex(sequence, start)] <= time) {
1.674 + start = m3gNextKeyframeIndex(sequence, start);
1.675 + }
1.676 + sequence->probablyNext = start;
1.677 +
1.678 + /* Calculate the interpolation factor if necessary; the quick
1.679 + exit also avoids a division by zero in the case that we
1.680 + have a quirky sequence with only multiple coincident
1.681 + keyframes. */
1.682 +
1.683 + if (time == sequence->keyframeTimes[start] || sequence->interpolation == M3G_STEP) {
1.684 + value = m3gKeyframeAt(sequence, start);
1.685 + for (i = 0; i < sequence->numComponents; i++)
1.686 + sample[i] = value[i];
1.687 + return (sequence->interpolation == M3G_STEP)
1.688 + ? (m3gTimeDelta(sequence, start) - (time - sequence->keyframeTimes[start]))
1.689 + : 1;
1.690 + }
1.691 + s = m3gDivif(time - sequence->keyframeTimes[start], m3gTimeDelta(sequence, start));
1.692 +
1.693 + /* Pick the correct interpolation function and pass the
1.694 + segment start and end keyframe indices. */
1.695 +
1.696 + end = m3gNextKeyframeIndex(sequence, start);
1.697 +
1.698 + switch (sequence->interpolation) {
1.699 + case M3G_LINEAR:
1.700 + m3gLerpSample(sequence, sample, s, start, end);
1.701 + break;
1.702 + case M3G_SLERP:
1.703 + m3gSlerpSample(sequence, sample, s, start, end);
1.704 + break;
1.705 + case M3G_SPLINE:
1.706 + m3gSplineSample(sequence, sample, s, start, end);
1.707 + break;
1.708 + case M3G_SQUAD:
1.709 + m3gSquadSample(sequence, sample, s, start, end);
1.710 + break;
1.711 + default:
1.712 + m3gRaiseError(M3G_INTERFACE(sequence), M3G_INVALID_ENUM);
1.713 + return 0;
1.714 + }
1.715 +
1.716 + return 1;
1.717 +}
1.718 +
1.719 +/*----------------------------------------------------------------------
1.720 + * Virtual function table
1.721 + *--------------------------------------------------------------------*/
1.722 +
1.723 +static const ObjectVFTable m3gvf_KeyframeSequence = {
1.724 + m3gObjectApplyAnimation,
1.725 + m3gObjectIsCompatible,
1.726 + m3gObjectUpdateProperty,
1.727 + m3gObjectDoGetReferences,
1.728 + m3gObjectFindID,
1.729 + m3gKeyframeSequenceDuplicate,
1.730 + m3gDestroyKeyframeSequence
1.731 +};
1.732 +
1.733 +
1.734 +/*----------------------------------------------------------------------
1.735 + * Public API functions
1.736 + *--------------------------------------------------------------------*/
1.737 +
1.738 +/*!
1.739 + * \brief Creates a new KeyframeSequence with default values
1.740 + *
1.741 + * \param hInterface M3G interface
1.742 + * \param numKeyframes number of keyframes
1.743 + * \param numComponents number of components
1.744 + * \param interpolation interpolation type
1.745 + * \retval KeyframeSequence new KeyframeSequence object
1.746 + * \retval NULL KeyframeSequence creating failed
1.747 + */
1.748 +/*@access M3GInterface@*/
1.749 +/*@access M3Gappearance@*/
1.750 +M3G_API M3GKeyframeSequence m3gCreateKeyframeSequence(M3GInterface hInterface,
1.751 + M3Gint numKeyframes,
1.752 + M3Gint numComponents,
1.753 + M3Gint interpolation)
1.754 +{
1.755 + Interface *m3g = (Interface *) hInterface;
1.756 + M3G_VALIDATE_INTERFACE(m3g);
1.757 +
1.758 + if (numKeyframes < 1 || numComponents < 1
1.759 + || interpolation < M3G_LINEAR || interpolation > M3G_STEP
1.760 + || ((interpolation == M3G_SLERP || interpolation == M3G_SQUAD)
1.761 + && numComponents != 4)) {
1.762 + m3gRaiseError(m3g, M3G_INVALID_VALUE);
1.763 + return NULL;
1.764 + }
1.765 +
1.766 + {
1.767 + KeyframeSequence *sequence = m3gAllocZ(m3g, sizeof(KeyframeSequence));
1.768 +
1.769 + if (sequence != NULL) {
1.770 + if (m3gInitKeyframeSequence(m3g,
1.771 + sequence,
1.772 + numKeyframes, numComponents,
1.773 + interpolation) == NULL) {
1.774 + m3gFree(m3g, sequence);
1.775 + return NULL;
1.776 + }
1.777 + }
1.778 +
1.779 + return (M3GKeyframeSequence) sequence;
1.780 + }
1.781 +}
1.782 +
1.783 +/*!
1.784 + * \brief Assigns a time and value to a keyframe sequence entry
1.785 + *
1.786 + * \param handle handle of the keyframe sequence object
1.787 + * \param ind index of the entry to set
1.788 + * \param time time to set in the entry
1.789 + * \param valueSize number of elements in the value; this must match
1.790 + * the number of elements given when constructing
1.791 + * the sequence
1.792 + * \param value pointer to an array of \c valueSize floats
1.793 + */
1.794 +M3G_API void m3gSetKeyframe(M3GKeyframeSequence handle,
1.795 + M3Gint ind,
1.796 + M3Gint time,
1.797 + M3Gint valueSize, const M3Gfloat *value)
1.798 +{
1.799 + KeyframeSequence *sequence = (KeyframeSequence *)handle;
1.800 + M3G_VALIDATE_OBJECT(sequence);
1.801 +
1.802 + /* Check for invalid inputs */
1.803 +
1.804 + if (value == NULL) {
1.805 + m3gRaiseError(M3G_INTERFACE(sequence), M3G_NULL_POINTER);
1.806 + return;
1.807 + }
1.808 + if (valueSize < sequence->numComponents || time < 0) {
1.809 + m3gRaiseError(M3G_INTERFACE(sequence), M3G_INVALID_VALUE);
1.810 + return;
1.811 + }
1.812 + if (ind < 0 || ind >= sequence->numKeyframes) {
1.813 + m3gRaiseError(M3G_INTERFACE(sequence), M3G_INVALID_INDEX);
1.814 + return;
1.815 + }
1.816 +
1.817 + /* Assign the time and value. Quaternion keyframes are also
1.818 + * normalized, as indicated in the specification. */
1.819 + {
1.820 + M3Gfloat *kf = (M3Gfloat *) m3gKeyframeAt(sequence, ind);
1.821 + int c;
1.822 +
1.823 + sequence->keyframeTimes[ind] = time;
1.824 +
1.825 + for (c = 0; c < sequence->numComponents; ++c) {
1.826 + kf[c] = value[c];
1.827 + }
1.828 +
1.829 + if (sequence->interpolation == M3G_SLERP
1.830 + || sequence->interpolation == M3G_SQUAD) {
1.831 + m3gNormalizeQuat((Quat*) kf);
1.832 + }
1.833 + }
1.834 +
1.835 + sequence->dirty = M3G_TRUE;
1.836 +}
1.837 +
1.838 +/*!
1.839 + * \brief Set valid range
1.840 + *
1.841 + * \param handle handle of the keyframe sequence object
1.842 + * \param first first valid keyframe
1.843 + * \param last last valid keyframe
1.844 + */
1.845 +M3G_API void m3gSetValidRange(M3GKeyframeSequence handle,
1.846 + M3Gint first, M3Gint last)
1.847 +{
1.848 + KeyframeSequence *sequence = (KeyframeSequence *)handle;
1.849 + M3G_VALIDATE_OBJECT(sequence);
1.850 +
1.851 + if (first < 0 || first >= sequence->numKeyframes ||
1.852 + last < 0 || last >= sequence->numKeyframes) {
1.853 + m3gRaiseError(M3G_INTERFACE(sequence), M3G_INVALID_INDEX);
1.854 + return;
1.855 + }
1.856 +
1.857 + sequence->firstValid = first;
1.858 + sequence->lastValid = last;
1.859 + sequence->dirty = M3G_TRUE;
1.860 +}
1.861 +
1.862 +/*!
1.863 + * \brief Set duration
1.864 + *
1.865 + * \param handle handle of the keyframe sequence object
1.866 + * \param duration duration
1.867 + */
1.868 +M3G_API void m3gSetDuration(M3GKeyframeSequence handle, M3Gint duration)
1.869 +{
1.870 + KeyframeSequence *sequence = (KeyframeSequence *)handle;
1.871 + M3G_VALIDATE_OBJECT(sequence);
1.872 +
1.873 + /* Check for errors */
1.874 + if (duration <= 0) {
1.875 + m3gRaiseError(M3G_INTERFACE(sequence), M3G_INVALID_VALUE);
1.876 + return;
1.877 + }
1.878 +
1.879 + sequence->duration = duration;
1.880 + sequence->dirty = M3G_TRUE;
1.881 +}
1.882 +
1.883 +/*!
1.884 + * \brief Get duration
1.885 + *
1.886 + * \param handle handle of the keyframe sequence object
1.887 + * \return duration
1.888 + */
1.889 +M3G_API M3Gint m3gGetDuration(M3GKeyframeSequence handle)
1.890 +{
1.891 + KeyframeSequence *sequence = (KeyframeSequence *)handle;
1.892 + M3G_VALIDATE_OBJECT(sequence);
1.893 + return sequence->duration;
1.894 +}
1.895 +
1.896 +/*!
1.897 + * \brief Get component count
1.898 + *
1.899 + * \param handle handle of the keyframe sequence object
1.900 + * \return component count
1.901 + */
1.902 +M3G_API M3Gint m3gGetComponentCount(M3GKeyframeSequence handle)
1.903 +{
1.904 + KeyframeSequence *sequence = (KeyframeSequence *)handle;
1.905 + M3G_VALIDATE_OBJECT(sequence);
1.906 + return sequence->numComponents;
1.907 +}
1.908 +
1.909 +/*!
1.910 + * \brief Get interpolation type
1.911 + *
1.912 + * \param handle handle of the keyframe sequence object
1.913 + * \return interpolation type
1.914 + */
1.915 +M3G_API M3Gint m3gGetInterpolationType(M3GKeyframeSequence handle)
1.916 +{
1.917 + KeyframeSequence *sequence = (KeyframeSequence *)handle;
1.918 + M3G_VALIDATE_OBJECT(sequence);
1.919 + return sequence->interpolation;
1.920 +}
1.921 +
1.922 +/*!
1.923 + * \brief Get keyframe value
1.924 + *
1.925 + * \param handle handle of the keyframe sequence object
1.926 + * \param frameIndex keyframe index
1.927 + * \param value value array
1.928 +
1.929 + * \return time value of the keyframe
1.930 + */
1.931 +M3G_API M3Gint m3gGetKeyframe (M3GKeyframeSequence handle, M3Gint frameIndex, M3Gfloat *value)
1.932 +{
1.933 + KeyframeSequence *sequence = (KeyframeSequence *)handle;
1.934 + M3G_VALIDATE_OBJECT(sequence);
1.935 +
1.936 + if (frameIndex < 0 || frameIndex >= sequence->numKeyframes) {
1.937 + m3gRaiseError(M3G_INTERFACE(sequence), M3G_INVALID_INDEX);
1.938 + return 0;
1.939 + }
1.940 +
1.941 + if (value != NULL) {
1.942 + m3gCopy( value,
1.943 + sequence->keyframes + frameIndex * sequence->numComponents,
1.944 + sequence->numComponents * sizeof(M3Gfloat));
1.945 + }
1.946 +
1.947 + return sequence->keyframeTimes[frameIndex];
1.948 +}
1.949 +
1.950 +/*!
1.951 + * \brief Get keyframe count
1.952 + *
1.953 + * \param handle handle of the keyframe sequence object
1.954 + * \return keyframe count
1.955 + */
1.956 +M3G_API M3Gint m3gGetKeyframeCount(M3GKeyframeSequence handle)
1.957 +{
1.958 + KeyframeSequence *sequence = (KeyframeSequence *)handle;
1.959 + M3G_VALIDATE_OBJECT(sequence);
1.960 + return sequence->numKeyframes;
1.961 +}
1.962 +
1.963 +/*!
1.964 + * \brief Get valid range
1.965 + *
1.966 + * \param handle handle of the keyframe sequence object
1.967 + * \param first pointer to valid range start
1.968 + * \param last pointer to valid range end
1.969 + */
1.970 +M3G_API void m3gGetValidRange(M3GKeyframeSequence handle, M3Gint *first, M3Gint *last)
1.971 +{
1.972 + KeyframeSequence *sequence = (KeyframeSequence *)handle;
1.973 + M3G_VALIDATE_OBJECT(sequence);
1.974 + *first = sequence->firstValid;
1.975 + *last = sequence->lastValid;
1.976 +}
1.977 +
1.978 +/*!
1.979 + * \brief Set repeat mode
1.980 + *
1.981 + * \param handle handle of the keyframe sequence object
1.982 + * \param mode repeat mode
1.983 + */
1.984 +M3G_API void m3gSetRepeatMode(M3GKeyframeSequence handle, M3Genum mode)
1.985 +{
1.986 + KeyframeSequence *sequence = (KeyframeSequence *)handle;
1.987 + M3G_VALIDATE_OBJECT(sequence);
1.988 + if (mode != M3G_CONSTANT && mode != M3G_LOOP) {
1.989 + m3gRaiseError(M3G_INTERFACE(sequence), M3G_INVALID_ENUM);
1.990 + return;
1.991 + }
1.992 + sequence->closed = (mode == M3G_LOOP) ? M3G_TRUE : M3G_FALSE;
1.993 +}
1.994 +
1.995 +/*!
1.996 + * \brief Get repeat mode
1.997 + *
1.998 + * \param handle handle of the keyframe sequence object
1.999 + * \return repeat mode
1.1000 + */
1.1001 +M3G_API M3Genum m3gGetRepeatMode(M3GKeyframeSequence handle)
1.1002 +{
1.1003 + KeyframeSequence *sequence = (KeyframeSequence *)handle;
1.1004 + M3G_VALIDATE_OBJECT(sequence);
1.1005 + return (sequence->closed ? M3G_LOOP : M3G_CONSTANT);
1.1006 +}
1.1007 +