
/****************************************************************************
 * 
 * VRML 2.0 to RW3.0 Converter
 * Copyright (C) 1998 Criterion Technologies
 *
 * Author  : Damian Scallan 
 *
 * Module  : animation.c
 *                                                                         
 * Purpose : To setup any hirarchical animation 
 *           that might be attached to the node
 *                                                                         
 ****************************************************************************/

/****************************************************************************
 Includes
 */
#include "rpplugin.h"
#include "animation.h"
#include "route.h"
#include "rpvrmlanim.h"
#include "rpvrml.h"
#include "animfuncttab.h"

static const char __RWUNUSED__ rcsid[] =
    "@@(#)$Id: animation.c,v 1.25 2001/01/26 12:10:11 johns Exp $";

/****************************************************************************
 Local Types
 */

typedef             RwBool(*AnimSetupCallBack) (RwFrame * frame, Field *
                                                keyValuesList,
                                                Field * keysList,
                                                RwReal cycleTime);

/****************************************************************************
 Local (static) Globals
 */

static RpVRMLAnimFunctions *animFuncts;

/****************************************************************************
 External Globals
 */

extern float        GscaleFactor;

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

   Anim state setup

   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */

static RpVRMLAnimState *
AnimStateCreate(Field * keysList, RwReal cycleTime, RwBool keyNormalize)
{
    RWFUNCTION(RWSTRING("AnimStateCreate"));
    RWASSERT(keysList);

    if (keysList)
    {
        RpVRMLAnimState    *rotateCntrl;
        RwInt32             numKeys, numFinalKeys, i, j;
        RwReal              lastTime;

        numKeys = Field_NumElements(keysList);
        numFinalKeys = numKeys;
        if (keyNormalize)
        {
            numFinalKeys++;
        }

        rotateCntrl =
            animFuncts->fpAnimControllerCreate(numFinalKeys - 1);
        if (!rotateCntrl)
        {
            RWRETURN(FALSE);
        }

        i = -1;
        lastTime = -1.0f;
        for (j = 0; j < numKeys; j++)
        {
            RwReal             *currentTime;

            currentTime = (RwReal *) FieldMffloat_GetValue(keysList, j);

            if (lastTime >= 0.0f)
            {
                float               duration;

                duration = *currentTime - lastTime;
                animFuncts->fpAnimControllerAddInterpolator(rotateCntrl,
                                                            i,
                                                            (RwInt16)
                                                            i,
                                                            (RwInt16)
                                                            (i + 1),
                                                            duration *
                                                            cycleTime);
            }

            lastTime = *currentTime;
            i++;
        }

        if (keyNormalize)
        {
            float               duration;

            duration = 1.0f - lastTime;
            animFuncts->fpAnimControllerAddInterpolator(rotateCntrl,
                                                        i, (RwInt16)
                                                        i, (RwInt16)
                                                        (i + 1),
                                                        duration *
                                                        cycleTime);
        }

        RWRETURN(rotateCntrl);
    }

    RWERROR((E_RW_PLUGINNOTINIT));
    RWRETURN(NULL);
}

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

   Rotation setup

   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */

static              RwBool
AnimSetupRotationKeys(RwFrame * frame, RpVRMLAnimRotate * rotateAnim,
                      Field * keyValuesList, RwBool keyNormalize)
{
    RWFUNCTION(RWSTRING("AnimSetupRotationKeys"));
    RWASSERT(frame);
    RWASSERT(rotateAnim);
    RWASSERT(keyValuesList);

    if (frame && rotateAnim && keyValuesList)
    {
        RpVRMLRotateKey    *rotateKeys;
        RwInt32             numKeys, numFinalKeys, i;

        numKeys = Field_NumElements(keyValuesList);
        numFinalKeys = numKeys;

        if (keyNormalize)
        {
            numFinalKeys++;
        }

        if (!animFuncts->fpAnimRotateAddKeys(rotateAnim, numFinalKeys))
        {
            RWRETURN(FALSE);
        }

        rotateKeys = animFuncts->fpAnimRotateGetKeys(rotateAnim);
        if (!rotateKeys)
        {
            RWRETURN(FALSE);
        }

        animFuncts->fpFrameAnimSetRotations(frame, rotateAnim);

        for (i = 0; i < numKeys; i++)
        {
            sfrotation         *sfr;

            sfr = FieldMfrotation_GetValue(keyValuesList, i);
            *rotateKeys = *(RpVRMLRotateKey *) sfr;
            rotateKeys++;
        }

        /* duplicate the final key */
        if (keyNormalize)
        {
            RpVRMLRotateKey    *lastKey;

            lastKey = rotateKeys - 1;
            *rotateKeys = *lastKey;
        }

        RWRETURN(TRUE);
    }

    RWERROR((E_RW_PLUGINNOTINIT));
    RWRETURN(FALSE);
}

