/*===========================================================================*
 *-                                                                         -*
 *-  Module  :   G2_SkinBemBPatchNode.c                                     -*
 *-                                                                         -*
 *-  Purpose :   Hybrid Patch SkinBem PipeLine for Playstation II.          -*
 *-              PS2 Manager PowerPipe version.                             -*
 *-                                                                         -*
 *===========================================================================*/

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

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

#include "rppatch.h"
#include "rpmatfx.h"
#include "rpskin.h"

#include "patchskyskin.h"
#include "patchsky.h"
#include "patch.h"
#include "patchatomic.h"
#include "patchgeometry.h"

#include "G2_SkinBemBPatch/G2_SkinBemBPatchNode.h"
#include "G2_SkinBemBPatch/G2_SkinBemBPatchData.h"

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

#include "../../driver/sky2/baasm.h"

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

/*===========================================================================*
 *--- Private Global Variables ----------------------------------------------*
 *===========================================================================*/
PatchSkyTransforms _rpPatchSkySkinBemBPatchTransforms;

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

/*===========================================================================*
 *--- Local Types -----------------------------------------------------------*
 *===========================================================================*/

/*===========================================================================*
 *--- Local Global Variables ------------------------------------------------*
 *===========================================================================*/
#if (!defined(DOXYGEN))
static const char rcsid[] __RWUNUSED__ = "";
#endif /* (!defined(DOXYGEN)) */

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

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

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

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

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

/*****************************************************************************
 - _rxPipelineNodePS2SkinBemBPatchPS2ManagerInstanceCallBack
 - Ps2 manager instance call back for rendering generation 2 bezier patches.
 - Inputs :   clusterData - Clusters
              numClusters - Number of cluster
 - Outputs:   RwBool - True on success.
 */
