/******************************Module*Header*******************************\
* Module Name: genaccel.c                                                  *
*                                                                          *
* This module provides support routines for acceleration functions.        *
*                                                                          *
* Created: 18-Feb-1994                                                     *
* Author: Otto Berkes [ottob]                                              *
*                                                                          *
* Copyright (c) 1994 Microsoft Corporation                                 *
\**************************************************************************/

#include "precomp.h"
#pragma hdrstop

#include "genline.h"

#ifdef GL_WIN_specular_fog
#define DO_NICEST_FOG(gc)\
         ((gc->state.hints.fog == GL_NICEST) && !(gc->polygon.shader.modeFlags & __GL_SHADE_SPEC_FOG))
#else //GL_WIN_specular_fog
#define DO_NICEST_FOG(gc)\
         (gc->state.hints.fog == GL_NICEST) 
#endif //GL_WIN_specular_fog

static ULONG internalSolidTexture[4] = {0xffffffff, 0xffffffff,
                                        0xffffffff, 0xffffffff};

GENTEXCACHE *GetGenTexCache(__GLcontext *gc, __GLtexture *tex)
{
    ULONG size;
    GENTEXCACHE *pGenTex;
    ULONG internalFormat;
    GLuint modeFlags = gc->polygon.shader.modeFlags;

    // Replace maps are only used for a subset of possible modes
    //   8 or 16bpp
    //   16-bit Z
    //
    //   No dithering.  Since dithering can turn on and off there
    //   are two cases:
    //     Dither off at TexImage time but on at texturing time -
    //       We create a map that's unused
    //     Dither on and then off - We won't create a map at
    //       TexImage time but it'll be created on the fly when
    //       dithering is turned on and everything is repicked
    //
    // Replace maps aren't created for DirectDraw textures because
    // the data isn't constant
    
    if (GENACCEL(gc).bpp < 8 ||
        GENACCEL(gc).bpp > 16 ||
        ((modeFlags & (__GL_SHADE_DEPTH_TEST | __GL_SHADE_DEPTH_ITER)) &&
         gc->modes.depthBits > 16) ||
        (modeFlags & __GL_SHADE_DITHER) ||
        gc->texture.ddtex.levels > 0)
    {
        return NULL;
    }

    internalFormat = tex->level[0].internalFormat;

    // We only support 8-bit palettes that are fully populated
    if (internalFormat == GL_COLOR_INDEX16_EXT ||
        (internalFormat == GL_COLOR_INDEX8_EXT &&
         tex->paletteSize != 256))
    {
        return NULL;
    }
    
    pGenTex = tex->pvUser;

    // Check and see whether the cached information can be reused
    // for the texture passed in
    if (pGenTex != NULL)
    {
        // gc's don't match so this must be a shared texture
        // Don't attempt to create a replace map for this gc
        if (gc != pGenTex->gc)
        {
            return NULL;
        }

        // Size and format must match to reuse the existing data area
        // If they don't, release the existing buffer.  A new one
        // will then be allocated
        if (internalFormat == GL_COLOR_INDEX8_EXT)
        {
            if (pGenTex->internalFormat != internalFormat ||
                pGenTex->width != tex->paletteTotalSize)
            {
                GCFREE(gc, pGenTex);
                tex->pvUser = NULL;
            }
        }
        else
        {
            if (pGenTex->internalFormat != internalFormat ||
                pGenTex->width != tex->level[0].width ||
                pGenTex->height != tex->level[0].height)
            {
                GCFREE(gc, pGenTex);
                tex->pvUser = NULL;
            }
        }
    }

    if (tex->pvUser == NULL)
    {
        if (internalFormat == GL_COLOR_INDEX8_EXT)
        {
            size = tex->paletteTotalSize * sizeof(DWORD);
        }
        else
        {
            size = tex->level[0].width * tex->level[0].height *
                GENACCEL(gc).xMultiplier;
        }

        pGenTex = (GENTEXCACHE *)GCALLOC(gc, size + sizeof(GENTEXCACHE));

        if (pGenTex != NULL)
        {
            tex->pvUser = pGenTex;
            pGenTex->gc = gc;
            pGenTex->paletteTimeStamp =
                ((__GLGENcontext *)gc)->PaletteTimestamp;
            if (internalFormat == GL_COLOR_INDEX8_EXT)
            {
                pGenTex->height = 0;
                pGenTex->width = tex->paletteTotalSize;
            }
            else
            {
            pGenTex->height = tex->level[0].height;
            pGenTex->width = tex->level[0].width;
            }
            pGenTex->internalFormat = internalFormat;
            pGenTex->texImageReplace = (UCHAR *)(pGenTex+1);
        }
    }

    return pGenTex;
}

BOOL FASTCALL __fastGenLoadTexImage(__GLcontext *gc, __GLtexture *tex)
{
    UCHAR *texBuffer;
    GLint internalFormat = tex->level[0].internalFormat;
    GENTEXCACHE *pGenTex;

    if (tex->level[0].buffer == NULL ||
	((internalFormat != GL_BGR_EXT) &&
         (internalFormat != GL_BGRA_EXT) &&
         (internalFormat != GL_COLOR_INDEX8_EXT)))
    {
        return FALSE;
    }

    // OK, the texture doesn't have a compressed replace-mode format, so
    // make one...

    if ((internalFormat == GL_BGR_EXT) ||
        (internalFormat == GL_BGRA_EXT)) {

        ULONG size;
        UCHAR *replaceBuffer;
        ULONG bytesPerPixel = GENACCEL(gc).xMultiplier;

        pGenTex = GetGenTexCache(gc, tex);
        if (pGenTex == NULL)
        {
            return FALSE;
        }

        texBuffer = (UCHAR *)tex->level[0].buffer;
        replaceBuffer = pGenTex->texImageReplace;

        {
            __GLcolorBuffer *cfb = gc->drawBuffer;
            ULONG rShift = cfb->redShift;
            ULONG gShift = cfb->greenShift;
            ULONG bShift = cfb->blueShift;
            ULONG rBits = ((__GLGENcontext *)gc)->gsurf.pfd.cRedBits;
            ULONG gBits = ((__GLGENcontext *)gc)->gsurf.pfd.cGreenBits;
            ULONG bBits = ((__GLGENcontext *)gc)->gsurf.pfd.cBlueBits;
            BYTE *pXlat = ((__GLGENcontext *)gc)->pajTranslateVector;
            ULONG i;

            size = tex->level[0].width * tex->level[0].height;
            for (i = 0; i < size; i++, texBuffer += 4) {
                ULONG color;

                color = ((((ULONG)texBuffer[2] << rBits) >> 8) << rShift) |
                    ((((ULONG)texBuffer[1] << gBits) >> 8) << gShift) |
                    ((((ULONG)texBuffer[0] << bBits) >> 8) << bShift);

                if (GENACCEL(gc).bpp == 8)
                    *replaceBuffer = pXlat[color & 0xff];
                else
                    *((USHORT *)replaceBuffer) = (USHORT)color;

                replaceBuffer += bytesPerPixel;
            }
        }
    } else {

        ULONG size;
        ULONG *replaceBuffer;

        // If we don't have palette data yet we can't create the
        // fast version.  It will be created when the ColorTable
        // call happens
        if (tex->paletteTotalData == NULL)
        {
            return FALSE;
        }

        pGenTex = GetGenTexCache(gc, tex);
        if (pGenTex == NULL)
        {
            return FALSE;
        }

        texBuffer = (UCHAR *)tex->paletteTotalData;
        replaceBuffer = (ULONG *)pGenTex->texImageReplace;
        size = tex->paletteTotalSize;

        {
            __GLcolorBuffer *cfb = gc->drawBuffer;
            ULONG rShift = cfb->redShift;
            ULONG gShift = cfb->greenShift;
            ULONG bShift = cfb->blueShift;
            ULONG rBits = ((__GLGENcontext *)gc)->gsurf.pfd.cRedBits;
            ULONG gBits = ((__GLGENcontext *)gc)->gsurf.pfd.cGreenBits;
            ULONG bBits = ((__GLGENcontext *)gc)->gsurf.pfd.cBlueBits;
            BYTE *pXlat = ((__GLGENcontext *)gc)->pajTranslateVector;
            ULONG i;

            for (i = 0; i < size; i++, texBuffer += 4) {
                ULONG color;

                color = ((((ULONG)texBuffer[2] << rBits) >> 8) << rShift) |
                    ((((ULONG)texBuffer[1] << gBits) >> 8) << gShift) |
                    ((((ULONG)texBuffer[0] << bBits) >> 8) << bShift);

                if (GENACCEL(gc).bpp == 8)
                    color = pXlat[color & 0xff];

                *replaceBuffer++ = (color | ((ULONG)texBuffer[3] << 24));
            }
        }
    }

    GENACCEL(gc).texImageReplace =
        ((GENTEXCACHE *)tex->pvUser)->texImageReplace;

    return TRUE;
}


