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

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

#include "rpskin.h"

#include "skin.h"
#include "skinskymatfx.h"

/* Only need one for the vu memory offsets. */
#include "SKY2_SkinBem/SKY2_SkinBemData.h"
/*#include "SKY2_SkinDup/SKY2_SkinDupData.h"*/
/*#include "SKY2_SkinEmb/SKY2_SkinEmbData.h"*/
/*#include "SKY2_SkinGem/SKY2_SkinGemData.h"*/

#include "SKY2_SkinGeneric/SKY2_SkinGenericNode.h"
#include "SKY2_SkinBem/SKY2_SkinBemNode.h"
#include "SKY2_SkinDup/SKY2_SkinDupNode.h"
#include "SKY2_SkinEmb/SKY2_SkinEmbNode.h"
#include "SKY2_SkinGem/SKY2_SkinGemNode.h"

#include "../../plugin/matfx/effectPipes.h"

/*===========================================================================*
 *--- Private Types ---------------------------------------------------------*
 *===========================================================================*/

/*===========================================================================*
 *--- Private Global Variables ----------------------------------------------*
 *===========================================================================*/

/*===========================================================================*
 *--- Private Defines -------------------------------------------------------*
 *===========================================================================*/

/*===========================================================================*
 *--- Local Types -----------------------------------------------------------*
 *===========================================================================*/
typedef struct SkinMatFXData
{
    /* MatFX pipes. */
    matFXElementState uv;
    matFXElementState uv2;
} RWALIGN(SkinMatFXData, rpMATFXALIGNMENT);

/*===========================================================================*
 *--- Local Global Variables ------------------------------------------------*
 *===========================================================================*/
#if (!defined(DXOYGEN))
static const char rcsid[] __RWUNUSED__ =
    "@@@@(#)$Id: ";
#endif /* (!defined(DXOYGEN)) */

/* Instance call back data. */
static SkinMatFXData MatFXData =
{
    { /*--- Single UV. ------------------------------------------------------*/
        rpMATFXEFFECTNULL, /*--- Element state type. ------------------------*/
        { /*--- Effect instance call backs. ---------------------------------*/
            _rxPipelineNodePS2SkinGenericPS2ManagerInstanceCallBack, /* Null */
            _rxPipelineNodePS2SkinEmbPS2ManagerInstanceCallBack,  /* Bump    */
            _rxPipelineNodePS2SkinGemPS2ManagerInstanceCallBack,  /* Env     */
            _rxPipelineNodePS2SkinBemPS2ManagerInstanceCallBack,  /* BumpEnv */
            _rxPipelineNodePS2SkinDupPS2ManagerInstanceCallBack   /* Dual    */
        },
        { /*--- VUcode arrays. ----------------------------------------------*/
            &_rpSkinSkySkinGenericTransforms,                     /* Null    */
            &_rpSkinSkySkinEmbTransforms,                         /* Bump    */
            &_rpSkinSkySkinGemTransforms,                         /* Env     */
            &_rpSkinSkySkinBemTransforms,                         /* BumpEnv */
            &_rpSkinSkySkinDupTransforms                          /* Dual    */
        }
    },
    { /*--- Dual UV. --------------------------------------------------------*/
        rpMATFXEFFECTNULL, /*--- Element state type. ------------------------*/
        { /*--- Effect instance call backs. ---------------------------------*/
            _rxPipelineNodePS2SkinGenericPS2ManagerInstanceCallBack, /* Null */
            _rxPipelineNodePS2SkinEmbPS2ManagerInstanceCallBack,  /* Bump    */
            _rxPipelineNodePS2SkinGemPS2ManagerInstanceCallBack,  /* Env     */
            _rxPipelineNodePS2SkinBemPS2ManagerInstanceCallBack,  /* BumpEnv */
            _rxPipelineNodePS2SkinDupPS2ManagerInstanceCallBack   /* Dual    */
        },
        { /*--- VUcode arrays. ----------------------------------------------*/
            &_rpSkinSkySkinGenericTransforms,                     /* Null    */
            &_rpSkinSkySkinEmbTransforms,                         /* Bump    */
            &_rpSkinSkySkinGemTransforms,                         /* Env     */
            &_rpSkinSkySkinBemTransforms,                         /* BumpEnv */
            &_rpSkinSkySkinDupTransforms                          /* Dual    */
        }
    }
};

/*===========================================================================*
 *--- Local Defines ---------------------------------------------------------*
 *===========================================================================*/

/*===========================================================================*
 *--- Local functions -------------------------------------------------------*
 *===========================================================================*/

/*===========================================================================*
 *--- Private functions -----------------------------------------------------*
 *===========================================================================*/

/*****************************************************************************
 _rpSkinMatFXUVPipelineInstanceCallBack

 TODO

 Inputs :
 Outputs :
 */
RwBool
_rpSkinMatFXUVPipelineInstanceCallBack( void **clusterData,
                                        RwUInt32 numClusters )
{
    RwBool ret;

    RWFUNCTION(RWSTRING("_rpSkinMatFXUVPipelineInstanceCallBack"));
    RWASSERT(NULL != clusterData);
    RWASSERT(3 == numClusters);

    ret = _rpMatFXMaterialsInstanceCallBack( clusterData,
                                             numClusters,
                                             &(MatFXData.uv) );

    RWRETURN(ret);
}

/*****************************************************************************
 _rpSkinMatFXUV2PipelineInstanceCallBack

 TODO

 Inputs :
 Outputs :
 */
