
/****************************************************************************
 *
 * This file is a product of Criterion Software Ltd.
 *
 * This file is provided as is with no warranties of any kind and is
 * provided without any obligation on Criterion Software Ltd.
 * or Canon Inc. to assist in its use or modification.
 *
 * Criterion Software Ltd. and Canon Inc. will not, under any
 * circumstances, be liable for any lost revenue or other damages
 * arising from the use of this file.
 *
 * Copyright (c) 2001 Criterion Software Ltd.
 * All Rights Reserved.
 *
 */

/****************************************************************************
 *
 * clmpskin.c
 *
 * Copyright (C) 2001 Criterion Technologies.
 *
 * Original author: Alexandre Hadjadj
 * Reviewed by:
 *
 * Purpose: Handling skin based animations
 *
 ****************************************************************************/

#include "rwcore.h"
#include "rpworld.h"
#include "rpskin.h"

#include "skeleton.h"
#include "menu.h"

#include "clmppick.h"
#include "clmpview.h"
#include "clmpskin.h"

static RwBool SkinMenuActive = FALSE;

static RpSkin *Skin = (RpSkin *)NULL;
#ifdef RPSKINLEGACY
static RpSkinAnim *SkinAnim = (RpSkinAnim *)NULL;
#endif
static RwReal SkinPerSecond = 1.0f;
 
RwBool SkinOn = FALSE;
RwBool ClumpHasSkinAnimation = FALSE;

RwInt32 AtomicTotalSkinBones = 0;
RwInt32 AtomicTotalAtomicTotalKeyFrame = 0;

/*
 *****************************************************************************
 */
static RwBool
SkinOnCB(RwBool justCheck)
{
    if( justCheck )
    {    
        if( !ClumpLoaded || !ClumpHasSkinAnimation )
        {
            SkinOn = FALSE;
            return FALSE;
        }
        return TRUE;
    }
    return TRUE;
}


/*
 *****************************************************************************
 */
static RwBool
SkinPerSecondCB(RwBool justCheck)
{
    if( justCheck )
    {
        if( !SkinOnCB(justCheck) )
        {
            return FALSE;
        }
        return TRUE;
    }

    SkinOn = TRUE;

    return TRUE;
}


/*
 *****************************************************************************
 */
static void
SkinMenuSetup(void)
{
    static RwChar SkinPerSecondLabel[] = RWSTRING("Skin Anim Speed");
    static RwChar SkinOnLabel[] = RWSTRING("Skin Animation_A");

    if( !SkinMenuActive )
    {
        MenuAddEntryBool(SkinOnLabel, &SkinOn, SkinOnCB);
        MenuAddEntryReal(SkinPerSecondLabel,
                         &SkinPerSecond,
                         SkinPerSecondCB, -10.0f, 10.0f, 0.1f);
        SkinMenuActive = TRUE;
    }
    
    return;
}


/*
 *****************************************************************************
 */
static void
SkinMenuDestroy(void)
{
    MenuRemoveEntry(&SkinOn);
    MenuRemoveEntry(&SkinPerSecond);

    SkinMenuActive = FALSE;
    
    return;
}


/*
 *****************************************************************************
 */
static RpAtomic *
SetupSkinCB(RpAtomic *Atomic, void *data)
{
    /*
     * Check if there is any attached RpSkin data 
     */
    Skin = RpSkinAtomicGetSkin(Atomic);

    if( Skin )
    {
        #ifdef RPSKINLEGACY
        /*
         * Create a skeleton and attach it to our skin 
         */
        RpSkinSetSkeleton(Skin, RpSkinSkeletonCreate(Skin));

        if( SkinAnim )
        {
            AtomicTotalSkinBones = Skin->numBones;
            AtomicTotalAtomicTotalKeyFrame = SkinAnim->numFrames;

            RpSkinSetCurrentAnim(Skin, SkinAnim);
            RpSkinSetCurrentAnimTime(Skin, 0.0f);

            ClumpHasSkinAnimation = TRUE;
        }
        #endif
    }

    return Atomic;
}


