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

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

#include "rpskin.h"

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

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

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

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

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

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

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

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

/*===========================================================================*
 *--- Local Defines ---------------------------------------------------------*
 *===========================================================================*/
#define SKINATOMICGETMATFXENABLED(_atomic)                              \
    ((RwBool)(*(((RwUInt8 *)_atomic) +                                  \
              RpAtomicGetPluginOffset(rwID_MATERIALEFFECTSPLUGIN))))

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

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

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

 Create the skin pipelines.

 Inputs :   pipes - RwUInt32 bit-field defining which pipes to create
                        rpSKINPIPELINESKINGENERIC = 0x01,
                        rpSKINPIPELINESKINMATFX   = 0x02,
 Outputs:   RwBool - on success.
 */
RwBool
_rpSkinPipelinesCreate( RwUInt32 pipes )
{
    RWFUNCTION(RWSTRING("_rpSkinPipelinesCreate"));

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

        /* Create the pipeline. */

        /* PS2Manager generic skin pipeline. */
        _rpSkinPS2ManagerPipeline(rpSKINSKYPIPELINEGENERIC) =
            _rpSkinPS2ManagerGenericPipeCreate();
        RWASSERT(NULL != _rpSkinPS2ManagerPipeline(rpSKINSKYPIPELINEGENERIC));

        /* PS2All material generic skin pipeline. */
        _rpSkinPS2AllMaterialPipeline(rpSKINSKYPIPELINEGENERIC) =
            _rpSkinPS2AllMaterialGenericPipeCreate();
        RWASSERT( NULL !=
                  _rpSkinPS2AllMaterialPipeline(rpSKINSKYPIPELINEGENERIC) );

        /* PS2All generic skin pipeline. */
        _rpSkinPS2AllPipeline(rpSKINSKYPIPELINEGENERIC) =
            _rpSkinPS2AllGenericPipeCreate(
                _rpSkinPS2AllMaterialPipeline(rpSKINSKYPIPELINEGENERIC) );
        RWASSERT(NULL != _rpSkinPS2AllPipeline(rpSKINSKYPIPELINEGENERIC));
    }

    /* Should we create the matfx pipelines. */
    if(pipes & rpSKINPIPELINESKINMATFX)
    {
        /* Setup the vu transforms. */
        _rpSkinSkySkinBemSetupTransforms();
        _rpSkinSkySkinEmbSetupTransforms();
        _rpSkinSkySkinDupSetupTransforms();
        _rpSkinSkySkinGemSetupTransforms();

        /* Create the pipeline. */

        /* PS2Manager matfx skin pipelines. */
        _rpSkinPS2ManagerPipeline(rpSKINSKYPIPELINEMATFX) =
            _rpSkinPS2ManagerSkinMatFXPipeCreate(UV);
        RWASSERT(NULL != _rpSkinPS2ManagerPipeline(rpSKINSKYPIPELINEMATFX));

        _rpSkinPS2ManagerPipeline(rpSKINSKYPIPELINEMATFXUV2) =
            _rpSkinPS2ManagerSkinMatFXPipeCreate(UV2);
        RWASSERT(NULL != _rpSkinPS2ManagerPipeline(rpSKINSKYPIPELINEMATFXUV2));

        /* TODO add the PS2All skin matfx pipes here. */

        /* PS2ALL material matfx skin single UV pipeline. */

        /* PS2ALL material matfx skin double UV pipeline. */

        /* PS2ALL matfx skin single UV pipeline. */

        /* PS2ALL matfx skin double UV pipeline. */

    }

    RWRETURN(TRUE);
}

/****************************************************************************
 _rpSkinPipelinesDestroy

 Destroy the skin pipelines.

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

    RWFUNCTION(RWSTRING("_rpSkinPipelinesDestroy"));

    for( iPipeline = rpSKINSKYPIPELINEGENERIC;
         iPipeline < rpSKINSKYPIPELINEMAX; 
         iPipeline = (SkinSkyPipeline)(1 + (RwUInt32)iPipeline))
    {
        /* PS2Manager generic skin pipeline. */
        if(NULL != _rpSkinPS2ManagerPipeline(iPipeline))
        {
            RxPipelineDestroy(_rpSkinPS2ManagerPipeline(iPipeline));
            _rpSkinPS2ManagerPipeline(iPipeline) = (RxPipeline *)NULL;
        }
        RWASSERT(NULL == _rpSkinPS2ManagerPipeline(iPipeline));

        /* PS2All material generic skin pipeline. */
        if(NULL != _rpSkinPS2AllMaterialPipeline(iPipeline))
        {
            RxPipelineDestroy(_rpSkinPS2AllMaterialPipeline(iPipeline));
            _rpSkinPS2AllMaterialPipeline(iPipeline) = (RxPipeline *)NULL;
        }
        RWASSERT(NULL == _rpSkinPS2AllMaterialPipeline(iPipeline));

        /* PS2All generic skin pipeline. */
        if(NULL != _rpSkinPS2AllPipeline(iPipeline))
        {
            RxPipelineDestroy(_rpSkinPS2AllPipeline(iPipeline));
            _rpSkinPS2AllPipeline(iPipeline) = (RxPipeline *)NULL;
        }
        RWASSERT(NULL == _rpSkinPS2AllPipeline(iPipeline));
    }

    RWRETURN(TRUE);
}

/****************************************************************************
 _rpSkinPipelinesAttach

 Attach the generic skinning pipeline to an atomic.

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

    SkinSkyPipeline iPipeline;
    RpGeometry *geometry;
    RxPipeline *pipeline;

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

    /* Get the geometry. */
    geometry = RpAtomicGetGeometry(atomic);
    RWASSERT(NULL != geometry);

    /* Get the uv2. */
    uv2 = ((RpGeometryGetFlags(geometry) & rpGEOMETRYTEXTURED2) != 0);

    /*
     * This is very dangerous, but I don't have time to edit matfx at the
     * moment, and all the files are lock, so ho hum, it'll do for now.
     * TODO - correct.
     */
    /* Is the atomic matfxed. */
    matfx = SKINATOMICGETMATFXENABLED(atomic);

    iPipeline = rpSKINSKYPIPELINEGENERIC;

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

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

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

    RWRETURN(atomic);
}

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

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