//=================================================================
//
// Copyright (c) Microsoft Corporation 1999 - All Rights Reserved.
//
//=================================================================

#ifndef _GRF_TYPES_
#define _GRF_TYPES_

#include "chunk.h"

extern "C" GRFCHUNKDATA     g_grdChunkData;

//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------

#define GRF_SCREEN_INITIALIZED      0x00000001
#define GRF_ZBUFFER_INITIALIZED     0x00000002
#define GRF_TEXTURE_INITIALIZED     0x00000004

//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------

// Fixed point related constants.
#define intSHIFT28_4    4
#define intSHIFT16_16   16
#define intSHIFT6_26    26
#define intSHIFT12_20   20

//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------

struct Vertex;
struct RenderData;
struct ChunkData;
struct Edge;
struct OtherEdge;
class RenderDevice;

typedef Vertex       GRFVERTEX;
typedef RenderData   GRFRENDERDATA;
typedef Edge         GRFEDGE;
typedef OtherEdge    GRFOTHEREDGE;
typedef RenderDevice GRFRENDERDEVICE;

//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------

typedef DWORD COLOR;
typedef long  PIXEL;

//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------

// Transformed and lit vertex using fixed point x,y.
struct Vertex
{
    long    x;          // 28.4 pixel coordinates.
    long    y;
    float   z;          // Varies between 0.0 (min) and 1.0 (max)
    float   rhw;        // Reciprocal of homogeneous w. = is 1 divided by the distance from the origin to the object along the z-axis. (e.g OneOverZ)
    COLOR   color;      // RGBA, a in MSB, blue in LSB, also used for Gouraud shading
    COLOR   specular;   // Lighting component added in Perspective mapper with shading when ENABLE_SPECULAR defined (raster.h) uses only LSB as the intensity.
    float   tu;
    float   tv;
};

//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------

// Used to step down the primary (left) sides of triangles.
struct Edge
{
    // Basic data common to all render modes.

    long      x, y, cy;
    long      xStep, xNum, xDenom, xError;

    // Gouraud shading information.
    FIX16_16  f16Alpha, f16AlphaStep, f16AlphaStepExtra;
    FIX16_16  f16Blue, f16BlueStep, f16BlueStepExtra;
    FIX16_16  f16Green, f16GreenStep, f16GreenStepExtra;
    FIX16_16  f16Red, f16RedStep, f16RedStepExtra;

    // Z information used for z-buffering and perspective texture mapping.

    float     Z, ZStep, ZStepExtra; // 1/z, step, and error step

    // Information for perspective texture mapping.

    float     oow, oowStep, oowStepExtra; // rhw, step, and error step
    DWORD     oowIncr;  // 0.32 format
    DWORD     dwOow;    // 0.32
    float     uow, uowStep, uowStepExtra; // u/z, u/z step, and u/z error step 
    float     vow, vowStep, vowStepExtra; // v/z, u/z step, and u/z error step

    // Information for affine texture mapping.

    float     u, uStep, uStepExtra;
    float     v, vStep, vStepExtra;

    FIX16_16    f16Fog, f16FogStep, f16FogStepExtra;
};

// Used to step down the secondary (right) sides of triangles.
struct OtherEdge
{
    long      x, y, cy;
    long      xStep, xNum, xDenom, xError;
};

//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------

// All information required by individual rasterizers is combined in this data.
struct RenderData
{
    // Frame buffer
    BYTE            * pbScreenLine;                        // Current scan line beeing rendered.

    // ZBuffer
    BYTE            * pbZBufferLine;                       // Current zbuffer line beeing filled.

    float             rguow[3];                 // u/w for each vertex
    float             rgvow[3];                 // v/w for each vertex

    // Actual gradient variables - valid across entire polygon

    // Perspective gradients.

    float             dZdx, dZdy; // d(1/z)/dx, d(1/z)/dy

    float             doowdx, doowdx16, doowdy; // d(1/w)/dx, d(1/w)/8dx, d(1/w)/dy
    float             duowdx, duowdx16, duowdy; // d(u/w)/dx, d(u/w)/8dx, d(u/w)/dy
    float             dvowdx, dvowdx16, dvowdy; // d(v/w)/dx, d(v/w)/8dx, d(v/w)/dy

    FIX16_16          f16dudxModifier;
    FIX16_16          f16dvdxModifier;

    // Affine Gradients

