/****************************************************************************
 * 
 *
 * Proposed new API for hierarchical animation controller
 * Copyright (C) 1999 Criterion Technologies
 *
 * Author  : Damian Scallan
 *
 * Module  : rpanim.h
 *
 * Purpose : Functions for creating and controlling sequences of articulated
 *           hierarchical keyframe animation
 *
 ****************************************************************************/

#ifndef RPANIM_H
#define RPANIM_H

/**
 * \defgroup rpanim RpAnim
 * \ingroup retired
 *
 * Animation Plug-In for RenderWare.
 */

/****************************************************************************
 Includes
 */

/* renderware */
#include "rwcore.h"
#include "rpworld.h"
#include "rtquat.h"
#include "rtslerp.h"

#include "rpanim.rpe"       /* automatically generated header file */

#if (defined(_RW_QUAT_ARGAND))

typedef RtQuatSlerpArgandCache RtQSlerpCache;

#define RtQSetupSlerpCache(qpFrom, qpTo, sCache)         \
    RtQuatSetupSlerpArgandCache(qpFrom, qpTo, sCache)

#define RtQSlerp(qpResult, qpFrom, qpTo, rT, sCache)     \
    RtQuatSlerpArgand(qpResult, qpFrom, qpTo, rT, sCache)

#else /* (defined(_RW_QUAT_ARGAND)) */

typedef RtQuatSlerpCache RtQSlerpCache;

#define RtQSetupSlerpCache(qpFrom, qpTo, sCache)         \
    RtQuatSetupSlerpCache(qpFrom, qpTo, sCache)

#define RtQSlerp(qpResult, qpFrom, qpTo, rT, sCache)     \
    RtQuatSlerp(qpResult, qpFrom, qpTo, rT, sCache)

#endif /* (defined(_RW_QUAT_ARGAND)) */

/****************************************************************************
 Global Types
 */

typedef struct rpAnimGlobals rpAnimGlobals;
struct rpAnimGlobals
{
        RwFreeList      *animListFreeList;
};


/* static frame sequence animation - contaains no state */

/**
 * \ingroup rpanim
 * \typedef RpRotateKey
 *  A structure describing a rotation key,
 * equivalent to the RenderWare quaterion type.
 */
typedef RtQuat  RpRotateKey;

/**
 * \ingroup rpanim
 * \typedef RpTranslateKey
 *  A structure describing a translation key,
 * equivalent to the RwV3d type.
 */
typedef RwV3d   RpTranslateKey;

typedef struct rpAnimInterpolator rpAnimInterpolator;
struct rpAnimInterpolator
{
        RwInt32         startKeyFrame;
        RwInt32         endKeyFrame;
        RwReal          time;
};

/**
 * \ingroup rpanim
 *  Animation keframe types */
