/*
 * RpMatFX Xbox multitexture
 */

#ifndef RPMFXXBOX_H
#define RPMFXXBOX_H

/**
 * \defgroup rpmatfxxbox RpMatFx Xbox specific
 * \ingroup rpmatfx
 *
 * Xbox specific documentation.
 */

/******************************************************************************
 *  Include files
 */
#include "rwcore.h"
#include "rpworld.h"
#include "rpmatfx.h"

typedef enum _rpD3DTEXTUREOP
{
    rpNAD3DTOP                    = 0,

    /* Control */
    rpD3DTOP_DISABLE              = 1,      /* disables stage */
    rpD3DTOP_SELECTARG1           = 2,      /* the default */
    rpD3DTOP_SELECTARG2           = 3,

    /* Modulate */
    rpD3DTOP_MODULATE             = 4,      /* multiply args together */
    rpD3DTOP_MODULATE2X           = 5,      /* multiply and  1 bit */
    rpD3DTOP_MODULATE4X           = 6,      /* multiply and  2 bits */

    /* Add */
    rpD3DTOP_ADD                  =  7,   /* add arguments together */
    rpD3DTOP_ADDSIGNED            =  8,   /* add with -0.5 bias */
    rpD3DTOP_ADDSIGNED2X          =  9,   /* as above but left  1 bit */
    rpD3DTOP_SUBTRACT             = 10,   /* Arg1 - Arg2, with no saturation */
    rpD3DTOP_ADDSMOOTH            = 11,   /* add 2 args, subtract product
                                        // Arg1 + Arg2 - Arg1*Arg2
                                        // = Arg1 + (1-Arg1)*Arg2 */

    /* Linear alpha blend: Arg1*(Alpha) + Arg2*(1-Alpha) */
    rpD3DTOP_BLENDDIFFUSEALPHA    = 12, /* iterated alpha */
    rpD3DTOP_BLENDTEXTUREALPHA    = 13, /* texture alpha */
    rpD3DTOP_BLENDFACTORALPHA     = 14, /* alpha from D3DRENDERSTATE_TEXTUREFACTOR */

    /* Linear alpha blend with pre-multiplied arg1 input: Arg1 + Arg2*(1-Alpha) */
    rpD3DTOP_BLENDTEXTUREALPHAPM  = 15, /* texture alpha */
    rpD3DTOP_BLENDCURRENTALPHA    = 16, /* by alpha of current color */

    /* Specular mapping */
    rpD3DTOP_PREMODULATE            = 17,     /* modulate with next texture before use */
    rpD3DTOP_MODULATEALPHA_ADDCOLOR = 18,     /* Arg1.RGB + Arg1.A*Arg2.RGB */
                                            /* COLOROP only */
    rpD3DTOP_MODULATECOLOR_ADDALPHA = 19,     /* Arg1.RGB*Arg2.RGB + Arg1.A */
                                            /* COLOROP only */
    rpD3DTOP_MODULATEINVALPHA_ADDCOLOR = 20,  /* (1-Arg1.A)*Arg2.RGB + Arg1.RGB */
                                            /* COLOROP only */
    rpD3DTOP_MODULATEINVCOLOR_ADDALPHA = 21,  /* (1-Arg1.RGB)*Arg2.RGB + Arg1.A */
                                            /* COLOROP only */

    /* This can do either diffuse or specular bump mapping with correct input.
       Performs the function (Arg1.R*Arg2.R + Arg1.G*Arg2.G + Arg1.B*Arg2.B)
       where each component has been scaled and offset to make it signed.
       The result is replicated into all four (including alpha) channels.
       This is a valid COLOROP only.*/
    rpD3DTOP_DOTPRODUCT3          = 22,

    /* Triadic ops */
    rpD3DTOP_MULTIPLYADD          = 23, /* Arg0 + Arg1*Arg2 */
    rpD3DTOP_LERP                 = 24, /* (Arg0)*Arg1 + (1-Arg0)*Arg2 */

    /* Bump mapping */
    rpD3DTOP_BUMPENVMAP           = 25, /* per pixel env map perturbation */
    rpD3DTOP_BUMPENVMAPLUMINANCE  = 26, /* with luminance channel */

    rpD3DTOP_MAX                  = 27,
    rpD3DTOP_FORCE_DWORD = 0x7fffffff
} rpD3DTEXTUREOP;