    float             dudx, dvdx, dudy, dvdy;  // du/dx, dv/dx, du/dy, dv/dy

    GRFRENDERDEVICE * pRenderDevice;    // Render device for which the render data is currently valid.

	int       cPixels;

    BOOL    fTargetIs555;

    DWORD   dwState;

    // Vertex data.
    GRFVERTEX         gvVertices[3];

    GRFEDGE         geEdge;
    GRFOTHEREDGE    geOtherEdge;

    PSPANFN     pspanfnEntry;
    BOOL        fMiddleIsRight;
    float       floatTemp;
    int         iTemp;
    int         iTop, iMiddle, iBottom;
    int         cyHeight;
    float       Const1;

    unsigned int cbZBufferPitch;
    BYTE         *pbZBuffer;

    FIX16_16    fix16du_Chunk_X16, fix16dv_Chunk_X16;

    FIX16_16  f16dAdx, f16dBdx, f16dGdx, f16dRdx;
    FIX16_16  f16dAdy, f16dBdy, f16dGdy, f16dRdy;
    FIX16_16  f16dFdx, f16dFdy;
    BOOL      fFogIsFlat;
};

//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------

class CDirect3DDevice;

class RenderDevice;

typedef void (RenderDevice::*PTRIFN)(void);

// NOTE: this must stay in sync with GRFRENDERDEVICE in grf.inc
class RenderDevice
{

private:

    DWORD            m_dwStatus;            // Whether or not the rasterizer has been initialized.

// Frame buffer:

    DWORD            m_dwScreenFormat;      // Image format (8, 444, 555, 565, 1555, 32)
    BYTE           * m_pbScreen;            // Frame buffer bytes.
    DWORD            m_cxScreenWidth;       // Dimensions of the image.
    DWORD            m_cyScreenHeight;
    DWORD            m_cbScreenPitch;

    DWORD            m_cbPixel;             // Bytes per pixel.

// Z buffer:

    DWORD            m_dwZBufferFormat;     // Z buffer format (8, 444, 555, 565, 1555, 32).
    BYTE           * m_pbZBuffer;           // Z buffer bytes.
    DWORD            m_cbZBufferPitch;

// Texture:

    DWORD            m_dwTextureFormat;     // Texture format (8, 444, 555, 565, 1555, 32).
    WORD           * m_pwTexture;           // Texture bytes.
    DWORD            m_cxTextureWidth;      // Dimensions of the texture.
    DWORD            m_cyTextureHeight;
    float            m_TextureWidth;
    float            m_TextureHeight;

    DWORD            m_cxTextureMask;       //   They are calculated from the width and height. 
    DWORD            m_cyTextureMask;       //   They are calculated from the width and height. 
    DWORD            m_cyTextureShift;

// 3D Rendering:

    DWORD            m_dwRenderState;      // How to draw triangles/polygons.

    BOOL             m_fTargetIs555;
    int              m_cMunged3ToTargetShift0;
    int              m_cMunged3ToTargetShift1;


// NOTE not in sync with ASM below this point

    void ReevaluateState(void);
    void PatchNativeCases(void);
    void IterateNoOp(void);
    void IterateZ(void);
    void IterateTextureZ(void);
    void IterateTexture(void);
    void IterateError(void);
    void IterateGouraudZ(void);
    void IteratePerspectiveTextureGouraudZ(void);
    void IterateAffineTextureGouraudZ(void);
    void IterateZFog(void);
    void IterateGouraudZFog(void);
    void IteratePerspectiveTextureGouraudZFog(void);
    void IterateAffineTextureGouraudZFog(void);

    // Each entry i m_rgdtd[] contains bytecodes that describe how to draw that state,
    // The first bytecode specifies the main dispatch (DrawTri) target that
    // checks for special cases and does span setup, and the remaining bytecodes
    // specify what chunk processors to call for each span.
    typedef struct {
        byte    bSpanProcessor[NUM_TABLE_SPAN_VECTORS];
                                    // 0 - after-trivial-z span vector
                                    // 1 - after-texturing span vector
                                    // 2 - after-munging span vector
                                    // 3 - after-shading span vector
    } DRAWTRIDESC;

    #define SIZE_M_RGDTD 0x100