static              RwBool
AnimSetupRotate(RwFrame * frame, Field * keyValuesList, Field *
                keysList, RwReal cycleTime)
{
    RWFUNCTION(RWSTRING("AnimSetupRotate"));
    RWASSERT(frame);
    RWASSERT(keyValuesList);
    RWASSERT(keysList);

    if (frame && keyValuesList && keysList)
    {
        RpVRMLAnimRotate   *rotateAnim;
        RpVRMLAnimState    *rotateState;
        RwReal              lastKey;
        RwBool              keyNormalize = FALSE;
        int                 numKeys;

        /* create a rotation animation */
        rotateAnim = animFuncts->fpAnimRotateCreate();
        if (!rotateAnim)
        {
            RWRETURN(FALSE);
        }

        /* get num keys */
        numKeys = Field_NumElements(keysList);

        /* do we need to normalize this animation */
        lastKey =
            *(RwReal *) FieldMffloat_GetValue(keysList, numKeys - 1);
        if (lastKey < (RwReal) (1))
        {
            keyNormalize = TRUE;
        }

        /* setup the rotation keys */
        if (!AnimSetupRotationKeys
            (frame, rotateAnim, keyValuesList, keyNormalize))
        {
            animFuncts->fpAnimRotateDestroy(rotateAnim);

            RWRETURN(FALSE);
        }

        /* setup the rotation interpolators */
        rotateState =
            AnimStateCreate(keysList, cycleTime, keyNormalize);
        if (!rotateState)
        {
            animFuncts->fpAnimRotateDestroy(rotateAnim);

            RWRETURN(FALSE);
        }
        animFuncts->fpAnimRotateSetController(rotateAnim, rotateState);

        RWRETURN(TRUE);
    }

    RWERROR((E_RW_PLUGINNOTINIT));
    RWRETURN(FALSE);
}

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

   Translation setup

   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */

static              RwBool
AnimSetupTranslationKeys(RwFrame * frame, RpVRMLAnimTranslate *
                         translateAnim, Field * keyValuesList,
                         RwBool keyNormalize)
{
    RWFUNCTION(RWSTRING("AnimSetupTranslationKeys"));
    RWASSERT(frame);
    RWASSERT(translateAnim);
    RWASSERT(keyValuesList);

    if (frame && translateAnim && keyValuesList)
    {
        RpVRMLTranslateKey *translateKeys;
        int                 numKeys, numFinalKeys, i;

        numKeys = Field_NumElements(keyValuesList);
        numFinalKeys = numKeys;

        if (keyNormalize)
        {
            numFinalKeys++;
        }

        if (!animFuncts->
            fpAnimTranslateAddKeys(translateAnim, numFinalKeys))
        {
            RWRETURN(FALSE);
        }

        translateKeys =
            animFuncts->fpAnimTranslateGetKeys(translateAnim);
        if (!translateKeys)
        {
            RWRETURN(FALSE);
        }

        animFuncts->fpFrameAnimSetTranslations(frame, translateAnim);

        for (i = 0; i < numKeys; i++)
        {
            sfvec3f            *sfv3f;

            sfv3f = FieldMfvec3f_GetValue(keyValuesList, i);
            *translateKeys = *(RpVRMLTranslateKey *) sfv3f;
            translateKeys->x *= GscaleFactor;
            translateKeys->y *= GscaleFactor;
            translateKeys->z *= GscaleFactor;
            translateKeys++;
        }

        /* duplicate the final key */
        if (keyNormalize)
        {
            RpVRMLTranslateKey *lastKey;

            lastKey = translateKeys - 1;
            *translateKeys = *lastKey;
        }

        RWRETURN(TRUE);
    }

    RWERROR((E_RW_PLUGINNOTINIT));
    RWRETURN(FALSE);
}

