/******************************Module*Header**********************************\
*
*                           *******************
*                           * GDI SAMPLE CODE *
*                           *******************
*
* Module Name: gdi.h
*
* Contains all the gdi related stuff
*
* Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
* Copyright (c) 1995-1999 Microsoft Corporation.  All rights reserved.
\*****************************************************************************/
#ifndef __GDI__H__
#define __GDI__H__

typedef struct _PDev PDev;

#define CLIP_LIMIT              50  // We'll take 800 bytes of stack space

typedef struct _ClipEnum
{
    LONG    c;
    RECTL   arcl[CLIP_LIMIT];       // Space for enumerating complex clipping
} ClipEnum;                         /* ce, pce */

//
// Text stuff. Specifies foreground and background colours for faking a 1bpp
// XLATEOBJ
//
typedef struct _XlateColors
{       
    ULONG   iBackColor;
    ULONG   iForeColor;
} XlateColors;

#define SF_VM           0x01        // kept in video memory
#define SF_SM           0x02        // kept in system memory
#define SF_AGP          0x04        // kept in AGP memory
#define SF_LIST         0x08        // in surface list
#define SF_ALLOCATED    0x10        // surface memory allocated by us
#define SF_DIRECTDRAW   0x20        // wrapper of a Direct Draw surface

typedef ULONG SurfFlags;

typedef struct _Surf
{
    SurfFlags       flags;          // Type (video memory or system memory)

    PDev*           ppdev;          // Need this for deleting the bitmap

    struct _Surf*   psurfNext;
    struct _Surf*   psurfPrev;
    
    ULONG           cBlt;           // Counts down the number of blts necessary
                                    // at the current uniqueness before we'll
                                    // consider putting the DIB back into
                                    // off-screen memory
    ULONG           iUniq;          // Tells us whether there have been any
                                    // heap 'free's since the last time we
                                    // looked at
    LONG            cx;             // Bitmap width in pixels
    LONG            cy;             // Bitmap height in pixels
    union
    {
        ULONG       ulByteOffset;   // Offset from start of video memory if
                                    // DT_VM
        VOID*       pvScan0;        // pointer to system memory if DT_SM
    };
    LONG            lDelta;         // Stride in bytes for this bitmap
    VIDEOMEMORY*    pvmHeap;        // DirectDraw heap this was allocated from
    HSURF           hsurf;          // Handle to associated GDI surface (if any)
                                    // this DIB

    // New fields to support linear heap allocation of surface
    // Only valid if dt == DT_VM
    ULONG           ulPackedPP;     // padcked partial products needed by
                                    // Permedia hardware for given surface
                                    // lDelta
    ULONG           ulPixOffset;    // Pixel Offset from start of video memory
    ULONG           ulPixDelta;     // stride in pixels

    ULONG           ulChecksum;

} Surf;                             // dsurf, pdsurf

#define NUM_BUFFER_POINTS   96      // Maximum number of points in a path
                                    //   for which we'll attempt to join
                                    //   all the path records so that the
                                    //   path may still be drawn by FastFill
#define FIX_SHIFT 4L
#define FIX_MASK (- (1 << FIX_SHIFT))

//
// Maximum number of rects we'll fill per call to the fill code
//
#define MAX_PATH_RECTS  50
#define RECT_BYTES      (MAX_PATH_RECTS * sizeof(RECTL))
#define EDGE_BYTES      (TMP_BUFFER_SIZE - RECT_BYTES)
#define MAX_EDGES       (EDGE_BYTES/sizeof(EDGE))

#define RIGHT 0
#define LEFT  1
#define NEARLY_ONE              0x0000FFFF

//
// Describe a single non-horizontal edge of a path to fill.
//
typedef struct _EDGE
{
    PVOID pNext;
    INT iScansLeft;
    INT X;
    INT Y;
    INT iErrorTerm;
    INT iErrorAdjustUp;
    INT iErrorAdjustDown;
    INT iXWhole;
    INT iXDirection;
    INT iWindingDirection;
} EDGE, *PEDGE;