    //        bit 7      bit 6       bit 5       bit 4       bit 3        bit 2     bit 1      bit 0
    //
    //       native    texturemap  texalpha  shadealpha  shadecolor  shadegouraud  shadeI       z
    //      (1-yes,     (1-yes,     (1-yes,     (1-yes,    (1-yes,     (1-Gouraud,  (1-I,     (1-yes,
    //       0-no)       0-no)       0-no)       0-no)      0-no)       0-flat)      0-RGB)    0-no)
    //
    static DRAWTRIDESC m_rgdtd[SIZE_M_RGDTD];

    // state-based table of trivial z and backend processors, used to
    // fine-tune the vectors selected from m_rgdtd[]. This table is
    // used to patch the trivialz and backend entries in rgpspanfn[],
    // which then expand to the right thing when the bytecodes in
    // m_rgdtd[] index into it.
    //
    // table organization:
    //
    //    bit 7          bit 6            bit 5       bit 4     bit 3     bit 2    bits 1-0
    //
    //                    use
    // pixel doubled  native format  tex/shadealpha  zcompare  zwrite   alphatest  alphablend
    //   (1-yes,         (1-yes,         (1-yes,       (1-LE,   (1-yes,  (1-yes,   (3-AlphaInvAlpha,
    //    0-no)           0-no)           0-no)         0-no)    0-no)    0-no)     2-1InvAlpha,
    //                                                                              1-11,
    //                                                                              0-10)

    // Each entry i m_rgtzab[] contains bytecodes that expand through
    // pspanfnTrivialZAndBackend[] to specify the trivialz and backend span
    // processor for that state.
    typedef struct {
        byte    bTrivialZ;
        byte    bBackend;
    } TRIVIALZ_AND_BACKEND;

    #define SIZE_M_RGTZAB 0x100

    // Trivialz and backend bytecode expansion table.
    // (defined in drawtri.cpp)
    static const TRIVIALZ_AND_BACKEND RenderDevice::m_rgtzab[SIZE_M_RGTZAB];

    // state-based table of handler functions to do setup and dispatch to chunk processors
    // table organization:
    //
    //    bit 4     bit 3       bit 2     bit 1    bit 0
    //
    //     fog   perspective   Gouraud   texture     z
    //   (1-yes,   (1-yes,      (1-yes,  (1-yes,   (1-yes,
    //    0-no)     0-affine)    0-no)    0-no)     0-no)

    #define SIZE_M_RGPHANDLERFN 0x20

    static const PTRIFN m_rgphandlerfn[SIZE_M_RGPHANDLERFN];

    // Current rendering state, using above encoding.
    // As a bit of a trick, the master table (m_rgdtd[]) index is
    // stored in the lower 8 bits of dw_CurrentState, additional
    // texture info is stored in the next 8 bits (note that texturing
    // info in the master table part is in the upper part of the lower
    // byte, so it can be shared if necessary), and the m_rgtzab[] index
    // is stored in the upper 16 bits, so we can operate on both at once.
    DWORD m_dwCurrentState;

#define STATE_ALPHABLEND_1_0        (0x000 << 16)   // used for trivialz/backend state word
#define STATE_ALPHABLEND_1_1        (0x001 << 16)   // used for trivialz/backend state word
#define STATE_ALPHABLEND_1_1MINUSA  (0x002 << 16)   // used for trivialz/backend state word
#define STATE_ALPHABLEND_A_1MINUSA  (0x003 << 16)   // used for trivialz/backend state word
#define STATE_ALPHABLEND_MASK       (0x003 << 16)   // used for trivialz/backend state word

#define STATE_ALPHATEST             (0x004 << 16)   // used for trivialz/backend state word

#define STATE_Z                     0x01

#define STATE_ZWRITE                (0x008 << 16)   // used for trivialz/backend state word
#define STATE_ZCOMPARE              (0x010 << 16)   // used for trivialz/backend state word

#define STATE_SHADEI                0x02
#define STATE_SHADEGOURAUD          0x04
#define STATE_SHADECOLOR            0x08

#define STATE_TEXORSHADEALPHA       (0x20 << 16)             // used for trivialz/backend state word
#define STATE_USENATIVE             ((0x40 << 16) | 0x80)    // used for trivialz/backend state word
                                                             // and also master state

#define STATE_SHADEALPHA            0x10
#define STATE_TEXALPHA              0x20
#define STATE_TEXTURECOLOR          0x40
//#define STATE_USENATIVE             ((0x40 << 16) | 0x80)    // used for trivialz/backend state word
//                                                             // and also master state

#define STATE_ZHANDLER              0x100
#define STATE_TEXTUREHANDLER        0x200
#define STATE_GOURAUDHANDLER        0x400
#define STATE_PERSPECTIVE           0x800
#define STATE_FOG                   0x1000

#define STATE_CANT_USE_NATIVE       0x2000          // used by fog, alpha 11, and non-native
                                                    // textures to indicate that native mode
                                                    // can't be used
#define STATE_CANT_USE_NATIVE_NONFOG 0x4000         // used by alpha 11, non-native textures,
                                                    // and clamp textures
                                                    // (non-fog causes of non-nativity) to
                                                    // indicate that native mode can't be used,
                                                    // so if fog gets turned off, we can tell
                                                    // if we can then go native
#define STATE_MONO_FOG              0x8000          // set if the fog color is to be
                                                    // based only on the blue component
                                                    // of the fog color, which is used
                                                    // as the fog intensity

#define STATE_PIXDOUBLE             (0x80 << 16)    // used for trivialz/backend state word

#define MASTER_STATE_MASK           0xFF
#define HANDLER_SHIFT               8
#define HANDLER_MASK                0x1F    // after shift
#define TRIVIALZ_AND_BACKEND_SHIFT  16