static              RwBool
AnimSetupTranslate(RwFrame * frame, Field * keyValuesList, Field *
                   keysList, RwReal cycleTime)
{
    RWFUNCTION(RWSTRING("AnimSetupTranslate"));
    RWASSERT(frame);
    RWASSERT(keyValuesList);
    RWASSERT(keysList);

    if (frame && keyValuesList && keysList)
    {
        RpVRMLAnimTranslate *translateAnim;
        RpVRMLAnimState    *translateState;
        RwReal              lastKey;
        RwBool              keyNormalize = FALSE;
        RwInt32             numKeys;

        /* create a rotation animation */
        translateAnim = animFuncts->fpAnimTranslateCreate();
        if (!translateAnim)
        {
            RWRETURN(FALSE);
        }

        /* get num Keys */
        numKeys = Field_NumElements(keysList);

        /* do we need to normalize this animation */
        lastKey =
            *(RwReal *) FieldMffloat_GetValue(keysList, numKeys - 1);
        if (lastKey < (RwReal) (1))
        {
            keyNormalize = TRUE;
        }

        /* setup the translation keys */
        if (!AnimSetupTranslationKeys(frame, translateAnim,
                                      keyValuesList, keyNormalize))
        {
            animFuncts->fpAnimTranslateDestroy(translateAnim);

            RWRETURN(FALSE);
        }

        /* setup the translation interpolators */
        translateState =
            AnimStateCreate(keysList, cycleTime, keyNormalize);
        if (!translateState)
        {
            animFuncts->fpAnimTranslateDestroy(translateAnim);

            RWRETURN(FALSE);
        }
        animFuncts->fpAnimTranslateSetController(translateAnim,
                                                 translateState);

        RWRETURN(TRUE);
    }

    RWERROR((E_RW_PLUGINNOTINIT));
    RWRETURN(FALSE);
}

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

   Scales setup

   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */

static              RwBool
AnimSetupScaleKeys(RwFrame * frame, RpVRMLAnimScale * scaleAnim, Field *
                   keyValuesList, RwBool keyNormalize)
{
    RWFUNCTION(RWSTRING("AnimSetupScaleKeys"));
    RWASSERT(frame);
    RWASSERT(scaleAnim);
    RWASSERT(keyValuesList);

    if (frame && scaleAnim && keyValuesList)
    {
        RpVRMLScaleKey     *scaleKeys;
        RwInt32             numKeys, numFinalKeys, i;

        numKeys = Field_NumElements(keyValuesList);
        numFinalKeys = numKeys;

        if (keyNormalize)
        {
            numFinalKeys++;
        }

        if (!animFuncts->fpAnimScaleAddKeys(scaleAnim, numFinalKeys))
        {
            RWRETURN(FALSE);
        }

        scaleKeys = animFuncts->fpAnimScaleGetKeys(scaleAnim);
        if (!scaleKeys)
        {
            RWRETURN(FALSE);
        }

        animFuncts->fpFrameAnimSetScales(frame, scaleAnim);

        for (i = 0; i < numKeys; i++)
        {
            sfvec3f            *sfv3f;

            sfv3f = FieldMfvec3f_GetValue(keyValuesList, i);
            *scaleKeys = *(RpVRMLScaleKey *) sfv3f;
            scaleKeys++;
        }

        /* duplicate the final key */
        if (keyNormalize)
        {
            RpVRMLScaleKey     *lastKey;

            lastKey = scaleKeys - 1;
            *scaleKeys = *lastKey;
        }

        RWRETURN(TRUE);
    }

    RWERROR((E_RW_PLUGINNOTINIT));
    RWRETURN(FALSE);
}