RwBool
_rxPipelineNodePS2SkinBemBPatchPS2ManagerInstanceCallBack(
    void **clusterData,
    RwUInt32 numClusters __RWUNUSEDRELEASE__ )
{
    /* Cluster expansion. */
    RxPS2Mesh *mesh;
    RxPS2DMASessionRecord *dmaSessionRec;
    RpAtomic *atomic;
    PatchAtomicData *atomicData;
    RpGeometry *geometry;
    RpSkin *skin;

    /* Skin extension. */
    RwUInt32 numMatrices;
    RwReal *destMBI;
    RwMatrix *mba = (RwMatrix *)NULL;
    RwUInt32 DMAstorage;
    RwUInt32 serialNum;

    /* Material data. */
    RpMaterial *material;
    rpMatFXMaterialData *materialData;

    /* Bump Env data. */
    RwTexture *bumpMapTexture;
    RwTexture *envMapTexture;
    RwReal envMapCoef;
    RwReal bumpMapCoef;
    RwBool blendmode;

    RWFUNCTION(RWSTRING("_rxPipelineNodePS2SkinBemBPatchPS2ManagerInstanceCallBack"));
    RWASSERT(NULL != clusterData);
    RWASSERT(3 == numClusters);
    RWASSERT(NULL != clusterData[0]);
    RWASSERT(NULL != clusterData[1]);
    RWASSERT(NULL != clusterData[2]);

    /* Collect the mesh and atomic data. */
    mesh = (RxPS2Mesh *)clusterData[0];
    RWASSERT(NULL != mesh);
    dmaSessionRec = (RxPS2DMASessionRecord *)clusterData[1];
    RWASSERT(NULL != dmaSessionRec);
    destMBI = (RwReal *)(clusterData[2]);
    RWASSERT(NULL != destMBI);
    atomic = dmaSessionRec->sourceObject.atomic;
    RWASSERT(NULL != atomic);
    atomicData = PATCHATOMICGETDATA(atomic);
    RWASSERT(NULL != atomicData);
    geometry = atomic->geometry;
    RWASSERT(NULL != geometry);
    skin = _rpPatchSkyGeometryGetSkin(geometry);
    RWASSERT(NULL != skin);
    numMatrices = _rpPatchSkySkinGetNumMatrices(skin);
    DMAstorage = 0;
    serialNum = ((RwUInt32 *)(*(mesh->cacheEntryRef) + 1))[3];

    /* Skin weights and indices instancing. */
    if(dmaSessionRec->serialNum != serialNum)
    {
        _rpSkinWeightsInstancing(mesh->mesh, skin, destMBI);
    }

    if(0 == mesh->meshNum)
    {
        RwUInt32 lod;

        /* Call the lod call back. */
        RWASSERT(NULL != atomicData->lod.callback);
        lod = (atomicData->lod.callback)(atomic, atomicData->lod.userData);
        RWASSERT(rpPATCHLODMINVALUE <= lod);
        RWASSERT(rpPATCHSKINLODMAXVALUE >= lod);

        /* Construct the 128 qw lod data. */
        _rpPatchSkyMakeLOD128(_rpPatchSkyLodQW, lod);

        /* Bones matrices uploading. */
        mba = _rpSkinMatrixUpdating(atomic, skin);
        RWASSERT(NULL != mba);

        DMAstorage = numMatrices * 4;
    }

    /* Get the material data. */
    RWASSERT(NULL != mesh->mesh);
    RWASSERT(NULL != mesh->mesh->material);
    material = mesh->mesh->material;
    RWASSERT(NULL != material);
    materialData = *MATFXMATERIALGETDATA(material);
    RWASSERT(NULL != materialData);

    /* Setup the material data. */
    bumpMapCoef = materialData->data[rpSECONDPASS].data.bumpMap.coef *
                  materialData->data[rpSECONDPASS].data.bumpMap.invBumpWidth;
    bumpMapTexture = materialData->data[rpSECONDPASS].data.bumpMap.texture;

    /* Do we have a bumpMap texture? */
    if(NULL == bumpMapTexture)
    {
        bumpMapTexture = material->texture;
    }

    blendmode  = materialData->data[rpTHIRDPASS].data.envMap.useFrameBufferAlpha;
    envMapCoef = materialData->data[rpTHIRDPASS].data.envMap.coef;
    envMapTexture = materialData->data[rpTHIRDPASS].data.envMap.texture;

    {
        RwUInt128 ltmp = 0;
        RwUInt64 prim = 0x0l;
        RwUInt64 fogSwitch = 0x0l;
        RwUInt64 rastex1 = 0;
        RwUInt64 rastex2 = 0;
        RwUInt64 tmp, tmp1;
        RwUInt32 val1, val2;

        /* Set the fog. */
        if(dmaSessionRec->transType & 1)
        {
            /* 2nd context fog activated. */
            fogSwitch = 0x1l;
        }

        /* Need to upload the base texture. */
        if(NULL != bumpMapTexture)
        {
            RWASSERT(NULL != bumpMapTexture->raster);
            RpSkyTexCacheAccessSpeculate(bumpMapTexture->raster);
            _rpMatFXUploadTexture(bumpMapTexture, dmaSessionRec, mesh);
            RpSkyTexGetTex0(bumpMapTexture->raster, &val1, &val2);
            rastex1 = ((RwUInt64) val1 << 32) | val2;
        }

        /* Upload the second texture. */
        if (NULL != envMapTexture)
        {
            RWASSERT(NULL != envMapTexture->raster);
            RpSkyTexCacheAccessSpeculate(envMapTexture->raster);
            RpSkyTexCacheAccessRaster(envMapTexture->raster, TRUE);
            RpSkyTexGetTex0(envMapTexture->raster, &val1, &val2);
            rastex2 = ((RwUInt64) val1 << 32) | val2;
        }

        /*------ DMA data transfer --------------------------*/
        sweFinaliseOpenLocalPkt(SWE_PKT_DMA_MODE_CHAIN_TTE  |
                                SWE_PKT_LOCAL | SWE_PKT_VU1 |
                                SWE_PKT_CIRCALLOC, /**/ -(30 + DMAstorage) /**/);
        RWASSERT(NULL != sweLocalPacket);
        /*---------------------------------------------------*/

        SWE_LOCAL_BLOCK_BEGIN();

        /*------- Transfer Information ----------------------*/
        tmp  = ((1l << 28)      | (/**/ 28 + DMAstorage /**/));
        tmp1 = ((((0x6cl << 24) | ((/**/ 23 + DMAstorage /**/) << 16) |
               ((long) (pipeASymbStaticDataStart))) << 32) |
               ((1l << 24) | (4 << 8) | (4)));
        MAKE128(ltmp, tmp1, tmp);
        SWEADDCONTFAST(ltmp);
        /*---------------------------------------------------*/

        /*------- Patch tesselation -------------------------*/
        SWEADDCONTFAST(_rpPatchSkyLodQW);
        /*---------------------------------------------------*/

        /*------- Small Frustum Clipping information --------*/
        SWEADDCONTFAST(skyCClipVect1);
        SWEADDCONTFAST(skyCClipVect2);
        /*---------------------------------------------------*/

        /*------------------ Emboss Bump Data --------------*/
        tmp  = (*(const RwUInt32 *) &bumpMapCoef);
        tmp1 = (*(const RwUInt32 *) &matFXBumpFarPlane);
        tmp1 = ((tmp1 << 32) | (*(const RwUInt32 *) &matFXBumpScale));
        MAKE128(ltmp, tmp1, tmp);
        SWEADDCONTFAST(ltmp);
        /*---------------------------------------------------*/

        /*------------------ Bump CTX1 Bump Tag2 ------------*/
        tmp = /* NLOOP */ 4l
            | /* EOP   */ (1l << 15)
            | /* PRE   */ (0l << 46)
            | /* FLG   */ (0l << 58)
            | /* NREG  */ (1l << 60);
        MAKE128(ltmp, 0xel, tmp);
        SWEADDCONTFAST(ltmp);
        MAKE128(ltmp, GS_ALPHA_1, 0x8000000002l);
        SWEADDCONTFAST(ltmp);
        MAKE128(ltmp, GS_TEST_1,  0x50002l);
        SWEADDCONTFAST(ltmp);
        MAKE128(ltmp, GS_FOGCOL,  skyFogcol);
        SWEADDCONTFAST(ltmp);
        MAKE128(ltmp, GS_TEX0_1,  rastex1);
        SWEADDCONTFAST(ltmp);
        /*---------------------------------------------------*/

        /*------------------ Bump CTX1 Bump Tag1 ------------*/
        tmp = /* NLOOP */ 2l
            | /* EOP   */ (1l << 15)
            | /* PRE   */ (0l << 46)
            | /* FLG   */ (0l << 58)
            | /* NREG  */ (1l << 60);
        MAKE128(ltmp, 0xel, tmp);
        SWEADDCONTFAST(ltmp);
        MAKE128(ltmp, GS_ALPHA_1, 0x8000000048l);
        SWEADDCONTFAST(ltmp);
        MAKE128(ltmp, GS_TEST_1,  0x50002l);
        SWEADDCONTFAST(ltmp);
        /*---------------------------------------------------*/

        /*------------ Bump Map matrix ----------------------*/
        ltmp = *((RwUInt128 *) & (matFXBumpMatrix.right));
        SWEADDCONTFAST(ltmp);
        ltmp = *((RwUInt128 *) & (matFXBumpMatrix.up));
        SWEADDCONTFAST(ltmp);
        ltmp = *((RwUInt128 *) & (matFXBumpMatrix.at));
        SWEADDCONTFAST(ltmp);
        /*---------------------------------------------------*/

        /*------------------ Dark Fog Tag -------------------*/
        tmp = /* NLOOP */ 2l
            | /* EOP   */ (1l << 15)
            | /* PRE   */ (0l << 46)
            | /* FLG   */ (0l << 58)
            | /* NREG  */ (1l << 60);
        MAKE128(ltmp, 0xel, tmp);
        SWEADDCONTFAST(ltmp);
        MAKE128(ltmp, GS_FOGCOL, 0x000000l);
        SWEADDCONTFAST(ltmp);
        MAKE128(ltmp, GS_TEX0_2, rastex2);
        SWEADDCONTFAST(ltmp);
        /*---------------------------------------------------*/

        /*----------- Context 2 Env Map GifTag --------------*/
        prim = ( /* fix  */ 0x0l << 10        |
                 /* ctxt */ 0x1l << 9         |
                 /* fst  */ 0x0l << 8         |
                 /* aa1  */ 0x0l << 7         |
                 /* abe  */ 0x1l << 6         |
                 /* fge  */ fogSwitch << 5    |
                 /* tme  */ 0x1l << 4         |
                 /* iip  */ 0x1l << 3         |
                 /* prim */ 0x4l << 0);
        tmp  = ( /* regs */ 0x3l << (60 - 32) |
                 /* flg  */ 0x0l << (58 - 32) |
                 /* prim */ prim << (47 - 32) |
                 /* pre  */ 0x1l << (46 - 32)) << 32;
        MAKE128(ltmp, 0x412l, tmp);
        SWEADDCONTFAST(ltmp);
        /*---------------------------------------------------*/

        /*------------ Env Map matrix -----------------------*/
        ltmp = *((RwUInt128 *) & (matFXEnvMatrix.right));
        SWEADDCONTFAST(ltmp);
        ltmp = *((RwUInt128 *) & (matFXEnvMatrix.up));
        SWEADDCONTFAST(ltmp);
        tmp  = *(const RwUInt64 *) & (matFXEnvMatrix.at.x);
        tmp1 = *(const RwUInt32 *) & (envMapCoef);
        tmp1 = ((tmp1 << 32) | (*(const RwUInt32 *) & (matFXEnvMatrix.at.z)));
        MAKE128(ltmp, tmp1, tmp);
        SWEADDCONTFAST(ltmp);
        /*---------------------------------------------------*/

        /*------------ Environment Map Datas ----------------*/
        tmp  = *(const RwUInt64 *) (matFXEnvParams);
        tmp1 = *(const RwUInt64 *) (matFXEnvParams + 2);
        MAKE128(ltmp, tmp1, tmp);
        SWEADDCONTFAST(ltmp);
        /*---------------------------------------------------*/

        /*-------- Upload Skin matrices ---------------------*/
        if(DMAstorage)
        {
            RwUInt32  i;
            for (i = 0; i < numMatrices; i++)
            {
                ltmp = *((RwUInt128 *) & mba->right.x);
                SWEADDCONTFAST(ltmp);
                ltmp = *((RwUInt128 *) & mba->up.x);
                SWEADDCONTFAST(ltmp);
                ltmp = *((RwUInt128 *) & mba->at.x);
                SWEADDCONTFAST(ltmp);
                ltmp = *((RwUInt128 *) & mba->pos.x);
                SWEADDCONTFAST(ltmp);
                mba++;
            }
        }
        /*---------------------------------------------------*/

        /*------------ Padding ------------------------------*/
        tmp  = VIFCMD_NOP   | (VIFCMD_NOP << 32);
        tmp1 = (VIFCMD_NOP) | ((VIFCMD_DIRECT | /**/ 4 /**/) << 32);
        MAKE128(ltmp, tmp1, tmp);
        SWEADDCONTFAST(ltmp);
        /*---------------------------------------------------*/

        /*------------- Second Context Registers ------------*/
        tmp = /* NLOOP */ 3l
            | /* EOP   */ (1l << 15)
            | /* PRE   */ (0l << 46)
            | /* FLG   */ (0l << 58)
            | /* NREG  */ (1l << 60);
        MAKE128(ltmp, 0xel, tmp);
        SWEADDCONTFAST(ltmp);
        MAKE128(ltmp, GS_ALPHA_2, 0x8000000048l | (0x20 >> blendmode));
        SWEADDCONTFAST(ltmp);
        MAKE128(ltmp, GS_CLAMP_2, 0x00);
        SWEADDCONTFAST(ltmp);
        MAKE128(ltmp, GS_TEST_2,  0x50002l);
        SWEADDCONTFAST(ltmp);
        /*---------------------------------------------------*/

        /*------- Terminate the DMA with an interrupt -------*/
        MAKE128(ltmp, 0l, (0xfl << 28));
        SWEADDCONTFAST(ltmp);
        /*---------------------------------------------------*/

        SWE_LOCAL_BLOCK_END();

        sweFinaliseOpenLocalPkt(SWE_LPS_CONT, 0);
    }

    _rpPatchSkyUpdateMetrics(_rpPatchSkyLodQW, mesh, 3);

    RWRETURN(TRUE);
}