    // handler to jump to for current rendering state
    PTRIFN m_pfnDrawTri;

    CDirect3DDevice *m_pcd3dd; // CD3DDevice this RenderDevice is embedded in

public:
    RenderDevice();
    ~RenderDevice();

    void SetCD3DD(CDirect3DDevice * pcd3dd) { m_pcd3dd = pcd3dd; }

    // Frame buffer:

    void InitScreen(DWORD dwFormat, BYTE *pbScreen, DWORD cbPitch, DWORD cxWidth, DWORD cyHeight);

    void SetScreen(BYTE *pbScreen);
    void SetScreenPitch(DWORD cbPitch);
    inline DWORD GetScreenFormat() { return m_dwScreenFormat; }
    inline BYTE * GetScreen() { return m_pbScreen; }
    inline DWORD GetScreenWidth() { return m_cxScreenWidth; }
    inline DWORD GetScreenHeight() { return m_cyScreenHeight; }
    inline DWORD GetScreenPitch() { return m_cbScreenPitch; }

    void InitZBuffer(DWORD dwFormat, BYTE *pbZBuffer, DWORD cbPitch);

    void SetZBuffer(BYTE *pbZBuffer);
    void SetZBufferPitch(DWORD cbPitch);
    inline DWORD GetZBufferFormat() { return m_dwZBufferFormat; }
    inline BYTE * GetZBuffer() { return m_pbZBuffer; }
    inline DWORD GetZBufferPitch() { return m_cbZBufferPitch; }

    // Texture:

    void InitTexture(DWORD dwFormat, BYTE *pbTexture, DWORD cbPitch, DWORD cxWidth, DWORD cyHeight,
                     WORD * pdwColorTable);

    inline DWORD GetTextureFormat() { return m_dwTextureFormat; }
    inline WORD * GetTexture() { return m_pwTexture; }
    inline DWORD GetTextureWidth() { return m_cxTextureWidth; }
    inline DWORD GetTextureHeight() { return m_cyTextureHeight; }

    // Color:

    DWORD Color2Pixel(COLOR col);

    // Triangle/Polygon routines:

    void SetRenderState(DWORD dwState);

    // 2D routines:

    void Line(unsigned int color, PIXEL x1,PIXEL y1,PIXEL x2,PIXEL y2);
    void Point(unsigned int color, PIXEL x1,PIXEL y1);

    void DrawTri(D3DTLVERTEX *P0, D3DTLVERTEX *P1, D3DTLVERTEX *P2);

    inline void StateReevaluationNeeded(void)
    {
        m_pfnDrawTri = &RenderDevice::ReevaluateState;
    }
    
    void SetTargetIs555(BOOL f) { m_fTargetIs555 = f; }
    void SetMunged3ToTargetShift0(int c) { m_cMunged3ToTargetShift0 = c; }
    void SetMunged3ToTargetShift1(int c) { m_cMunged3ToTargetShift1 = c; }
    void UpdateRenderData(void);
    void VerifyUV(void);
};

//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------

extern "C" void __cdecl GRF_LineNoClip (DWORD color, PIXEL x1, PIXEL y1, PIXEL x2, PIXEL y2);
extern "C" void __cdecl GRF_PointNoClip (DWORD color, PIXEL x1, PIXEL y1);

#endif // _GRF_TYPES_