static              RwBool
AnimSetupScale(RwFrame * frame, Field * keyValuesList, Field *
               keysList, RwReal cycleTime)
{
    RWFUNCTION(RWSTRING("AnimSetupScale"));
    RWASSERT(frame);
    RWASSERT(keyValuesList);
    RWASSERT(keysList);

    if (frame && keyValuesList && keysList)
    {
        RpVRMLAnimScale    *scaleAnim;
        RpVRMLAnimState    *scaleState;
        RwReal              lastKey;
        RwBool              keyNormalize = FALSE;
        RwInt32             numKeys;

        /* create a rotation animation */
        scaleAnim = animFuncts->fpAnimScaleCreate();
        if (!scaleAnim)
        {
            RWRETURN(FALSE);
        }

        /* get num keys */
        numKeys = Field_NumElements(keysList);

        /* do we need to normalize this animation */
        lastKey =
            *(RwReal *) FieldMffloat_GetValue(keysList, numKeys - 1);
        if (lastKey < (RwReal) (1))
        {
            keyNormalize = TRUE;
        }

        /* setup the rotation keys */
        if (!AnimSetupScaleKeys
            (frame, scaleAnim, keyValuesList, keyNormalize))
        {
            animFuncts->fpAnimScaleDestroy(scaleAnim);

            RWRETURN(FALSE);
        }

        /* setup the rotation interpolators */
        scaleState = AnimStateCreate(keysList, cycleTime, keyNormalize);
        if (!scaleState)
        {
            animFuncts->fpAnimScaleDestroy(scaleAnim);

            RWRETURN(FALSE);
        }
        animFuncts->fpAnimScaleSetController(scaleAnim, scaleState);

        RWRETURN(TRUE);
    }

    RWERROR((E_RW_PLUGINNOTINIT));
    RWRETURN(FALSE);
}

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

   Scale Orient setup

   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */

static              RwBool
AnimSetupScaleOrientKeys(RwFrame * frame, RpVRMLAnimRotate *
                         scaleOrientAnim, Field * keyValuesList,
                         RwBool keyNormalize)
{
    RWFUNCTION(RWSTRING("AnimSetupScaleOrientKeys"));
    RWASSERT(frame);
    RWASSERT(scaleOrientAnim);
    RWASSERT(keyValuesList);

    if (frame && scaleOrientAnim && keyValuesList)
    {
        RpVRMLRotateKey    *rotateKeys;
        RwInt32             numKeys, numFinalKeys, i;

        numKeys = Field_NumElements(keyValuesList);
        numFinalKeys = numKeys;

        if (keyNormalize)
        {
            numFinalKeys++;
        }

        if (!animFuncts->
            fpAnimRotateAddKeys(scaleOrientAnim, numFinalKeys))
        {
            RWRETURN(FALSE);
        }

        rotateKeys = animFuncts->fpAnimRotateGetKeys(scaleOrientAnim);
        if (!rotateKeys)
        {
            RWRETURN(FALSE);
        }

        animFuncts->fpFrameAnimSetScaleOrients(frame, scaleOrientAnim);

        for (i = 0; i < numKeys; i++)
        {
            sfrotation         *sfr;

            sfr = FieldMfrotation_GetValue(keyValuesList, i);
            *rotateKeys = *(RpVRMLRotateKey *) sfr;
            rotateKeys++;
        }

        /* duplicate the final key */
        if (keyNormalize)
        {
            RpVRMLRotateKey    *lastKey;

            lastKey = rotateKeys - 1;
            *rotateKeys = *lastKey;
        }

        RWRETURN(TRUE);
    }

    RWERROR((E_RW_PLUGINNOTINIT));
    RWRETURN(FALSE);
}