/* define the texture arguments */
#define rpD3DTA_SELECTMASK        0x0000000f  /* mask for arg selector */
#define rpD3DTA_DIFFUSE           0x00000000  /* select diffuse color (read only) */
#define rpD3DTA_CURRENT           0x00000001  /* select stage destination register (read/write) */
#define rpD3DTA_TEXTURE           0x00000002  /* select texture color (read only) */
#define rpD3DTA_TFACTOR           0x00000003  /* select RENDERSTATE_TEXTUREFACTOR (read only) */
#define rpD3DTA_SPECULAR          0x00000004  /* select specular color (read only) */
#define rpD3DTA_TEMP              0x00000005  /* select temporary register color (read/write) */
#define rpD3DTA_COMPLEMENT        0x00000010  /* take 1.0 - x (read modifier) */
#define rpD3DTA_ALPHAREPLICATE    0x00000020  /* replicate alpha to color components (read modifier) */

/* texture coordinates transform flag */
typedef enum _rpD3DTEXTURETRANSFORMFLAGS
{
    rpD3DTTFF_DISABLE         = 0,    /* texture coordinates are passed directly */
    rpD3DTTFF_COUNT1          = 1,    /* rasterizer should expect 1-D texture coords */
    rpD3DTTFF_COUNT2          = 2,    /* rasterizer should expect 2-D texture coords */
    rpD3DTTFF_COUNT3          = 3,    /* rasterizer should expect 3-D texture coords */
    rpD3DTTFF_COUNT4          = 4,    /* rasterizer should expect 4-D texture coords */
    rpD3DTTFF_PROJECTED       = 256,  /* texcoords to be divided by COUNTth element */
    rpD3DTTFF_FORCE_DWORD     = 0x7fffffff
} rpD3DTEXTURETRANSFORMFLAGS;

/* flags for the colorSign member of the MatFXXboxStage structure */
#define rpD3DTSIGN_ASIGNED           0x10000000
#define rpD3DTSIGN_AUNSIGNED         0
#define rpD3DTSIGN_RSIGNED           0x20000000
#define rpD3DTSIGN_RUNSIGNED         0
#define rpD3DTSIGN_GSIGNED           0x40000000
#define rpD3DTSIGN_GUNSIGNED         0
#define rpD3DTSIGN_BSIGNED           0x80000000
#define rpD3DTSIGN_BUNSIGNED         0

/* valid values for alphakill */
typedef enum _rpD3DTEXTUREALPHAKILL
{
    rpD3DTALPHAKILL_DISABLE       = 0,
    rpD3DTALPHAKILL_ENABLE        = 4,

    rpD3DTALPHAKILL_FORCE_DWORD   = 0x7fffffff /* force 32-bit size enum */
} rpD3DTEXTUREALPHAKILL;

/* flags for the texCoordIndex member of the MatFXXboxStage structure */
#define rpD3DTSS_TCI_PASSTHRU                             0x00000000
#define rpD3DTSS_TCI_CAMERASPACENORMAL                    0x00010000
#define rpD3DTSS_TCI_CAMERASPACEPOSITION                  0x00020000
#define rpD3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR          0x00030000
#define rpD3DTSS_TCI_OBJECT                               0x00040000
#define rpD3DTSS_TCI_SPHERE                               0x00050000

#define rpD3DTSS_TCI_TEXCOORDINDEX_MAX                    8
#define rpD3DTSS_TCI_TEXGEN_MAX                           0x00060000

/* final blend types supported on Xbox */
typedef enum _rpD3DBLEND
{
    rpD3DBLEND_ZERO               = 0,
    rpD3DBLEND_ONE                = 1,
    rpD3DBLEND_SRCCOLOR           = 0x300,
    rpD3DBLEND_INVSRCCOLOR        = 0x301,
    rpD3DBLEND_SRCALPHA           = 0x302,
    rpD3DBLEND_INVSRCALPHA        = 0x303,
    rpD3DBLEND_DESTALPHA          = 0x304,
    rpD3DBLEND_INVDESTALPHA       = 0x305,
    rpD3DBLEND_DESTCOLOR          = 0x306,
    rpD3DBLEND_INVDESTCOLOR       = 0x307,
    rpD3DBLEND_SRCALPHASAT        = 0x308,
    rpD3DBLEND_CONSTANTCOLOR      = 0x8001,
    rpD3DBLEND_INVCONSTANTCOLOR   = 0x8002,
    rpD3DBLEND_CONSTANTALPHA      = 0x8003,
    rpD3DBLEND_INVCONSTANTALPHA   = 0x8004,

    rpD3DBLEND_FORCE_DWORD        = 0x7fffffff /* force 32-bit size enum */

} rpD3DBLEND;

