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

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

#include "rppatch.h"

#include "patchskymatfx.h"

/* Only need one for the vu memory offsets. */
#include "G2_BemBPatch/G2_BemBPatchData.h"
/*#include "G2_DupBPatch/G2_DupBPatchData.h"*/
/*#include "G2_EmbBPatch/G2_EmbBPatchData.h"*/
/*#include "G2_GemBPatch/G2_GemBPatchData.h"*/

#include "G2_BPatch/G2_BPatchNode.h"
#include "G2_BemBPatch/G2_BemBPatchNode.h"
#include "G2_DupBPatch/G2_DupBPatchNode.h"
#include "G2_EmbBPatch/G2_EmbBPatchNode.h"
#include "G2_GemBPatch/G2_GemBPatchNode.h"

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

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

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

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

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

/*===========================================================================*
 *--- Local Global Variables ------------------------------------------------*
 *===========================================================================*/
#if (!defined(DXOYGEN))
static const char rcsid[] __RWUNUSED__ =
    "@@@@(#)$Id: patchskymatfx.c,v 1.8 2001/09/26 16:45:08 rabin Exp $";
#endif /* (!defined(DXOYGEN)) */

/* Instance call back data. */
static PatchMatFXData MatFXData =
{
    { /*--- Single UV. -----------------------------------------------------*/
        rpMATFXEFFECTNULL, /*--- Element state type. -----------------------*/
        { /*--- Effect instance call backs. --------------------------------*/
            _rxPipelineNodePS2BPatchPS2ManagerInstanceCallBack,    /* Null  */
            _rxPipelineNodePS2EmbBPatchPS2ManagerInstanceCallBack, /* Bump  */
            _rxPipelineNodePS2GemBPatchPS2ManagerInstanceCallBack, /* Env   */
            _rxPipelineNodePS2BemBPatchPS2ManagerInstanceCallBack, /* BpEnv */
            _rxPipelineNodePS2DupBPatchPS2ManagerInstanceCallBack  /* Dual  */
        },
        { /*--- VUcode arrays. ---------------------------------------------*/
            &_rpPatchSkyBPatchTransforms,                          /* Null  */
            &_rpPatchSkyEmbBPatchTransforms,                       /* Bump  */
            &_rpPatchSkyGemBPatchTransforms,                       /* Env   */
            &_rpPatchSkyBemBPatchTransforms,                       /* BpEnv */
            &_rpPatchSkyDupBPatchTransforms                        /* Dual  */
        }
    },
    { /*--- Dual UV. -------------------------------------------------------*/
        rpMATFXEFFECTNULL, /*--- Element state type. -----------------------*/
        { /*--- Effect instance call backs. --------------------------------*/
            _rxPipelineNodePS2BPatchPS2ManagerInstanceCallBack,    /* Null  */
            _rxPipelineNodePS2EmbBPatchPS2ManagerInstanceCallBack, /* Bump  */
            _rxPipelineNodePS2GemBPatchPS2ManagerInstanceCallBack, /* Env   */
            _rxPipelineNodePS2BemBPatchPS2ManagerInstanceCallBack, /* BpEnv */
            _rxPipelineNodePS2DupBPatchPS2ManagerInstanceCallBack  /* Dual  */
        },
        { /*--- VUcode arrays. ---------------------------------------------*/
            &_rpPatchSkyBPatchTransforms,                          /* Null  */
            &_rpPatchSkyEmbBPatchTransforms,                       /* Bump  */
            &_rpPatchSkyGemBPatchTransforms,                       /* Env   */
            &_rpPatchSkyBemBPatchTransforms,                       /* BpEnv */
            &_rpPatchSkyDupBPatchTransforms                        /* Dual  */
        }
    }
};

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

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

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

/*****************************************************************************
 _rpPatchMatFXUVPipelineInstanceCallBack

 TODO

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

    RWFUNCTION(RWSTRING("_rpPatchMatFXUVPipelineInstanceCallBack"));
    RWASSERT(NULL != clusterData);
    RWASSERT(2 == numClusters);

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

    RWRETURN(ret);
}

/*****************************************************************************
 _rpPatchMatFXUV2PipelineInstanceCallBack

 TODO

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

    RWFUNCTION(RWSTRING("_rpPatchMatFXUV2PipelineInstanceCallBack"));
    RWASSERT(NULL != clusterData);
    RWASSERT(2 == numClusters);

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

    RWRETURN(ret);
}

/****************************************************************************
 _rpPatchMatFXPipelineCreate

 Creates the matfx patch pipeline.

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

    RWFUNCTION(RWSTRING("_rpPatchMatFXPipelineCreate"));

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

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

    pipe->pluginId = rwID_PATCHPLUGIN;

    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);

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

    result = RxPipelineNodePS2MatInstanceGenerateCluster( plnode,
                                                          UVClusterDef,
                                                          UVType );
    RWASSERT(NULL != result);

    result = RxPipelineNodePS2MatInstanceGenerateCluster( plnode,
                                                          &RxClPS2rgba,
                                                          CL_RGBA );
    RWASSERT(NULL != result);

    result = RxPipelineNodePS2MatInstanceGenerateCluster( plnode,
                                                          &RxClPS2normal,
                                                          CL_NORMAL );
    RWASSERT(NULL != result);

    plnode = RxPipelineNodePS2ManagerSetPointListVUBufferSize( plnode,
                 pipeASymbStrideOfInputCluster,
                 pipeASymbTSVertexCount);
    RWASSERT(NULL != plnode);

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

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

    plnode = RxPipelineNodePS2ManagerSetVIFOffset(plnode, pipeASymbVIFOffset);
    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 --------------------------------------------------*
 *===========================================================================*/