typedef struct _EDGEDATA
{
    LONG      lCurrentXPos;     // Current x position
    LONG      lXAdvance;        // Number of pixels to advance x on each scan
    LONG      lError;           // Current DDA error
    LONG      lErrorUp;         // DDA error increment on each scan
    LONG      lErrorDown;       // DDA error adjustment
    POINTFIX* pptfx;            // Points to start of current edge
    LONG      lPtfxDelta;       // Delta (in bytes) from pptfx to next point
    LONG      lNumOfScanToGo;   // Number of scans to go for this edge
} EDGEDATA;                     // Ed, pEd

//
//
// The x86 C compiler insists on making a divide and modulus operation
// into two DIVs, when it can in fact be done in one.  So we use this
// macro.
//
// Note: QUOTIENT_REMAINDER implicitly takes unsigned arguments.

#if defined(i386)

#define QUOTIENT_REMAINDER(ulNumerator, ulDenominator, ulQuotient, ulRemainder) \
{                                                               \
    __asm mov eax, ulNumerator                                  \
    __asm sub edx, edx                                          \
    __asm div ulDenominator                                     \
    __asm mov ulQuotient, eax                                   \
    __asm mov ulRemainder, edx                                  \
}

#else

#define QUOTIENT_REMAINDER(ulNumerator, ulDenominator, ulQuotient, ulRemainder) \
{                                                               \
    ulQuotient  = (ULONG) ulNumerator / (ULONG) ulDenominator;  \
    ulRemainder = (ULONG) ulNumerator % (ULONG) ulDenominator;  \
}

#endif

//
// Rendering constant definition
//
#define __RENDER_TEXTURE_ENABLE             (1 << 13)

#define __FX_TEXREADMODE_SWRAP_REPEAT       (1 << 1)
#define __FX_TEXREADMODE_TWRAP_REPEAT       (1 << 3)
#define __FX_TEXREADMODE_8HIGH              (3 << 13)
#define __FX_TEXREADMODE_8WIDE              (3 << 9)
#define __FX_TEXREADMODE_2048HIGH           (11 << 13)
#define __FX_TEXREADMODE_2048WIDE           (11 << 9)

#define __FX_TEXTUREREADMODE_PACKED_DATA    (1 << 24)

#define __FX_8x8REPEAT_TEXTUREREADMODE      ( __PERMEDIA_ENABLE               \
                                            | __FX_TEXREADMODE_TWRAP_REPEAT   \
                                            | __FX_TEXREADMODE_SWRAP_REPEAT   \
                                            | __FX_TEXREADMODE_8HIGH          \
                                            | __FX_TEXREADMODE_8WIDE)

#define __FX_TEXTUREDATAFORMAT_32BIT_RGBA   0x00
#define __FX_TEXTUREDATAFORMAT_32BIT        0x10
#define __FX_TEXTUREDATAFORMAT_8BIT         0xe
#define __FX_TEXTUREDATAFORMAT_16BIT        0x11
#define __FX_TEXTUREDATAFORMAT_4BIT         0xf

#define __P2_TEXTURE_DATAFORMAT_FLIP        (1 << 9)

#define __FX_TEXLUTMODE_DIRECT_ENTRY        (1 << 1)
#define __FX_TEXLUTMODE_4PIXELS_PER_ENTRY   (2 << 10)   //log2
#define __FX_TEXLUTMODE_2PIXELS_PER_ENTRY   (1 << 10)   //log2
#define __FX_TEXLUTMODE_1PIXEL_PER_ENTRY    0           //log2

#define STRETCH_MAX_EXTENT 32767

