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

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

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

#include "patch.h"

#include "patchskygeneric.h"
#include "patchskymatfx.h"

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

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

/*===========================================================================*
 *--- Private Global Variables ----------------------------------------------*
 *===========================================================================*/
RwUInt128 _rpPatchSkyLodQW = 0;

PatchGlobals _rpPatchGlobals =
{
    0,                   /* RwInt32        engineOffset                     */
    0,                   /* RwInt32        atomicOffset                     */
    0,                   /* RwInt32        geometryOffset                   */
    { 0, 0 },            /* RwModuleInfo   module                           */
    (RwFreeList *)NULL,  /* RwFreeList    *atomicFreeList                   */
    (RwFreeList *)NULL,  /* RwFreeList    *geometryFreeList                 */
    {                    /* PatchPlatform  platform                         */
        {                /* RxPipeline    *pipelines[rpPATCHSKYPIPELINEMAX] */
            (RxPipeline *)NULL, /* rpPATCHSKYPIPELINEGENERIC                */
            (RxPipeline *)NULL, /* rpPATCHSKYPIPELINEMATFX                  */
            (RxPipeline *)NULL, /* rpPATCHSKYPIPELINEMATFXUV2               */
            (RxPipeline *)NULL, /* rpPATCHSKYPIPELINESKINNED                */
            (RxPipeline *)NULL, /* rpPATCHSKYPIPELINESKINMATFX              */
            (RxPipeline *)NULL, /* rpPATCHSKYPIPELINESKINMATFXUV2           */
        }
    }
};

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

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

/*===========================================================================*
 *--- Local Global Variables ------------------------------------------------*
 *===========================================================================*/
#if (!defined(DXOYGEN))
static const char rcsid[] __RWUNUSED__ =
    "@@@@(#)$Id: patchmatfxsky.c,v 1.3 2001/09/26 12:26:30 johns Exp $";
#endif /* (!defined(DXOYGEN)) */

/*===========================================================================*
 *--- Local Defines ---------------------------------------------------------*
 *===========================================================================*/
#define PatchPipeline(pipeline)                                         \
    (_rpPatchGlobals.platform.pipelines[pipeline])

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

/****************************************************************************
 PatchMeshSearchForEffect

 Works through the patch meshes materials searching for the first material
 effect.

 Inputs : patchMesh - RpPatchMesh we should search.
 Outputs: RpMatFXMaterialFlags - First effect found, or rpMATFXEFFECTNULL
                                 if none.
 */
static RpMatFXMaterialFlags
PatchMeshSearchForEffect(RpPatchMesh *patchMesh)
{
    RwUInt32 iMaterial;

    RWFUNCTION(RWSTRING("PatchMeshSearchForEffect"));
    RWASSERT(NULL != patchMesh);

    /* Search the materials for effects. */
    for( iMaterial = 0; iMaterial < RpPatchMeshGetNumMaterials(patchMesh);
         iMaterial++ )
    {
        RpMatFXMaterialFlags effect;
        RpMaterial *material;

        material = RpPatchMeshGetMaterial(patchMesh, iMaterial);
        RWASSERT(NULL != material);

        effect = RpMatFXMaterialGetEffects(material);

        if(effect != rpMATFXEFFECTNULL)
        {
            RWRETURN(effect);
        }
    }

    RWRETURN(rpMATFXEFFECTNULL);
}

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

/****************************************************************************
 _rpSkinPipelinesCreate

 Create the patch pipelines.

 Inputs :   pipes - RwUInt32 bit-field defining which pipes to create
                        rpPATCHPIPELINEGENERIC = 0x01,
                        rpPATCHPIPELINESKINNED = 0x02,
                        rpPATCHPIPELINEMATFX   = 0x04,
 Outputs:   RwBool - on success.
 */
