#ifndef _SKIN_H
#define _SKIN_H

/*===========================================================================*
 *--- Include files ---------------------------------------------------------*
 *===========================================================================*/
#include "rwcore.h"
#include "rpworld.h"

#include "rpplugin.h"
#include "rpdbgerr.h"

#include "rphanim.h"
#include "rpskin.h"

#if (defined(SKY2_DRVMODEL_H))
#include "sky2/skinsky.h"
#elif (defined(XBOX_DRVMODEL_H) && !defined(WIN_OSTYPES_H))
#include "xbox/skinxbox.h"
#elif (defined(GCN_DRVMODEL_H))
#include "gcn/skingcn.h"
#elif (defined(D3D8_DRVMODEL_H))
#include "d3d8/skind3d8.h"
#else
#include "generic/skingeneric.h"
#endif

/*===========================================================================*
 *--- Private Types ---------------------------------------------------------*
 *===========================================================================*/
enum SkinPipeline
{
    rpNASKINPIPELINE          = 0,
    rpSKINPIPELINESKINGENERIC = 0x01,
    rpSKINPIPELINESKINMATFX   = 0x02,
    rpSKINPIPELINEFORCEENUMSIZEINT = RWFORCEENUMSIZEINT
};
typedef enum SkinPipeline SkinPipeline;

typedef void * SkinUnaligned;

typedef struct SkinPlatformData SkinPlatformData;
typedef struct SkinGlobalPlatform SkinGlobalPlatform;

typedef struct SkinBone SkinBone;
struct SkinBone
{
    RwUInt32 boneTag;
};

typedef struct SkinBoneData SkinBoneData;
struct SkinBoneData
{
    SkinBone      *aligned;
    SkinUnaligned  unaligned;
    RwUInt32       numBones;
    RwMatrix       *invBoneToSkinMat;
};

typedef struct SkinVertexMaps SkinVertexMaps;
struct SkinVertexMaps
{
    RwUInt32        *matrixIndices;
    RwMatrixWeights *matrixWeights;
};

struct RpSkin
{
    SkinBoneData     boneData;
    SkinVertexMaps   vertexMaps;
    SkinPlatformData platformData;
};

typedef struct SkinAtomicData SkinAtomicData;
struct SkinAtomicData
{
    RpHAnimHierarchy *hierarchy;
};

typedef struct SkinMatrixCache SkinMatrixCache;
struct SkinMatrixCache
{
    RwMatrix      *aligned;
    SkinUnaligned  unaligned;
};

typedef struct SkinGlobals SkinGlobals;
struct SkinGlobals
{
    /* Offsets. */
    RwInt32 engineOffset;
    RwInt32 atomicOffset;
    RwInt32 geometryOffset;

    /* Matrix Cache. */
    SkinMatrixCache     matrixCache;

    /* Plugin data. */
    RwFreeList         *freeList;
    RwModuleInfo        module;

    /* Platform global data. */
    SkinGlobalPlatform  platform;
};

/*===========================================================================*
 *--- Private Global Variables ----------------------------------------------*
 *===========================================================================*/
extern SkinGlobals _rpSkinGlobals;

/*===========================================================================*
 *--- Private Defines -------------------------------------------------------*
 *===========================================================================*/
#define RPSKINENGINEGETDATA(engineInstance)                              \
     ((_rpSkinLinkCallBack *)(((RwUInt8 *)engineInstance) +              \
                  _rpSkinGlobals.engineOffset))

#define RPSKINENGINEGETCONSTDATA(engineInstance)                         \
     ((const _rpSkinLinkCallBack *)(((const RwUInt8 *)engineInstance) +  \
                  _rpSkinGlobals.engineOffset))

#define RPSKINATOMICGETDATA(atomicInstance)                              \
     ((SkinAtomicData *)(((RwUInt8 *)atomicInstance) +                   \
                  _rpSkinGlobals.atomicOffset))

#define RPSKINATOMICGETCONSTDATA(atomicInstance)                         \
     ((const SkinAtomicData *)(((const RwUInt8 *)atomicInstance) +       \
                  _rpSkinGlobals.atomicOffset))

#define RPSKINGEOMETRYGETDATA(geometryInstance)                          \
     ((RpSkin **)(((RwUInt8 *)geometryInstance) +                        \
                  _rpSkinGlobals.geometryOffset))

#define RPSKINGEOMETRYGETCONSTDATA(geometryInstance)                     \
     ((const RpSkin **)(((const RwUInt8 *)geometryInstance) +            \
                  _rpSkinGlobals.geometryOffset))

/*===========================================================================*
 *--- Private Functions -----------------------------------------------------*
 *===========================================================================*/

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

extern RwBool
_rpSkinPipelinesCreate(RwUInt32 pipes);

extern RwBool
_rpSkinPipelinesDestroy(void);

extern RpAtomic *
_rpSkinPipelinesAttach(RpAtomic *atomic);

extern RpGeometry *
_rpSkinInitialize(RpGeometry *geometry);

extern RpGeometry *
_rpSkinDeinitialize(RpGeometry *geometry);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* (defined(_SKIN_H)) */