//
//-----------------------Function***Prototypes--------------------------------
//
// Low-level blt function prototypes
//
//----------------------------------------------------------------------------
typedef struct _GFNPB
{
    VOID (*pgfn)(struct _GFNPB *); // pointer to graphics function

    PDev *      ppdev;      // driver ppdev
    
    Surf *      psurfDst;   // destination surface
    RECTL *     prclDst;    // original unclipped destination rectangle
    
    Surf *      psurfSrc;   // source surface
    RECTL *     prclSrc;    // original unclipped source rectangle
    POINTL *    pptlSrc;    // original unclipped source point
                            // NOTE: pdsurfSrc must be null if
                            // there is no source.  If there is
                            // a source either (pptlSrc must be
                            // valid) or (pptlSrc is NULL and prclSrc
                            // is valid).
    
    RECTL *     pRects;     // rectangle list
    LONG        lNumRects;  // number of rectangles in list
    ULONG       colorKey;   // colorKey for transparent operations
    ULONG       solidColor; // solid color used in fills
    RBrush *    prbrush;    // pointer to brush
    POINTL *    pptlBrush;  // brush origin
    CLIPOBJ *   pco;        // clipping object
    XLATEOBJ *  pxlo;       // color translatoin object
    POINTL *    pptlMask;   // original uncliped mask origin
    ULONG       ulRop4;     // original rop4
    UCHAR       ucAlpha;    // alpha value for constant blends
    TRIVERTEX * ptvrt;      // verticies used for gradient fills
    ULONG       ulNumTvrt;  // number of verticies
    PVOID       pvMesh;     // connectivity for gradient fills
    ULONG       ulNumMesh;  // number of connectivity elements
    ULONG       ulMode;     // drawing mode
    SURFOBJ *   psoSrc;     // GDI managed surface source
    SURFOBJ *   psoDst;     // GDI managed surface destination
} GFNPB;

long flt_to_fix_1_30(float f);

BOOL    bConstructGET(EDGE*     pGETHead,
                      EDGE*     pFreeEdges,
                      PATHOBJ*  ppo,
                      PATHDATA* pd,
                      BOOL      bMore,
                      RECTL*    pClipRect);

EDGE*   pAddEdgeToGET(EDGE*     pGETHead,
                      EDGE*     pFreeEdge,
                      POINTFIX* ppfxEdgeStart,
                      POINTFIX* ppfxEdgeEnd,
                      RECTL*    pClipRect);

void    vAdjustErrorTerm(INT*   pErrorTerm,
                         INT    iErrorAdjustUp,
                         INT    iErrorAdjustDown,
                         INT    yJump,
                         INT*   pXStart,
                         INT    iXDirection);

VOID    vAdvanceAETEdges(EDGE* pAETHead);

VOID    vMoveNewEdges(EDGE* pGETHead,
                      EDGE* pAETHead,
                      INT   iCurrentY);

VOID    vXSortAETEdges(EDGE* pAETHead);

//
// Prototypes for lower level rendering functions
//
BOOL    bFillPolygon(PDev*      ppdev,
                     Surf*      pSurfDst,
                     LONG       lEdges,
                     POINTFIX*  pptfxFirst,
                     ULONG      ulSolidColor,
                     ULONG      ulRop4,
                     CLIPOBJ*   pco,
                     RBrush*    prb,
                     POINTL*    pptlBrush);

BOOL    bFillSpans(PDev*      ppdev,
                   Surf*      pSurfDst,
                   LONG       lEdges,
                   POINTFIX*  pptfxFirst,
                   POINTFIX*  pptfxTop,
                   POINTFIX*  pptfxLast,
                   ULONG      ulSolidColor,
                   ULONG      ulRop4,
                   CLIPOBJ*   pco,
                   RBrush*    prb,
                   POINTL*    pptlBrush);

BOOL    bInitializeStrips(PDev*     ppdev,
                          ULONG     iSolidColor,
                          DWORD     logicop,
                          RECTL*    prclClip);