/*****************************************************************************
 - _rpPatchSkySkinBemBPatchSetupTransforms
 - Initalises the _rpPatchSkySkinBemBPatchTransforms transforms.
 - Inputs :   none.
 - Outputs:   none.
 */
void
_rpPatchSkySkinBemBPatchSetupTransforms()
{
    RwUInt32 code;

    RWFUNCTION(RWSTRING("_rpPatchSkySkinBemBPatchSetupTransforms"));

    /* Empty the vu code array. */
    for( code = 0; code < VU1CODEARRAYSIZE; code++ )
    {
        _rpPatchSkySkinBemBPatchTransforms[code] = &vu1nullTrans;
    }

    _rpPatchSkySkinBemBPatchTransforms[TRANSNFOG | TRANSNCL  | TRANSSTRIP | TRANSPER] = &G2_SkinBemBPatch;
    _rpPatchSkySkinBemBPatchTransforms[TRANSFOG  | TRANSNCL  | TRANSSTRIP | TRANSPER] = &G2_SkinBemBPatch;
    _rpPatchSkySkinBemBPatchTransforms[TRANSNFOG | TRANSCLIP | TRANSSTRIP | TRANSPER] = &G2_SkinBemBPatch;
    _rpPatchSkySkinBemBPatchTransforms[TRANSFOG  | TRANSCLIP | TRANSSTRIP | TRANSPER] = &G2_SkinBemBPatch;

    RWRETURNVOID();
}

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

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