/*
 *****************************************************************************
 */
RwBool 
SkinLoadSKA(RpClump * clump, RwChar * skaPath)
{
    #ifdef RPSKINLEGACY
    RpSkinAnim *skinAnim = (RpSkinAnim *)NULL;
    RwChar *pathName;

    pathName = RsPathnameCreate(skaPath);

    /*
     * Read the file... 
     */
    skinAnim = RpSkinAnimRead(pathName);

    if (skinAnim)
    {
        SkinAnim = skinAnim;
        RpClumpForAllAtomics(clump, SetupSkinCB, NULL);
        SkinOn = TRUE;
    }
    else
    {
        /* 
         * Still need to create skeleton to render clump...
         */        
        RpClumpForAllAtomics(clump, SetupSkinCB, NULL);
        SkinOn = FALSE;
    }

    SkinPerSecond = 1.0f;

    RsPathnameDestroy (pathName);

    return SkinOn;
    #else
    return FALSE;
    #endif /* RPSKINLEGACY */
}


/*
 *****************************************************************************
 */
RwBool 
SkinClumpInitialize(RpClump * clump, RwChar * clumpFileName)
{
    RwChar *skaFileName = (char *)NULL;
    RwBool result = FALSE;
    
    ClumpHasSkinAnimation = FALSE;

    /*
     * Try to load <clumpName>.ska file...
     */
    skaFileName = (RwChar *) 
        RwMalloc(sizeof(RwChar) * 
                 (rwstrlen(clumpFileName) + 1));

    if (skaFileName == (char *)NULL)
    {
        ClumpHasSkinAnimation = FALSE;
        SkinMenuDestroy();
        RwFree (skaFileName);
        return FALSE;
    }

    rwstrcpy(skaFileName, clumpFileName);
    skaFileName[rwstrlen(skaFileName) - 3] = 0;
    rwstrcat(skaFileName, RWSTRING("ska"));

    /*
     * Check if there is any attached RpSkin data ...
     */
    result = SkinLoadSKA(clump, skaFileName);

    if( result )
    {
        SkinMenuSetup();
    }
    else
    {
        SkinMenuDestroy();
    }

    RwFree(skaFileName);

    return result;
}


/*
 *****************************************************************************
 */
static RpAtomic *
UpdateSkinAnimation (RpAtomic * atomic, void *pData)
{
    RwReal *pTimeStep = (RwReal *)pData;
    RpSkin *pSkin = RpSkinAtomicGetSkin(atomic);

    if( pSkin )
    {
        #ifdef RPSKINLEGACY
        /*
         * If we have a skin then move along its animation 
         */
        RpSkinAddAnimTime(pSkin, *pTimeStep);
        #endif
    }

    return atomic;
}


/*
 *****************************************************************************
 */
void
SkinClumpUpdate (RwReal delta)
{
    if (SkinOn)
    {
        RwReal inc;

        /*
         * Animated skin controlled by a timer...
         */
        inc = delta * SkinPerSecond;

        if (AtomicSelected)
        {
            UpdateSkinAnimation(AtomicSelected, &inc);
        }
        else
        {
            RpClumpForAllAtomics(Clump, UpdateSkinAnimation, &inc);
        }
    }

    return;
}


/*
 *****************************************************************************
 */
void
SkinDestroy(void)
{
    if (Skin)
    {
        #ifdef RPSKINLEGACY
        RpSkinSkeletonDestroy(Skin);
        Skin = (RpSkin *)NULL;
        
        if (SkinAnim)
        {
            RpSkinAnimDestroy(SkinAnim);
            SkinAnim = (RpSkinAnim *)NULL;
        }
        #endif
    }

    return;
}


/*
 *****************************************************************************
 */