void    vAlphaBlend(GFNPB * ppb);
void    vAlphaBlendDownload(GFNPB * ppb);
void    vConstantAlphaBlend(GFNPB * ppb);
void    vConstantAlphaBlendDownload(GFNPB * ppb);
void    vCopyBlt(GFNPB * ppb);
void    vCopyBltNative(GFNPB * ppb);
void    vGradientFillRect(GFNPB * ppb);
void    vGradientFillTri(GFNPB * ppb);
void    vImageDownload(GFNPB * ppb);
void    vInvert(GFNPB * ppb);
void    vMonoDownload(GFNPB * ppb);
void    vMonoOffset(GFNPB * ppb);
void    vMonoPatFill(GFNPB * ppb);
void    vPatFill(GFNPB * ppb);
void    vPatternFillRects(GFNPB * ppb);
void    vPatRealize(GFNPB * ppb);
void    vResetStrips(PDev* ppdev);
void    vRop2Blt(GFNPB * ppb);
void    vSolidFill(GFNPB * ppb);
void    vSolidFillWithRop(GFNPB * ppb);
void    vTransparentBlt(GFNPB * ppb);

//
// Text stuff
//
BOOL    bEnableText(PDev* ppdev);
VOID    vDisableText(PDev* ppdev);
VOID    vAssertModeText(PDev* ppdev, BOOL bEnable);

//
// Palette stuff
//
BOOL    bEnablePalette(PDev* ppdev);
BOOL    bInitializePalette(PDev* ppdev, DEVINFO* pdi);
VOID    vDisablePalette(PDev* ppdev);
VOID    vUninitializePalette(PDev* ppdev);

//
// Upload and download functions
//
VOID    vDownloadNative(GFNPB* ppb);
VOID    vUploadNative(GFNPB* ppb);

//
// StretchBlt stuff
//
DWORD   dwGetPixelSize(ULONG    ulBitmapFormat,
                       DWORD*   pdwFormatBits,
                       DWORD*   pdwFormatExtention);

BOOL    bStretchInit(SURFOBJ*    psoDst,
                     SURFOBJ*    psoSrc);

VOID    vStretchBlt(SURFOBJ*    psoDst,
                    SURFOBJ*    psoSrc,
                    RECTL*      rDest,
                    RECTL*      rSrc,
                    RECTL*      prclClip);

VOID    vStretchReset(PDev* ppdev);

//
// Work in progress
//

VOID    vCheckGdiContext(PPDev ppdev);
VOID    vOldStyleDMA(PPDev ppdev);
VOID    vNewStyleDMA(PPDev ppdev);

// Input buffer access methods

//
// InputBufferStart/InputBufferContinue/InputBufferCommit
//
//     This method is used when the caller does not know
//     the upper limit of the amount of space that needs to be reserved
//     or needs to reserve space that exceeds that maximum allowed to
//     be reserved MAX_FIFO_RESERVATION.
//
//     InputBufferStart() is used to get a pointer to the first available entry in
//     the input fifo, a pointer to the end of the reservation and
//     a pointer to the end of the usable area of the buffer.
//
//     InputBufferContinue() is called to extend the current reservation.
//
//     InputBufferCommit() is called when the caller is done using the reserved space.
//
//     Please see textout.c for an example usage of these methods.
//
// InputBufferReserve/InputBufferCommit
//
//     This method is used when the caller needs to make only one
//     reservation of some small known quantity.
//
//     InputBufferReserve() is called to establish the reservation.
//
//     InputBufferCommit() is called when the caller is done using the reserved space.
//
//     Please see textout.c for the usage of InputBufferReserve/InputBufferCommit. 
//
// A caller is free to use these access methods at any time.  Once either
// InputBufferStart or InputBufferReserve is called, the caller must pair the
// call with either a InputBufferFinish or a InputBufferCommit before making
// another reservation.
//
// A caller is free to use either of these methods at any time.
//
// Before calling any of the CPermedia class access methods, the caller
// must call InputBufferFlush (see below).  Because of this, a caller must
// call InputBufferFlush or InputBufferExecute before returning to GDI.
//
// When the caller is done and wishes to initial the transmission of what
// has been placed in the input fifo, the caller can call InputBufferExecute
// (see below).
// 
// InputBufferFlush
//
//      InputBufferFlush is a neccessary evil only as long as these macros are not
//      part of the official input buffer access schemes.  Flush is really
//      the means we sync up our copy of the input buffer state to the
//      CPermedia class.  If these methods were instead part of the fundamental
//      input fifo mechanism, then we could do away with the need for Flush.
//
// InputBufferExecute
//
//      Flush is a neccessary evil only as long as these macros are not
//      part of the official input buffer access schemes.  If and when these
//      new access schemes are made part of the official input fifo buffer
//      mechanism, then it can be replaced by that mechanism's input fifo
//      execute method.
//
//
// InputBufferMakeSpace
//
//      This is a private call and no one should find need to call it directly.
//
//
// Other Notes:
//
// We will play with making the access routines inline functions instead
// of macros taking a look at the code generated.  If acceptable,
// these macros may turn into function calls in the non-Debug build.
//
// The InputBufferStart/InputBufferContinue mechansism keeps state on the stack
// to avoid the dereferences to ppdev freeing up a register in cases where ppdev
// references are not needed in the inner loop that contains InputBufferContinue.
//