RwBool
_rpSkinMatFXUV2PipelineInstanceCallBack( void **clusterData,
                                         RwUInt32 numClusters )
{
    RwBool ret;

    RWFUNCTION(RWSTRING("_rpSkinMatFXUV2PipelineInstanceCallBack"));
    RWASSERT(NULL != clusterData);
    RWASSERT(3 == numClusters);

    ret = _rpMatFXMaterialsInstanceCallBack( clusterData,
                                             numClusters,
                                             &(MatFXData.uv2) );

    RWRETURN(ret);
}

/****************************************************************************
 _rpSkinMatFXPipelineCreate

 Creates the skin matfx pipeline.

 Inputs :   uv2  - RwBool dual set of uvs.
 Outputs:   RxPipeline * - Pointer to the created pipeline.
 */
RxPipeline *
_rpSkinPS2ManagerSkinMatFXPipeCreate(RwBool dualUVs)
{
    RxPipeline *pipe;
    RxLockedPipe *lpipe;
    RxNodeDefinition *manager;
    RxPipelineNode *plnode;
    RxPipelineNode *result;
    RxClusterDefinition *UVClusterDef;
    RwUInt32 UVType;
    RxPipelineNodePS2ManagerInstanceCallBack UVCallBack;

    RWFUNCTION(RWSTRING("_rpSkinPS2ManagerSkinMatFXPipeCreate"));

    if(dualUVs)
    {
        UVClusterDef = &RxClPS2uv2;
        UVType = CL_UV2;
        UVCallBack = _rpSkinMatFXUV2PipelineInstanceCallBack;
    }
    else
    {
        UVClusterDef = &RxClPS2uv;
        UVType = CL_UV;
        UVCallBack = _rpSkinMatFXUVPipelineInstanceCallBack;
    }

    pipe = RxPipelineCreate();
    RWASSERT(NULL != pipe);

    pipe->pluginId = rwID_SKINPLUGIN;

    lpipe = RxPipelineLock(pipe);
    RWASSERT(NULL != lpipe);

    manager = RxNodeDefinitionGetPS2Manager(rxOBJTYPE_ATOMIC);
    RWASSERT(NULL != manager);

    lpipe = RxLockedPipeAddFragment( lpipe,
                                     (RwUInt32 *)NULL,
                                     manager,
                                     (RxNodeDefinition *)NULL );
    RWASSERT(NULL != lpipe);

    plnode = RxPipelineFindNodeByName( lpipe, manager->name,
                                       (RxPipelineNode *)NULL,
                                       (RwInt32 *)NULL );
    RWASSERT(NULL != plnode);

    plnode = RxPipelineNodePS2ManagerGenerateCluster(plnode,
                                                     &RxClPS2xyz,
                                                     CL_XYZ);
    RWASSERT(plnode != NULL);

    plnode = RxPipelineNodePS2ManagerGenerateCluster(plnode,
                                                     UVClusterDef,
                                                     UVType);
    RWASSERT(plnode != NULL);

    plnode = RxPipelineNodePS2ManagerGenerateCluster(plnode,
                                                     &RxClPS2rgba,
                                                     CL_RGBA);
    RWASSERT(plnode != NULL);
    plnode = RxPipelineNodePS2ManagerGenerateCluster(plnode,
                                                     &RxClPS2normal,
                                                     CL_NORMAL);
    RWASSERT(plnode != NULL);

    plnode = RxPipelineNodePS2ManagerGenerateCluster(plnode,
                                                     &RxClPS2user1,
                                                     CL_USER1);
    RWASSERT(NULL != plnode);

    plnode = RxPipelineNodePS2ManagerSetVUBufferSizes(plnode,
                 pipeASymbSkinStrideOfInputCluster,
                 pipeASymbSkinTSVertexCount,
                 pipeASymbSkinTLTriCount);
    RWASSERT(NULL != plnode);

    lpipe = RxLockedPipeUnlock(lpipe);
    RWASSERT(NULL != lpipe);

    plnode = RxPipelineFindNodeByName( lpipe, manager->name,
                                       (RxPipelineNode *)NULL,
                                       (RwInt32 *)NULL);
    RWASSERT(NULL != plnode);

    plnode = RxPipelineNodePS2ManagerSetVIFOffset(plnode,
                                                  pipeASymbSkinVIFOffset);
    RWASSERT(NULL != plnode);

    /*---- New VU Array description allowing BF Culling ----*/
    ((RxPipelineNodePS2ObjAllInOneData *)plnode->privateData)->genericVU1Index
        = TRUE;

    /*----
    result = RxPipelineNodePS2ManagerSetVU1CodeArray( plnode,
                 MatFXData[effect].vucode );
    RWASSERT(NULL != result);
      ----*/

    result = RxPipelineNodePS2ManagerSetInstanceCallBack(plnode, UVCallBack);
    RWASSERT(NULL != result);

    result = RxPipelineNodePS2ManagerSetPostObjectCallBack(plnode,
                 _rpMatFXMaterialsPostObjectCallBack);
    RWASSERT(NULL != result);

    result = RxPipelineNodePS2ManagerNoTexture(plnode, TRUE);
    RWASSERT(NULL != result);

    RWRETURN(pipe);
}

/*===========================================================================*
 *--- Plugin Engine Functions -----------------------------------------------*
 *===========================================================================*/

/*===========================================================================*
 *--- Plugin API Functions --------------------------------------------------*
 *===========================================================================*/