enum RpAnimType
{
    rpERR = 0,  /**<error code */
    rpTRANSLATE,/**<translation key */
    rpROTATE,    /**<rotation key */
    rpANIMTYPEFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum RpAnimType RpAnimType;

typedef struct rpAnimTransformState rpAnimTransformState;
struct rpAnimTransformState
{
        RwUInt32        flags;
        /* place quat slerp cache here for now */
        RtQSlerpCache   quatSlerpCache;
};

/**
 * \ingroup rpanim
 * \typedef RpAnimSequence
 *  A typedef for \ref RpAnimSequence
 */
typedef struct RpAnimSequence RpAnimSequence;

/**
 * \ingroup rpanim
 * \struct RpAnimSequence
 *  A structure describing an animation sequence
 */
struct RpAnimSequence
{
        RwInt32         refCnt;            /**< Internal use */
        RwChar         *name;              /**< Internal use */
        RpAnimType      type;              /**< Internal use */
        RwInt32         numKeys;           /**< Internal use */
        void           *keys;              /**< Internal use */
        RwInt32         numInterpolators;  /**< Internal use */
        rpAnimInterpolator *interps;       /**< Internal use */
};

typedef struct rpAnimSequenceList rpAnimSequenceList;
struct rpAnimSequenceList
{
        RpAnimSequence *sequence;
        rpAnimSequenceList *next;
};

/* dynamic clump sequence animation - contains state */

typedef struct rpAnimState rpAnimState;
struct rpAnimState
{
        RpAnimSequence *sequence;
        rpAnimInterpolator *currentInterp;
        RwReal          position;
};

enum rpStateFlags
{
    rpDIRTY = 0x01,
    rpNEWINTERP = 0x02,
    rpSTATEFLAGSFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum rpStateFlags rpStateFlags;

typedef struct rpAnimFrame rpAnimFrame;
struct rpAnimFrame
{              /* pointer extends frame */
        RwInt32         numTranslateSequences;
        rpAnimSequenceList *translateSequences;
        RwInt32         numRotateSequences;
        rpAnimSequenceList *rotateSequences;
};

typedef struct rpAnimFrameState rpAnimFrameState;
struct rpAnimFrameState
{
        rpAnimTransformState transformState;
        rpAnimState  *translateState;
        rpAnimState  *rotateState;
};

typedef struct rpAnimFrameList rpAnimFrameList;
struct rpAnimFrameList
{
        RwFrame        *frame;
        rpAnimFrameState animFrameState;
        rpAnimFrameList *next;
};

/**
 * \ingroup rpanim
 * \typedef RpAnimClumpSequence
 *  Clump animation sequnce. This should be
 * considered an opaque type. Use the RpAnimClumpSequence API functions to access.
 */
typedef struct RpAnimClumpSequence RpAnimClumpSequence;

/**
 * \ingroup rpanim
 * \typedef RpClump *  RpAnimClumpSequenceCallBack
 \ref RpAnimClumpSequenceCallBack is the callback
 * function supplied for clump sequence callback functions.
 *
 * \param  clump   Pointer to the clump.
 * \param  clump sequnence   Pointer to the current clump sequnence, supplied by the iterator.
 * \param  pos   The amount the animation has over-run its duration.
 * \param  data   User-supplied data pointer.
 */
typedef RpClump *
        (*RpAnimClumpSequenceCallBack)(RpClump *clump,
                                       RpAnimClumpSequence *animClumpSeq,
                                       RwReal pos,
                                       void *data);
struct RpAnimClumpSequence
{
        RwChar         *name;
        RwReal          duration;
        RwReal          position;
        RwBool          forward;
        RwInt32         priority;
        rpAnimFrameList *frameList;
        RpAnimClumpSequenceCallBack fpAnimClumpSeqCB;
        void           *callBackData;
        RpAnimClumpSequence *next;
};

typedef struct rpAnimClump rpAnimClump;
struct         rpAnimClump
{
        RwInt32         numAnimClumpSequences;
        rwFrameList     frameList;  /*  to quickly reset priorities */
        RpAnimClumpSequence *clumpSequenceList;
        RpAnimClumpSequence *activeClumpSequenceList;
};

/**
 * \ingroup rpanim
 * \typedef RpAnimClumpSequence *  RpAnimClumpForAllSequencesCallBack
 \ref RpAnimClumpForAllSequencesCallBack is the callback
 * function supplied to iterate over all the clump sequnces  attached to a clump.
 *
 * \param  clump sequence   Pointer to the current clump sequnence, supplied by the iterator.
 * \param  active   Indicates whether the sequence is active.
 * \param  data   User-supplied data pointer.
 */
typedef RpAnimClumpSequence *
        (*RpAnimClumpForAllSequencesCallBack)(RpAnimClumpSequence *animClumpSequence,
                                              RwBool active,
                                              void *data);

/**
 * \ingroup rpanim
 * \typedef RpAnimSequence *  RpAnimFrameForAllSequencesCallBack
 \ref RpAnimFrameForAllSequencesCallBack is the callback
 * function supplied to iterate over all the sequnces  attached to a frame.
 *
 * \param  sequence   Pointer to the current frame sequnence, supplied by the iterator.
 * \param  data   User-supplied data pointer.
 */
typedef RpAnimSequence *
        (*RpAnimFrameForAllSequencesCallBack)(RpAnimSequence *animSequence,
                                              void *data);

typedef struct RpAnimDatabaseEntry RpAnimDatabaseEntry;

struct RpAnimDatabaseEntry
{
        RwChar *name;
        RwInt32 numAnimSequences;
        RwInt32 *tagArray;
        RpAnimSequence **animSequences;
        RpAnimDatabaseEntry *next;
};

typedef struct RpAnimDatabase RpAnimDatabase;

struct RpAnimDatabase
{
        RwInt32 numEntries;
        RpAnimDatabaseEntry *entries;
};


/****************************************************************************
 Function prototypes
 */

#ifdef    __cplusplus
extern          "C"
{
#endif         /* __cplusplus */

/* Clump Anim API */

extern RwBool
RpAnimPluginAttach(void);

extern RpClump *
RpAnimClumpAddSequence(RpClump *clump,
                       const RwChar *sequenceName,
                       RpAnimClumpSequenceCallBack fpAnimClumpSeqCB,
                       void *sequenceCallBackData);

extern RpClump *
RpAnimClumpRemoveSequence(RpClump *clump,
                          RwChar *sequenceName);

extern RpClump *
RpAnimClumpStartSequence(RpClump *clump,
                         const RwChar *sequenceName,
                         RwBool forward,
                         RwInt32 priority,
                         RwReal time);

extern RpClump *
RpAnimClumpStopSequence(RpClump *clump,
                        RwChar *sequenceName);

extern RpClump *
RpAnimClumpForAllSequences(RpClump *clump,
                           RpAnimClumpForAllSequencesCallBack fpAnimClumpSeqCB,
                           void *sequenceCallBackData);

extern RpClump *
RpAnimClumpSetSequenceCallBack(RpClump *clump, RwChar *sequenceName,
                               RpAnimClumpSequenceCallBack fpAnimClumpSeqCB,
                               void *sequenceCallBackData);

extern RwChar *
RpAnimClumpSequenceGetName(RpAnimClumpSequence *animSequence);

extern RpClump *
RpAnimClumpAddTime(RpClump *clump,
                   RwReal time);

/* Frame Anim API */

extern RwFrame *
RpAnimFrameAddSequence(RwFrame *frame,
                       RpAnimSequence *sequence);

extern RwFrame *
RpAnimFrameRemoveSequence(RwFrame *frame,
                          RpAnimSequence *sequence);

extern RwInt32
RpAnimFrameGetNumTranslationSequences(RwFrame *frame);

extern RpAnimSequence *
RpAnimFrameGetTranslationSequence(RwFrame *frame,
                                  RwChar *sequenceName);

extern RwInt32
RpAnimFrameGetNumRotationSequences(RwFrame *frame);

extern RpAnimSequence *
RpAnimFrameGetRotationSequence(RwFrame *frame,
                               RwChar *sequenceName);

extern RwFrame *
RpAnimFrameForAllSequences(RwFrame *frame,
                           RpAnimFrameForAllSequencesCallBack callback,
                           void *data);

/* RpAnimSequence API */

extern RpAnimSequence *
RpAnimSequenceCreate(const RwChar *sequenceName,
                     RpAnimType type,
                     RwInt32
                     numKeys,
                     RwInt32 numInterps);

extern RwBool
RpAnimSequenceDestroy(RpAnimSequence *animSequence);

extern RwChar *
RpAnimSequenceGetName(RpAnimSequence *animSequence);

extern RpAnimType
RpAnimSequenceGetType(RpAnimSequence *animSequence);

extern RwInt32
RpAnimSequenceGetNumKeys(RpAnimSequence *animSequence);

extern RwInt32
RpAnimSequenceGetNumInterpolators(RpAnimSequence *animSequence);

extern RpAnimSequence *
RpAnimSequenceSetTranslateKey(RpAnimSequence *animSequence,
                              RwInt32 keyNum,
                              RwV3d *trans);

extern RpAnimSequence *
RpAnimSequenceSetRotateKey(RpAnimSequence *animSequence,
                           RwInt32 keyNum,
                           RtQuat *quat);

extern RpTranslateKey *
RpAnimSequenceGetTranslateKey(RpAnimSequence *animSequence,
                              RwInt32 keyNum);

extern RpRotateKey *
RpAnimSequenceGetRotateKey(RpAnimSequence *animSequence,
                           RwInt32 keyNum);

extern RpAnimSequence *
RpAnimSequenceSetInterpolator(RpAnimSequence *animSequence,
                              RwInt32 interpNum,
                              RwInt32 startKeyFrame,
                              RwInt32 endKeyFrame,
                              RwReal duration);


extern RpClump *
RpAnimClumpSequenceOptimize(RpClump *clump,
                            RwChar *name,
                            RwReal delta);

extern RpAnimDatabase *
RpAnimDatabaseCreate(void);

extern RwBool
RpAnimDatabaseDestroy(RpAnimDatabase *database);

extern RpAnimDatabase *
RpAnimDatabaseCopyClumpSequence(RpAnimDatabase *database,
                                RpClump *clump,
                                RwChar *name);

extern RpAnimDatabase *
RpAnimDatabaseCopyAllClumpSequences(RpAnimDatabase *database,
                                    RpClump *clump);

extern RpAnimDatabase *
RpAnimDatabaseCopySequenceToClump(RpAnimDatabase *database,
                                  RpClump *clump,
                                  RwChar *name);

extern RpAnimDatabase *
RpAnimDatabaseCopyAllSequencesToClump(RpAnimDatabase *database,
                                      RpClump *clump);

extern RpAnimDatabase *
RpAnimDatabaseStreamWrite(RpAnimDatabase *database,
                          RwStream *stream);

extern RpAnimDatabase *
RpAnimDatabaseStreamRead(RwStream *stream);

extern RpAnimDatabase *
RpAnimDatabaseCopyDatabaseSequence(RpAnimDatabase *target,
                                   RpAnimDatabase *source,
                                   RwChar *name);

extern RpAnimDatabase *
RpAnimDatabaseCopyAllDatabaseSequences(RpAnimDatabase *target,
                                       RpAnimDatabase *source);

extern RwBool
RpAnimDatabaseContainsSequence(RpAnimDatabase *database,
                               RwChar *name);

extern RwInt32
RpAnimDatabaseStreamGetSize(RpAnimDatabase *database);

/* RpAnim SPI */
extern RpAnimDatabaseEntry *
_rpAnimDatabaseEntryCreate(RwInt32 numSequences);

extern RwInt32
_rpAnimSeqGetFrameTag(RwFrame *frame);

extern RwFrame *
_rpAnimSeqSetFrameTag(RwFrame *frame,
                      RwInt32 tag);

/* RwCore SPI */

extern RwUInt32
_rwStringStreamGetSize(const RwChar *string);

extern const RwChar *
_rwStringStreamWrite(const RwChar *string,
                     RwStream *stream);

extern RwChar *
_rwStringStreamFindAndRead(RwChar *string, 
                          RwStream * stream);

#ifdef    __cplusplus
}
#endif         /* __cplusplus */

/* Compatibility macros */

#define rwStringStreamGetSize(string) \
       _rwStringStreamGetSize(string)

#define rwStringStreamWrite(string, stream) \
       _rwStringStreamWrite(string, stream)

#define rwStringStreamFindAndRead(string, stream) \
       _rwStringStreamFindAndRead(string, stream)

#endif         /* RPANIM_H */