// MAX_IN_FIFO_RESERVATION should be bumped up considerably when we add an
// emulation buffer for the non-DMA case

#define MAX_INPUT_BUFFER_RESERVATION (INPUT_BUFFER_SIZE>>3) // in longs

#if DBG
extern
void InputBufferStart(
    PPDev   ppdev,
    ULONG   ulLongs,
    PULONG* ppulBuffer,
    PULONG* ppulBufferEnd,
    PULONG* ppulReservationEnd);

extern
void InputBufferContinue(
    PPDev   ppdev,
    ULONG   ulLongs,
    PULONG* ppulBuffer,
    PULONG* ppulBufferEnd,
    PULONG* ppulReservationEnd);

extern
void InputBufferReserve(
    PPDev   ppdev,
    ULONG   ulLongs,
    PULONG* ppulBuffer);

extern
void InputBufferCommit(
    PPDev   ppdev,
    PULONG  pulBuffer);

#else
#define InputBufferStart(ppdev, ulLongs, ppulBuffer, ppulBufferEnd, ppulReservationEnd) \
{ \
    *(ppulBuffer) = ppdev->pulInFifoPtr; \
    *(ppulReservationEnd) =  *(ppulBuffer) + ulLongs; \
    *(ppulBufferEnd) = ppdev->pulInFifoEnd; \
    if(*(ppulReservationEnd) > *(ppulBufferEnd)) \
    { \
        InputBufferSwap(ppdev); \
        *(ppulBuffer) = ppdev->pulInFifoPtr; \
        *(ppulReservationEnd) =  *(ppulBuffer) + ulLongs; \
        *(ppulBufferEnd) = ppdev->pulInFifoEnd; \
    } \
}

#define InputBufferContinue(ppdev, ulLongs, ppulBuffer, ppulBufferEnd, ppulReservationEnd) \
{ \
    *(ppulReservationEnd) = *(ppulBuffer) + ulLongs; \
    if(*(ppulReservationEnd) > *(ppulBufferEnd)) \
    { \
        ppdev->pulInFifoPtr = *(ppulBuffer); \
        InputBufferSwap(ppdev); \
        *(ppulBuffer) = ppdev->pulInFifoPtr; \
        *(ppulReservationEnd) = *(ppulBuffer) + ulLongs; \
        *(ppulBufferEnd) = ppdev->pulInFifoEnd; \
    } \
}

#define InputBufferReserve(ppdev, ulLongs, ppulBuffer) \
{ \
    if(ppdev->pulInFifoPtr + ulLongs > ppdev->pulInFifoEnd) \
    { \
        InputBufferSwap(ppdev); \
    } \
    *(ppulBuffer) = ppdev->pulInFifoPtr; \
}

#define InputBufferCommit(ppdev, pulBuffer) ppdev->pulInFifoPtr = pulBuffer

#endif

void FASTCALL InputBufferFlush(PPDev ppdev);
void FASTCALL InputBufferSwap(PPDev ppdev);

void InputBufferSync(PPDev ppdev);

extern BOOL bGdiContext;

#endif // __GDI__H__