static              RwBool
AnimSetupScaleOrient(RwFrame * frame, Field * keyValuesList, Field *
                     keysList, RwReal cycleTime)
{
    RWFUNCTION(RWSTRING("AnimSetupScaleOrient"));
    RWASSERT(frame);
    RWASSERT(keyValuesList);
    RWASSERT(keysList);

    if (frame && keyValuesList && keysList)
    {
        RpVRMLAnimRotate   *rotateAnim;
        RpVRMLAnimState    *scaleOrientState;
        RwReal              lastKey;
        RwBool              keyNormalize = FALSE;
        RwInt32             numKeys;

        /* create a rotation animation */
        rotateAnim = animFuncts->fpAnimRotateCreate();
        if (!rotateAnim)
        {
            RWRETURN(FALSE);
        }

        /* get num keys */
        numKeys = Field_NumElements(keysList);

        /* do we need to normalize this animation */
        lastKey =
            *(RwReal *) FieldMffloat_GetValue(keysList, numKeys - 1);
        if (lastKey < (RwReal) (1))
        {
            keyNormalize = TRUE;
        }

        /* setup the rotation keys */
        if (!AnimSetupScaleOrientKeys(frame, rotateAnim,
                                      keyValuesList, keyNormalize))
        {
            animFuncts->fpAnimRotateDestroy(rotateAnim);

            RWRETURN(FALSE);
        }

        /* setup the rotation interpolators */
        scaleOrientState =
            AnimStateCreate(keysList, cycleTime, keyNormalize);
        if (!scaleOrientState)
        {
            animFuncts->fpAnimRotateDestroy(rotateAnim);

            RWRETURN(FALSE);
        }
        animFuncts->fpAnimRotateSetController(rotateAnim,
                                              scaleOrientState);

        RWRETURN(TRUE);
    }

    RWERROR((E_RW_PLUGINNOTINIT));
    RWRETURN(FALSE);
}

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

   Animation setup

   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */

static              RwReal
AnimGetTime(AbstractNode * an)
{
    RWFUNCTION(RWSTRING("AnimGetTime"));
    RWASSERT(an);

    if (an)
    {
        AbstractNode       *timeNode;

        timeNode = Anstractnode_GetTimeSensor(an);
        if (timeNode)
        {
            sftime             *cycleTime;
            AbstractField      *af;
            Field              *field;

            af = AbstractNode_GetAbstractField(timeNode,
                                               "cycleInterval");
            if (!af)
            {
                RWRETURN((RwReal) (0));
            }

            field = AbstractField_GetField(af);
            cycleTime = FieldSftime_GetValue(field);
            if (!cycleTime)
            {
                RWRETURN((RwReal) (0));
            }

            RWRETURN((RwReal) (*cycleTime));
        }

        RWRETURN((RwReal) (0));
    }

    RWERROR((E_RW_PLUGINNOTINIT));
    RWRETURN((RwReal) (0));
}

static Field       *
AnimGetKeyList(AbstractNode * anInterp)
{
    RWFUNCTION(RWSTRING("AnimGetKeyList"));
    RWASSERT(anInterp);

    if (anInterp)
    {
        AbstractField      *af;
        Field              *keysList;

        af = AbstractNode_GetAbstractField(anInterp, "key");
        if (!af)
        {
            RWRETURN(FALSE);
        }

        keysList = AbstractField_GetField(af);

        RWRETURN(keysList);
    }

    RWERROR((E_RW_PLUGINNOTINIT));
    RWRETURN(FALSE);
}

static Field       *
AnimGetKeyValueList(AbstractNode * anInterp)
{
    RWFUNCTION(RWSTRING("AnimGetKeyValueList"));
    RWASSERT(anInterp);

    if (anInterp)
    {
        AbstractField      *af;
        Field              *keyValuesList;

        af = AbstractNode_GetAbstractField(anInterp, "keyValue");
        if (!af)
        {
            RWRETURN(FALSE);
        }

        keyValuesList = AbstractField_GetField(af);

        RWRETURN(keyValuesList);
    }

    RWERROR((E_RW_PLUGINNOTINIT));
    RWRETURN(FALSE);
}