/*
** Pick the fastest triangle rendering implementation available based on
** the current mode set.  Use any available accelerated resources if
** available, or use the generic routines for unsupported modes.
*/

void FASTCALL __fastGenCalcDeltas(__GLcontext *gc, __GLvertex *a, __GLvertex *b, __GLvertex *c);
void FASTCALL __fastGenCalcDeltasTexRGBA(__GLcontext *gc, __GLvertex *a, __GLvertex *b, __GLvertex *c);
void FASTCALL __fastGenDrvCalcDeltas(__GLcontext *gc, __GLvertex *a, __GLvertex *b, __GLvertex *c);

void __fastGenSetInitialParameters(__GLcontext *gc, const __GLvertex *a,
                                   __GLfloat dx, __GLfloat dy);
void __fastGenSetInitialParametersTexRGBA(__GLcontext *gc, const __GLvertex *a,
                                          __GLfloat dx, __GLfloat dy);

void __ZippyFT(
    __GLcontext *gc,
    __GLvertex *a,
    __GLvertex *b,
    __GLvertex *c,
    GLboolean ccw);

VOID FASTCALL InitAccelTextureValues(__GLcontext *gc, __GLtexture *tex)
{
    ULONG wLog2;
    ULONG hLog2;

    GENACCEL(gc).tex = tex;
    GENACCEL(gc).texImage = (ULONG *)tex->level[0].buffer;
    if (tex->level[0].internalFormat == GL_COLOR_INDEX8_EXT ||
        tex->level[0].internalFormat == GL_COLOR_INDEX16_EXT)
    {
        GENACCEL(gc).texPalette = (ULONG *)tex->paletteTotalData;
    }
    else
    {
        GENACCEL(gc).texPalette = NULL;
    }

    wLog2 = tex->level[0].widthLog2;
    hLog2 = tex->level[0].heightLog2;

    GENACCEL(gc).sMask = (~(~0 << wLog2)) << TEX_SCALESHIFT;
    GENACCEL(gc).tMask = (~(~0 << hLog2)) << TEX_SCALESHIFT;
    GENACCEL(gc).tShift = TEX_SCALESHIFT - (wLog2 + TEX_SHIFTPER4BPPTEXEL);
    GENACCEL(gc).tMaskSubDiv =
        (~(~0 << hLog2)) << (wLog2 + TEX_T_FRAC_BITS + TEX_SHIFTPER1BPPTEXEL);
    GENACCEL(gc).tShiftSubDiv =
        TEX_SCALESHIFT - (wLog2 + TEX_T_FRAC_BITS + TEX_SHIFTPER1BPPTEXEL);
    GENACCEL(gc).texXScale = (__GLfloat)tex->level[0].width * TEX_SCALEFACT;
    GENACCEL(gc).texYScale = (__GLfloat)tex->level[0].height * TEX_SCALEFACT;
}

BOOL FASTCALL bUseGenTriangles(__GLcontext *gc)
{
    GLuint modeFlags = gc->polygon.shader.modeFlags;
    GLuint enables = gc->state.enables.general;
    __GLGENcontext *gengc = (__GLGENcontext *)gc;
    ULONG bpp = GENACCEL(gc).bpp;
    int iType;
    BOOL fZippy;
    BOOL bTryFastTexRGBA;
    PFNZIPPYSUB pfnZippySub;
    BOOL fUseFastGenSpan;
    GLboolean bMcdZ;
    ULONG internalFormat;
    ULONG textureMode;
    BOOL bRealTexture;
    BOOL bAccelDecal;

    if ((enables & (__GL_ALPHA_TEST_ENABLE |
                    __GL_STENCIL_TEST_ENABLE)) ||
        (modeFlags & (__GL_SHADE_STENCIL_TEST | __GL_SHADE_LOGICOP |
                      __GL_SHADE_ALPHA_TEST | __GL_SHADE_SLOW_FOG
#ifdef GL_WIN_specular_fog
                      | __GL_SHADE_SPEC_FOG
#endif //GL_WIN_specular_fog
                      )) ||
        !gc->state.raster.rMask ||
        !gc->state.raster.gMask ||
        !gc->state.raster.bMask ||
        (gc->drawBuffer->buf.flags & COLORMASK_ON) ||
        ALPHA_WRITE_ENABLED( gc->drawBuffer ) ||
        (gengc->gsurf.pfd.cColorBits < 8) ||
        ((modeFlags & __GL_SHADE_DEPTH_TEST) && (!gc->state.depth.writeEnable))
       )
        return FALSE;

    if (modeFlags & __GL_SHADE_TEXTURE) {
        internalFormat = gc->texture.currentTexture->level[0].internalFormat;
        textureMode = gc->state.texture.env[0].mode;
        bAccelDecal = (gc->texture.currentTexture->level[0].baseFormat !=
                       GL_RGBA);
        
        if (!((((textureMode == GL_DECAL) && bAccelDecal) ||
               (textureMode == GL_REPLACE) ||
               (textureMode == GL_MODULATE)) &&
              (gc->texture.currentTexture &&
               (gc->texture.currentTexture->params.minFilter == GL_NEAREST) &&
               (gc->texture.currentTexture->params.magFilter == GL_NEAREST) &&
               (gc->texture.currentTexture->params.sWrapMode == GL_REPEAT) &&
               (gc->texture.currentTexture->params.tWrapMode == GL_REPEAT) &&
               (gc->texture.currentTexture->level[0].border == 0) &&
               (internalFormat == GL_BGR_EXT ||
                internalFormat == GL_BGRA_EXT ||
                internalFormat == GL_COLOR_INDEX8_EXT))))
            return FALSE;

        InitAccelTextureValues(gc, gc->texture.currentTexture);
    }

    bMcdZ = ((((__GLGENcontext *)gc)->pMcdState != NULL) &&
             (((__GLGENcontext *)gc)->pMcdState->pDepthSpan != NULL) &&
             (((__GLGENcontext *)gc)->pMcdState->pMcdSurf != NULL) &&
             !(((__GLGENcontext *)gc)->pMcdState->McdBuffers.mcdDepthBuf.bufFlags & MCDBUF_ENABLED));

    bTryFastTexRGBA = ((gc->state.raster.drawBuffer != GL_FRONT_AND_BACK) &&
                       ((modeFlags & __GL_SHADE_DEPTH_TEST &&
                         modeFlags & __GL_SHADE_DEPTH_ITER)
                    || (!(modeFlags & __GL_SHADE_DEPTH_TEST) &&
                        !(modeFlags & __GL_SHADE_DEPTH_ITER))) &&
                       (modeFlags & __GL_SHADE_STIPPLE) == 0);

    fZippy = (bTryFastTexRGBA &&
              ((gc->drawBuffer->buf.flags & DIB_FORMAT) != 0) &&
              ((gc->drawBuffer->buf.flags & MEMORY_DC) != 0) &&
              gc->transform.reasonableViewport);

    GENACCEL(gc).flags &= ~(
            GEN_DITHER | GEN_RGBMODE | GEN_TEXTURE | GEN_SHADE |
            GEN_FASTZBUFFER | GEN_LESS | SURFACE_TYPE_DIB | GEN_TEXTURE_ORTHO
        );

    if ((enables & __GL_BLEND_ENABLE) ||
        (modeFlags & __GL_SHADE_TEXTURE)) {
        GENACCEL(gc).__fastCalcDeltaPtr = __fastGenCalcDeltasTexRGBA;
        GENACCEL(gc).__fastSetInitParamPtr = __fastGenSetInitialParametersTexRGBA;
    } else {
        GENACCEL(gc).__fastCalcDeltaPtr = __fastGenCalcDeltas;
        GENACCEL(gc).__fastSetInitParamPtr = __fastGenSetInitialParameters;
    }

#ifdef GL_WIN_phong_shading      
    if (modeFlags & __GL_SHADE_PHONG)
    {
        gc->procs.fillTriangle = __glFillPhongTriangle;
    }
    else
#endif //GL_WIN_phong_shading      
    {
#ifdef _MCD_
        // If MCD driver is being used, then we need to call the "floating
        // point state safe" version of fillTriangle.  This version will
        // not attempt to span floating point operations over a call that
        // may invoke the MCD driver (which will corrupt the FP state).

        if (gengc->pMcdState)
        {
            gc->procs.fillTriangle = __fastGenMcdFillTriangle;
        }
        else
        {
            gc->procs.fillTriangle = __fastGenFillTriangle;
        }
#else //_MCD_
        gc->procs.fillTriangle = __fastGenFillTriangle;
#endif //_MCD_
    }
    
    // If we're doing perspective-corrected texturing, we will support
    // the following combinations:
    //  z....... <, <=
    //  alpha... src, 1-src
    //  dither.. on/off
    //  bpp..... 332, 555, 565, 888

    // NOTE:  We will always try this path first for general texturing.

    if ((modeFlags & __GL_SHADE_TEXTURE) || (enables & __GL_BLEND_ENABLE)) {
        LONG pixType = -1;

        if (gc->state.hints.perspectiveCorrection != GL_NICEST)
            GENACCEL(gc).flags |= GEN_TEXTURE_ORTHO;

        if (!bTryFastTexRGBA)
            goto perspTexPathFail;

        if ((enables & __GL_BLEND_ENABLE) &&
            ((gc->state.raster.blendSrc != GL_SRC_ALPHA) ||
             (gc->state.raster.blendDst != GL_ONE_MINUS_SRC_ALPHA)))
            return FALSE;

        if (!(modeFlags & __GL_SHADE_TEXTURE)) {

            if (!(modeFlags & __GL_SHADE_RGB))
                goto perspTexPathFail;

            bRealTexture = FALSE;
            
            GENACCEL(gc).flags |= GEN_TEXTURE_ORTHO;
            GENACCEL(gc).texPalette = NULL;
            textureMode = GL_MODULATE;
            internalFormat = GL_BGRA_EXT;
            GENACCEL(gc).texImage =  (ULONG *)internalSolidTexture;
            GENACCEL(gc).sMask = 0;
            GENACCEL(gc).tMask = 0;
            GENACCEL(gc).tShift = 0;
            GENACCEL(gc).tMaskSubDiv = 0;
            GENACCEL(gc).tShiftSubDiv = 0;
        }
        else
        {
            bRealTexture = TRUE;
        }

        if (bpp == 8) {
            if ((gengc->gc.drawBuffer->redShift   == 0) &&
                (gengc->gc.drawBuffer->greenShift == 3) &&
                (gengc->gc.drawBuffer->blueShift  == 6))
                pixType = 0;
        } else if (bpp == 16) {
            if ((gengc->gc.drawBuffer->greenShift == 5) &&
                (gengc->gc.drawBuffer->blueShift  == 0)) {

                if (gengc->gc.drawBuffer->redShift == 10)
                    pixType = 1;
                else if (gengc->gc.drawBuffer->redShift == 11)
                    pixType = 2;
            }
        } else if ((bpp == 32) || (bpp == 24)) {
            if ((gengc->gc.drawBuffer->redShift == 16) &&
                (gengc->gc.drawBuffer->greenShift == 8) &&
                (gengc->gc.drawBuffer->blueShift  == 0))
                pixType = 3;
        }

        if (pixType < 0)
            goto perspTexPathFail;

        pixType *= 6;

        if (modeFlags & __GL_SHADE_DEPTH_ITER) {

            if (bMcdZ)
                goto perspTexPathFail;

            if (!((gc->state.depth.testFunc == GL_LESS) ||
                 (gc->state.depth.testFunc == GL_LEQUAL)))
                goto perspTexPathFail;

            if (gc->modes.depthBits > 16)
                goto perspTexPathFail;

            if (gc->state.depth.testFunc == GL_LEQUAL)
                pixType += 1;
            else
                pixType += 2;

            GENACCEL(gc).__fastFillSubTrianglePtr = __ZippyFSTZ;
        }

        if (enables & __GL_BLEND_ENABLE)
            pixType += 3;

        // Note:  For selecting the sub-triangle filling routine, assume
        // that we will use one of the "zippy" routines.  Then, check at the
        // end whether or not we can actually do this, or if we have to fall
        // back to a more generic (and slower) routine.

        if (internalFormat != GL_COLOR_INDEX8_EXT &&
            internalFormat != GL_COLOR_INDEX16_EXT) {

            //
            // Handle full RGB(A) textures
            //

            // Check if we can support the size...

            if (bRealTexture &&
                GENACCEL(gc).tex &&
                ((GENACCEL(gc).tex->level[0].widthLog2 > TEX_MAX_SIZE_LOG2) ||
                 (GENACCEL(gc).tex->level[0].heightLog2 > TEX_MAX_SIZE_LOG2)))
                goto perspTexPathFail;

            if ((textureMode == GL_DECAL) ||
                (textureMode == GL_REPLACE)) {

                // we don't handle the goofy alpha case for decal...

                if ((textureMode == GL_DECAL) &&
                    (enables & __GL_BLEND_ENABLE))
                    return FALSE;

                // If we're not dithering, we can go with the compressed
                // texture format.  Otherwise, we're forced to use flat-shading
                // procs to get the texture colors to dither properly.  Ouch...

                // We'd like to also go through this path if a DirectDraw
                // texture is used because replace maps can't be created,
                // but they only work with dithering
                if (modeFlags & __GL_SHADE_DITHER) {
                    GENACCEL(gc).__fastTexSpanFuncPtr =
                        __fastPerspTexFlatFuncs[pixType];
                } else {
                    if ((bpp >= 8 && bpp <= 16) &&
                        !(enables & __GL_BLEND_ENABLE)) {

                        // handle the case where we can use compressed textures
                        // for optimal performance.  We do this for bit depths
                        // <= 16 bits, no dithering, and no blending.

                        if (!GENACCEL(gc).tex->pvUser) {
                            if (!__fastGenLoadTexImage(gc, GENACCEL(gc).tex))
                                return FALSE;
                        } else {

                            // If the compressed texture image was created for
                            // another gc, revert to using the RGBA image.
                            // We do this by using the alpha paths.
                            //
                            // NOTE:  This logic depends on A being forced to
                            // 1 for all RGB textures.

                            if (gc != ((GENTEXCACHE *)GENACCEL(gc).tex->pvUser)->gc)
                            {
                                pixType += 3;
                            }
                            else
                            {
                                // Check that the cached data is the right size
                                ASSERTOPENGL(((GENTEXCACHE *)GENACCEL(gc).tex->pvUser)->width == GENACCEL(gc).tex->level[0].width &&
                                             ((GENTEXCACHE *)GENACCEL(gc).tex->pvUser)->height == GENACCEL(gc).tex->level[0].height,
                                             "Cached texture size mismatch\n");
                            }
                        }
                    }

                    GENACCEL(gc).__fastTexSpanFuncPtr =
                        __fastPerspTexReplaceFuncs[pixType];
                }

                if (!(modeFlags & __GL_SHADE_DEPTH_ITER))
                    GENACCEL(gc).__fastFillSubTrianglePtr = __ZippyFSTTex;

            } else if (textureMode == GL_MODULATE) {
                if (modeFlags & __GL_SHADE_SMOOTH) {
                    GENACCEL(gc).__fastTexSpanFuncPtr =
                        __fastPerspTexSmoothFuncs[pixType];
                    if (!(modeFlags & __GL_SHADE_DEPTH_ITER))
                        GENACCEL(gc).__fastFillSubTrianglePtr = __ZippyFSTRGBTex;
                } else {
                    GENACCEL(gc).__fastTexSpanFuncPtr =
                        __fastPerspTexFlatFuncs[pixType];
                    if (!(modeFlags & __GL_SHADE_DEPTH_ITER))
                        GENACCEL(gc).__fastFillSubTrianglePtr = __ZippyFSTTex;
                }
            }
        } else {
            //
            // Handle palettized textures
            //

            // Check if we can support the size...

            if (bRealTexture &&
                GENACCEL(gc).tex &&
                ((GENACCEL(gc).tex->level[0].widthLog2 > TEX_MAX_SIZE_LOG2) ||
                 (GENACCEL(gc).tex->level[0].heightLog2 > TEX_MAX_SIZE_LOG2)))
                return FALSE;

            if ((textureMode == GL_DECAL) ||
                (textureMode == GL_REPLACE)) {

                // we don't handle the goofy alpha case for decal...

                if ((textureMode == GL_DECAL) &&
                    (enables & __GL_BLEND_ENABLE))
                    return FALSE;

                // If we're not dithering, we can go with the compressed
                // texture format.  Otherwise, we're forced to use flat-shading
                // procs to get the texture colors to dither properly.  Ouch...

                // We'd like to also go through this path if a DirectDraw
                // texture is used because replace maps can't be created,
                // but they only work with dithering
                if (modeFlags & __GL_SHADE_DITHER) {
                    GENACCEL(gc).__fastTexSpanFuncPtr =
                        __fastPerspTexFlatFuncs[pixType];
                } else {

                    GENACCEL(gc).__fastTexSpanFuncPtr =
                        __fastPerspTexPalReplaceFuncs[pixType];

                    if (bpp >= 8 && bpp <= 16) {
                        // handle the case where we can use compressed paletted
                        // textures for optimal performance.  We do this for
                        // bit depths <= 16 bits with no dithering.

                        if (!GENACCEL(gc).tex->pvUser) {
                            if (!__fastGenLoadTexImage(gc, GENACCEL(gc).tex))
                                return FALSE;
                        } else {

        // If the compressed texture image was created for
        // another gc, we have no choice but to fall back to flat shading.
        // We should find a better solution for this...
                            if (gc != ((GENTEXCACHE *)GENACCEL(gc).tex->pvUser)->gc)
                            {
                                GENACCEL(gc).__fastTexSpanFuncPtr =
                                    __fastPerspTexFlatFuncs[pixType];
                            }
                            else
                            {
                                ASSERTOPENGL(((GENTEXCACHE *)GENACCEL(gc).tex->pvUser)->width == GENACCEL(gc).tex->paletteTotalSize,
                                             "Cached texture size mismatch\n");
                            }
                        }
                    }
                }

                if (!(modeFlags & __GL_SHADE_DEPTH_ITER))
                    GENACCEL(gc).__fastFillSubTrianglePtr = __ZippyFSTTex;

            } else if (textureMode == GL_MODULATE) {
                if (modeFlags & __GL_SHADE_SMOOTH) {
                    GENACCEL(gc).__fastTexSpanFuncPtr =
                        __fastPerspTexSmoothFuncs[pixType];
                    if (!(modeFlags & __GL_SHADE_DEPTH_ITER))
                        GENACCEL(gc).__fastFillSubTrianglePtr = __ZippyFSTRGBTex;
                } else {
                    GENACCEL(gc).__fastTexSpanFuncPtr =
                        __fastPerspTexFlatFuncs[pixType];
                    if (!(modeFlags & __GL_SHADE_DEPTH_ITER))
                        GENACCEL(gc).__fastFillSubTrianglePtr = __ZippyFSTTex;
                }
            }
        }

        if (!fZippy)
            GENACCEL(gc).__fastFillSubTrianglePtr = __fastGenFillSubTriangleTexRGBA;
        else
            GENACCEL(gc).flags |= SURFACE_TYPE_DIB;

        return TRUE;

    }

perspTexPathFail:

    // We don't support any alpha modes yet...

    if (enables & __GL_BLEND_ENABLE)
        return FALSE;

    fUseFastGenSpan = FALSE;

    if (bpp == 8) {
        iType = 2;
        if (
               (gengc->gc.drawBuffer->redShift   != 0)
            || (gengc->gc.drawBuffer->greenShift != 3)
            || (gengc->gc.drawBuffer->blueShift  != 6)
           ) {
            fUseFastGenSpan = TRUE;
        }
    } else if (bpp == 16) {
        if (
               (gengc->gc.drawBuffer->greenShift == 5)
            && (gengc->gc.drawBuffer->blueShift  == 0)
           ) {
            if (gengc->gc.drawBuffer->redShift == 10) {
                iType = 3;
            } else if (gengc->gc.drawBuffer->redShift == 11) {
                iType = 4;
            } else {
                iType = 3;
                fUseFastGenSpan = TRUE;
            }
        } else {
            iType = 3;
            fUseFastGenSpan = TRUE;
        }
    } else {
        if (bpp == 24) {
            iType = 0;
        } else {
            iType = 1;
        }
        if (
               (gengc->gc.drawBuffer->redShift   != 16)
            || (gengc->gc.drawBuffer->greenShift != 8)
            || (gengc->gc.drawBuffer->blueShift  != 0)
           ) {
            fUseFastGenSpan = TRUE;
        }
    }

    if (modeFlags & __GL_SHADE_DITHER) {
        if (   (bpp == 8)
            || (bpp == 16)
            || ((modeFlags & __GL_SHADE_DEPTH_ITER) == 0)
           ) {
            GENACCEL(gc).flags |= GEN_DITHER;
        }
        iType += 5;
    }

    // Use the accelerated span functions (with no inline z-buffering) if
    // we support the z-buffer function AND we're not using hardware
    // z-buffering:

    if (modeFlags & __GL_SHADE_DEPTH_ITER) {
        if (bMcdZ) {
            fUseFastGenSpan = TRUE;
        } else if (!fZippy) {
            fUseFastGenSpan = TRUE;
        } else if (gc->state.depth.testFunc == GL_LESS) {
            GENACCEL(gc).flags |= GEN_LESS;
        } else if (gc->state.depth.testFunc != GL_LEQUAL) {
            fUseFastGenSpan = TRUE;
        }
        iType += 10;
    }

    if (modeFlags & __GL_SHADE_RGB) {
        GENACCEL(gc).flags |= GEN_RGBMODE;
        pfnZippySub = __ZippyFSTRGB;

        if (modeFlags & __GL_SHADE_TEXTURE) {
            GENACCEL(gc).flags |= (GEN_TEXTURE | GEN_TEXTURE_ORTHO);

            if (gc->state.hints.perspectiveCorrection == GL_NICEST)
                return FALSE;

            if (internalFormat == GL_COLOR_INDEX8_EXT ||
                internalFormat == GL_COLOR_INDEX16_EXT)
                return FALSE;

            if (textureMode == GL_DECAL) {
                if (modeFlags & __GL_SHADE_DITHER)
                    GENACCEL(gc).__fastTexSpanFuncPtr =
                        __fastGenTexFuncs[iType];
                else
                    GENACCEL(gc).__fastTexSpanFuncPtr =
                        __fastGenTexDecalFuncs[iType];

                pfnZippySub = __ZippyFSTTex;
            } else {
                GENACCEL(gc).flags |= GEN_SHADE;
                pfnZippySub = __ZippyFSTRGBTex;
                GENACCEL(gc).__fastTexSpanFuncPtr =
                    __fastGenTexFuncs[iType];
            }

            if (GENACCEL(gc).__fastTexSpanFuncPtr == __fastGenSpan) {
                fUseFastGenSpan = TRUE;
            }
        } else {
            GENACCEL(gc).__fastSmoothSpanFuncPtr = __fastGenRGBFuncs[iType];
            GENACCEL(gc).__fastFlatSpanFuncPtr   = __fastGenRGBFlatFuncs[iType];

            if (GENACCEL(gc).__fastSmoothSpanFuncPtr == __fastGenSpan) {
                fUseFastGenSpan = TRUE;
            }
        }
    } else {
        pfnZippySub = __ZippyFSTCI;
        GENACCEL(gc).__fastSmoothSpanFuncPtr = __fastGenCIFuncs[iType];
        GENACCEL(gc).__fastFlatSpanFuncPtr = __fastGenCIFlatFuncs[iType];
    }

    if (modeFlags & __GL_SHADE_STIPPLE)
    {
        fUseFastGenSpan = TRUE;
    }
    
    if (fUseFastGenSpan) {
        GENACCEL(gc).__fastTexSpanFuncPtr          = __fastGenSpan;
        GENACCEL(gc).__fastSmoothSpanFuncPtr       = __fastGenSpan;
        GENACCEL(gc).__fastFlatSpanFuncPtr         = __fastGenSpan;
        GENACCEL(gc).__fastFillSubTrianglePtr      = __fastGenFillSubTriangle;
    } else {
        if (fZippy) {
            GENACCEL(gc).flags |= SURFACE_TYPE_DIB;

            if (   (iType == 2)
                && (
                    (modeFlags
                     & (__GL_SHADE_RGB | __GL_SHADE_SMOOTH)
                    ) == 0
                   )
               ) {
                GENACCEL(gc).__fastFillSubTrianglePtr = __ZippyFSTCI8Flat;
            } else if (iType >= 10) {
                GENACCEL(gc).__fastFillSubTrianglePtr = __ZippyFSTZ;
                GENACCEL(gc).flags |= GEN_FASTZBUFFER;
            } else {
                GENACCEL(gc).flags &= ~(HAVE_STIPPLE);
                GENACCEL(gc).__fastFillSubTrianglePtr = pfnZippySub;
            }
        } else {
            GENACCEL(gc).__fastFillSubTrianglePtr = __fastGenFillSubTriangle;
        }
    }

    return TRUE;
}

void FASTCALL __fastGenPickTriangleProcs(__GLcontext *gc)
{
    GLuint modeFlags = gc->polygon.shader.modeFlags;
    __GLGENcontext *genGc = (__GLGENcontext *)gc;

    CASTINT(gc->polygon.shader.rLittle) = 0;
    CASTINT(gc->polygon.shader.rBig) =    0;
    CASTINT(gc->polygon.shader.gLittle) = 0;
    CASTINT(gc->polygon.shader.gBig) =    0;
    CASTINT(gc->polygon.shader.bLittle) = 0;
    CASTINT(gc->polygon.shader.bBig) =    0;
    CASTINT(gc->polygon.shader.sLittle) = 0;
    CASTINT(gc->polygon.shader.sBig) =    0;
    CASTINT(gc->polygon.shader.tLittle) = 0;
    CASTINT(gc->polygon.shader.tBig) =    0;

    GENACCEL(gc).spanDelta.r = 0;
    GENACCEL(gc).spanDelta.g = 0;
    GENACCEL(gc).spanDelta.b = 0;
    GENACCEL(gc).spanDelta.a = 0;

    /*
    ** Setup cullFace so that a single test will do the cull check.
    */
    if (modeFlags & __GL_SHADE_CULL_FACE) {
        switch (gc->state.polygon.cull) {
          case GL_FRONT:
            gc->polygon.cullFace = __GL_CULL_FLAG_FRONT;
            break;
          case GL_BACK:
            gc->polygon.cullFace = __GL_CULL_FLAG_BACK;
            break;
          case GL_FRONT_AND_BACK:
            gc->procs.renderTriangle = __glDontRenderTriangle;
            gc->procs.fillTriangle = 0;         /* Done to find bugs */
            return;
        }
    } else {
        gc->polygon.cullFace = __GL_CULL_FLAG_DONT;
    }

    /* Build lookup table for face direction */
    switch (gc->state.polygon.frontFaceDirection) {
      case GL_CW:
        if (gc->constants.yInverted) {
            gc->polygon.face[__GL_CW] = __GL_BACKFACE;
            gc->polygon.face[__GL_CCW] = __GL_FRONTFACE;
        } else {
            gc->polygon.face[__GL_CW] = __GL_FRONTFACE;
            gc->polygon.face[__GL_CCW] = __GL_BACKFACE;
        }
        break;
      case GL_CCW:
        if (gc->constants.yInverted) {
            gc->polygon.face[__GL_CW] = __GL_FRONTFACE;
            gc->polygon.face[__GL_CCW] = __GL_BACKFACE;
        } else {
            gc->polygon.face[__GL_CW] = __GL_BACKFACE;
            gc->polygon.face[__GL_CCW] = __GL_FRONTFACE;
        }
        break;
    }

    /* Make polygon mode indexable and zero based */
    gc->polygon.mode[__GL_FRONTFACE] =
        (GLubyte) (gc->state.polygon.frontMode & 0xf);
    gc->polygon.mode[__GL_BACKFACE] =
        (GLubyte) (gc->state.polygon.backMode & 0xf);

    if (gc->renderMode == GL_FEEDBACK) {
        gc->procs.renderTriangle = __glFeedbackTriangle;
        gc->procs.fillTriangle = 0;             /* Done to find bugs */
        return;
    }
    if (gc->renderMode == GL_SELECT) {
        gc->procs.renderTriangle = __glSelectTriangle;
        gc->procs.fillTriangle = 0;             /* Done to find bugs */
        return;
    }

    if ((gc->state.polygon.frontMode == gc->state.polygon.backMode) &&
        (gc->state.polygon.frontMode == GL_FILL)) {
      if (modeFlags & __GL_SHADE_SMOOTH_LIGHT) {
          gc->procs.renderTriangle = __glRenderSmoothTriangle;
#ifdef GL_WIN_phong_shading
      } else if (modeFlags & __GL_SHADE_PHONG) {
          gc->procs.renderTriangle = __glRenderPhongTriangle;
#endif //GL_WIN_phong_shading
      } else {
          gc->procs.renderTriangle = __glRenderFlatTriangle;
      }
    } else {
        gc->procs.renderTriangle = __glRenderTriangle;
    }

    if (gc->state.enables.general & __GL_POLYGON_SMOOTH_ENABLE) {
#ifdef GL_WIN_phong_shading
        if (modeFlags & __GL_SHADE_PHONG)
            gc->procs.fillTriangle = __glFillAntiAliasedPhongTriangle;
        else
#endif //GL_WIN_phong_shading
            gc->procs.fillTriangle = __glFillAntiAliasedTriangle;
    } else {
        if ((gc->state.raster.drawBuffer == GL_NONE) ||
            !bUseGenTriangles(gc))
#ifdef GL_WIN_phong_shading
            if (modeFlags & __GL_SHADE_PHONG)
                gc->procs.fillTriangle = __glFillPhongTriangle;
            else
#endif //GL_WIN_phong_shading
                gc->procs.fillTriangle = __glFillTriangle;
    }

    if ((modeFlags & __GL_SHADE_CHEAP_FOG) && 
        !(modeFlags & __GL_SHADE_SMOOTH_LIGHT)) {
        gc->procs.fillTriangle2 = gc->procs.fillTriangle;
        gc->procs.fillTriangle = __glFillFlatFogTriangle;
    }
#ifdef GL_WIN_specular_fog
    /*
    ** The case where 1) Specular fog is enabled AND 2) flat-shaded
    */
    if ((modeFlags & (__GL_SHADE_SPEC_FOG | 
                      __GL_SHADE_SMOOTH_LIGHT |
                      __GL_SHADE_PHONG)) == __GL_SHADE_SPEC_FOG)
    {
        gc->procs.fillTriangle2 = gc->procs.fillTriangle;
        gc->procs.fillTriangle = __glFillFlatSpecFogTriangle;
    }
#endif //GL_WIN_specular_fog
}


void FASTCALL __fastGenPickSpanProcs(__GLcontext *gc)
{
    __GLGENcontext *genGc = (__GLGENcontext *)gc;
    GLuint enables = gc->state.enables.general;
    GLuint modeFlags = gc->polygon.shader.modeFlags;
    __GLcolorBuffer *cfb = gc->drawBuffer;
    __GLspanFunc *sp;
    __GLstippledSpanFunc *ssp;
    int spanCount;
    GLboolean replicateSpan;
    GLboolean bMcdZ = ((((__GLGENcontext *)gc)->pMcdState != NULL) &&
                       (((__GLGENcontext *)gc)->pMcdState->pDepthSpan != NULL) &&
                       (((__GLGENcontext *)gc)->pMcdState->pMcdSurf != NULL) &&
                       !(((__GLGENcontext *)gc)->pMcdState->McdBuffers.mcdDepthBuf.bufFlags & MCDBUF_ENABLED));

    // Always reset the color scale values at the beginning of the pick
    // procs.  Lines, triangles, and spans may all use these values...

    GENACCEL(gc).rAccelScale = (GLfloat)ACCEL_FIX_SCALE;
    GENACCEL(gc).gAccelScale = (GLfloat)ACCEL_FIX_SCALE;
    GENACCEL(gc).bAccelScale = (GLfloat)ACCEL_FIX_SCALE;

    // Note:  we need to scale between 0 and 255 to get proper alpha
    // blending.  The software-accelerated blending code assumes this
    // scaling for simplicity...

    GENACCEL(gc).aAccelScale = (GLfloat)(ACCEL_FIX_SCALE) *
                               (GLfloat)255.0 / gc->drawBuffer->alphaScale;

    replicateSpan = GL_FALSE;
    sp = gc->procs.span.spanFuncs;
    ssp = gc->procs.span.stippledSpanFuncs;

    /* Load phase one procs */
    if (!gc->transform.reasonableViewport) {
        *sp++ = __glClipSpan;
        *ssp++ = NULL;
    }

    if (modeFlags & __GL_SHADE_STIPPLE) {
        *sp++ = __glStippleSpan;
        *ssp++ = __glStippleStippledSpan;

        if (modeFlags & __GL_SHADE_DEPTH_TEST)
        {
            if (bMcdZ)
            {
                GENACCEL(gc).__fastStippleDepthTestSpan =
                    GenMcdStippleAnyDepthTestSpan;
            }
            else
            {
                if (gc->state.depth.testFunc == GL_LESS)
                {
                    if (gc->modes.depthBits == 32)
                    {
                        GENACCEL(gc).__fastStippleDepthTestSpan =
                            __fastGenStippleLt32Span;
                    }
                    else
                    {
                        GENACCEL(gc).__fastStippleDepthTestSpan =
                            __fastGenStippleLt16Span;
                    }
                }
                else
                {
                    GENACCEL(gc).__fastStippleDepthTestSpan =
                        __fastGenStippleAnyDepthTestSpan;
                }
            }
        }
        else
        {
            GENACCEL(gc).__fastStippleDepthTestSpan = __glStippleSpan;
        }
    }

    /* Load phase three procs */
    if (modeFlags & __GL_SHADE_RGB) {
        if (modeFlags & __GL_SHADE_SMOOTH) {
            *sp = __glShadeRGBASpan;
            *ssp = __glShadeRGBASpan;
#ifdef GL_WIN_phong_shading
        } else if (modeFlags & __GL_SHADE_PHONG) {
            *sp = __glPhongRGBASpan;
            *ssp = __glPhongRGBASpan;
        
#endif //GL_WIN_phong_shading
        } else {
            *sp = __glFlatRGBASpan;
            *ssp = __glFlatRGBASpan;
        }
    } else {
        if (modeFlags & __GL_SHADE_SMOOTH) {
            *sp = __glShadeCISpan;
            *ssp = __glShadeCISpan;
#ifdef GL_WIN_phong_shading
        } else if (modeFlags & __GL_SHADE_PHONG) {
            *sp = __glPhongCISpan;
            *ssp = __glPhongCISpan;
#endif //GL_WIN_phong_shading
        } else {
            *sp = __glFlatCISpan;
            *ssp = __glFlatCISpan;
        }
    }
    sp++;
    ssp++;

    if (modeFlags & __GL_SHADE_TEXTURE) {
        *sp++ = __glTextureSpan;
        *ssp++ = __glTextureStippledSpan;
    }

#ifdef GL_WIN_specular_fog
    if (modeFlags & (__GL_SHADE_SLOW_FOG | __GL_SHADE_SPEC_FOG))
#else //GL_WIN_specular_fog
    if (modeFlags & __GL_SHADE_SLOW_FOG)
#endif //GL_WIN_specular_fog
    {
        if (DO_NICEST_FOG (gc)) {
            *sp = __glFogSpanSlow;
            *ssp = __glFogStippledSpanSlow;
        } else {
            *sp = __glFogSpan;
            *ssp = __glFogStippledSpan;
        }
        sp++;
        ssp++;
    }

    if (modeFlags & __GL_SHADE_ALPHA_TEST) {
        *sp++ = __glAlphaTestSpan;
        *ssp++ = __glAlphaTestStippledSpan;
    }

    /* Load phase two procs */
    if (modeFlags & __GL_SHADE_STENCIL_TEST) {
        *sp++ = __glStencilTestSpan;
        *ssp++ = __glStencilTestStippledSpan;
        if (modeFlags & __GL_SHADE_DEPTH_TEST) {
            if (bMcdZ) {
                *sp = GenMcdDepthTestStencilSpan;
                *ssp = GenMcdDepthTestStencilStippledSpan;
            } else {
                *sp = __glDepthTestStencilSpan;
                *ssp = __glDepthTestStencilStippledSpan;
            }
        } else {
            *sp = __glDepthPassSpan;
            *ssp = __glDepthPassStippledSpan;
        }
        sp++;
        ssp++;
    } else {
        if (modeFlags & __GL_SHADE_DEPTH_TEST) {
            if (bMcdZ) {
                *sp++  =  GenMcdDepthTestSpan;
                *ssp++ = GenMcdDepthTestStippledSpan;
                if (gc->state.depth.writeEnable)
                    ((__GLGENcontext *)gc)->pMcdState->softZSpanFuncPtr =
                        __fastDepthFuncs[gc->state.depth.testFunc & 0x7];
                else
                    ((__GLGENcontext *)gc)->pMcdState->softZSpanFuncPtr =
                        (__GLspanFunc)NULL;

                GENACCEL(gc).__fastZSpanFuncPtr = GenMcdDepthTestSpan;
            } else {
                if (gc->state.depth.writeEnable) {
                    if( gc->modes.depthBits == 32 ) {
                        *sp++ = GENACCEL(gc).__fastZSpanFuncPtr =
                            __fastDepthFuncs[gc->state.depth.testFunc & 0x7];
                    } else {
                        *sp++ = GENACCEL(gc).__fastZSpanFuncPtr =
                            __fastDepth16Funcs[gc->state.depth.testFunc & 0x7];
                    }
                } else {
                    *sp++ = GENACCEL(gc).__fastZSpanFuncPtr =
                        __glDepthTestSpan;
                }

                *ssp++ = __glDepthTestStippledSpan;
            }
        }
    }

    if (gc->state.raster.drawBuffer == GL_FRONT_AND_BACK) {
        spanCount = (int)((ULONG_PTR)(sp - gc->procs.span.spanFuncs));
        gc->procs.span.n = spanCount;
        replicateSpan = GL_TRUE;
    }

    /* Span routines deal with masking, dithering, logicop, blending */
    *sp++ = cfb->storeSpan;
    *ssp++ = cfb->storeStippledSpan;

    spanCount = (int)((ULONG_PTR)(sp - gc->procs.span.spanFuncs));
    gc->procs.span.m = spanCount;
    if (replicateSpan) {
        gc->procs.span.processSpan = __glProcessReplicateSpan;
    } else {
        gc->procs.span.processSpan = __glProcessSpan;
        gc->procs.span.n = spanCount;
    }
}

// These are the bits in modeFlags that affect lines

#ifdef GL_WIN_specular_fog
#define __FAST_LINE_SPEC_FOG __GL_SHADE_SPEC_FOG
#else
#define __FAST_LINE_SPEC_FOG 0
#endif //GL_WIN_specular_fog

#ifdef GL_WIN_phong_shading
#define __FAST_LINE_PHONG __GL_SHADE_PHONG
#else
#define __FAST_LINE_PHONG 0
#endif //GL_WIN_phong_shading

#define __FAST_LINE_MODE_FLAGS \
    (__GL_SHADE_DEPTH_TEST | __GL_SHADE_SMOOTH | __GL_SHADE_TEXTURE | \
     __GL_SHADE_LINE_STIPPLE | __GL_SHADE_STENCIL_TEST | __GL_SHADE_LOGICOP | \
     __GL_SHADE_BLEND | __GL_SHADE_ALPHA_TEST | __GL_SHADE_MASK | \
     __GL_SHADE_SLOW_FOG | __GL_SHADE_CHEAP_FOG | __FAST_LINE_SPEC_FOG | \
     __FAST_LINE_PHONG)

/******************************Public*Routine******************************\
* __fastGenPickLineProcs
*
* Picks the line-rendering procedures.  Most of this function was copied from
* the soft code.  Some differences include:
*   1. The beginPrim function pointers are hooked by the accelerated code
*   2. If the attribute state is such that acceleration can be used,
*      __fastGenLineSetup is called to initialize the state machine.
*
* History:
*  22-Mar-1994 -by- Eddie Robinson [v-eddier]
* Wrote it.
\**************************************************************************/


void FASTCALL __fastGenPickLineProcs(__GLcontext *gc)
{
    __GLGENcontext *genGc = (__GLGENcontext *) gc;
    GENACCEL *genAccel;
    GLuint enables = gc->state.enables.general;
    GLuint modeFlags = gc->polygon.shader.modeFlags;
    __GLspanFunc *sp;
    __GLstippledSpanFunc *ssp;
    int spanCount;
    GLboolean wideLine;
    GLboolean replicateLine;
    GLuint aaline;
    GLboolean bMcdZ = ((genGc->pMcdState != NULL) &&
                       (genGc->pMcdState->pDepthSpan != NULL) &&
                       (genGc->pMcdState->pMcdSurf != NULL) &&
                       !(genGc->pMcdState->McdBuffers.mcdDepthBuf.bufFlags & MCDBUF_ENABLED));

    /*
    ** The fast line code replaces the line function pointers, so reset them
    ** to a good state
    */
    gc->procs.lineBegin  = __glNopLineBegin;
    gc->procs.lineEnd    = __glNopLineEnd;

    if (gc->renderMode == GL_FEEDBACK) {
        gc->procs.renderLine = __glFeedbackLine;
    } else if (gc->renderMode == GL_SELECT) {
        gc->procs.renderLine = __glSelectLine;
    } else {
        if (genAccel = (GENACCEL *) genGc->pPrivateArea) {
            if (!(modeFlags & __FAST_LINE_MODE_FLAGS & ~genAccel->flLineAccelModes) &&
                !(gc->state.enables.general & __GL_LINE_SMOOTH_ENABLE) &&
                !(gc->state.enables.general & __GL_SCISSOR_TEST_ENABLE) &&
                !(gc->state.raster.drawBuffer == GL_NONE) &&
                !gc->buffers.doubleStore &&
                !genGc->pMcdState &&
                (genGc->dwCurrentFlags & (GLSURF_HDC | GLSURF_METAFILE)) ==
                GLSURF_HDC)
            {
                __fastLineComputeOffsets(genGc);

#if NT_NO_BUFFER_INVARIANCE
                if (!(gc->drawBuffer->buf.flags & DIB_FORMAT)) {
                    if (genAccel->bFastLineDispAccel) {
                        if (__fastGenLineSetupDisplay(gc))
                            return;
                    }
                } else {
                    if (genAccel->bFastLineDIBAccel) {
                        if (__fastGenLineSetupDIB(gc))
                            return;
                    }
                }
#else
                if (genAccel->bFastLineDispAccel) {
                    if (__fastGenLineSetupDisplay(gc))
                        return;
                }
#endif
            }
        }

        if (__glGenSetupEitherLines(gc))
        {
            return;
        }

        replicateLine = wideLine = GL_FALSE;

        aaline = gc->state.enables.general & __GL_LINE_SMOOTH_ENABLE;
        if (aaline)
        {
            gc->procs.renderLine = __glRenderAntiAliasLine;
        }
        else
        {
            gc->procs.renderLine = __glRenderAliasLine;
        }
        
        sp = gc->procs.line.lineFuncs;
        ssp = gc->procs.line.stippledLineFuncs;

        if (!aaline && (modeFlags & __GL_SHADE_LINE_STIPPLE)) {
            *sp++ = __glStippleLine;
            *ssp++ = NULL;
        }

        if (!aaline && gc->state.line.aliasedWidth > 1) {
            wideLine = GL_TRUE;
        }
        spanCount = (int)((ULONG_PTR)(sp - gc->procs.line.lineFuncs));
        gc->procs.line.n = spanCount;

        *sp++ = __glScissorLine;
        *ssp++ = __glScissorStippledLine;

        if (!aaline) {
            if (modeFlags & __GL_SHADE_STENCIL_TEST) {
                *sp++ = __glStencilTestLine;
                *ssp++ = __glStencilTestStippledLine;
                if (modeFlags & __GL_SHADE_DEPTH_TEST) {
                    if (bMcdZ) {
                        *sp = GenMcdDepthTestStencilLine;
                        *ssp = GenMcdDepthTestStencilStippledLine;
                    } else if( gc->modes.depthBits == 32 ) {
                        *sp = __glDepthTestStencilLine;
                        *ssp = __glDepthTestStencilStippledLine;
                    }
                    else {
                        *sp = __glDepth16TestStencilLine;
                        *ssp = __glDepth16TestStencilStippledLine;
                    }
                } else {
                    *sp = __glDepthPassLine;
                    *ssp = __glDepthPassStippledLine;
                }
                sp++;
                ssp++;
            } else {
                if (modeFlags & __GL_SHADE_DEPTH_TEST) {
                    if (gc->state.depth.testFunc == GL_NEVER) {
                        /* Unexpected end of line routine picking! */
                        spanCount = (int)((ULONG_PTR)(sp - gc->procs.line.lineFuncs));
                        gc->procs.line.m = spanCount;
                        gc->procs.line.l = spanCount;
                        goto pickLineProcessor;
#ifdef __GL_USEASMCODE
                    } else {
                        unsigned long ix;

                        if (gc->state.depth.writeEnable) {
                            ix = 0;
                        } else {
                            ix = 8;
                        }
                        ix += gc->state.depth.testFunc & 0x7;

                        if (ix == (GL_LEQUAL & 0x7)) {
                            *sp++ = __glDepthTestLine_LEQ_asm;
                        } else {
                            *sp++ = __glDepthTestLine_asm;
                            gc->procs.line.depthTestPixel = LDepthTestPixel[ix];
                        }
#else
                    } else {
                        if (bMcdZ) {
                            *sp++ = GenMcdDepthTestLine;
                        } else {
                            if( gc->modes.depthBits == 32 )
                                *sp++ = __glDepthTestLine;
                            else
                                *sp++ = __glDepth16TestLine;
                        }
#endif
                    }
                    if (bMcdZ) {
                        *ssp++ = GenMcdDepthTestStippledLine;
                    } else {
                        if( gc->modes.depthBits == 32 )
                            *ssp++ = __glDepthTestStippledLine;
                        else
                            *ssp++ = __glDepth16TestStippledLine;
                    }
                }
            }
        }

        /* Load phase three procs */
        if (modeFlags & __GL_SHADE_RGB) {
            if (modeFlags & __GL_SHADE_SMOOTH) {
                *sp = __glShadeRGBASpan;
                *ssp = __glShadeRGBASpan;
#ifdef GL_WIN_phong_shading
            } else if (modeFlags & __GL_SHADE_PHONG) {
                *sp = __glPhongRGBASpan;
                *ssp = __glPhongRGBASpan;
#endif //GL_WIN_phong_shading
            } else {
                *sp = __glFlatRGBASpan;
                *ssp = __glFlatRGBASpan;
            }
        } else {
            if (modeFlags & __GL_SHADE_SMOOTH) {
                *sp = __glShadeCISpan;
                *ssp = __glShadeCISpan;
#ifdef GL_WIN_phong_shading
            } else if (modeFlags & __GL_SHADE_PHONG) {
                *sp = __glPhongCISpan;
                *ssp = __glPhongCISpan;
#endif //GL_WIN_phong_shading
            } else {
                *sp = __glFlatCISpan;
                *ssp = __glFlatCISpan;
            }
        }
        sp++;
        ssp++;
        if (modeFlags & __GL_SHADE_TEXTURE) {
            *sp++ = __glTextureSpan;
            *ssp++ = __glTextureStippledSpan;
        }
#ifdef GL_WIN_specular_fog
        if (modeFlags & (__GL_SHADE_SLOW_FOG | __GL_SHADE_SPEC_FOG))
#else //GL_WIN_specular_fog
        if (modeFlags & __GL_SHADE_SLOW_FOG)
#endif //GL_WIN_specular_fog
        {
            if (DO_NICEST_FOG (gc)) {
                *sp = __glFogSpanSlow;
                *ssp = __glFogStippledSpanSlow;
            } else {
                *sp = __glFogSpan;
                *ssp = __glFogStippledSpan;
            }
            sp++;
            ssp++;
        }

        if (aaline) {
            *sp++ = __glAntiAliasLine;
            *ssp++ = __glAntiAliasStippledLine;
        }

        if (aaline) {
            if (modeFlags & __GL_SHADE_STENCIL_TEST) {
                *sp++ = __glStencilTestLine;
                *ssp++ = __glStencilTestStippledLine;
                if (modeFlags & __GL_SHADE_DEPTH_TEST) {
                    if (bMcdZ) {
                        *sp = GenMcdDepthTestStencilLine;
                        *ssp = GenMcdDepthTestStencilStippledLine;
                    } else if( gc->modes.depthBits == 32 ) {
                        *sp = __glDepthTestStencilLine;
                        *ssp = __glDepthTestStencilStippledLine;
                    }
                    else {
                        *sp = __glDepth16TestStencilLine;
                        *ssp = __glDepth16TestStencilStippledLine;
                    }
                } else {
                    *sp = __glDepthPassLine;
                    *ssp = __glDepthPassStippledLine;
                }
                sp++;
                ssp++;
            } else {
                if (modeFlags & __GL_SHADE_DEPTH_TEST) {
                    if (gc->state.depth.testFunc == GL_NEVER) {
                        /* Unexpected end of line routine picking! */
                        spanCount = (int)((ULONG_PTR)(sp - gc->procs.line.lineFuncs));
                        gc->procs.line.m = spanCount;
                        gc->procs.line.l = spanCount;
                        goto pickLineProcessor;
#ifdef __GL_USEASMCODE
                    } else {
                        unsigned long ix;

                        if (gc->state.depth.writeEnable) {
                            ix = 0;
                        } else {
                            ix = 8;
                        }
                        ix += gc->state.depth.testFunc & 0x7;
                        *sp++ = __glDepthTestLine_asm;
                        gc->procs.line.depthTestPixel = LDepthTestPixel[ix];
#else
                    } else {
                        if (bMcdZ)
                            *sp++ = GenMcdDepthTestLine;
                        else if( gc->modes.depthBits == 32 )
                            *sp++ = __glDepthTestLine;
                        else
                            *sp++ = __glDepth16TestLine;
#endif
                    }
                    if (bMcdZ)
                        *ssp++ = GenMcdDepthTestStippledLine;
                    else if (gc->modes.depthBits == 32)
                        *ssp++ = __glDepthTestStippledLine;
                    else
                        *ssp++ = __glDepth16TestStippledLine;
                }
            }
        }

        if (modeFlags & __GL_SHADE_ALPHA_TEST) {
            *sp++ = __glAlphaTestSpan;
            *ssp++ = __glAlphaTestStippledSpan;
        }

        if (gc->buffers.doubleStore) {
            replicateLine = GL_TRUE;
        }
        spanCount = (int)((ULONG_PTR)(sp - gc->procs.line.lineFuncs));
        gc->procs.line.m = spanCount;

        *sp++ = __glStoreLine;
        *ssp++ = __glStoreStippledLine;

        spanCount = (int)((ULONG_PTR)(sp - gc->procs.line.lineFuncs));
        gc->procs.line.l = spanCount;

        sp = &gc->procs.line.wideLineRep;
        ssp = &gc->procs.line.wideStippledLineRep;
        if (wideLine) {
            *sp = __glWideLineRep;
            *ssp = __glWideStippleLineRep;
            sp = &gc->procs.line.drawLine;
            ssp = &gc->procs.line.drawStippledLine;
        }
        if (replicateLine) {
            *sp = __glDrawBothLine;
            *ssp = __glDrawBothStippledLine;
        } else {
            *sp = __glNopGCBOOL;
            *ssp = __glNopGCBOOL;
            gc->procs.line.m = gc->procs.line.l;
        }
        if (!wideLine) {
            gc->procs.line.n = gc->procs.line.m;
        }

pickLineProcessor:
        if (!wideLine && !replicateLine && spanCount == 3) {
            gc->procs.line.processLine = __glProcessLine3NW;
        } else {
            gc->procs.line.processLine = __glProcessLine;
        }
        if ((modeFlags & __GL_SHADE_CHEAP_FOG) &&
                !(modeFlags & __GL_SHADE_SMOOTH_LIGHT)) {
            gc->procs.renderLine2 = gc->procs.renderLine;
            gc->procs.renderLine = __glRenderFlatFogLine;
        }
    }
}

BOOL FASTCALL __glGenCreateAccelContext(__GLcontext *gc)
{
    __GLGENcontext *genGc = (__GLGENcontext *)gc;
    PIXELFORMATDESCRIPTOR *pfmt;
    ULONG bpp;

    pfmt = &genGc->gsurf.pfd;
    bpp = pfmt->cColorBits;

    genGc->pPrivateArea = (VOID *)(&genGc->genAccel);

    __glQueryLineAcceleration(gc);

    gc->procs.pickTriangleProcs = __fastGenPickTriangleProcs;
    gc->procs.pickSpanProcs     = __fastGenPickSpanProcs;

    // Set up constant-color values:

    GENACCEL(gc).constantR = ((1 << pfmt->cRedBits) - 1) << 16;
    GENACCEL(gc).constantG = ((1 << pfmt->cGreenBits) - 1) << 16;
    GENACCEL(gc).constantB = ((1 << pfmt->cBlueBits) - 1) << 16;
    if( pfmt->cAlphaBits )
        GENACCEL(gc).constantA = ((1 << pfmt->cAlphaBits) - 1) << 16;
    else
        GENACCEL(gc).constantA = 0xff << 16;

    GENACCEL(gc).bpp = bpp;
    GENACCEL(gc).xMultiplier = ((bpp + 7) / 8);

    if (gc->modes.depthBits == 16 )
        GENACCEL(gc).zScale = (__GLfloat)65536.0;
    else
        GENACCEL(gc).zScale = (__GLfloat)1.0;

    return TRUE;
}


MCDHANDLE FASTCALL __glGenLoadTexture(__GLcontext *gc, __GLtexture *tex,
                                      ULONG flags)
{
    __GLGENcontext *gengc = (__GLGENcontext *)gc;
    MCDHANDLE texHandle;
    DWORD texKey;

#ifdef _MCD_
    if (gengc->pMcdState) {
        texHandle = GenMcdCreateTexture(gengc, tex, flags);
        if (texHandle) {
            tex->textureKey = GenMcdTextureKey(gengc, texHandle);
            gc->textureKey = tex->textureKey;
        }
        return texHandle;
    } else
#endif
        return 0;
}


BOOL FASTCALL __glGenMakeTextureCurrent(__GLcontext *gc, __GLtexture *tex, MCDHANDLE loadKey)
{
    GLint internalFormat;

    if (!tex)
        return FALSE;

    InitAccelTextureValues(gc, tex);

    // Update the driver texture key in the context:

    if (((__GLGENcontext *)gc)->pMcdState && (gc->textureKey = tex->textureKey)) {
        GenMcdUpdateTextureState((__GLGENcontext *)gc, tex, loadKey);
    }

    // Previously we called bUseGenTriangles here to determine whether we were
    // doing 'fast' texturing, and if so, setup the texture cache pointers
    // below.  But this slowed down texture bind time, so for now we always
    // execute this next section of code (safe, since we check for valid ptrs).

    if (tex->level[0].internalFormat == GL_COLOR_INDEX8_EXT)
    {
        if (tex->pvUser)
            GENACCEL(gc).texImageReplace =
                ((GENTEXCACHE *)tex->pvUser)->texImageReplace;
    }
    else if (tex->level[0].internalFormat != GL_COLOR_INDEX16_EXT)
    {
        if (tex->pvUser)
            GENACCEL(gc).texImageReplace =
                ((GENTEXCACHE *)tex->pvUser)->texImageReplace;

        GENACCEL(gc).texPalette = NULL;
    }

    return TRUE;
}


BOOL FASTCALL __glGenUpdateTexture(__GLcontext *gc, __GLtexture *tex, MCDHANDLE loadKey)
{

//!! NOTE !!
//!! This should really be broken into separate load and update calls since
//!! loading and updating are different operations.  The texture texture
//!! data cache will never shrink with the current implementation.

    // Do not quit if the load fails because we want the repick to occur
    // in MakeTextureCurrent in both the success and failure cases
    __fastGenLoadTexImage(gc, tex);

    __glGenMakeTextureCurrent(gc, tex, loadKey);

    return TRUE;
}


void FASTCALL __glGenFreeTexture(__GLcontext *gc, __GLtexture *tex, MCDHANDLE loadKey)
{
    __GLGENcontext  *gengc = (__GLGENcontext *)gc;

    if (GENACCEL(gc).texImage)
        GENACCEL(gc).texImage = NULL;

    if (tex->pvUser) {
        GCFREE(gc, tex->pvUser);
        tex->pvUser = NULL;
    }

#ifdef _MCD_
    if (gengc->pMcdState && loadKey) {
        GenMcdDeleteTexture(gengc, loadKey);
    }
#endif
}

void FASTCALL __glGenUpdateTexturePalette(__GLcontext *gc, __GLtexture *tex,
                                          MCDHANDLE loadKey, ULONG start,
                                          ULONG count)
{
    UCHAR *texBuffer;
    GENTEXCACHE *pGenTex;
    __GLcolorBuffer *cfb = gc->drawBuffer;
    BYTE *pXlat = ((__GLGENcontext *)gc)->pajTranslateVector;
    ULONG rBits, gBits, bBits;
    ULONG rShift, gShift, bShift;
    ULONG i, end;
    ULONG *replaceBuffer;

    ASSERTOPENGL(tex->paletteTotalData != NULL,
                 "__GenUpdateTexturePalette: null texture data\n");

#ifdef _MCD_
    if (((__GLGENcontext *)gc)->pMcdState && loadKey) {
        GenMcdUpdateTexturePalette((__GLGENcontext *)gc, tex, loadKey, start, 
                                   count);
    }
#endif

    pGenTex = GetGenTexCache(gc, tex);
    if (!pGenTex)
        return;

    GENACCEL(gc).texImageReplace = pGenTex->texImageReplace;

    replaceBuffer = (ULONG *)(pGenTex->texImageReplace) + start;
    texBuffer = (UCHAR *)(tex->paletteTotalData + start);

    rShift = cfb->redShift;
    gShift = cfb->greenShift;
    bShift = cfb->blueShift;
    rBits = ((__GLGENcontext *)gc)->gsurf.pfd.cRedBits;
    gBits = ((__GLGENcontext *)gc)->gsurf.pfd.cGreenBits;
    bBits = ((__GLGENcontext *)gc)->gsurf.pfd.cBlueBits;

    end = start + count;

    for (i = start; i < end; i++, texBuffer += 4) {
        ULONG color;

        color = ((((ULONG)texBuffer[2] << rBits) >> 8) << rShift) |
                ((((ULONG)texBuffer[1] << gBits) >> 8) << gShift) |
                ((((ULONG)texBuffer[0] << bBits) >> 8) << bShift);

        if (GENACCEL(gc).bpp == 8)
            color = pXlat[color & 0xff];

        *replaceBuffer++ = (color | ((ULONG)texBuffer[3] << 24));
    }
}

#ifdef GL_EXT_flat_paletted_lighting
void FASTCALL __glGenSetPaletteOffset(__GLcontext *gc, __GLtexture *tex,
                                      GLint offset)
{
    GENTEXCACHE *pGenTex;

    if (GENACCEL(gc).texPalette == NULL)
    {
        return;
    }
    
    GENACCEL(gc).texPalette = (ULONG *)tex->paletteTotalData+offset;
    
    pGenTex = GetGenTexCache(gc, tex);
    if (pGenTex == NULL)
    {
        return;
    }

    // Replace map for paletted textures is a replace map of the
    // entire palette, so offset it
    if (GENACCEL(gc).texImageReplace != NULL)
    {
        GENACCEL(gc).texImageReplace = (UCHAR *)
            ((ULONG *)pGenTex->texImageReplace+offset);
    }
    
    // Consider - Call MCD
}
#endif

void FASTCALL __glGenDestroyAccelContext(__GLcontext *gc)
{
    __GLGENcontext *genGc = (__GLGENcontext *)gc;

    /* Free any platform-specific private data area */

    if (genGc->pPrivateArea) {

        if (GENACCEL(gc).pFastLineBuffer) {
            GCFREE(gc, GENACCEL(gc).pFastLineBuffer);
#ifndef _CLIENTSIDE_
            wglDeletePath(GENACCEL(gc).pFastLinePathobj);
#endif
        }

        genGc->pPrivateArea = NULL;
    }
}