#ifndef EFFECTPIPESSKY_H
#define EFFECTPIPESSKY_H

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

#include <rpskin.h>

#if (defined(RPSKINLEGACY))
#include "../skinpp/skinlink.h"
#else /* (defined(RPSKINLEGACY)) */
#include "../skin/skinlink.h"
#endif /* (defined(RPSKINLEGACY)) */

/*===========================================================================*
 *--- Defines ---------------------------------------------------------------*
 *===========================================================================*/
#define VIFCMD_UNPACK  (0x6cl << 24)
#define VIFCMD_CYCLE   (0x01l << 24)
#define VIFCMD_DIRECT  (0x50l << 24)
#define VIFCMD_NOP     (0x00l << 24)

/*===========================================================================*
 *--- Types -----------------------------------------------------------------*
 *===========================================================================*/
typedef RwBool (*matFXInstanceCallBack)( void **clusterData,
                                         RwUInt32 numClusters );

struct MatFXDualData
{
    RwTexture       *texture;
    RwBlendFunction  srcBlendMode;
    RwBlendFunction  dstBlendMode;
    void            *padAlign;
    /*--- device specific ---*/
    RwUInt64         alpha_2;
    RwUInt64         clamp_2;
    RwUInt64         test_2;
};

struct MatFXBumpMapData
{
    RwFrame   *frame;
    RwTexture *texture;
    RwTexture *bumpTexture;
    RwReal    coef;
    RwReal    invBumpWidth;
};


typedef void * RWALIGN(matFXVUcode[VU1CODEARRAYSIZE], rpMATFXALIGNMENT);

typedef struct matFXElementState RWALIGN( matFXElementState, rpMATFXALIGNMENT);
struct matFXElementState
{
    /* Element state type. */
    RpMatFXMaterialFlags effectType;
    /* Instance call backs. */
    matFXInstanceCallBack instanceCallBacks[rpMATFXEFFECTMAX];
    /* VU code array. */
    matFXVUcode *vuCodeCache[rpMATFXEFFECTMAX];
};

typedef struct matFXState RWALIGN(matFXState, rpMATFXALIGNMENT);
struct matFXState
{
    /* Atomic pipelines. */
    RxPipeline *atomicPipeline;
    RxPipeline *atomicPipelineUV2;

    /* World pipelines. */
    RxPipeline *worldSectorPipeline;
    RxPipeline *worldSectorPipelineUV2;

    /* Skin pipelines. */
    RxPipeline *skinPipeline;
    RxPipeline *skinPipelineUV2;

    /* Atomic, World and skinning pipelines. */
    matFXElementState atomic;
    matFXElementState atomicUV2;
    matFXElementState worldSector;
    matFXElementState worldSectorUV2;
    matFXElementState skinning;
    matFXElementState skinningUV2;
};

typedef RwReal RWALIGN(matFXEnvArray[4], rpMATFXALIGNMENT);

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

/*===========================================================================*
 *--- Public Global Variables -----------------------------------------------*
 *===========================================================================*/

/*--- Static and skinning pipeline data ----------*/
extern matFXState matFXPipeState;

/*--- Skinning function and variable pointers. ---*/
extern _rpSkinLink matFXSkinning;

/*--- BumpMap variables ----*/
extern RwReal    matFXBumpScale;    /* FX fading coefficient */
extern RwReal    matFXBumpFarPlane; /* Plane beyond at which FX fade out completely */
extern RwMatrix  matFXBumpMatrix;   /* Temporary storage before uploading matrices */

/*--- EnvMap variables ---*/
extern matFXEnvArray matFXEnvParams; /* Environment mapping offset and scale factor */
extern RwMatrix  matFXEnvMatrix;     /* Temporary storage before uploading matrices */

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

/*--- Upload texture --------------------------------------------------------*/
extern RwBool
_rpMatFXUploadTexture( const RwTexture *texture,
                       const RxPS2DMASessionRecord *DMASessionRecord,
                       const RxPS2Mesh *Mesh );

