/****************************************************************************
 *                                                                          *
 *  Module  :   patchsky.c                                                  *
 *                                                                          *
 *  Purpose :                                                               *
 *                                                                          *
 ****************************************************************************/

/****************************************************************************
 Includes
 */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

/* RW includes */
#include "rpplugin.h"
#include <rpdbgerr.h>
#include <rwcore.h>
#include <rpworld.h>
#include <rpmatfx.h>

#include "rppatch310.h"
#include "patchvar.h"
#include "patchgen.h"

#include "patchsky.h"

#include "stddata.h"

#if (!defined(DOXYGEN))
static const char   rcsid[] __RWUNUSED__ =
    "@@@@(#)$Id: patchsky.c,v 1.18 2001/09/24 12:39:25 johns Exp $";
#endif /* (!defined(DOXYGEN)) */

/****************************************************************************
 Local Defines
 */

/****************************************************************************
 Globals (across program)
 */

/****************************************************************************
 Functions
 */

/*
 *
 *
 *
 */
static              RwBool
PatchNodePS2ManagerInstanceCallBack(void **clusterData,
                                    RwUInt32 numClusters __RWUNUSED__)
{
    RwBool              result = TRUE;
    RxPS2DMASessionRecord *const dmaSessionRec =
        (RxPS2DMASessionRecord *) (clusterData[1]);
    RwInt32             lod;
    RwReal              dx1, dx2, dx3;
    RpAtomic           *atomic;
    RwSkySplitBits128   packed;

    RWFUNCTION(RWSTRING("PatchNodePS2ManagerInstanceCallBack"));

    RWASSERT(dmaSessionRec);

    atomic = dmaSessionRec->sourceObject.atomic;

    lod = rpPatchGlobals.atomicLODCallBack(atomic);

    dx1 = ((RwReal) 1) / (RwReal) (lod - 1);
    dx2 = dx1 * dx1;
    dx3 = dx2 * dx1;

    /* RwUInt32            prim = 0x0l; */

    sweFinaliseOpenLocalPkt(SWE_PKT_DMA_MODE_CHAIN_TTE |
                            SWE_PKT_LOCAL |
                            SWE_PKT_VU1 |
                            SWE_PKT_CIRCALLOC, -(RPPATCHNUMQWORD + 2));
    /* 1 QW */
    if (!sweLocalPacket)
    {
        RWRETURN(FALSE);
    }
    /*------- Transfer Information ----------------------*/
    packed.field_64[1] = ((((0x6cl << 24) | (1 << 16) | /* 1 QW */
                            ((long) (pipeASymbStaticDataStart))) << 32)
                          | ((1l << 24) | (4 << 8) | (4)));
    packed.field_64[0] = ((1l << 28) | (RPPATCHNUMQWORD)); /* 1 QW */
    SWEADDCONTFAST(packed.field128);

    /*------- Patch tesselation -------------------------*/

    packed.field_32[3].nUInt = lod;
    packed.field_32[2].nReal = dx1;
    packed.field_32[1].nReal = dx2;
    packed.field_32[0].nReal = dx3;
    SWEADDCONTFAST(packed.field128);

    /*------- Terminate the DMA with an interrupt -------*/
    packed.field_64[1] = 0l;
    packed.field_64[0] = (0xfl << 28);
    SWEADDCONTFAST(packed.field128);

    /*---------------------------------------------------*/
    sweFinaliseOpenLocalPkt(SWE_LPS_CONT, 0);

    RWRETURN(result);
}

static RxPipelineNode *
PatchPipelineInitialize(RxLockedPipe * lpipe,
                        RxNodeDefinition * manager)
{
    RxPipelineNode     *status;
    RxPipelineNode     *plnode;

    RWFUNCTION(RWSTRING("PatchPipelineInitialize"));

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

    RWASSERT(plnode != NULL);

    status =
        RxPipelineNodePS2ManagerSetVIFOffset(plnode,
                                             pipeASymbVIFOffset);
    status =
        RxPipelineNodePS2ManagerSetVU1CodeArray(plnode,
                                                rpPatchGlobals.sky.
                                                vucode);

    status =
        RxPipelineNodePS2ManagerSetInstanceCallBack(plnode,
                                                    PatchNodePS2ManagerInstanceCallBack);

    RWRETURN(status);
}

/*
 *
 *
 *
 */
RxPipeline         *
_rpPatchPipelineCreate(void)
{
    RwInt32             i;
    RxPipeline         *pipe;
    void              **vucode;

    RWFUNCTION(RWSTRING("_rpPatchPipelineCreate"));

    pipe = (RxPipeline *) NULL;

    /*  Clean The Vu-code Array */
    for (i = 0; i < 16; i++)
    {
        rpPatchGlobals.sky.vucode[i] = &FP_nulltransform;
        /* rpPatchGlobals.sky.vucode[i] = &FP_Generic; */
    }

    /* Set Patch Vu codes */

    vucode = rpPatchGlobals.sky.vucode;

    vucode[TRANSNFOG | TRANSNCL | TRANSSTRIP | TRANSPER] = &FP_Generic;
    vucode[TRANSFOG | TRANSNCL | TRANSSTRIP | TRANSPER] = &FP_Generic;
    vucode[TRANSNFOG | TRANSCLIP | TRANSSTRIP | TRANSPER] = &FP_Generic;
    vucode[TRANSFOG | TRANSCLIP | TRANSSTRIP | TRANSPER] = &FP_Generic;

    pipe = RxPipelineCreate();

    if (pipe)
    {
        RxLockedPipe       *lpipe = (RxPipeline *) NULL;

        pipe->pluginId = rwID_PATCHPLUGIN;

        lpipe = RxPipelineLock(pipe);

        if (NULL != lpipe)
        {
            RxPipelineNode     *plnode;
            RxPipelineNode     *status;
            RxNodeDefinition   *manager;

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

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

            status =
                RxPipelineNodePS2ManagerGenerateCluster(plnode,
                                                        &RxClPS2uv,
                                                        CL_UV);
            RWASSERT(NULL != status);

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

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

            RxPipelineNodePS2ManagerSetPointListVUBufferSize(plnode,
                                                             pipeASymbStrideOfInputCluster,
                                                             pipeASymbTSVertexCount);

            lpipe = RxLockedPipeUnlock(lpipe);

            if (lpipe != NULL)
                status = PatchPipelineInitialize(lpipe, manager);
        }

    }

    RWRETURN(pipe);
}
