sl@0: /* sl@0: * Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: * This component and the accompanying materials are made available sl@0: * under the terms of the License "Eclipse Public License v1.0" sl@0: * which accompanies this distribution, and is available sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: * sl@0: * Initial Contributors: sl@0: * Nokia Corporation - initial contribution. sl@0: * sl@0: * Contributors: sl@0: * sl@0: * Description: AnimationTrack implementation sl@0: * sl@0: */ sl@0: sl@0: sl@0: /*! sl@0: * \internal sl@0: * \file sl@0: * \brief AnimationTrack implementation sl@0: */ sl@0: sl@0: #ifndef M3G_CORE_INCLUDE sl@0: # error included by m3g_core.c; do not compile separately. sl@0: #endif sl@0: sl@0: #include "m3g_animationtrack.h" sl@0: #include "m3g_keyframesequence.h" sl@0: #include "m3g_memory.h" sl@0: sl@0: sl@0: /*---------------------------------------------------------------------- sl@0: * Internal functions sl@0: *--------------------------------------------------------------------*/ sl@0: sl@0: /*! sl@0: * \internal sl@0: * \brief Destroys this AnimationTrack object. sl@0: * sl@0: * \param obj AnimationTrack object sl@0: */ sl@0: static void m3gDestroyAnimationTrack(Object *obj) sl@0: { sl@0: AnimationTrack *animTrack = (AnimationTrack *) obj; sl@0: M3G_VALIDATE_OBJECT(animTrack); sl@0: sl@0: M3G_ASSIGN_REF(animTrack->sequence, NULL); sl@0: M3G_ASSIGN_REF(animTrack->controller, NULL); sl@0: sl@0: m3gDestroyObject(&animTrack->object); sl@0: } sl@0: sl@0: /*! sl@0: * \internal sl@0: * \brief Calculates animation track contribution. sl@0: * sl@0: * \param track AnimationTrack object sl@0: * \param time current world time sl@0: * \param accumSamples accumulated samples sl@0: * \param sampleInfo sample information sl@0: */ sl@0: static void m3gGetContribution(const AnimationTrack *track, M3Gint time, sl@0: M3Gfloat *accumSamples, SampleInfo *sampleInfo) sl@0: { sl@0: if (track->controller == NULL || !m3gIsActive(track->controller, time)) { sl@0: sampleInfo->weight = 0; sl@0: sampleInfo->validity = (track->controller ? sl@0: m3gTimeToActivation(track->controller, time) : sl@0: 0x7FFFFFFF); sl@0: if (sampleInfo->validity < 1) sl@0: sampleInfo->validity = 1; sl@0: return; sl@0: } sl@0: { sl@0: M3Gfloat stackSampleVector[4]; sl@0: Interface *m3g = M3G_INTERFACE(track); sl@0: M3Gint i, sampleTime, sampleValidity; sl@0: M3Gfloat weight; sl@0: M3Gint sampleLength = m3gGetNumComponents(track->sequence); sl@0: M3Gfloat *sample; sl@0: sl@0: /* Before sampling, make sure that this track has some effect sl@0: * on the end result */ sl@0: sl@0: weight = m3gGetWeight(track->controller); sl@0: sampleInfo->weight = weight; sl@0: sl@0: if (weight <= 0.0f) { sl@0: sampleInfo->validity = 0x7FFFFFFF; sl@0: return; sl@0: } sl@0: sl@0: /* We use the stack-allocated sample vector by default, but sl@0: * the MORPH_WEIGHTS target may have more than 4 components, sl@0: * in which case we resort to the global temp vector. This sl@0: * means that the temp vector can not be used in the keyframe sl@0: * sampling code, but it doesn't seem likely that it would be sl@0: * needed there. */ sl@0: sl@0: if (sampleLength > 4) { sl@0: sample = (M3Gfloat*) m3gAllocTemp(m3g, (M3Gsize) sampleLength * sizeof(M3Gfloat)); sl@0: if (!sample) { sl@0: sampleInfo->validity = 0; sl@0: return; /* automatic out-of-memory error */ sl@0: } sl@0: } sl@0: else { sl@0: sample = stackSampleVector; sl@0: } sl@0: sl@0: sampleTime = m3gRoundToInt(m3gGetPosition(track->controller, time)); sl@0: sampleValidity = m3gGetSample(track->sequence, sampleTime, sample); sl@0: sampleInfo->validity = sampleValidity; sl@0: sl@0: /* Only bother if there was no error in GetSample... */ sl@0: sl@0: if (sampleValidity > 0) { sl@0: sl@0: /* Resolve the validity time of the sample */ sl@0: sl@0: sampleValidity = m3gTimeToDeactivation(track->controller, time); sl@0: if (sampleValidity < sampleInfo->validity) { sl@0: sampleInfo->validity = sampleValidity; sl@0: } sl@0: sl@0: /* Add the weighted sample to the accumulated value sl@0: * and return */ sl@0: sl@0: for (i = 0; i < sampleLength; ++i) { sl@0: accumSamples[i] = m3gAdd(accumSamples[i], sl@0: m3gMul(sample[i], weight)); sl@0: } sl@0: } sl@0: if (sample != stackSampleVector) { sl@0: m3gFreeTemp(m3g); sl@0: } sl@0: } sl@0: } sl@0: sl@0: /*! sl@0: * \internal sl@0: * \brief Checks animation property size. sl@0: * sl@0: * \param m3g M3G interface sl@0: * \param property animation property sl@0: * \param numComponents number of components sl@0: * \retval M3G_TRUE valid size for property sl@0: * \retval M3G_FALSE invalid size for property sl@0: */ sl@0: static M3Gbool m3gIsValidSize(Interface *m3g, M3Gint property, M3Gint numComponents) sl@0: { sl@0: switch (property) { sl@0: case M3G_ANIM_ALPHA: sl@0: case M3G_ANIM_DENSITY: sl@0: case M3G_ANIM_FAR_DISTANCE: sl@0: case M3G_ANIM_FIELD_OF_VIEW: sl@0: case M3G_ANIM_INTENSITY: sl@0: case M3G_ANIM_NEAR_DISTANCE: sl@0: case M3G_ANIM_PICKABILITY: sl@0: case M3G_ANIM_SHININESS: sl@0: case M3G_ANIM_SPOT_ANGLE: sl@0: case M3G_ANIM_SPOT_EXPONENT: sl@0: case M3G_ANIM_VISIBILITY: sl@0: return (numComponents == 1); sl@0: case M3G_ANIM_CROP: sl@0: return (numComponents == 2 || numComponents == 4); sl@0: case M3G_ANIM_COLOR: sl@0: case M3G_ANIM_AMBIENT_COLOR: sl@0: case M3G_ANIM_DIFFUSE_COLOR: sl@0: case M3G_ANIM_EMISSIVE_COLOR: sl@0: case M3G_ANIM_SPECULAR_COLOR: sl@0: return (numComponents == 3); sl@0: case M3G_ANIM_TRANSLATION: sl@0: return (numComponents == 3); sl@0: case M3G_ANIM_ORIENTATION: sl@0: return (numComponents == 4); sl@0: case M3G_ANIM_SCALE: sl@0: return (numComponents == 1 || numComponents == 3); sl@0: case M3G_ANIM_MORPH_WEIGHTS: sl@0: return (numComponents > 0); sl@0: default: sl@0: m3gRaiseError(m3g, M3G_INVALID_ENUM); sl@0: } sl@0: return M3G_FALSE; sl@0: } sl@0: sl@0: /*! sl@0: * \internal sl@0: * \brief Overloaded Object3D method. sl@0: * sl@0: * \param self AnimationTrack object sl@0: * \param references array of reference objects sl@0: * \return number of references sl@0: */ sl@0: static M3Gint m3gAnimationTrackDoGetReferences(Object *self, Object **references) sl@0: { sl@0: AnimationTrack *track = (AnimationTrack *) self; sl@0: M3Gint num = m3gObjectDoGetReferences(self, references); sl@0: if (track->sequence != NULL) { sl@0: if (references != NULL) sl@0: references[num] = (Object *)track->sequence; sl@0: num++; sl@0: } sl@0: if (track->controller != NULL) { sl@0: if (references != NULL) sl@0: references[num] = (Object *)track->controller; sl@0: num++; sl@0: } sl@0: return num; sl@0: } sl@0: sl@0: /*! sl@0: * \internal sl@0: * \brief Overloaded Object3D method sl@0: */ sl@0: static Object *m3gAnimationTrackFindID(Object *self, M3Gint userID) sl@0: { sl@0: AnimationTrack *track = (AnimationTrack *) self; sl@0: Object *found = m3gObjectFindID(self, userID); sl@0: sl@0: if (!found && track->sequence != NULL) { sl@0: found = m3gFindID((Object*) track->sequence, userID); sl@0: } sl@0: if (!found && track->controller != NULL) { sl@0: found = m3gFindID((Object*) track->controller, userID); sl@0: } sl@0: return found; sl@0: } sl@0: sl@0: /*! sl@0: * \internal sl@0: * \brief Overloaded Object3D method. sl@0: * sl@0: * \param originalObj original AnimationTrack object sl@0: * \param cloneObj pointer to cloned AnimationTrack object sl@0: * \param pairs array for all object-duplicate pairs sl@0: * \param numPairs number of pairs sl@0: */ sl@0: static M3Gbool m3gAnimationTrackDuplicate(const Object *originalObj, sl@0: Object **cloneObj, sl@0: Object **pairs, sl@0: M3Gint *numPairs) sl@0: { sl@0: AnimationTrack *original = (AnimationTrack *)originalObj; sl@0: AnimationTrack *clone = sl@0: (AnimationTrack *)m3gCreateAnimationTrack(originalObj->interface, sl@0: original->sequence, sl@0: original->property); sl@0: *cloneObj = (Object *)clone; sl@0: if (*cloneObj == NULL) { sl@0: return M3G_FALSE; sl@0: } sl@0: sl@0: if(m3gObjectDuplicate(originalObj, cloneObj, pairs, numPairs)) { sl@0: M3G_ASSIGN_REF(clone->controller, original->controller); sl@0: return M3G_TRUE; sl@0: } sl@0: else { sl@0: return M3G_FALSE; sl@0: } sl@0: } sl@0: sl@0: /*---------------------------------------------------------------------- sl@0: * Virtual function table sl@0: *--------------------------------------------------------------------*/ sl@0: sl@0: static const ObjectVFTable m3gvf_AnimationTrack = { sl@0: m3gObjectApplyAnimation, sl@0: m3gObjectIsCompatible, sl@0: m3gObjectUpdateProperty, sl@0: m3gAnimationTrackDoGetReferences, sl@0: m3gAnimationTrackFindID, sl@0: m3gAnimationTrackDuplicate, sl@0: m3gDestroyAnimationTrack sl@0: }; sl@0: sl@0: sl@0: /*---------------------------------------------------------------------- sl@0: * Public API functions sl@0: *--------------------------------------------------------------------*/ sl@0: sl@0: /*! sl@0: * \brief Creates a new AnimationTrack with default values sl@0: * sl@0: * \param hInterface M3G interface sl@0: * \param hSequence KeyframeSequence object sl@0: * \param property target animation property sl@0: * \retval AnimationTrack new AnimationTrack object sl@0: * \retval NULL AnimationTrack creating failed sl@0: */ sl@0: M3G_API M3GAnimationTrack m3gCreateAnimationTrack(M3GInterface hInterface, sl@0: M3GKeyframeSequence hSequence, sl@0: M3Gint property) sl@0: { sl@0: KeyframeSequence *sequence = (KeyframeSequence *)hSequence; sl@0: Interface *m3g = (Interface *) hInterface; sl@0: M3G_VALIDATE_INTERFACE(m3g); sl@0: sl@0: /* Check for invalid arguments */ sl@0: sl@0: if (sequence == NULL) { sl@0: m3gRaiseError(m3g, M3G_NULL_POINTER); sl@0: return NULL; sl@0: } sl@0: if (property < M3G_ANIM_ALPHA || property > M3G_ANIM_VISIBILITY) { sl@0: m3gRaiseError(m3g, M3G_INVALID_ENUM); sl@0: return NULL; sl@0: } sl@0: if (!m3gIsValidSize(m3g, property, m3gGetNumComponents(sequence))) { sl@0: m3gRaiseError(m3g, M3G_INVALID_VALUE); sl@0: return NULL; sl@0: } sl@0: sl@0: /* Allocate and initialize the object */ sl@0: sl@0: { sl@0: AnimationTrack *track = m3gAllocZ(m3g, sizeof(AnimationTrack)); sl@0: sl@0: if (track != NULL) { sl@0: M3G_ASSIGN_REF(track->sequence, sequence); sl@0: track->property = property; sl@0: m3gInitObject(&track->object, m3g, M3G_CLASS_ANIMATION_TRACK); sl@0: } sl@0: sl@0: return track; sl@0: } sl@0: } sl@0: sl@0: /*! sl@0: * \brief Get animation controller. sl@0: * sl@0: * \param hTrack AnimationTrack object sl@0: * \retval AnimationController object sl@0: */ sl@0: M3G_API M3GAnimationController m3gGetController(M3GAnimationTrack hTrack) sl@0: { sl@0: AnimationTrack *track = (AnimationTrack *) hTrack; sl@0: M3G_VALIDATE_OBJECT(track); sl@0: sl@0: return track->controller; sl@0: } sl@0: sl@0: /*! sl@0: * \brief Get key frame sequence. sl@0: * sl@0: * \param hTrack AnimationTrack object sl@0: * \retval KeyframeSequence object sl@0: */ sl@0: M3G_API M3GKeyframeSequence m3gGetSequence(M3GAnimationTrack hTrack) sl@0: { sl@0: AnimationTrack *track = (AnimationTrack *) hTrack; sl@0: M3G_VALIDATE_OBJECT(track); sl@0: sl@0: return track->sequence; sl@0: } sl@0: sl@0: /*! sl@0: * \brief Get animation target property. sl@0: * sl@0: * \param hTrack AnimationTrack object sl@0: * \retval target property sl@0: */ sl@0: M3G_API M3Gint m3gGetTargetProperty(M3GAnimationTrack hTrack) sl@0: { sl@0: AnimationTrack *track = (AnimationTrack *) hTrack; sl@0: M3G_VALIDATE_OBJECT(track); sl@0: sl@0: return track->property; sl@0: } sl@0: sl@0: /*! sl@0: * \brief Set animation controller. sl@0: * sl@0: * \param hTrack AnimationTrack object sl@0: * \param hController AnimationController object sl@0: */ sl@0: M3G_API void m3gSetController(M3GAnimationTrack hTrack, sl@0: M3GAnimationController hController) sl@0: { sl@0: AnimationTrack *track = (AnimationTrack *) hTrack; sl@0: M3G_VALIDATE_OBJECT(track); sl@0: sl@0: M3G_ASSIGN_REF(track->controller, hController); sl@0: } sl@0: