/******************************Module*Header*******************************\
* Module Name: span.h
*
* This include file is used to generate various flavors of textured and
* shaded spans, or scanlines.
*
* 14-Oct-1994   mikeke  Combined span_t.h and span_s.h to share common
*                       code.  Speeded things up a little.  Had a little
*                       fun with the C preprocessor.
* 11-April-1994 Otto Berkes [ottob] Created
*
* Copyright (c) 1994 Microsoft Corporation
\**************************************************************************/

#undef STRING1
#undef STRING2
#undef STRING3
#undef STRING4

#if GENERIC
    void FASTCALL __fastGenSpan
#else
    #if ZBUFFER
        #define STRING1 __fastGenMask
    #else
        #define STRING1 __fastGen
    #endif

    #if TEXTURE
        #if SHADE
            #define STRING2 Tex
        #else
            #define STRING2 TexDecal
        #endif
    #elif RGBMODE
        #define STRING2 RGB
    #else
        #define STRING2 CI
    #endif

    #if DITHER
        #define STRING3 STRCAT2(COLORFORMAT, Dith)
    #else
        #define STRING3 COLORFORMAT
    #endif

    #define STRING4 Span

    void FASTCALL STRCAT4(STRING1, STRING2, STRING3, STRING4)
#endif
(__GLGENcontext *gengc)
{
    #if (SHADE) || !(RGBMODE) || (TEXTURE && DITHER)
        ULONG rAccum;
        LONG rDelta;

        #if RGBMODE
            ULONG gAccum;
            ULONG bAccum;
            LONG gDelta;
            LONG bDelta;
        #endif
    #endif

    #if TEXTURE
        LONG sAccum;
        LONG tAccum;
        LONG sDelta;
        LONG tDelta;
        ULONG tShift;
        ULONG sMask, tMask;
    #endif

    ULONG rShift;
    ULONG rBits;
    #if RGBMODE
        ULONG gShift;
        ULONG gBits;
        ULONG bShift;
        ULONG bBits;
    #endif

    BYTE *pPix;
    BYTE *texAddr;
    BYTE *texBits;
    LONG count;
    LONG totalCount;

    #if DITHER
        PDWORD pdither;
        #if (BPP == 24) || (GENERIC)
            DWORD iDither;
        #endif
    #endif

    #if (BPP == 8) || (GENERIC)
        BYTE *pXlat;
    #elif (!RGBMODE)
        ULONG *pXlat;
    #endif

    #if GENERIC
        DWORD flags = GENACCEL(gengc).flags;
        DWORD bpp = GENACCEL(gengc).bpp;
    #endif

    #if GENERIC
        if (flags & GEN_TEXTURE)
    #endif
    #if TEXTURE
        {
            __GLtexture *tex = ((__GLcontext *)gengc)->texture.currentTexture;

            sMask = GENACCEL(gengc).sMask;
            tMask = GENACCEL(gengc).tMask;
            tShift = GENACCEL(gengc).tShift;
            sDelta = GENACCEL(gengc).spanDelta.s;
            tDelta = GENACCEL(gengc).spanDelta.t;
            sAccum = GENACCEL(gengc).spanValue.s;
            tAccum = GENACCEL(gengc).spanValue.t;
            #if !(SHADE) && !(DITHER) && ((BPP == 8) || (BPP == 16))
                texAddr = (BYTE *)GENACCEL(gengc).texImageReplace;
            #else
                texAddr = (BYTE *)GENACCEL(gengc).texImage;
            #endif
        }
    #endif

    // get color deltas and accumulators

    #ifndef RSHIFT
        rShift = gengc->gsurf.pfd.cRedShift;
	rBits = gengc->gsurf.pfd.cRedBits;
        #if RGBMODE
            gShift = gengc->gsurf.pfd.cGreenShift;
	    gBits = gengc->gsurf.pfd.cGreenBits;
            bShift = gengc->gsurf.pfd.cBlueShift;
	    bBits = gengc->gsurf.pfd.cBlueBits;
        #endif
    #endif

    #if (GENERIC)
        if (!(flags & GEN_SHADE) && 
            (flags & (GEN_TEXTURE | GEN_DITHER)) == (GEN_TEXTURE | GEN_DITHER)) {
            rAccum = (GENACCEL(gengc).spanValue.r >> rBits) & 0xff00;
            gAccum = (GENACCEL(gengc).spanValue.g >> gBits) & 0xff00;
            bAccum = (GENACCEL(gengc).spanValue.b >> bBits) & 0xff00;
            rDelta = 0;
            gDelta = 0;
            bDelta = 0;
        } else {
            rAccum = GENACCEL(gengc).spanValue.r;
            gAccum = GENACCEL(gengc).spanValue.g;
            bAccum = GENACCEL(gengc).spanValue.b;
            rDelta = GENACCEL(gengc).spanDelta.r;
            gDelta = GENACCEL(gengc).spanDelta.g;
            bDelta = GENACCEL(gengc).spanDelta.b;
        }
    #else

        #if !(SHADE) && (TEXTURE) && (DITHER)
            #ifndef RSHIFT
                rAccum = (GENACCEL(gengc).spanValue.r >> rBits) & 0xff00;
                gAccum = (GENACCEL(gengc).spanValue.g >> gBits) & 0xff00;
                bAccum = (GENACCEL(gengc).spanValue.b >> bBits) & 0xff00;
            #else
                rAccum = (GENACCEL(gengc).spanValue.r >> RBITS) & 0xff00;
                gAccum = (GENACCEL(gengc).spanValue.g >> GBITS) & 0xff00;
                bAccum = (GENACCEL(gengc).spanValue.b >> BBITS) & 0xff00;
            #endif
        #else
            #if (SHADE) || !(RGBMODE)
                rAccum = GENACCEL(gengc).spanValue.r;
                #if RGBMODE
                    gAccum = GENACCEL(gengc).spanValue.g;
                    bAccum = GENACCEL(gengc).spanValue.b;
                #endif
            #endif
        #endif

        #if (SHADE) || !(RGBMODE)
            rDelta = GENACCEL(gengc).spanDelta.r;
            #if RGBMODE
                gDelta = GENACCEL(gengc).spanDelta.g;
                bDelta = GENACCEL(gengc).spanDelta.b;
            #endif
        #endif
    #endif

    // get address of destination

    if (GENACCEL(gengc).flags & SURFACE_TYPE_DIB) {
        pPix = GENACCEL(gengc).pPix +
            gengc->gc.polygon.shader.frag.x * (BPP / 8);
    } else {
        pPix = gengc->ColorsBits;
    }

    // set up pointer to translation table as needed

    #if GENERIC
        if ((bpp != 8) && (!(flags & GEN_RGBMODE))) {
            pXlat = gengc->pajTranslateVector + sizeof(DWORD);
        }
    #else
        #if (BPP == 8)
            // No need to set up xlat vector
        #elif (!RGBMODE)
            pXlat = (ULONG *)(gengc->pajTranslateVector + sizeof(DWORD));
        #endif
    #endif

    #if GENERIC
        if (GENACCEL(gengc).flags & GEN_DITHER) {
            // LATER !!! mikeke
            // fix this so the destination is always aligned with the x value
            // !!! make sure this is correct in generic case
            // look at flat it assumes alignment
            //

            if (GENACCEL(gengc).flags & GEN_TEXTURE)
                pdither = ditherTexture;
            else
                pdither = ditherShade;

            pdither += (gengc->gc.polygon.shader.frag.y & 0x3) * 8;
            iDither = gengc->gc.polygon.shader.frag.x & 0x3;
        } else {
            // LATER !!! mikeke
            // add these outside of the loop

            if (!(GENACCEL(gengc).flags & GEN_TEXTURE)) {
                rAccum += 0x0800;
                gAccum += 0x0800;
                bAccum += 0x0800;
            }
            //pdither = 0;
        }
    #else
        #if DITHER
            // LATER !!! mikeke
            // fix this so the destination is always aligned with the x value
            // !!! make sure this is correct in generic case
            // look at flat it assumes alignment
            //

            #if (BPP == 24)
                pdither = (gengc->gc.polygon.shader.frag.y & 0x3) * 8
                    #if (TEXTURE)
                        + ditherTexture
                    #else
                        + ditherShade
                    #endif
                    ;
                iDither = gengc->gc.polygon.shader.frag.x & 0x3;
            #else
                pdither = (gengc->gc.polygon.shader.frag.y & 0x3) * 8
                    #if (TEXTURE)
                        + ditherTexture
                    #else
                        + ditherShade
                    #endif

                    + ((
                          (gengc->gc.polygon.shader.frag.x & 0x3)
                        - (((ULONG_PTR)pPix / (BPP / 8)) & 0x3)
                      ) & 0x3 );
            #endif
        #else
            // LATER !!! mikeke
            // add these outside of the loop
            #if !(RGBMODE)
                rAccum += 0x0800;
            #else //RGBMODE
                #if (TEXTURE) && !(GENERIC)
                #else //!TEXTURE
                    rAccum += 0x0800;
                    gAccum += 0x0800;
                    bAccum += 0x0800;
                #endif //TEXTURE
            #endif //RGBMODE
        #endif
    #endif

    #if GENERIC
        {
            ULONG *pMask;

            pMask = gengc->gc.polygon.shader.stipplePat;

            for (totalCount = gengc->gc.polygon.shader.length;
                    totalCount > 0; totalCount -= 32
                ) {
                ULONG maskTest;
                ULONG mask = *pMask++;

                if (mask == 0) {
                    #if (SHADE) || !(RGBMODE)
                        rAccum += (rDelta << 5);
                        #if RGBMODE
                            gAccum += (gDelta << 5);
                            bAccum += (bDelta << 5);
                        #endif
                    #endif

                    #if TEXTURE
                        sAccum += (sDelta << 5);
                        tAccum += (tDelta << 5);
                    #endif

                    //iDither = (iDither + 32) & 0x3;
                    pPix += (32 * (BPP / 8));
                } else {
                    maskTest = 0x80000000;

                    if ((count = totalCount) > 32)
                        count = 32;

                    for (; count; count--, maskTest >>= 1) {
                        if (mask & maskTest) {
                            #include "spangen.h"
                        }
                        #include "span3.h"
                    }
                }
            }
        }
    #elif ZBUFFER
        {
            GLuint zAccum = gengc->gc.polygon.shader.frag.z;
            GLint  zDelta = gengc->gc.polygon.shader.dzdx;
            PBYTE zbuf = (PBYTE)gengc->gc.polygon.shader.zbuf;

            if (GENACCEL(gengc).flags & GEN_LESS) {
                if (gengc->gc.modes.depthBits == 16) {
                    for (count = gengc->gc.polygon.shader.length;;) {
                        if ( ((__GLz16Value)(zAccum >> Z16_SHIFT)) < *((__GLz16Value*)zbuf) ) {
                            *((__GLz16Value*)zbuf) = ((__GLz16Value)(zAccum >> Z16_SHIFT));
                            #include "span2.h"
                        }
                        if (--count == 0)
                            return;
                        zbuf += 2;
                        zAccum += zDelta;
                        #include "span3.h"
                    }
                } else {
                    for (count = gengc->gc.polygon.shader.length;;) {
                        if ( zAccum < *((GLuint*)zbuf) ) {
                            *((GLuint*)zbuf) = zAccum;
                            #include "span2.h"
                        }
                        if (--count == 0)
                            return;
                        zbuf += 4;
                        zAccum += zDelta;
                        #include "span3.h"
                    }
                }
            } else {
                if (gengc->gc.modes.depthBits == 16) {
                    for (count = gengc->gc.polygon.shader.length;;) {
                        if ( ((__GLz16Value)(zAccum >> Z16_SHIFT)) <= *((__GLz16Value*)zbuf) ) {
                            *((__GLz16Value*)zbuf) = ((__GLz16Value)(zAccum >> Z16_SHIFT));
                            #include "span2.h"
                        }
                        if (--count == 0)
                            return;
                        zbuf += 2;
                        zAccum += zDelta;
                        #include "span3.h"
                    }
                } else {
                    for (count = gengc->gc.polygon.shader.length;;) {
                        if ( zAccum <= *((GLuint*)zbuf) ) {
                            *((GLuint*)zbuf) = zAccum;
                            #include "span2.h"
                        }
                        if (--count == 0)
                            return;
                        zbuf += 4;
                        zAccum += zDelta;
                        #include "span3.h"
                    }
                }
            }
        }
    #else
        for (count = gengc->gc.polygon.shader.length;;) {
            #include "span2.h"
            if (--count == 0)
                return;
            #include "span3.h"
        }
    #endif
}

#undef ditherVal