/*--- Instance call back ----------------------------------------------------*/
extern RwBool
_rpMatFXMaterialsInstanceCallBack( void ** clusterData,
                                   RwUInt32 numClusters,
                                   matFXElementState *state );
extern RwBool
_rpMatFXMaterialsPostObjectCallBack(RxPS2DMASessionRecord *record);

#ifdef __cplusplus
}
#endif /* __cplusplus */

/*===========================================================================*
 *--- Defines ---------------------------------------------------------------*
 *===========================================================================*/
#if (defined(RPSKINLEGACY))

#define MatFXSkinAtomicGetData(atomic)                              \
     ((RpSkin **)(((RwUInt8 *)atomic) +                             \
                  matFXSkinning.skinAtomicGlobals->atomicOffset ))

#define MatFXSkinGetNumBones(skin)                                  \
     (skin->numBones)

#define MatFXSkinMatrixUpdating(atomic, skin)                       \
    (matFXSkinning.skinMBMatUpdating(atomic, skin))

#define MatFXSkinWeightsInstancing(mesh, skin, destMBI)             \
    (matFXSkinning.skinMBWeightsInstancing(mesh, skin, destMBI))


#else /* (defined(RPSKINLEGACY)) */

#define MatFXSkinAtomicGetData(atomic)                              \
    ((RpSkin **)(((RwUInt8 *)(atomic->geometry)) +                  \
                  matFXSkinning.skinGlobals->geometryOffset ))

#define MatFXSkinGetNumBones(skin)                                  \
    (skin->boneData.numBones)

#define MatFXSkinMatrixUpdating(atomic, skin)                       \
    (matFXSkinning.skinMatUpdating(atomic, skin))

#define MatFXSkinWeightsInstancing(mesh, skin, destMBI)             \
    (matFXSkinning.skinWeightsInstancing(mesh, skin, destMBI))

#endif /* (defined(RPSKINLEGACY)) */


/* --- DEBUGGING MACROS -----------------------------------------------------*/

#if (0 && defined(RWVERBOSE) && defined(RWDEBUG))

#if (!(defined(RWDEBUGSTACKDEPTH)))
#define RWDEBUGSTACKDEPTH (RWSRCGLOBAL(debugStackDepth))
#endif /* (!(defined(RWDEBUGSTACKDEPTH))) */

/* Message macros */
#warning Redefining RWFUNCTION etc

#undef RWAPIFUNCTION
#define RWAPIFUNCTION(function)                         \
static const RwChar __dbFunctionName[] = function;      \
const RwInt32 startstackdepth = RWDEBUGSTACKDEPTH++;    \
printf("\n%s(%d):%s (%d) < \n",                         \
        __FILE__, __LINE__,                             \
       __dbFunctionName,  startstackdepth)

#undef RWFUNCTION
#define RWFUNCTION(function) RWAPIFUNCTION(function)

#undef RWRETURN
#define RWRETURN(result)                                \
MACRO_START                                             \
{                                                       \
    RwInt32 _validateStackDepth = --RWDEBUGSTACKDEPTH;  \
                                                        \
    printf("%s(%d):%s (%d) > \n",                       \
           __FILE__, __LINE__,                          \
           __dbFunctionName, _validateStackDepth);      \
                                                        \
    return (result);                                    \
}                                                       \
MACRO_STOP

#undef RWRETURNVOID
#define RWRETURNVOID()                                  \
MACRO_START                                             \
{                                                       \
    RwInt32 _validateStackDepth = --RWDEBUGSTACKDEPTH;  \
                                                        \
    printf("%s(%d):%s (%d) > \n",                       \
           __FILE__, __LINE__,                          \
           __dbFunctionName, _validateStackDepth);      \
                                                        \
    return ;                                            \
}                                                       \
MACRO_STOP

#endif /* (0 && defined (RWVERBOSE) && defined(RWDEBUG)) */

#endif /* EFFECTPIPESSKY_H */