typedef struct _rpD3DMATRIX
{
    RwReal _11, _12, _13, _14;
    RwReal _21, _22, _23, _24;
    RwReal _31, _32, _33, _34;
    RwReal _41, _42, _43, _44;
} rpD3DMATRIX;

/*
 * Xbox structs
 */
typedef struct _MatFXXboxStage
{
    RwInt32 colorOp;
    RwInt32 colorArg0;
    RwInt32 colorArg1;
    RwInt32 colorArg2;

    RwInt32 alphaOp;
    RwInt32 alphaArg0;
    RwInt32 alphaArg1;
    RwInt32 alphaArg2;
    RwInt32 resultArg;
    RwInt32 textureTransformFlags;

    RwInt32 colorSign;
    RwInt32 alphaKill;

    RwReal bumpEnvMat00;
    RwReal bumpEnvMat01;
    RwReal bumpEnvMat11;
    RwReal bumpEnvMat10;

    RwInt32 texCoordIndex;
    RwInt32 borderColor;

    /*RwMatrix texTransformMatrix;*/
    rpD3DMATRIX texTransformMatrix;

} MatFXXboxStage;

typedef struct _MatFXXboxFinalBlend
{
    RwInt32 srcBlend;
    RwInt32 dstBlend;
} MatFXXboxFinalBlend;

typedef struct _MatFXXboxMiscState
{
    RwInt32 textureFactor;
} MatFXXboxMiscState;

#ifdef XBOX_DRVMODEL_H
typedef RpMaterial *(*RpMatFXXboxMTCallBack)(
    RpMaterial             *material,
    void                   *object,
    void                   *data);

#else
typedef RpMaterial *(*RpMatFXXboxMTCallBack)(
    RpMaterial             *material,
    void                   *object,
    void                   *data);
#endif /* XBOX_DRVMODEL_H */

typedef struct _MatFXXboxCallbacks
{
    /*RpMatFXXboxMTCallBack instanceCallback;*/
    RpMatFXXboxMTCallBack preRenderCallback;
    RwBool useVertexShader;
    RwBool usePixelShader;
} MatFXXboxCallbacks;

#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */

/* Access functions for the Xbox multi-texturing extension */
extern RwInt32
RpMatFXGetXboxMaterialNbStages( const RpMaterial* mat );

extern RwInt32
RpMatFXGetXboxMaterialNbTextures( const RpMaterial* mat );

extern RwTexture*
RpMatFXGetXboxMaterialTexture( const RpMaterial* mat, RwInt32 stage );

extern RwInt32
RpMatFXGetXboxMaterialTexStage( const RpMaterial* mat, RwInt32 stage );

extern MatFXXboxStage*
RpMatFXGetXboxMaterialStage( const RpMaterial* mat, RwInt32 stage );

extern MatFXXboxFinalBlend*
RpMatFXGetXboxMaterialFinalBlend ( const RpMaterial* mat );

extern MatFXXboxMiscState*
RpMatFXGetXboxMaterialMiscState ( const RpMaterial* mat );

extern void
RpMatFXSetXboxMaterialNbStages( RpMaterial* mat, RwInt32 nbStages );

extern void
RpMatFXSetXboxMaterialNbTextures( RpMaterial* mat, RwInt32 nbTextures );

extern void
RpMatFXSetXboxMaterialTexture( RpMaterial* mat, RwInt32 stage, RwTexture* texture );

extern void
RpMatFXSetXboxMaterialTexStage( RpMaterial* mat, RwInt32 texStage, RwInt32 stage);

extern void
RpMatFXSetXboxMaterialStage( RpMaterial* mat, RwInt32 stage, MatFXXboxStage* stageSetup);

extern void
RpMatFXSetXboxMaterialFinalBlend ( RpMaterial* mat, MatFXXboxFinalBlend* finalBlend );

extern void
RpMatFXSetXboxMaterialMiscState ( RpMaterial* mat, MatFXXboxMiscState* miscState );

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* RPMFXXBOX_H */