RwBool
_rpPatchPipelinesCreate(RwUInt32 pipes)
{
    RWFUNCTION(RWSTRING("_rpPatchPipelinesCreate"));

    /* Should we create the generic pipeline. */
    if(pipes & rpPATCHPIPELINEGENERIC)
    {
        /* Setup the vu transforms. */
        _rpPatchSkyBPatchSetupTransforms();

        /* Create the pipeline. */
        PatchPipeline(rpPATCHSKYPIPELINEGENERIC) =
            _rpPatchGenericPipelineCreate(UV);
        RWASSERT(NULL != PatchPipeline(rpPATCHSKYPIPELINEGENERIC));
    }

    /* Should we create the matfx pipeline. */
    if(pipes & rpPATCHPIPELINEMATFX)
    {
        /* Setup the vu transforms. */
        _rpPatchSkyBemBPatchSetupTransforms();
        _rpPatchSkyEmbBPatchSetupTransforms();
        _rpPatchSkyDupBPatchSetupTransforms();
        _rpPatchSkyGemBPatchSetupTransforms();

        /* Create the pipeline. */
        PatchPipeline(rpPATCHSKYPIPELINEMATFX) =
            _rpPatchMatFXPipelineCreate(UV);
        RWASSERT(NULL != PatchPipeline(rpPATCHSKYPIPELINEMATFX));

        PatchPipeline(rpPATCHSKYPIPELINEMATFXUV2) =
            _rpPatchMatFXPipelineCreate(UV2);
        RWASSERT(NULL != PatchPipeline(rpPATCHSKYPIPELINEMATFXUV2));
    }

    RWRETURN(TRUE);
}

/****************************************************************************
 _rpPatchPipelinesDestroy

 Destroy the patch pipelines.

 Inputs :   None
 Outputs:   RwBool - on success.
 */
RwBool
_rpPatchPipelinesDestroy(void)
{
    PatchSkyPipeline iPipeline;

    RWFUNCTION(RWSTRING("_rpPatchPipelinesDestroy"));

    for( iPipeline = rpPATCHSKYPIPELINEGENERIC;
         iPipeline < rpPATCHSKYPIPELINEMAX; 
         iPipeline = (PatchSkyPipeline)(1 + (RwUInt32)iPipeline) )
    {
        if(NULL != PatchPipeline(iPipeline))
        {
            RxPipelineDestroy(PatchPipeline(iPipeline));
            PatchPipeline(iPipeline) = (RxPipeline *)NULL;
        }
        RWASSERT(NULL == PatchPipeline(iPipeline));
    }

    RWRETURN(TRUE);
}

/****************************************************************************
 _rpPatchPipelinesAttach

 Attach the correct patch pipeline to the atomic.

 Inputs :   atomic *   - Pointer to the atomic.
 Outputs:   RpAtomic * - Pointer to the atomic on success.
 */
RpAtomic *
_rpPatchPipelinesAttach(RpAtomic *atomic)
{
    RpPatchMesh *patchMesh;
    RwBool uv2;
    RwBool matfx;

    PatchSkyPipeline iPipeline;
    RxPipeline *pipeline;

    RWFUNCTION(RWSTRING("_rpPatchPipelinesAttach"));
    RWASSERT(NULL != atomic);

    /* Get the patch mesh. */
    patchMesh = RpPatchAtomicGetPatchMesh(atomic);
    RWASSERT(NULL != patchMesh);

    /* Get the uv2. */
    uv2 = ((RpPatchMeshGetFlags(patchMesh) & rpPATCHMESHTEXTURED2) != 0);

    /* Is the patch mesh matfxed. */
    matfx = (PatchMeshSearchForEffect(patchMesh) != rpMATFXEFFECTNULL);

    iPipeline = rpPATCHSKYPIPELINEGENERIC;

    /* Is the patch mesh matfxed or uv2. */
    /* We only allow uv2 if matfx is on. */
    iPipeline = (PatchSkyPipeline)
        ((uv2 * matfx) + matfx + (RwUInt32)iPipeline);
    RWASSERT(rpPATCHSKYPIPELINEMAX > iPipeline);

    pipeline = PatchPipeline(iPipeline);
    RWASSERT(NULL != pipeline);

    atomic = RpAtomicSetPipeline(atomic, pipeline);
    RWASSERT(NULL != atomic);

    RWRETURN(atomic);
}

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

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