static              RwBool
AnimSetup(RwFrame * frame, AbstractNode * interpNode,
          AnimSetupCallBack animCB)
{
    RWFUNCTION(RWSTRING("AnimSetup"));
    RWASSERT(frame);
    RWASSERT(interpNode);
    RWASSERT(animCB);

    if (frame && interpNode && animCB)
    {
        Field              *keysList;
        Field              *keyValuesList;
        RwInt32             numKeys, numKeyValues;
        RwReal              cycleTime;

        /* get the key list */
        keysList = AnimGetKeyList(interpNode);
        if (!keysList)
        {
            RWRETURN(FALSE);
        }
        numKeys = Field_NumElements(keysList);

        /* get the key value list */
        keyValuesList = AnimGetKeyValueList(interpNode);
        if (!keyValuesList)
        {
            RWRETURN(FALSE);
        }
        numKeyValues = Field_NumElements(keyValuesList);

        /* check we have a valid number of keys */
        if (numKeys != numKeyValues)
        {
            RwInt32             lineNum = interpNode->lineNum;
            char               *name = interpNode->name;

            RWERROR((E_RP_VRML_KEYS, lineNum, name, numKeys,
                     numKeyValues));
            RWRETURN(FALSE);
        }

        /* get the animation cycle time */
        cycleTime = AnimGetTime(interpNode);
        if (cycleTime <= 0.0f)
        {
            RWRETURN(FALSE);
        }

        if (!animCB(frame, keyValuesList, keysList, cycleTime))
        {
            RWRETURN(FALSE);
        }

        RWRETURN(TRUE);
    }

    RWERROR((E_RW_PLUGINNOTINIT));
    RWRETURN(FALSE);
}

RwBool
AnimationSetup(AbstractNode * an, RwFrame * frame)
{
    RWFUNCTION(RWSTRING("AnimationSetup"));
    RWASSERT(an);
    RWASSERT(frame);

    if (an && frame)
    {
        AbstractNode       *orienInterpNode, *posInterpNode;
        AbstractNode       *scaleInterpNode, *scaleOrientInterpNode;

        animFuncts = _rpVrmAnimFunctionsGet();

        orienInterpNode = Route_GetFirstOrientationInterpolator(an);
        while (orienInterpNode)
        {
            if (!AnimSetup
                (frame, orienInterpNode,
                 (AnimSetupCallBack) AnimSetupRotate))
            {
                RWRETURN(FALSE);
            }

            /* get the next */
            orienInterpNode = Route_GetNextOrientationInterpolator(an);
        }

        posInterpNode = Route_GetFirstPositionInterpolator(an);
        while (posInterpNode)
        {
            if (!AnimSetup
                (frame, posInterpNode,
                 (AnimSetupCallBack) AnimSetupTranslate))
            {
                RWRETURN(FALSE);
            }

            /* get the next */
            posInterpNode = Route_GetNextPositionInterpolator(an);
        }

        scaleInterpNode = Route_GetFirstScaleInterpolator(an);
        while (scaleInterpNode)
        {
            if (!AnimSetup
                (frame, scaleInterpNode,
                 (AnimSetupCallBack) AnimSetupScale))
            {
                RWRETURN(FALSE);
            }

            /* get the next */
            scaleInterpNode = Route_GetNextScaleInterpolator(an);
        }

        scaleOrientInterpNode =
            Route_GetFirstScaleOrientInterpolator(an);
        while (scaleOrientInterpNode)
        {
            if (!AnimSetup(frame, scaleOrientInterpNode,
                           (AnimSetupCallBack) AnimSetupScaleOrient))
            {
                RWRETURN(FALSE);
            }

            /* get the next */
            scaleOrientInterpNode =
                Route_GetNextScaleOrientInterpolator(an);
        }

        RWRETURN(TRUE);
    }

    RWERROR((E_RW_PLUGINNOTINIT));
    RWRETURN(FALSE);
}
