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

#include <windows.h>
#include <ddraw.h>
#include <d3d.h>
#include <assert.h>
#include "softm.h"
#include "globals.h"
#include "smddraw.h"
#include "smd3d.h"
#include "raster.h"
#include "pixconv.h"

int cTrivialAccept;
int cTrivialPartial;
int cTrivialReject;

void SpanNoOp(void);
void SpanBad(void);

void SpanShade_FlatRGB(void);
void SpanShade_FlatRGBA(void);
void SpanShade_FlatRGBMul(void);
void SpanShade_FlatRGBAMul(void);
void SpanShade_FlatRGBMulA(void);
void SpanShade_FlatA(void);
void SpanShade_FlatAMul(void);
void SpanShade_FlatIMul(void);
void SpanShade_FlatIMulA(void);
void SpanShade_FlatIAMul(void);
void SpanShade_GouraudRGB(void);
void SpanShade_GouraudRGBA(void);
void SpanShade_GouraudIMul(void);
void SpanShade_GouraudIAMul(void);
void SpanShade_GouraudIMulA(void);
void SpanShade_GouraudRGBMul(void);
void SpanShade_GouraudRGBAMul(void);
void SpanShade_GouraudRGBMulA(void);
void SpanShade_GouraudA(void);
void SpanShade_GouraudAMul(void);
void SpanShade_Native_FlatRGB(void);
void SpanShade_Native_GouraudRGB(void);

void SpanTrivialZ_Bad(void);
void SpanTrivialZ_CW(void);
void SpanTrivialZ_C(void);
void SpanTrivialZ_W(void);
void SpanTrivialZ_Noop(void);
void SpanTrivialZ_CW_Native(void);
void SpanTrivialZ_C_Native(void);

void SpanBackend_Bad(void);
void SpanBackend_NoZ_10_NoAlphaTest(void);
void SpanBackend_NoZ_10_AlphaTest(void);
void SpanBackend_NoZ_11_NoAlphaTest(void);
void SpanBackend_NoZ_11_AlphaTest(void);
void SpanBackend_NoZ_1InvAlpha_NoAlphaTest(void);
void SpanBackend_NoZ_1InvAlpha_AlphaTest(void);
void SpanBackend_NoZ_AlphaInvAlpha_NoAlphaTest(void);
void SpanBackend_NoZ_AlphaInvAlpha_AlphaTest(void);
void SpanBackend_ZC_10_NoAlphaTest(void);
void SpanBackend_ZC_10_AlphaTest(void);
void SpanBackend_ZC_11_NoAlphaTest(void);
void SpanBackend_ZC_11_AlphaTest(void);
void SpanBackend_ZC_1InvAlpha_NoAlphaTest(void);
void SpanBackend_ZC_1InvAlpha_AlphaTest(void);
void SpanBackend_ZC_AlphaInvAlpha_NoAlphaTest(void);
void SpanBackend_ZC_AlphaInvAlpha_AlphaTest(void);
void SpanBackend_ZCCond_10_NoAlphaTest(void);
void SpanBackend_ZCCond_10_AlphaTest(void);
void SpanBackend_ZCCond_11_NoAlphaTest(void);
void SpanBackend_ZCCond_11_AlphaTest(void);
void SpanBackend_ZCCond_1InvAlpha_NoAlphaTest(void);
void SpanBackend_ZCCond_1InvAlpha_AlphaTest(void);
void SpanBackend_ZCCond_AlphaInvAlpha_NoAlphaTest(void);
void SpanBackend_ZCCond_AlphaInvAlpha_AlphaTest(void);
void SpanBackend_ZCW_10_NoAlphaTest(void);
void SpanBackend_ZCW_10_AlphaTest(void);
void SpanBackend_ZCW_11_NoAlphaTest(void);
void SpanBackend_ZCW_11_AlphaTest(void);
void SpanBackend_ZCW_1InvAlpha_NoAlphaTest(void);
void SpanBackend_ZCW_1InvAlpha_AlphaTest(void);
void SpanBackend_ZCW_AlphaInvAlpha_NoAlphaTest(void);
void SpanBackend_ZCW_AlphaInvAlpha_AlphaTest(void);
void SpanBackend_ZCWCond_10_NoAlphaTest(void);
void SpanBackend_ZCWCond_10_AlphaTest(void);
void SpanBackend_ZCWCond_11_NoAlphaTest(void);
void SpanBackend_ZCWCond_11_AlphaTest(void);
void SpanBackend_ZCWCond_1InvAlpha_NoAlphaTest(void);
void SpanBackend_ZCWCond_1InvAlpha_AlphaTest(void);
void SpanBackend_ZCWCond_AlphaInvAlpha_NoAlphaTest(void);
void SpanBackend_ZCWCond_AlphaInvAlpha_AlphaTest(void);
void SpanBackend_ZW_10_NoAlphaTest(void);
void SpanBackend_ZW_10_AlphaTest(void);
void SpanBackend_ZW_11_NoAlphaTest(void);
void SpanBackend_ZW_11_AlphaTest(void);
void SpanBackend_ZW_1InvAlpha_NoAlphaTest(void);
void SpanBackend_ZW_1InvAlpha_AlphaTest(void);
void SpanBackend_ZW_AlphaInvAlpha_NoAlphaTest(void);
void SpanBackend_ZW_AlphaInvAlpha_AlphaTest(void);
void SpanBackend_Native_NoZ_10_NoAlphaTest(void);
void SpanBackend_Native_ZC_10_NoAlphaTest(void);
void SpanBackend_Native_ZCCond_10_NoAlphaTest(void);
void SpanBackend_Native_ZCW_10_NoAlphaTest(void);
void SpanBackend_Native_ZCWCond_10_NoAlphaTest(void);
void SpanBackend_Native_ZW_10_NoAlphaTest(void);

void SpanBackend2X_NoZ_10_NoAlphaTest(void);
void SpanBackend2X_NoZ_10_AlphaTest(void);
void SpanBackend2X_NoZ_11_NoAlphaTest(void);
void SpanBackend2X_NoZ_11_AlphaTest(void);
void SpanBackend2X_NoZ_1InvAlpha_NoAlphaTest(void);
void SpanBackend2X_NoZ_1InvAlpha_AlphaTest(void);
void SpanBackend2X_NoZ_AlphaInvAlpha_NoAlphaTest(void);
void SpanBackend2X_NoZ_AlphaInvAlpha_AlphaTest(void);
void SpanBackend2X_ZC_10_NoAlphaTest(void);
void SpanBackend2X_ZC_10_AlphaTest(void);
void SpanBackend2X_ZC_11_NoAlphaTest(void);
void SpanBackend2X_ZC_11_AlphaTest(void);
void SpanBackend2X_ZC_1InvAlpha_NoAlphaTest(void);
void SpanBackend2X_ZC_1InvAlpha_AlphaTest(void);
void SpanBackend2X_ZC_AlphaInvAlpha_NoAlphaTest(void);
void SpanBackend2X_ZC_AlphaInvAlpha_AlphaTest(void);
void SpanBackend2X_ZCCond_10_NoAlphaTest(void);
void SpanBackend2X_ZCCond_10_AlphaTest(void);
void SpanBackend2X_ZCCond_11_NoAlphaTest(void);
void SpanBackend2X_ZCCond_11_AlphaTest(void);
void SpanBackend2X_ZCCond_1InvAlpha_NoAlphaTest(void);
void SpanBackend2X_ZCCond_1InvAlpha_AlphaTest(void);
void SpanBackend2X_ZCCond_AlphaInvAlpha_NoAlphaTest(void);
void SpanBackend2X_ZCCond_AlphaInvAlpha_AlphaTest(void);
void SpanBackend2X_ZCW_10_NoAlphaTest(void);
void SpanBackend2X_ZCW_10_AlphaTest(void);
void SpanBackend2X_ZCW_11_NoAlphaTest(void);
void SpanBackend2X_ZCW_11_AlphaTest(void);
void SpanBackend2X_ZCW_1InvAlpha_NoAlphaTest(void);
void SpanBackend2X_ZCW_1InvAlpha_AlphaTest(void);
void SpanBackend2X_ZCW_AlphaInvAlpha_NoAlphaTest(void);
void SpanBackend2X_ZCW_AlphaInvAlpha_AlphaTest(void);
void SpanBackend2X_ZCWCond_10_NoAlphaTest(void);
void SpanBackend2X_ZCWCond_10_AlphaTest(void);
void SpanBackend2X_ZCWCond_11_NoAlphaTest(void);
void SpanBackend2X_ZCWCond_11_AlphaTest(void);
void SpanBackend2X_ZCWCond_1InvAlpha_NoAlphaTest(void);
void SpanBackend2X_ZCWCond_1InvAlpha_AlphaTest(void);
void SpanBackend2X_ZCWCond_AlphaInvAlpha_NoAlphaTest(void);
void SpanBackend2X_ZCWCond_AlphaInvAlpha_AlphaTest(void);
void SpanBackend2X_ZW_10_NoAlphaTest(void);
void SpanBackend2X_ZW_10_AlphaTest(void);
void SpanBackend2X_ZW_11_NoAlphaTest(void);
void SpanBackend2X_ZW_11_AlphaTest(void);
void SpanBackend2X_ZW_1InvAlpha_NoAlphaTest(void);
void SpanBackend2X_ZW_1InvAlpha_AlphaTest(void);
void SpanBackend2X_ZW_AlphaInvAlpha_NoAlphaTest(void);
void SpanBackend2X_ZW_AlphaInvAlpha_AlphaTest(void);
void SpanBackend2X_Native_NoZ_10_NoAlphaTest(void);
void SpanBackend2X_Native_ZC_10_NoAlphaTest(void);
void SpanBackend2X_Native_ZCCond_10_NoAlphaTest(void);
void SpanBackend2X_Native_ZCW_10_NoAlphaTest(void);
void SpanBackend2X_Native_ZCWCond_10_NoAlphaTest(void);
void SpanBackend2X_Native_ZW_10_NoAlphaTest(void);

typedef void (*PSPANFN)(void);

// bytecode expansion table for chunk processors. Not const because:
// entry 1 needs to be patchable for the current backend chunk processor;
// entry 2 needs to be patchable for the current munging chunk processor.
// entry 3 needs to be patchable for the current texture mapper
// (Entry 0 is no op.)
// NOTE: keep MAX_SPAN_FN in sync with this.
// NOTE this patching makes this code non-reentrant or shareable, even if calls are
// alternated; the table has to stay the same between state changes. The table and
// the following table would have to be stored in RenderDevice, not globals, to fix this.
PSPANFN rgpspanfn[MAX_SPAN_FN + 1] = {
    SpanNoOp,
    NULL,
    NULL,
    NULL,
    SpanShade_FlatRGB,
    SpanShade_FlatRGBA,
    SpanShade_FlatRGBMul,
    SpanShade_FlatRGBAMul,
    SpanShade_FlatRGBMulA,
    SpanShade_FlatA,
    SpanShade_FlatAMul,
    SpanShade_FlatIMul,
    SpanShade_FlatIMulA,
    SpanShade_FlatIAMul,
    SpanShade_GouraudRGB,
    SpanShade_GouraudRGBA,
    SpanShade_GouraudIMul,
    SpanShade_GouraudIAMul,
    SpanShade_GouraudIMulA,
    SpanShade_GouraudRGBMul,
    SpanShade_GouraudRGBAMul,
    SpanShade_GouraudRGBMulA,
    SpanShade_GouraudA,
    SpanShade_GouraudAMul,
    SpanShade_Native_FlatRGB,
    SpanShade_Native_GouraudRGB,
    SpanBad,
};

// bytecode expansion table for trivialz and backend chunk processors that
// are used to patch rgspanfn[]. Not const because entry 0 needs to be
// patchable to the current native-one-pass chunk processor, and entry 1
// needs to be patchable to the after-trivialz vector, to handle no-op cases
// by skipping trivialz altogether.
// NOTE mikeab ASM code relies on the first entry being the current native-one-pass
// chunk processor--do not change this!

PSPANFN rgpspanfnTrivialZAndBackend[SIZE_RGPSPANFNTRIVIALZANDBACKEND] = {
    NULL,   // current native-one-pass chunk processor
    NULL,   // current trivialz-no-op chunk processor (copied from after-trivialz vector)
    SpanTrivialZ_CW,
    SpanTrivialZ_C,
    SpanTrivialZ_W,
    SpanBackend_Bad,
    SpanBackend_NoZ_10_NoAlphaTest,
    SpanBackend_NoZ_10_AlphaTest,
    SpanBackend_NoZ_11_NoAlphaTest,
    SpanBackend_NoZ_11_AlphaTest,
    SpanBackend_NoZ_1InvAlpha_NoAlphaTest,
    SpanBackend_NoZ_1InvAlpha_AlphaTest,
    SpanBackend_NoZ_AlphaInvAlpha_NoAlphaTest,
    SpanBackend_NoZ_AlphaInvAlpha_AlphaTest,
    SpanBackend_ZC_10_NoAlphaTest,
    SpanBackend_ZC_10_AlphaTest,
    SpanBackend_ZC_11_NoAlphaTest,
    SpanBackend_ZC_11_AlphaTest,
    SpanBackend_ZC_1InvAlpha_NoAlphaTest,
    SpanBackend_ZC_1InvAlpha_AlphaTest,
    SpanBackend_ZC_AlphaInvAlpha_NoAlphaTest,
    SpanBackend_ZC_AlphaInvAlpha_AlphaTest,
    SpanBackend_ZCCond_10_NoAlphaTest,
    SpanBackend_ZCCond_10_AlphaTest,
    SpanBackend_ZCCond_11_NoAlphaTest,
    SpanBackend_ZCCond_11_AlphaTest,
    SpanBackend_ZCCond_1InvAlpha_NoAlphaTest,
    SpanBackend_ZCCond_1InvAlpha_AlphaTest,
    SpanBackend_ZCCond_AlphaInvAlpha_NoAlphaTest,
    SpanBackend_ZCCond_AlphaInvAlpha_AlphaTest,
    SpanBackend_ZCW_10_NoAlphaTest,
    SpanBackend_ZCW_10_AlphaTest,
    SpanBackend_ZCW_11_NoAlphaTest,
    SpanBackend_ZCW_11_AlphaTest,
    SpanBackend_ZCW_1InvAlpha_NoAlphaTest,
    SpanBackend_ZCW_1InvAlpha_AlphaTest,
    SpanBackend_ZCW_AlphaInvAlpha_NoAlphaTest,
    SpanBackend_ZCW_AlphaInvAlpha_AlphaTest,
    SpanBackend_ZCWCond_10_NoAlphaTest,
    SpanBackend_ZCWCond_10_AlphaTest,
    SpanBackend_ZCWCond_11_NoAlphaTest,
    SpanBackend_ZCWCond_11_AlphaTest,
    SpanBackend_ZCWCond_1InvAlpha_NoAlphaTest,
    SpanBackend_ZCWCond_1InvAlpha_AlphaTest,
    SpanBackend_ZCWCond_AlphaInvAlpha_NoAlphaTest,
    SpanBackend_ZCWCond_AlphaInvAlpha_AlphaTest,
    SpanBackend_ZW_10_NoAlphaTest,
    SpanBackend_ZW_10_AlphaTest,
    SpanBackend_ZW_11_NoAlphaTest,
    SpanBackend_ZW_11_AlphaTest,
    SpanBackend_ZW_1InvAlpha_NoAlphaTest,
    SpanBackend_ZW_1InvAlpha_AlphaTest,
    SpanBackend_ZW_AlphaInvAlpha_NoAlphaTest,
    SpanBackend_ZW_AlphaInvAlpha_AlphaTest,
    SpanBackend_Native_NoZ_10_NoAlphaTest,
    SpanBackend_Native_ZC_10_NoAlphaTest,
    SpanBackend_Native_ZCCond_10_NoAlphaTest,
    SpanBackend_Native_ZCW_10_NoAlphaTest,
    SpanBackend_Native_ZCWCond_10_NoAlphaTest,
    SpanBackend_Native_ZW_10_NoAlphaTest,
    SpanTrivialZ_Bad,
    SpanTrivialZ_CW_Native,
    SpanBackend2X_NoZ_10_NoAlphaTest,
    SpanBackend2X_NoZ_10_AlphaTest,
    SpanBackend2X_NoZ_11_NoAlphaTest,
    SpanBackend2X_NoZ_11_AlphaTest,
    SpanBackend2X_NoZ_1InvAlpha_NoAlphaTest,
    SpanBackend2X_NoZ_1InvAlpha_AlphaTest,
    SpanBackend2X_NoZ_AlphaInvAlpha_NoAlphaTest,
    SpanBackend2X_NoZ_AlphaInvAlpha_AlphaTest,
    SpanBackend2X_ZC_10_NoAlphaTest,
    SpanBackend2X_ZC_10_AlphaTest,
    SpanBackend2X_ZC_11_NoAlphaTest,
    SpanBackend2X_ZC_11_AlphaTest,
    SpanBackend2X_ZC_1InvAlpha_NoAlphaTest,
    SpanBackend2X_ZC_1InvAlpha_AlphaTest,
    SpanBackend2X_ZC_AlphaInvAlpha_NoAlphaTest,
    SpanBackend2X_ZC_AlphaInvAlpha_AlphaTest,
    SpanBackend2X_ZCCond_10_NoAlphaTest,
    SpanBackend2X_ZCCond_10_AlphaTest,
    SpanBackend2X_ZCCond_11_NoAlphaTest,
    SpanBackend2X_ZCCond_11_AlphaTest,
    SpanBackend2X_ZCCond_1InvAlpha_NoAlphaTest,
    SpanBackend2X_ZCCond_1InvAlpha_AlphaTest,
    SpanBackend2X_ZCCond_AlphaInvAlpha_NoAlphaTest,
    SpanBackend2X_ZCCond_AlphaInvAlpha_AlphaTest,
    SpanBackend2X_ZCW_10_NoAlphaTest,
    SpanBackend2X_ZCW_10_AlphaTest,
    SpanBackend2X_ZCW_11_NoAlphaTest,
    SpanBackend2X_ZCW_11_AlphaTest,
    SpanBackend2X_ZCW_1InvAlpha_NoAlphaTest,
    SpanBackend2X_ZCW_1InvAlpha_AlphaTest,
    SpanBackend2X_ZCW_AlphaInvAlpha_NoAlphaTest,
    SpanBackend2X_ZCW_AlphaInvAlpha_AlphaTest,
    SpanBackend2X_ZCWCond_10_NoAlphaTest,
    SpanBackend2X_ZCWCond_10_AlphaTest,
    SpanBackend2X_ZCWCond_11_NoAlphaTest,
    SpanBackend2X_ZCWCond_11_AlphaTest,
    SpanBackend2X_ZCWCond_1InvAlpha_NoAlphaTest,
    SpanBackend2X_ZCWCond_1InvAlpha_AlphaTest,
    SpanBackend2X_ZCWCond_AlphaInvAlpha_NoAlphaTest,
    SpanBackend2X_ZCWCond_AlphaInvAlpha_AlphaTest,
    SpanBackend2X_ZW_10_NoAlphaTest,
    SpanBackend2X_ZW_10_AlphaTest,
    SpanBackend2X_ZW_11_NoAlphaTest,
    SpanBackend2X_ZW_11_AlphaTest,
    SpanBackend2X_ZW_1InvAlpha_NoAlphaTest,
    SpanBackend2X_ZW_1InvAlpha_AlphaTest,
    SpanBackend2X_ZW_AlphaInvAlpha_NoAlphaTest,
    SpanBackend2X_ZW_AlphaInvAlpha_AlphaTest,
    SpanBackend2X_Native_NoZ_10_NoAlphaTest,
    SpanBackend2X_Native_ZC_10_NoAlphaTest,
    SpanBackend2X_Native_ZCCond_10_NoAlphaTest,
    SpanBackend2X_Native_ZCW_10_NoAlphaTest,
    SpanBackend2X_Native_ZCWCond_10_NoAlphaTest,
    SpanBackend2X_Native_ZW_10_NoAlphaTest,
    SpanTrivialZ_W_Native,
    SpanTrivialZ_C_Native,
};

#define MUNGED3_SATURATION_MASK_BLUE    (0x1F << 5)
#define MUNGED3_SATURATION_MASK_GREEN   (0x1F << 15)
#define MUNGED3_SATURATION_MASK_RED     (0x1F << 25)
#define MUNGED3_SATURATION_MASK         (MUNGED3_SATURATION_MASK_BLUE | \
                                         MUNGED3_SATURATION_MASK_GREEN | \
                                         MUNGED3_SATURATION_MASK_RED)
#define MUNGED3_SATURATED_BLUE          (0x1F)
#define MUNGED3_SATURATED_GREEN         (0x1F << 10)
#define MUNGED3_SATURATED_RED           (0x1F << 20)
#define MUNGED3_CLEAR_PADS              (MUNGED3_SATURATED_BLUE | \
                                         MUNGED3_SATURATED_GREEN | \
                                         MUNGED3_SATURATED_RED)

#if defined(_DEBUG)
BOOL ReportClamp = FALSE;
#endif


// converts 4-byte munged format to two identical pixels in the target format (555 or 565)
inline DWORD FROM_MUNGED3_TO_TARGET2X(MUNGED3 m3)
{
    DWORD   t;

    t = ((m3 & 0x0000001F) |
        ((m3 & 0x00007C00) >> g_grdChunkData.cMunged3ToTargetShift0) |
        ((m3 & 0x01F00000) >> g_grdChunkData.cMunged3ToTargetShift1));

    return t | (t << 16);
}


// converts the target format (555 or 565) to 4-byte munged format
inline DWORD FROM_TARGET_TO_MUNGED3(DWORD dwPix)
{
    return (dwPix & 0x0000001F) |
           ((dwPix << g_grdChunkData.cMunged3ToTargetShift0) & 0x0007C00) |
           ((dwPix << g_grdChunkData.cMunged3ToTargetShift1) & 0x1F00000);
}


// converts a GOURAUD_RGB to native format.
inline WORD GOURAUD_RGB_TO_NATIVE(GOURAUD_RGB grgb)
{
    return (WORD)(((grgb & 0x000003E0) >> 5) |
                  ((grgb & 0x001F0000) >> (6 + g_grdChunkData.cMunged3ToTargetShift0)) |
                  ((grgb & 0xF8000000) >> (7 + g_grdChunkData.cMunged3ToTargetShift1)));
}


// does a 11 alpha blend (with saturation) of g_grdChunkData.rgm3WorkingBuffer[i+16]
// and pwPix[i], and stores the result at pwPix[i].
inline void Draw11Pixel(WORD *pwPix, int i)
{
    DWORD   dwPix;

    if (g_grdChunkData.rgm3WorkingBuffer[i+16] != 0)
    {
        dwPix = g_grdChunkData.rgm3WorkingBuffer[i+16] + FROM_TARGET_TO_MUNGED3(pwPix[i]);

        if (dwPix & MUNGED3_SATURATION_MASK)
        {
            if (dwPix & MUNGED3_SATURATION_MASK_BLUE)
                dwPix |= MUNGED3_SATURATED_BLUE;

            if (dwPix & MUNGED3_SATURATION_MASK_GREEN)
                dwPix |= MUNGED3_SATURATED_GREEN;

            if (dwPix & MUNGED3_SATURATION_MASK_RED)
                dwPix |= MUNGED3_SATURATED_RED;

            dwPix &= MUNGED3_CLEAR_PADS;
        }

        pwPix[i] = FROM_MUNGED3_TO_TARGET(dwPix);
    }
}


// does a 11 alpha blend (with saturation) of g_grdChunkData.rgm3WorkingBuffer[i+16]
// and pwPix[i], duplicates the result into two identical pixels in a dword,
// and stores the result at pdwPix[i].
inline void Draw11Pixel2X(DWORD *pdwPix, int i)
{
    DWORD   dwPix;

    if (g_grdChunkData.rgm3WorkingBuffer[i+16] != 0)
    {
        dwPix = g_grdChunkData.rgm3WorkingBuffer[i+16] + FROM_TARGET_TO_MUNGED3(pdwPix[i]);

        if (dwPix & MUNGED3_SATURATION_MASK)
        {
            if (dwPix & MUNGED3_SATURATION_MASK_BLUE)
                dwPix |= MUNGED3_SATURATED_BLUE;

            if (dwPix & MUNGED3_SATURATION_MASK_GREEN)
                dwPix |= MUNGED3_SATURATED_GREEN;

            if (dwPix & MUNGED3_SATURATION_MASK_RED)
                dwPix |= MUNGED3_SATURATED_RED;

            dwPix &= MUNGED3_CLEAR_PADS;
        }

        dwPix = FROM_MUNGED3_TO_TARGET(dwPix);
        pdwPix[i] = dwPix | (dwPix << 16);
    }
}


// does an AlphaInvAlpha alpha blend of g_grdChunkData.rgm3WorkingBuffer[i+16]
// and pwPix[i], and stores the result at pwPix[i].
inline void DrawAlphaInvAlphaPixel(WORD *pwPix, int i)
{
    DWORD   dwPix;
    MUNGED1 m1Alpha;

    m1Alpha = g_grdChunkData.rgm1WorkingAlphaBuffer[i+16];

    if (m1Alpha == 0x1F)
    {
        dwPix = g_grdChunkData.rgm3WorkingBuffer[i+16];
    }
    else
    {
        dwPix = MUL_MUNGED3_TIMES_MUNGED1_WITH_FIXUP(FROM_TARGET_TO_MUNGED3(pwPix[i]), (~m1Alpha) & 0x1F);
        dwPix += MUL_MUNGED3_TIMES_MUNGED1_WITH_FIXUP(g_grdChunkData.rgm3WorkingBuffer[i+16], m1Alpha);
    }

    pwPix[i] = FROM_MUNGED3_TO_TARGET(dwPix);
}


// does an AlphaInvAlpha alpha blend of g_grdChunkData.rgm3WorkingBuffer[i+16]
// and pwPix[i], duplicates the result into two identical pixels in a dword,
// and stores the result at pdwPix[i].
inline void DrawAlphaInvAlphaPixel2X(DWORD *pdwPix, int i)
{
    DWORD   dwPix;
    MUNGED1 m1Alpha;

    m1Alpha = g_grdChunkData.rgm1WorkingAlphaBuffer[i+16];

    if (m1Alpha == 0x1F)
    {
        dwPix = g_grdChunkData.rgm3WorkingBuffer[i+16];
    }
    else
    {
        dwPix = MUL_MUNGED3_TIMES_MUNGED1_WITH_FIXUP(FROM_TARGET_TO_MUNGED3(pdwPix[i]), (~m1Alpha) & 0x1F);
        dwPix += MUL_MUNGED3_TIMES_MUNGED1_WITH_FIXUP(g_grdChunkData.rgm3WorkingBuffer[i+16], m1Alpha);
    }

    dwPix = FROM_MUNGED3_TO_TARGET(dwPix);
    pdwPix[i] = dwPix | (dwPix << 16);
}


// does an 1InvAlpha alpha blend (with saturation) of g_grdChunkData.rgm3WorkingBuffer[i+16]
// and pwPix[i], and stores the result at pwPix[i].
inline void Draw1InvAlphaPixel(WORD *pwPix, int i)
{
    DWORD   dwPix;
    MUNGED1 m1Alpha;

    m1Alpha = g_grdChunkData.rgm1WorkingAlphaBuffer[i+16];

    if (m1Alpha == 0x1F)
    {
        dwPix = g_grdChunkData.rgm3WorkingBuffer[i+16];
    }
    else
    {
        dwPix = MUL_MUNGED3_TIMES_MUNGED1_WITH_FIXUP(FROM_TARGET_TO_MUNGED3(pwPix[i]), (~m1Alpha) & 0x1F);
        dwPix += g_grdChunkData.rgm3WorkingBuffer[i+16];

        if (dwPix & MUNGED3_SATURATION_MASK)
        {
            if (dwPix & MUNGED3_SATURATION_MASK_BLUE)
                dwPix |= MUNGED3_SATURATED_BLUE;

            if (dwPix & MUNGED3_SATURATION_MASK_GREEN)
                dwPix |= MUNGED3_SATURATED_GREEN;

            if (dwPix & MUNGED3_SATURATION_MASK_RED)
                dwPix |= MUNGED3_SATURATED_RED;

            dwPix &= MUNGED3_CLEAR_PADS;
        }
    }

    pwPix[i] = FROM_MUNGED3_TO_TARGET(dwPix);
}


// does an 1InvAlpha alpha blend (with saturation) of g_grdChunkData.rgm3WorkingBuffer[i+16]
// and pwPix[i], duplicates the result into two identical pixels in a dword,
// and stores the result at pdwPix[i].
inline void Draw1InvAlphaPixel2X(DWORD *pdwPix, int i)
{
    DWORD   dwPix;
    MUNGED1 m1Alpha;

    m1Alpha = g_grdChunkData.rgm1WorkingAlphaBuffer[i+16];

    if (m1Alpha == 0x1F)
    {
        dwPix = g_grdChunkData.rgm3WorkingBuffer[i+16];
    }
    else
    {
        dwPix = MUL_MUNGED3_TIMES_MUNGED1_WITH_FIXUP(FROM_TARGET_TO_MUNGED3(pdwPix[i]), (~m1Alpha) & 0x1F);
        dwPix += g_grdChunkData.rgm3WorkingBuffer[i+16];

        if (dwPix & MUNGED3_SATURATION_MASK)
        {
            if (dwPix & MUNGED3_SATURATION_MASK_BLUE)
                dwPix |= MUNGED3_SATURATED_BLUE;

            if (dwPix & MUNGED3_SATURATION_MASK_GREEN)
                dwPix |= MUNGED3_SATURATED_GREEN;

            if (dwPix & MUNGED3_SATURATION_MASK_RED)
                dwPix |= MUNGED3_SATURATED_RED;

            dwPix &= MUNGED3_CLEAR_PADS;
        }
    }

    dwPix = FROM_MUNGED3_TO_TARGET(dwPix);
    pdwPix[i] = dwPix | (dwPix << 16);
}


//----------------------------------------------------------------------------
// chunk processor: does nothing.
//----------------------------------------------------------------------------
void SpanNoOp(void)
{
}


//----------------------------------------------------------------------------
// chunk processor: report error in debug build, does nothing in release.
// Should never be called.
//----------------------------------------------------------------------------
void SpanBad(void)
{
    assert(0);
}


//----------------------------------------------------------------------------
// Trivialz-pass chunk processors.
//
// Handle trivialz read (compare), write, read/write, and no-op.
//----------------------------------------------------------------------------

// chunk processor: should never be called, used in cases that shouldn't use trivialz.
void SpanTrivialZ_Bad(void)
{
    assert(0);
}


// chunk processor: does trivial z accept/reject and sets z
// NOTE: this only works with modes that include '=', because we have to
// be able to later write the correct pixels using z compare again if
// this isn't trivially accepted
#if USE_C
void SpanTrivialZ_CW(void)
{
    int     i, cAccept = 0;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if ((dwZ >> 16) <= pwZ[i])
        {
            pwZ[i] = (WORD)(dwZ >> 16);
            cAccept--;
        }

        dwZ += dwZIncr;
    } while (++i < 0);

    if (cAccept < 0)
    {
        if (cAccept == g_grdChunkData.cPixels_Chunk)
        {
            g_grdChunkData.fNeedToDoBackendZCompare = FALSE;
#if defined(_DEBUG)
            cTrivialAccept++;
#endif
        }
        else
        {
            g_grdChunkData.fNeedToDoBackendZCompare = TRUE;
#if defined(_DEBUG)
            cTrivialPartial++;
#endif
        }
        (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_TRIVIALZ])();
    }
#if defined(_DEBUG)
    else
    {
        cTrivialReject++;
    }
#endif

}
#else
__declspec(naked) void SpanTrivialZ_CW(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov esi,[g_grdChunkData.pZ_Chunk]
    mov ebx,[g_grdChunkData.dwZ_Chunk]
    ror ebx,16
    mov eax,[g_grdChunkData.ZIncr_Chunk]
    ror eax,16
    sub edx,edx
mloopz:
    cmp bx,[esi+ecx*2]
    ja  zskip
    mov [esi+ecx*2],bx
    dec edx
zskip:
    add ebx,eax
    adc ebx,0
    inc ecx
    jnz mloopz

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif

    test edx,edx
    jz  Done
    xor edx,[g_grdChunkData.cPixels_Chunk]
    mov [g_grdChunkData.fNeedToDoBackendZCompare],edx
#if defined(_DEBUG)
    jz  Accept
    inc [cTrivialPartial]
    jmp Skip
Accept:
    inc [cTrivialAccept]
Skip:
#endif

    jmp dword ptr [g_grdChunkData.pspanfnWorking+PSPANFN_AFTER_TRIVIALZ*4]

Done:
#if defined(_DEBUG)
    inc [cTrivialReject]
#endif

    ret
    }
}
#endif


// chunk processor: does trivial z accept/reject and sets z for native mode
// This is the same as SpanTrivialZ_CW, except that it uses the native mode
// copy routine if trivial accept is found, and the native mode zcw routine
// if not; span vectors are ignored.
// NOTE: this only works with modes that include '=', because we have to
// be able to later write the correct pixels using z compare again if
// this isn't trivially accepted
#if USE_C
void SpanTrivialZ_CW_Native(void)
{
    int     i, cAccept = 0;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if ((dwZ >> 16) <= pwZ[i])
        {
            pwZ[i] = (WORD)(dwZ >> 16);
            cAccept--;
        }

        dwZ += dwZIncr;
    } while (++i < 0);

    if (cAccept < 0)
    {
        if (cAccept == g_grdChunkData.cPixels_Chunk)
        {
            (*rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS])();

#if defined(_DEBUG)
            cTrivialAccept++;
#endif
        }
        else
        {
            g_grdChunkData.fNeedToDoBackendZCompare = TRUE;
	        (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_TRIVIALZ])();
#if defined(_DEBUG)
            cTrivialPartial++;
#endif
        }
    }
#if defined(_DEBUG)
    else
    {
        cTrivialReject++;
    }
#endif

}
#else
__declspec(naked) void SpanTrivialZ_CW_Native(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov esi,[g_grdChunkData.pZ_Chunk]
    mov ebx,[g_grdChunkData.dwZ_Chunk]
    ror ebx,16
    mov eax,[g_grdChunkData.ZIncr_Chunk]
    ror eax,16
    sub edx,edx
mloopz:
    cmp bx,[esi+ecx*2]
    ja  zskip
    mov [esi+ecx*2],bx
    dec edx
zskip:
    add ebx,eax
    adc ebx,0
    inc ecx
    jnz mloopz

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif

    cmp edx,[g_grdChunkData.cPixels_Chunk]
    jnz  NotTrivialAccept
#if defined(_DEBUG)
    inc [cTrivialAccept]
#endif
    jmp dword ptr [rgpspanfnTrivialZAndBackend+NATIVE_SINGLE_PASS*4]

NotTrivialAccept:
    test edx,edx
    jnz  Partial

#if defined(_DEBUG)
    inc [cTrivialReject]
#endif
    ret

Partial:
#if defined(_DEBUG)
    inc [cTrivialPartial]
#endif
    mov [g_grdChunkData.fNeedToDoBackendZCompare],1
    jmp dword ptr [g_grdChunkData.pspanfnWorking+PSPANFN_AFTER_TRIVIALZ*4]
    }
}
#endif


// chunk processor: writes z unconditionally.
#if USE_C
void SpanTrivialZ_W(void)
{
    int     i;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        pwZ[i] = (WORD)(dwZ >> 16);
        dwZ += dwZIncr;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_TRIVIALZ])();
}
#endif


// chunk processor: writes z unconditionally.
#if USE_C
void SpanTrivialZ_W_Native(void)
{
    int     i;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        pwZ[i] = (WORD)(dwZ >> 16);
        dwZ += dwZIncr;
    } while (++i < 0);

    // now jump directly to copying the pixels in a single pass
    (*rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS])();
}
#endif


// chunk processor: does trivial z accept/reject without setting z.
#if USE_C
void SpanTrivialZ_C(void)
{
    int     i, cAccept = 0;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if ((dwZ >> 16) <= pwZ[i])
        {
            cAccept--;
        }

        dwZ += dwZIncr;
    } while (++i < 0);

    if (cAccept < 0)
    {
        if (cAccept == g_grdChunkData.cPixels_Chunk)
        {
            g_grdChunkData.fNeedToDoBackendZCompare = FALSE;
#if defined(_DEBUG)
            cTrivialAccept++;
#endif
        }
        else
        {
            g_grdChunkData.fNeedToDoBackendZCompare = TRUE;
#if defined(_DEBUG)
            cTrivialPartial++;
#endif
        }

        (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_TRIVIALZ])();
    }
#if defined(_DEBUG)
    else
    {
        cTrivialReject++;
    }
#endif
}
#else
__declspec(naked) void SpanTrivialZ_C(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov esi,[g_grdChunkData.pZ_Chunk]
    mov ebx,[g_grdChunkData.dwZ_Chunk]
    ror ebx,16
    mov eax,[g_grdChunkData.ZIncr_Chunk]
    ror eax,16
    sub edx,edx
mloopz:
    cmp [esi+ecx*2],bx
    adc edx,-1
    add ebx,eax
    adc ebx,0
    inc ecx
    jnz mloopz

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif

    test edx,edx
    jz  Done
    xor edx,[g_grdChunkData.cPixels_Chunk]
    mov [g_grdChunkData.fNeedToDoBackendZCompare],edx
#if defined(_DEBUG)
    jz  Accept
    inc [cTrivialPartial]
    jmp Skip
Accept:
    inc [cTrivialAccept]
Skip:
#endif

    jmp dword ptr [g_grdChunkData.pspanfnWorking+PSPANFN_AFTER_TRIVIALZ*4]

Done:
#if defined(_DEBUG)
    inc [cTrivialReject]
#endif

    ret
    }
}
#endif


// chunk processor: does trivial z accept/reject without setting z.
#if USE_C
void SpanTrivialZ_C_Native(void)
{
    int     i, cAccept = 0;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if ((dwZ >> 16) <= pwZ[i])
        {
            cAccept--;
        }

        dwZ += dwZIncr;
    } while (++i < 0);

    if (cAccept < 0)
    {
        if (cAccept == g_grdChunkData.cPixels_Chunk)
        {
            (*rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS])();

#if defined(_DEBUG)
            cTrivialAccept++;
#endif
        }
        else
        {
            g_grdChunkData.fNeedToDoBackendZCompare = TRUE;
            (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_TRIVIALZ])();
#if defined(_DEBUG)
            cTrivialPartial++;
#endif
        }
    }
#if defined(_DEBUG)
    else
    {
        cTrivialReject++;
    }
#endif
}
#else
__declspec(naked) void SpanTrivialZ_C_Native(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov esi,[g_grdChunkData.pZ_Chunk]
    mov ebx,[g_grdChunkData.dwZ_Chunk]
    ror ebx,16
    mov eax,[g_grdChunkData.ZIncr_Chunk]
    ror eax,16
    sub edx,edx
mloopz:
    cmp [esi+ecx*2],bx
    adc edx,-1
    add ebx,eax
    adc ebx,0
    inc ecx
    jnz mloopz

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif

    cmp edx,[g_grdChunkData.cPixels_Chunk]
    jnz  NotTrivialAccept
#if defined(_DEBUG)
    inc [cTrivialAccept]
#endif
    jmp dword ptr [rgpspanfnTrivialZAndBackend+NATIVE_SINGLE_PASS*4]

NotTrivialAccept:
    test edx,edx
    jnz  Partial

#if defined(_DEBUG)
    inc [cTrivialReject]
#endif
    ret

Partial:
#if defined(_DEBUG)
    inc [cTrivialPartial]
#endif
    mov [g_grdChunkData.fNeedToDoBackendZCompare],1
    jmp dword ptr [g_grdChunkData.pspanfnWorking+PSPANFN_AFTER_TRIVIALZ*4]
    }
}
#endif


//----------------------------------------------------------------------------
// Backend-pass chunk processors.
//
// Handle following combinations:
//
// z: !z, zcomp, zcomp conditional, zcomp+write, zcomp+write conditional, zwrite
// alphablend: 10, 11, 1InvAlpha, AlphaInvAlpha
// alphatest: yes/no
//
// "conditional" means that if the trivialz pass didn't trivially accept or
// reject the whole span, the backend has to do the comparisons again; flagged
// by g_grdChunkData.fNeedToDoBackendZCompare as set in trivialz pass.
//----------------------------------------------------------------------------

// chunk processor: should never be called, used in cases that shouldn't use backend.
void SpanBackend_Bad(void)
{
    assert(0);
}


// !z, 10, !alphatest
#if USE_C
void SpanBackend_NoZ_10_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        pwPix[i] = FROM_MUNGED3_TO_TARGET(g_grdChunkData.rgm3WorkingBuffer[i+16]);
    } while (++i < 0);
}
#else
__declspec(naked) void SpanBackend_NoZ_10_NoAlphaTest(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov edx,[g_grdChunkData.pPix_Chunk]
    cmp [g_grdChunkData.cMunged3ToTargetShift0],5
    jz  mloop555
mloop565:
    mov esi,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    mov ebp,esi
    mov eax,esi
    shr esi,4
    and ebp,0x01F00000
    shr ebp,9
    and eax,0x1F
    and esi,0x7C0
    or  eax,ebp
    or  eax,esi
    mov [edx+ecx*2],ax
    inc ecx
    jnz mloop565

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif
    ret

mloop555:
    mov esi,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    mov ebp,esi
    mov eax,esi
    shr esi,5
    and ebp,0x01F00000
    shr ebp,10
    and eax,0x1F
    and esi,0x3E0
    or  eax,ebp
    or  eax,esi
    mov [edx+ecx*2],ax
    inc ecx
    jnz mloop555

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif
    ret
    }
}
#endif


// !z, 10, alphatest
void SpanBackend_NoZ_10_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
        {
            pwPix[i] = FROM_MUNGED3_TO_TARGET(g_grdChunkData.rgm3WorkingBuffer[i+16]);
        }
    } while (++i < 0);
}


// !z, 11, !alphatest
void SpanBackend_NoZ_11_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        Draw11Pixel(pwPix, i);
    } while (++i < 0);
}


// !z, 11, alphatest
void SpanBackend_NoZ_11_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
        {
            Draw11Pixel(pwPix, i);
        }
    } while (++i < 0);
}


// !z, AlphaInvAlpha, !alphatest
void SpanBackend_NoZ_AlphaInvAlpha_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        DrawAlphaInvAlphaPixel(pwPix, i);
    } while (++i < 0);
}


// !z, AlphaInvAlpha, alphatest
void SpanBackend_NoZ_AlphaInvAlpha_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
        {
            DrawAlphaInvAlphaPixel(pwPix, i);
        }
    } while (++i < 0);
}


// !z, 1InvAlpha, !alphatest
void SpanBackend_NoZ_1InvAlpha_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        Draw1InvAlphaPixel(pwPix, i);
    } while (++i < 0);
}


// !z, 1InvAlpha, alphatest
void SpanBackend_NoZ_1InvAlpha_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
        {
            Draw1InvAlphaPixel(pwPix, i);
        }
    } while (++i < 0);
}


// zcomp, 10, !alphatest
void SpanBackend_ZC_10_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if ((dwZ >> 16) <= pwZ[i])
        {
            pwPix[i] = FROM_MUNGED3_TO_TARGET(g_grdChunkData.rgm3WorkingBuffer[i+16]);
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp, 10, alphatest
void SpanBackend_ZC_10_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pwPix[i] = FROM_MUNGED3_TO_TARGET(g_grdChunkData.rgm3WorkingBuffer[i+16]);
            }
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp, 11, !alphatest
void SpanBackend_ZC_11_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if ((dwZ >> 16) <= pwZ[i])
        {
            Draw11Pixel(pwPix, i);
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp, 11, alphatest
void SpanBackend_ZC_11_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                Draw11Pixel(pwPix, i);
            }
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp, AlphaInvAlpha, !alphatest
void SpanBackend_ZC_AlphaInvAlpha_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if ((dwZ >> 16) <= pwZ[i])
        {
            DrawAlphaInvAlphaPixel(pwPix, i);
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp, AlphaInvAlpha, alphatest
void SpanBackend_ZC_AlphaInvAlpha_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                DrawAlphaInvAlphaPixel(pwPix, i);
            }
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp, 1InvAlpha, !alphatest
void SpanBackend_ZC_1InvAlpha_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if ((dwZ >> 16) <= pwZ[i])
        {
            Draw1InvAlphaPixel(pwPix, i);
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp, 1InvAlpha, alphatest
void SpanBackend_ZC_1InvAlpha_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                Draw1InvAlphaPixel(pwPix, i);
            }
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp conditional, 10, !alphatest
#if USE_C
void SpanBackend_ZCCond_10_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            pwPix[i] = FROM_MUNGED3_TO_TARGET(g_grdChunkData.rgm3WorkingBuffer[i+16]);
        } while (++i < 0);
    }
    else
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
        DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
        WORD    *pwZ = g_grdChunkData.pZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pwPix[i] = FROM_MUNGED3_TO_TARGET(g_grdChunkData.rgm3WorkingBuffer[i+16]);
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}
#else
__declspec(naked) void SpanBackend_ZCCond_10_NoAlphaTest(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    cmp [g_grdChunkData.fNeedToDoBackendZCompare],0
    jnz DoCompare
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov edx,[g_grdChunkData.pPix_Chunk]
    cmp [g_grdChunkData.cMunged3ToTargetShift0],5
    jz  mloop555
mloop565:
    mov esi,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    mov ebp,esi
    mov eax,esi
    shr esi,4
    and ebp,0x01F00000
    shr ebp,9
    and eax,0x1F
    and esi,0x7C0
    or  eax,ebp
    or  eax,esi
    mov [edx+ecx*2],ax
    inc ecx
    jnz mloop565

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif
    ret

mloop555:
    mov esi,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    mov ebp,esi
    mov eax,esi
    shr esi,5
    and ebp,0x01F00000
    shr ebp,10
    and eax,0x1F
    and esi,0x3E0
    or  eax,ebp
    or  eax,esi
    mov [edx+ecx*2],ax
    inc ecx
    jnz mloop555

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif
    ret

DoCompare:
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov esi,[g_grdChunkData.pZ_Chunk]
    mov ebx,[g_grdChunkData.dwZ_Chunk]
    ror ebx,16
    mov edi,[g_grdChunkData.ZIncr_Chunk]
    ror edi,16
    mov edx,[g_grdChunkData.pPix_Chunk]
    cmp [g_grdChunkData.cMunged3ToTargetShift0],5
    jz  mloopz555
mloopz:
    cmp bx,[esi+ecx*2]
    ja  zskip
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    mov ebp,eax
    shr eax,4
    and ebp,0x01F00000
    shr ebp,9
    and eax,0x7C0
    or  ebp,eax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    and eax,0x1F
    or  eax,ebp
    mov [edx+ecx*2],ax
zskip:
    add ebx,edi
    adc ebx,0
    inc ecx
    jnz mloopz

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif
    ret

mloopz555:
    cmp bx,[esi+ecx*2]
    ja  zskip555
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    mov ebp,eax
    shr eax,5
    and ebp,0x01F00000
    shr ebp,10
    and eax,0x3E0
    or  ebp,eax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    and eax,0x1F
    or  eax,ebp
    mov [edx+ecx*2],ax
zskip555:
    add ebx,edi
    adc ebx,0
    inc ecx
    jnz mloopz555

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif
    ret
    }
}
#endif


// zcomp conditional, 10, alphatest
void SpanBackend_ZCCond_10_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                pwPix[i] = FROM_MUNGED3_TO_TARGET(g_grdChunkData.rgm3WorkingBuffer[i+16]);
            }
        } while (++i < 0);
    }
    else
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
        DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
        WORD    *pwZ = g_grdChunkData.pZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    pwPix[i] = FROM_MUNGED3_TO_TARGET(g_grdChunkData.rgm3WorkingBuffer[i+16]);
                }
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp conditional, 11, !alphatest
void SpanBackend_ZCCond_11_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            Draw11Pixel(pwPix, i);
        } while (++i < 0);
    }
    else
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
        DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
        WORD    *pwZ = g_grdChunkData.pZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                Draw11Pixel(pwPix, i);
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp conditional, 11, alphatest
void SpanBackend_ZCCond_11_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                Draw11Pixel(pwPix, i);
            }
        } while (++i < 0);
    }
    else
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
        DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
        WORD    *pwZ = g_grdChunkData.pZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    Draw11Pixel(pwPix, i);
                }
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp conditional, AlphaInvAlpha, !alphatest
void SpanBackend_ZCCond_AlphaInvAlpha_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            DrawAlphaInvAlphaPixel(pwPix, i);
        } while (++i < 0);
    }
    else
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
        DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
        WORD    *pwZ = g_grdChunkData.pZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                DrawAlphaInvAlphaPixel(pwPix, i);
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp conditional, AlphaInvAlpha, alphatest
void SpanBackend_ZCCond_AlphaInvAlpha_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                DrawAlphaInvAlphaPixel(pwPix, i);
            }
        } while (++i < 0);
    }
    else
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
        DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
        WORD    *pwZ = g_grdChunkData.pZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    DrawAlphaInvAlphaPixel(pwPix, i);
                }
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp conditional, 1InvAlpha, !alphatest
void SpanBackend_ZCCond_1InvAlpha_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            Draw1InvAlphaPixel(pwPix, i);
        } while (++i < 0);
    }
    else
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
        DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
        WORD    *pwZ = g_grdChunkData.pZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                Draw1InvAlphaPixel(pwPix, i);
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp conditional, 1InvAlpha, alphatest
void SpanBackend_ZCCond_1InvAlpha_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                Draw1InvAlphaPixel(pwPix, i);
            }
        } while (++i < 0);
    }
    else
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
        DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
        WORD    *pwZ = g_grdChunkData.pZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    Draw1InvAlphaPixel(pwPix, i);
                }
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp+write, 10, !alphatest
void SpanBackend_ZCW_10_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if ((dwZ >> 16) <= pwZ[i])
        {
            pwZ[i] = (WORD)(dwZ >> 16);
            pwPix[i] = FROM_MUNGED3_TO_TARGET(g_grdChunkData.rgm3WorkingBuffer[i+16]);
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp+write, 10, alphatest
void SpanBackend_ZCW_10_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                pwPix[i] = FROM_MUNGED3_TO_TARGET(g_grdChunkData.rgm3WorkingBuffer[i+16]);
            }
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp+write, 11, !alphatest
void SpanBackend_ZCW_11_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if ((dwZ >> 16) <= pwZ[i])
        {
            pwZ[i] = (WORD)(dwZ >> 16);
            Draw11Pixel(pwPix, i);
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp+write, 11, alphatest
void SpanBackend_ZCW_11_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                Draw11Pixel(pwPix, i);
            }
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp+write, AlphaInvAlpha, !alphatest
void SpanBackend_ZCW_AlphaInvAlpha_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if ((dwZ >> 16) <= pwZ[i])
        {
            pwZ[i] = (WORD)(dwZ >> 16);
            DrawAlphaInvAlphaPixel(pwPix, i);
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp+write, AlphaInvAlpha, alphatest
void SpanBackend_ZCW_AlphaInvAlpha_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                DrawAlphaInvAlphaPixel(pwPix, i);
            }
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp+write, 1InvAlpha, !alphatest
void SpanBackend_ZCW_1InvAlpha_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if ((dwZ >> 16) <= pwZ[i])
        {
            pwZ[i] = (WORD)(dwZ >> 16);
            Draw1InvAlphaPixel(pwPix, i);
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp+write, 1InvAlpha, alphatest
void SpanBackend_ZCW_1InvAlpha_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                Draw1InvAlphaPixel(pwPix, i);
            }
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp+write conditional, 10, !alphatest
void SpanBackend_ZCWCond_10_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            pwPix[i] = FROM_MUNGED3_TO_TARGET(g_grdChunkData.rgm3WorkingBuffer[i+16]);
            pwZ[i] = (WORD)(dwZ >> 16);
            dwZ += dwZIncr;
        } while (++i < 0);
    }
    else
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                pwPix[i] = FROM_MUNGED3_TO_TARGET(g_grdChunkData.rgm3WorkingBuffer[i+16]);
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp+write conditional, 10, alphatest
void SpanBackend_ZCWCond_10_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                pwPix[i] = FROM_MUNGED3_TO_TARGET(g_grdChunkData.rgm3WorkingBuffer[i+16]);
                pwZ[i] = (WORD)(dwZ >> 16);
                dwZ += dwZIncr;
            }
        } while (++i < 0);
    }
    else
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    pwZ[i] = (WORD)(dwZ >> 16);
                    pwPix[i] = FROM_MUNGED3_TO_TARGET(g_grdChunkData.rgm3WorkingBuffer[i+16]);
                }
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp+write conditional, 11, !alphatest
void SpanBackend_ZCWCond_11_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            Draw11Pixel(pwPix, i);
            pwZ[i] = (WORD)(dwZ >> 16);
            dwZ += dwZIncr;
        } while (++i < 0);
    }
    else
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                Draw11Pixel(pwPix, i);
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp+write conditional, 11, alphatest
void SpanBackend_ZCWCond_11_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                Draw11Pixel(pwPix, i);
                pwZ[i] = (WORD)(dwZ >> 16);
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
    else
    {

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    pwZ[i] = (WORD)(dwZ >> 16);
                    Draw11Pixel(pwPix, i);
                }
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp+write conditional, AlphaInvAlpha, !alphatest
void SpanBackend_ZCWCond_AlphaInvAlpha_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            DrawAlphaInvAlphaPixel(pwPix, i);
            pwZ[i] = (WORD)(dwZ >> 16);
            dwZ += dwZIncr;
        } while (++i < 0);
    }
    else
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                DrawAlphaInvAlphaPixel(pwPix, i);
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp+write conditional, AlphaInvAlpha, alphatest
void SpanBackend_ZCWCond_AlphaInvAlpha_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                DrawAlphaInvAlphaPixel(pwPix, i);
                pwZ[i] = (WORD)(dwZ >> 16);
                dwZ += dwZIncr;
            }
        } while (++i < 0);
    }
    else
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    pwZ[i] = (WORD)(dwZ >> 16);
                    DrawAlphaInvAlphaPixel(pwPix, i);
                }
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp+write conditional, 1InvAlpha, !alphatest
void SpanBackend_ZCWCond_1InvAlpha_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            Draw1InvAlphaPixel(pwPix, i);
            pwZ[i] = (WORD)(dwZ >> 16);
            dwZ += dwZIncr;
        } while (++i < 0);
    }
    else
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                Draw1InvAlphaPixel(pwPix, i);
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp+write conditional, 1InvAlpha, alphatest
void SpanBackend_ZCWCond_1InvAlpha_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                Draw1InvAlphaPixel(pwPix, i);
                pwZ[i] = (WORD)(dwZ >> 16);
                dwZ += dwZIncr;
            }
        } while (++i < 0);
    }
    else
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    pwZ[i] = (WORD)(dwZ >> 16);
                    Draw1InvAlphaPixel(pwPix, i);
                }
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zwrite, 10, !alphatest
void SpanBackend_ZW_10_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        pwZ[i] = (WORD)(dwZ >> 16);
        pwPix[i] = FROM_MUNGED3_TO_TARGET(g_grdChunkData.rgm3WorkingBuffer[i+16]);
        dwZ += dwZIncr;
    } while (++i < 0);
}


// zwrite, 10, alphatest
void SpanBackend_ZW_10_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
        {
            pwZ[i] = (WORD)(dwZ >> 16);
            pwPix[i] = FROM_MUNGED3_TO_TARGET(g_grdChunkData.rgm3WorkingBuffer[i+16]);
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zwrite, 11, !alphatest
void SpanBackend_ZW_11_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        pwZ[i] = (WORD)(dwZ >> 16);
        Draw11Pixel(pwPix, i);
        dwZ += dwZIncr;
    } while (++i < 0);
}


// zwrite, 11, alphatest
void SpanBackend_ZW_11_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
        {
            pwZ[i] = (WORD)(dwZ >> 16);
            Draw11Pixel(pwPix, i);
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zwrite, AlphaInvAlpha, !alphatest
void SpanBackend_ZW_AlphaInvAlpha_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        pwZ[i] = (WORD)(dwZ >> 16);
        DrawAlphaInvAlphaPixel(pwPix, i);
        dwZ += dwZIncr;
    } while (++i < 0);
}


// zwrite, AlphaInvAlpha, alphatest
void SpanBackend_ZW_AlphaInvAlpha_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
        {
            pwZ[i] = (WORD)(dwZ >> 16);
            DrawAlphaInvAlphaPixel(pwPix, i);
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zwrite, 1InvAlpha, !alphatest
void SpanBackend_ZW_1InvAlpha_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        pwZ[i] = (WORD)(dwZ >> 16);
        Draw1InvAlphaPixel(pwPix, i);
        dwZ += dwZIncr;
    } while (++i < 0);
}


// zwrite, 1InvAlpha, alphatest
void SpanBackend_ZW_1InvAlpha_AlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
        {
            pwZ[i] = (WORD)(dwZ >> 16);
            Draw1InvAlphaPixel(pwPix, i);
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// !z, 10, !alphatest, reads native format from working buffer
#if USE_C
void SpanBackend_Native_NoZ_10_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        pwPix[i] = (WORD)g_grdChunkData.rgm3WorkingBuffer[i+16];
    } while (++i < 0);
}
#else
__declspec(naked) void SpanBackend_Native_NoZ_10_NoAlphaTest(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov edx,[g_grdChunkData.pPix_Chunk]
    cmp ecx,-16
    jz  DoFullSpan
mloop:
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    mov [edx+ecx*2],ax
    inc ecx
    jnz mloop

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif
    ret

DoFullSpan:
    mov ecx,[g_grdChunkData.rgm3WorkingBuffer+0*4]
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+1*4]
    mov [edx+0*2-16*2],cx
    mov ecx,[g_grdChunkData.rgm3WorkingBuffer+2*4]
    mov [edx+1*2-16*2],ax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+3*4]
    mov [edx+2*2-16*2],cx
    mov ecx,[g_grdChunkData.rgm3WorkingBuffer+4*4]
    mov [edx+3*2-16*2],ax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+5*4]
    mov [edx+4*2-16*2],cx
    mov ecx,[g_grdChunkData.rgm3WorkingBuffer+6*4]
    mov [edx+5*2-16*2],ax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+7*4]
    mov [edx+6*2-16*2],cx
    mov ecx,[g_grdChunkData.rgm3WorkingBuffer+8*4]
    mov [edx+7*2-16*2],ax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+9*4]
    mov [edx+8*2-16*2],cx
    mov ecx,[g_grdChunkData.rgm3WorkingBuffer+10*4]
    mov [edx+9*2-16*2],ax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+11*4]
    mov [edx+10*2-16*2],cx
    mov ecx,[g_grdChunkData.rgm3WorkingBuffer+12*4]
    mov [edx+11*2-16*2],ax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+13*4]
    mov [edx+12*2-16*2],cx
    mov ecx,[g_grdChunkData.rgm3WorkingBuffer+14*4]
    mov [edx+13*2-16*2],ax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+15*4]
    mov [edx+14*2-16*2],cx
    mov [edx+15*2-16*2],ax

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif
    ret
    }
}
#endif


// zcomp, 10, !alphatest
void SpanBackend_Native_ZC_10_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if ((dwZ >> 16) <= pwZ[i])
        {
            pwPix[i] = (WORD)g_grdChunkData.rgm3WorkingBuffer[i+16];
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp conditional, 10, !alphatest
#if USE_C
void SpanBackend_Native_ZCCond_10_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            pwPix[i] = (WORD)g_grdChunkData.rgm3WorkingBuffer[i+16];
        } while (++i < 0);
    }
    else
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
        DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
        WORD    *pwZ = g_grdChunkData.pZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pwPix[i] = (WORD)g_grdChunkData.rgm3WorkingBuffer[i+16];
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}
#else
__declspec(naked) void SpanBackend_Native_ZCCond_10_NoAlphaTest(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    cmp [g_grdChunkData.fNeedToDoBackendZCompare],0
    jnz DoCompare
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov edx,[g_grdChunkData.pPix_Chunk]
    cmp ecx,-16
    jz  DoFullSpan
mloop:
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    mov [edx+ecx*2],ax
    inc ecx
    jnz mloop

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif
    ret

DoFullSpan:
    mov ecx,[g_grdChunkData.rgm3WorkingBuffer+0*4]
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+1*4]
    mov [edx+0*2-16*2],cx
    mov ecx,[g_grdChunkData.rgm3WorkingBuffer+2*4]
    mov [edx+1*2-16*2],ax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+3*4]
    mov [edx+2*2-16*2],cx
    mov ecx,[g_grdChunkData.rgm3WorkingBuffer+4*4]
    mov [edx+3*2-16*2],ax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+5*4]
    mov [edx+4*2-16*2],cx
    mov ecx,[g_grdChunkData.rgm3WorkingBuffer+6*4]
    mov [edx+5*2-16*2],ax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+7*4]
    mov [edx+6*2-16*2],cx
    mov ecx,[g_grdChunkData.rgm3WorkingBuffer+8*4]
    mov [edx+7*2-16*2],ax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+9*4]
    mov [edx+8*2-16*2],cx
    mov ecx,[g_grdChunkData.rgm3WorkingBuffer+10*4]
    mov [edx+9*2-16*2],ax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+11*4]
    mov [edx+10*2-16*2],cx
    mov ecx,[g_grdChunkData.rgm3WorkingBuffer+12*4]
    mov [edx+11*2-16*2],ax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+13*4]
    mov [edx+12*2-16*2],cx
    mov ecx,[g_grdChunkData.rgm3WorkingBuffer+14*4]
    mov [edx+13*2-16*2],ax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+15*4]
    mov [edx+14*2-16*2],cx
    mov [edx+15*2-16*2],ax

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif
    ret

DoCompare:
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov esi,[g_grdChunkData.pZ_Chunk]
    mov ebx,[g_grdChunkData.dwZ_Chunk]
    ror ebx,16
    mov edi,[g_grdChunkData.ZIncr_Chunk]
    ror edi,16
    mov edx,[g_grdChunkData.pPix_Chunk]
mloopz:
    cmp bx,[esi+ecx*2]
    ja  zskip
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    mov [edx+ecx*2],ax
zskip:
    add ebx,edi
    adc ebx,0
    inc ecx
    jnz mloopz

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif
    ret
    }
}
#endif


// zcomp+write, 10, !alphatest
void SpanBackend_Native_ZCW_10_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        if ((dwZ >> 16) <= pwZ[i])
        {
            pwZ[i] = (WORD)(dwZ >> 16);
            pwPix[i] = (WORD)g_grdChunkData.rgm3WorkingBuffer[i+16];
        }

        dwZ += dwZIncr;
    } while (++i < 0);
}


// zcomp+write conditional, 10, !alphatest
void SpanBackend_Native_ZCWCond_10_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    if (!g_grdChunkData.fNeedToDoBackendZCompare)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            pwPix[i] = (WORD)g_grdChunkData.rgm3WorkingBuffer[i+16];
            pwZ[i] = (WORD)(dwZ >> 16);
            dwZ += dwZIncr;
        } while (++i < 0);
    }
    else
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                pwPix[i] = (WORD)g_grdChunkData.rgm3WorkingBuffer[i+16];
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zwrite, 10, !alphatest
void SpanBackend_Native_ZW_10_NoAlphaTest(void)
{
    int     i;
    WORD    *pwPix = g_grdChunkData.pPix_Chunk;
    DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        pwZ[i] = (WORD)(dwZ >> 16);
        pwPix[i] = (WORD)g_grdChunkData.rgm3WorkingBuffer[i+16];
        dwZ += dwZIncr;
    } while (++i < 0);
}


//----------------------------------------------------------------------------
// Pixel-doubled (in both directions) backend-pass chunk processors.
//
// Handle following combinations:
//
// z: !z, zcomp, zcomp conditional, zcomp+write, zcomp+write conditional, zwrite
// alphablend: 10, 11, 1InvAlpha, AlphaInvAlpha
// alphatest: yes/no
//
// "conditional" means that if the trivialz pass didn't trivially accept or
// reject the whole span, the backend has to do the comparisons again; flagged
// by g_grdChunkData.fNeedToDoBackendZCompare as set in trivialz pass.
//----------------------------------------------------------------------------

// !z, 10, !alphatest
void SpanBackend2X_NoZ_10_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            pdwPix[i] = FROM_MUNGED3_TO_TARGET2X(g_grdChunkData.rgm3WorkingBuffer[i+16]);
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// !z, 10, alphatest
void SpanBackend2X_NoZ_10_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                pdwPix[i] = FROM_MUNGED3_TO_TARGET2X(g_grdChunkData.rgm3WorkingBuffer[i+16]);
            }
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// !z, 11, !alphatest
void SpanBackend2X_NoZ_11_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            Draw11Pixel2X(pdwPix, i);
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// !z, 11, alphatest
void SpanBackend2X_NoZ_11_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                Draw11Pixel2X(pdwPix, i);
            }
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// !z, AlphaInvAlpha, !alphatest
void SpanBackend2X_NoZ_AlphaInvAlpha_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            DrawAlphaInvAlphaPixel2X(pdwPix, i);
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// !z, AlphaInvAlpha, alphatest
void SpanBackend2X_NoZ_AlphaInvAlpha_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                DrawAlphaInvAlphaPixel2X(pdwPix, i);
            }
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// !z, 1InvAlpha, !alphatest
void SpanBackend2X_NoZ_1InvAlpha_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            Draw1InvAlphaPixel2X(pdwPix, i);
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// !z, 1InvAlpha, alphatest
void SpanBackend2X_NoZ_1InvAlpha_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                Draw1InvAlphaPixel2X(pdwPix, i);
            }
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp, 10, !alphatest
void SpanBackend2X_ZC_10_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pdwPix[i] = FROM_MUNGED3_TO_TARGET2X(g_grdChunkData.rgm3WorkingBuffer[i+16]);
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp, 10, alphatest
void SpanBackend2X_ZC_10_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    pdwPix[i] = FROM_MUNGED3_TO_TARGET2X(g_grdChunkData.rgm3WorkingBuffer[i+16]);
                }
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp, 11, !alphatest
void SpanBackend2X_ZC_11_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                Draw11Pixel2X(pdwPix, i);
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp, 11, alphatest
void SpanBackend2X_ZC_11_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    Draw11Pixel2X(pdwPix, i);
                }
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp, AlphaInvAlpha, !alphatest
void SpanBackend2X_ZC_AlphaInvAlpha_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                DrawAlphaInvAlphaPixel2X(pdwPix, i);
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp, AlphaInvAlpha, alphatest
void SpanBackend2X_ZC_AlphaInvAlpha_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    DrawAlphaInvAlphaPixel2X(pdwPix, i);
                }
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp, 1InvAlpha, !alphatest
void SpanBackend2X_ZC_1InvAlpha_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                Draw1InvAlphaPixel2X(pdwPix, i);
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp, 1InvAlpha, alphatest
void SpanBackend2X_ZC_1InvAlpha_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    Draw1InvAlphaPixel2X(pdwPix, i);
                }
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp conditional, 10, !alphatest
#if USE_C
void SpanBackend2X_ZCCond_10_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                pdwPix[i] = FROM_MUNGED3_TO_TARGET2X(g_grdChunkData.rgm3WorkingBuffer[i+16]);
            } while (++i < 0);
        }
        else
        {
            DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
            DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
            WORD    *pwZ = g_grdChunkData.pZ_Chunk;

            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    pdwPix[i] = FROM_MUNGED3_TO_TARGET2X(g_grdChunkData.rgm3WorkingBuffer[i+16]);
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}
#else
__declspec(naked) void SpanBackend2X_ZCCond_10_NoAlphaTest(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    mov ebp,2
    mov edx,[g_grdChunkData.pPix_Chunk]
    cmp [g_grdChunkData.fNeedToDoBackendZCompare],0
    jnz DoCompare
    cmp [g_grdChunkData.cMunged3ToTargetShift0],5
    jz  do555
dloop565:
    push ebp
    mov ecx,[g_grdChunkData.cPixels_Chunk]
mloop565:
    mov esi,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    mov ebp,esi
    mov eax,esi
    shr esi,4
    and ebp,0x01F00000
    shr ebp,9
    and eax,0x1F
    and esi,0x7C0
    or  eax,ebp
    or  eax,esi
    mov esi,eax
    shl eax,16
    or  eax,esi
    mov [edx+ecx*4],eax
    inc ecx
    jnz mloop565

    mov ecx,[g_grdChunkData.cbScanDoubleOffset]
    pop ebp
    add edx,ecx
    dec ebp
    jnz dloop565

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif
    ret

do555:
dloop555:
    push ebp
    mov ecx,[g_grdChunkData.cPixels_Chunk]
mloop555:
    mov esi,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    mov ebp,esi
    mov eax,esi
    shr esi,5
    and ebp,0x01F00000
    shr ebp,10
    and eax,0x1F
    and esi,0x3E0
    or  eax,ebp
    or  eax,esi
    mov esi,eax
    shl eax,16
    or  eax,esi
    mov [edx+ecx*4],eax
    inc ecx
    jnz mloop555

    mov ecx,[g_grdChunkData.cbScanDoubleOffset]
    pop ebp
    add edx,ecx
    dec ebp
    jnz dloop555

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif
    ret

DoCompare:
    mov esi,[g_grdChunkData.pZ_Chunk]
    mov edi,[g_grdChunkData.ZIncr_Chunk]
    ror edi,16
    cmp [g_grdChunkData.cMunged3ToTargetShift0],5
    jz  dloopz555
dloopz:
    push ebp
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov ebx,[g_grdChunkData.dwZ_Chunk]
    ror ebx,16
mloopz:
    cmp bx,[esi+ecx*2]
    ja  zskip
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    mov ebp,eax
    shr eax,4
    and ebp,0x01F00000
    shr ebp,9
    and eax,0x7C0
    or  ebp,eax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    and eax,0x1F
    or  eax,ebp
    mov ebp,eax
    shl eax,16
    or  eax,ebp
    mov [edx+ecx*4],eax
zskip:
    add ebx,edi
    adc ebx,0
    inc ecx
    jnz mloopz

    mov ecx,[g_grdChunkData.cbScanDoubleOffset]
    pop ebp
    add edx,ecx
    dec ebp
    jnz dloopz

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif
    ret

dloopz555:
    push ebp
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov ebx,[g_grdChunkData.dwZ_Chunk]
    ror ebx,16
mloopz555:
    cmp bx,[esi+ecx*2]
    ja  zskip555
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    mov ebp,eax
    shr eax,5
    and ebp,0x01F00000
    shr ebp,10
    and eax,0x3E0
    or  ebp,eax
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    and eax,0x1F
    or  eax,ebp
    mov ebp,eax
    shl eax,16
    or  eax,ebp
    mov [edx+ecx*4],eax
zskip555:
    add ebx,edi
    adc ebx,0
    inc ecx
    jnz mloopz555

    mov ecx,[g_grdChunkData.cbScanDoubleOffset]
    pop ebp
    add edx,ecx
    dec ebp
    jnz dloopz555

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif
    ret
    }
}
#endif


// zcomp conditional, 10, alphatest
void SpanBackend2X_ZCCond_10_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
                {
                    pdwPix[i] = FROM_MUNGED3_TO_TARGET2X(g_grdChunkData.rgm3WorkingBuffer[i+16]);
                }
            } while (++i < 0);
        }
        else
        {
            DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
            DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
            WORD    *pwZ = g_grdChunkData.pZ_Chunk;

            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
                {
                    if ((dwZ >> 16) <= pwZ[i])
                    {
                        pdwPix[i] = FROM_MUNGED3_TO_TARGET2X(g_grdChunkData.rgm3WorkingBuffer[i+16]);
                    }
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp conditional, 11, !alphatest
void SpanBackend2X_ZCCond_11_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                Draw11Pixel2X(pdwPix, i);
            } while (++i < 0);
        }
        else
        {
            DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
            DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
            WORD    *pwZ = g_grdChunkData.pZ_Chunk;

            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    Draw11Pixel2X(pdwPix, i);
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp conditional, 11, alphatest
void SpanBackend2X_ZCCond_11_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
                {
                    Draw11Pixel2X(pdwPix, i);
                }
            } while (++i < 0);
        }
        else
        {
            DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
            DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
            WORD    *pwZ = g_grdChunkData.pZ_Chunk;

            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
                {
                    if ((dwZ >> 16) <= pwZ[i])
                    {
                        Draw11Pixel2X(pdwPix, i);
                    }
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp conditional, AlphaInvAlpha, !alphatest
void SpanBackend2X_ZCCond_AlphaInvAlpha_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                DrawAlphaInvAlphaPixel2X(pdwPix, i);
            } while (++i < 0);
        }
        else
        {
            DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
            DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
            WORD    *pwZ = g_grdChunkData.pZ_Chunk;

            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    DrawAlphaInvAlphaPixel2X(pdwPix, i);
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp conditional, AlphaInvAlpha, alphatest
void SpanBackend2X_ZCCond_AlphaInvAlpha_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
                {
                    DrawAlphaInvAlphaPixel2X(pdwPix, i);
                }
            } while (++i < 0);
        }
        else
        {
            DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
            DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
            WORD    *pwZ = g_grdChunkData.pZ_Chunk;

            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
                {
                    if ((dwZ >> 16) <= pwZ[i])
                    {
                        DrawAlphaInvAlphaPixel2X(pdwPix, i);
                    }
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp conditional, 1InvAlpha, !alphatest
void SpanBackend2X_ZCCond_1InvAlpha_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                Draw1InvAlphaPixel2X(pdwPix, i);
            } while (++i < 0);
        }
        else
        {
            DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
            DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
            WORD    *pwZ = g_grdChunkData.pZ_Chunk;

            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    Draw1InvAlphaPixel2X(pdwPix, i);
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp conditional, 1InvAlpha, alphatest
void SpanBackend2X_ZCCond_1InvAlpha_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
                {
                    Draw1InvAlphaPixel2X(pdwPix, i);
                }
            } while (++i < 0);
        }
        else
        {
            DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
            DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
            WORD    *pwZ = g_grdChunkData.pZ_Chunk;

            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
                {
                    if ((dwZ >> 16) <= pwZ[i])
                    {
                        Draw1InvAlphaPixel2X(pdwPix, i);
                    }
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp+write, 10, !alphatest
void SpanBackend2X_ZCW_10_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                pdwPix[i] = FROM_MUNGED3_TO_TARGET2X(g_grdChunkData.rgm3WorkingBuffer[i+16]);
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp+write, 10, alphatest
void SpanBackend2X_ZCW_10_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    pwZ[i] = (WORD)(dwZ >> 16);
                    pdwPix[i] = FROM_MUNGED3_TO_TARGET2X(g_grdChunkData.rgm3WorkingBuffer[i+16]);
                }
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp+write, 11, !alphatest
void SpanBackend2X_ZCW_11_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                Draw11Pixel2X(pdwPix, i);
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp+write, 11, alphatest
void SpanBackend2X_ZCW_11_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    pwZ[i] = (WORD)(dwZ >> 16);
                    Draw11Pixel2X(pdwPix, i);
                }
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp+write, AlphaInvAlpha, !alphatest
void SpanBackend2X_ZCW_AlphaInvAlpha_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                DrawAlphaInvAlphaPixel2X(pdwPix, i);
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp+write, AlphaInvAlpha, alphatest
void SpanBackend2X_ZCW_AlphaInvAlpha_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    pwZ[i] = (WORD)(dwZ >> 16);
                    DrawAlphaInvAlphaPixel2X(pdwPix, i);
                }
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp+write, 1InvAlpha, !alphatest
void SpanBackend2X_ZCW_1InvAlpha_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                Draw1InvAlphaPixel2X(pdwPix, i);
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp+write, 1InvAlpha, alphatest
void SpanBackend2X_ZCW_1InvAlpha_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    pwZ[i] = (WORD)(dwZ >> 16);
                    Draw1InvAlphaPixel2X(pdwPix, i);
                }
            }

            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zcomp+write conditional, 10, !alphatest
void SpanBackend2X_ZCWCond_10_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                pdwPix[i] = FROM_MUNGED3_TO_TARGET2X(g_grdChunkData.rgm3WorkingBuffer[i+16]);
                pwZ[i] = (WORD)(dwZ >> 16);
                dwZ += dwZIncr;
            } while (++i < 0);
        }
        else
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    pwZ[i] = (WORD)(dwZ >> 16);
                    pdwPix[i] = FROM_MUNGED3_TO_TARGET2X(g_grdChunkData.rgm3WorkingBuffer[i+16]);
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }
    }
}


// zcomp+write conditional, 10, alphatest
void SpanBackend2X_ZCWCond_10_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
                {
                    pdwPix[i] = FROM_MUNGED3_TO_TARGET2X(g_grdChunkData.rgm3WorkingBuffer[i+16]);
                    pwZ[i] = (WORD)(dwZ >> 16);
                    dwZ += dwZIncr;
                }
            } while (++i < 0);
        }
        else
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
                {
                    if ((dwZ >> 16) <= pwZ[i])
                    {
                        pwZ[i] = (WORD)(dwZ >> 16);
                        pdwPix[i] = FROM_MUNGED3_TO_TARGET2X(g_grdChunkData.rgm3WorkingBuffer[i+16]);
                    }
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp+write conditional, 11, !alphatest
void SpanBackend2X_ZCWCond_11_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                Draw11Pixel2X(pdwPix, i);
                pwZ[i] = (WORD)(dwZ >> 16);
                dwZ += dwZIncr;
            } while (++i < 0);
        }
        else
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    pwZ[i] = (WORD)(dwZ >> 16);
                    Draw11Pixel2X(pdwPix, i);
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp+write conditional, 11, alphatest
void SpanBackend2X_ZCWCond_11_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
                {
                    Draw11Pixel2X(pdwPix, i);
                    pwZ[i] = (WORD)(dwZ >> 16);
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }
        else
        {

            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
                {
                    if ((dwZ >> 16) <= pwZ[i])
                    {
                        pwZ[i] = (WORD)(dwZ >> 16);
                        Draw11Pixel2X(pdwPix, i);
                    }
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp+write conditional, AlphaInvAlpha, !alphatest
void SpanBackend2X_ZCWCond_AlphaInvAlpha_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                DrawAlphaInvAlphaPixel2X(pdwPix, i);
                pwZ[i] = (WORD)(dwZ >> 16);
                dwZ += dwZIncr;
            } while (++i < 0);
        }
        else
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    pwZ[i] = (WORD)(dwZ >> 16);
                    DrawAlphaInvAlphaPixel2X(pdwPix, i);
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp+write conditional, AlphaInvAlpha, alphatest
void SpanBackend2X_ZCWCond_AlphaInvAlpha_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
                {
                    DrawAlphaInvAlphaPixel2X(pdwPix, i);
                    pwZ[i] = (WORD)(dwZ >> 16);
                    dwZ += dwZIncr;
                }
            } while (++i < 0);
        }
        else
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
                {
                    if ((dwZ >> 16) <= pwZ[i])
                    {
                        pwZ[i] = (WORD)(dwZ >> 16);
                        DrawAlphaInvAlphaPixel2X(pdwPix, i);
                    }
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp+write conditional, 1InvAlpha, !alphatest
void SpanBackend2X_ZCWCond_1InvAlpha_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                Draw1InvAlphaPixel2X(pdwPix, i);
                pwZ[i] = (WORD)(dwZ >> 16);
                dwZ += dwZIncr;
            } while (++i < 0);
        }
        else
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    pwZ[i] = (WORD)(dwZ >> 16);
                    Draw1InvAlphaPixel2X(pdwPix, i);
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp+write conditional, 1InvAlpha, alphatest
void SpanBackend2X_ZCWCond_1InvAlpha_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
                {
                    Draw1InvAlphaPixel2X(pdwPix, i);
                    pwZ[i] = (WORD)(dwZ >> 16);
                    dwZ += dwZIncr;
                }
            } while (++i < 0);
        }
        else
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
                {
                    if ((dwZ >> 16) <= pwZ[i])
                    {
                        pwZ[i] = (WORD)(dwZ >> 16);
                        Draw1InvAlphaPixel2X(pdwPix, i);
                    }
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zwrite, 10, !alphatest
void SpanBackend2X_ZW_10_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            pwZ[i] = (WORD)(dwZ >> 16);
            pdwPix[i] = FROM_MUNGED3_TO_TARGET2X(g_grdChunkData.rgm3WorkingBuffer[i+16]);
            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zwrite, 10, alphatest
void SpanBackend2X_ZW_10_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                pdwPix[i] = FROM_MUNGED3_TO_TARGET2X(g_grdChunkData.rgm3WorkingBuffer[i+16]);
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zwrite, 11, !alphatest
void SpanBackend2X_ZW_11_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            pwZ[i] = (WORD)(dwZ >> 16);
            Draw11Pixel2X(pdwPix, i);
            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zwrite, 11, alphatest
void SpanBackend2X_ZW_11_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                Draw11Pixel2X(pdwPix, i);
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zwrite, AlphaInvAlpha, !alphatest
void SpanBackend2X_ZW_AlphaInvAlpha_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            pwZ[i] = (WORD)(dwZ >> 16);
            DrawAlphaInvAlphaPixel2X(pdwPix, i);
            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zwrite, AlphaInvAlpha, alphatest
void SpanBackend2X_ZW_AlphaInvAlpha_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                DrawAlphaInvAlphaPixel2X(pdwPix, i);
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zwrite, 1InvAlpha, !alphatest
void SpanBackend2X_ZW_1InvAlpha_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            pwZ[i] = (WORD)(dwZ >> 16);
            Draw1InvAlphaPixel2X(pdwPix, i);
            dwZ += dwZIncr;
        } while (++i < 0);
    }
}


// zwrite, 1InvAlpha, alphatest
void SpanBackend2X_ZW_1InvAlpha_AlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if (g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] > 0)
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                Draw1InvAlphaPixel2X(pdwPix, i);
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// !z, 10, !alphatest, reads native format from working buffer
#if USE_C
void SpanBackend2X_Native_NoZ_10_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            pdwPix[i] = g_grdChunkData.rgm3WorkingBuffer[i+16] |
                        (g_grdChunkData.rgm3WorkingBuffer[i+16] << 16);
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}
#else
__declspec(naked) void SpanBackend2X_Native_NoZ_10_NoAlphaTest(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    mov edx,[g_grdChunkData.pPix_Chunk]

    mov ebp,2
dloop:
    mov ecx,[g_grdChunkData.cPixels_Chunk]
mloop:
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    mov ebx,eax
    shl eax,16
    or  eax,ebx
    mov [edx+ecx*4],eax
    inc ecx
    jnz mloop

    add edx,[g_grdChunkData.cbScanDoubleOffset]
    dec ebp
    jnz dloop

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif
    ret
    }
}
#endif


// zcomp, 10, !alphatest
void SpanBackend2X_Native_ZC_10_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pdwPix[i] = g_grdChunkData.rgm3WorkingBuffer[i+16] |
                            (g_grdChunkData.rgm3WorkingBuffer[i+16] << 16);
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp conditional, 10, !alphatest
#if USE_C
void SpanBackend2X_Native_ZCCond_10_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    for (j=0; j<2; j++)
    {
        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                pdwPix[i] = g_grdChunkData.rgm3WorkingBuffer[i+16] |
                            (g_grdChunkData.rgm3WorkingBuffer[i+16] << 16);
            } while (++i < 0);
        }
        else
        {
            DWORD   dwZ = g_grdChunkData.dwZ_Chunk;
            DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
            WORD    *pwZ = g_grdChunkData.pZ_Chunk;

            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    pdwPix[i] = g_grdChunkData.rgm3WorkingBuffer[i+16] |
                                (g_grdChunkData.rgm3WorkingBuffer[i+16] << 16);
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}
#else
__declspec(naked) void SpanBackend2X_Native_ZCCond_10_NoAlphaTest(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    mov edx,[g_grdChunkData.pPix_Chunk]
    mov ebp,2
dloop:
    cmp [g_grdChunkData.fNeedToDoBackendZCompare],0
    jnz DoCompare
    mov ecx,[g_grdChunkData.cPixels_Chunk]
mloop:
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    mov ebx,eax
    shl eax,16
    or  eax,ebx
    mov [edx+ecx*4],eax
    inc ecx
    jnz mloop

    jmp Done

DoCompare:
    push ebp
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov esi,[g_grdChunkData.pZ_Chunk]
    mov ebx,[g_grdChunkData.dwZ_Chunk]
    ror ebx,16
    mov edi,[g_grdChunkData.ZIncr_Chunk]
    ror edi,16
mloopz:
    cmp bx,[esi+ecx*2]
    ja  zskip
    mov eax,[g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4]
    mov ebp,eax
    shl eax,16
    or  eax,ebp
    mov [edx+ecx*4],eax
zskip:
    add ebx,edi
    adc ebx,0
    inc ecx
    jnz mloopz
    pop ebp

Done:
    add edx,[g_grdChunkData.cbScanDoubleOffset]
    dec ebp
    jnz dloop

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif
    ret
    }
}
#endif


// zcomp+write, 10, !alphatest
void SpanBackend2X_Native_ZCW_10_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            if ((dwZ >> 16) <= pwZ[i])
            {
                pwZ[i] = (WORD)(dwZ >> 16);
                pdwPix[i] = g_grdChunkData.rgm3WorkingBuffer[i+16] |
                            (g_grdChunkData.rgm3WorkingBuffer[i+16] << 16);
            }

            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zcomp+write conditional, 10, !alphatest
void SpanBackend2X_Native_ZCWCond_10_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        if (!g_grdChunkData.fNeedToDoBackendZCompare)
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                pdwPix[i] = g_grdChunkData.rgm3WorkingBuffer[i+16] |
                            (g_grdChunkData.rgm3WorkingBuffer[i+16] << 16);
                pwZ[i] = (WORD)(dwZ >> 16);
                dwZ += dwZIncr;
            } while (++i < 0);
        }
        else
        {
            i = g_grdChunkData.cPixels_Chunk;

            do
            {
                if ((dwZ >> 16) <= pwZ[i])
                {
                    pwZ[i] = (WORD)(dwZ >> 16);
                    pdwPix[i] = g_grdChunkData.rgm3WorkingBuffer[i+16] |
                                (g_grdChunkData.rgm3WorkingBuffer[i+16] << 16);
                }

                dwZ += dwZIncr;
            } while (++i < 0);
        }

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


// zwrite, 10, !alphatest
void SpanBackend2X_Native_ZW_10_NoAlphaTest(void)
{
    int     i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD   dwZIncr = g_grdChunkData.ZIncr_Chunk;
    WORD    *pwZ = g_grdChunkData.pZ_Chunk;

    for (j=0; j<2; j++)
    {
        DWORD   dwZ = g_grdChunkData.dwZ_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            pwZ[i] = (WORD)(dwZ >> 16);
            pdwPix[i] = g_grdChunkData.rgm3WorkingBuffer[i+16] |
                        (g_grdChunkData.rgm3WorkingBuffer[i+16] << 16);
            dwZ += dwZIncr;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}


//----------------------------------------------------------------------------
// Shade-pass chunk processors.
//----------------------------------------------------------------------------

// chunk processor: draws flat color into working buffer.
#if USE_C
void SpanShade_FlatRGB(void)
{
    int     i;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        g_grdChunkData.rgm3WorkingBuffer[i+16] = g_grdChunkData.m3FlatRGB;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}
#else
__declspec(naked) void SpanShade_FlatRGB(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov eax,[g_grdChunkData.m3FlatRGB]
    cmp ecx,-16
    jz  Do16
mloop:
    mov [g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4],eax
    inc ecx
    jnz mloop

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif

    jmp dword ptr [g_grdChunkData.pspanfnWorking+PSPANFN_AFTER_SHADING*4]

Do16:
    mov edi,offset g_grdChunkData.rgm3WorkingBuffer
    neg ecx
    rep stosd

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif

    jmp dword ptr [g_grdChunkData.pspanfnWorking+PSPANFN_AFTER_SHADING*4]
    }
}
#endif


// chunk processor: draws flat color into working buffer in native format.
#if USE_C
void SpanShade_Native_FlatRGB(void)
{
    int     i;
    DWORD   t;

    i = g_grdChunkData.cPixels_Chunk;
    t = g_grdChunkData.dwNativeFlatRGB;

    do
    {
        g_grdChunkData.rgm3WorkingBuffer[i+16] = t;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}
#else
__declspec(naked) void SpanShade_Native_FlatRGB(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov eax,[g_grdChunkData.dwNativeFlatRGB]
    cmp ecx,-16
    jz  Do16
mloop:
    mov [g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4],eax
    inc ecx
    jnz mloop

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif

    jmp dword ptr [g_grdChunkData.pspanfnWorking+PSPANFN_AFTER_SHADING*4]

Do16:
    mov edi,offset g_grdChunkData.rgm3WorkingBuffer
    neg ecx
    rep stosd

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif

    jmp dword ptr [g_grdChunkData.pspanfnWorking+PSPANFN_AFTER_SHADING*4]
    }
}
#endif


// chunk processor: draws Gouraud color into working buffer.
#if USE_C
void SpanShade_GouraudRGB(void)
{
    int     i;
    GOURAUD_RB  grb = g_grdChunkData.grb_Chunk;
    GOURAUD_AG  gag = g_grdChunkData.gag_Chunk;
    GOURAUD_RB  grbIncrement = g_grdChunkData.grbIncrement_Chunk;
    GOURAUD_AG  gagIncrement = g_grdChunkData.gagIncrement_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        g_grdChunkData.rgm3WorkingBuffer[i+16] = GOURAUD_RB_AG_TO_MUNGED3(grb, gag);
        grb += grbIncrement;
        // don't need to mask grb because in 16 pixels we can only get 4 bits of
        // carry, which can't reach from blue to red, and which only gets partway
        // into the fractional bits of green on the OR, and GOURAUD_RB_AG_TO_MUNGED3()
        // masks all problematic bits
        gag += gagIncrement;
        // don't need to mask gag because it can only carry into alpha, which we're not
        // using, and GOURAUD_RB_AG_TO_MUNGED3() masks those bits
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}
#endif


// chunk processor: draws Gouraud into working buffer in native format.
#if USE_C
void SpanShade_Native_GouraudRGB(void)
{
    int     i;
    GOURAUD_RGB grgb = g_grdChunkData.grgb_Chunk;
    GOURAUD_RGB grgbIncrement = g_grdChunkData.grgbIncrement_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        g_grdChunkData.rgm3WorkingBuffer[i+16] = (DWORD)GOURAUD_RGB_TO_NATIVE(grgb);
        grgb += grgbIncrement;
        grgb &= GOURAUD_RGB_CARRY_MASK;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}
#else
__declspec(naked) void SpanShade_Native_GouraudRGB(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov edx,[g_grdChunkData.grgb_Chunk]
    mov eax,[g_grdChunkData.cMunged3ToTargetShift0]
    mov edi,[g_grdChunkData.grgbIncrement_Chunk]
    cmp eax,5
    jz  Do555
// 565 destination
mloop565:
    mov eax,edx
    mov ebx,edx
    shr eax,5
    mov esi,edx
    shr ebx,10
    and esi,0xF8000000
    shr esi,16
    and eax,0x0000001F
    and ebx,0x000007C0
    or  eax,esi
    add edx,edi
    or  eax,ebx
    and edx,GOURAUD_RGB_CARRY_MASK
    mov [g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4],eax
    inc ecx
    jnz mloop565

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif

    jmp dword ptr [g_grdChunkData.pspanfnWorking+PSPANFN_AFTER_SHADING*4]

Do555:
mloop555:
    mov eax,edx
    mov ebx,edx
    shr eax,5
    mov esi,edx
    shr ebx,11
    and esi,0xF8000000
    shr esi,17
    and eax,0x0000001F
    and ebx,0x000003E0
    or  eax,esi
    or  eax,ebx
    mov [g_grdChunkData.rgm3WorkingBuffer+ecx*4+16*4],eax
    inc ecx
    jnz mloop555

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif

    jmp dword ptr [g_grdChunkData.pspanfnWorking+PSPANFN_AFTER_SHADING*4]
    }
}
#endif


// chunk processor: draws Gouraud color and Gouraud alpha into working buffer.
void SpanShade_GouraudRGBA(void)
{
    int     i;
    GOURAUD_RB  grb = g_grdChunkData.grb_Chunk;
    GOURAUD_AG  gag = g_grdChunkData.gag_Chunk;
    GOURAUD_RB  grbIncrement = g_grdChunkData.grbIncrement_Chunk;
    GOURAUD_AG  gagIncrement = g_grdChunkData.gagIncrement_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        GOURAUD_RB_AG_TO_MUNGED3_AND_MUNGED1(grb, gag,
                                             &g_grdChunkData.rgm3WorkingBuffer[i+16],
                                             &g_grdChunkData.rgm1WorkingAlphaBuffer[i+16]);
        grb += grbIncrement;
        grb &= GOURAUD_RB_CARRY_MASK;
        gag += gagIncrement;
        gag &= GOURAUD_AG_CARRY_MASK;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


// chunk processor: draws flat color and alpha into working buffer.
void SpanShade_FlatRGBA(void)
{
    int     i;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        g_grdChunkData.rgm3WorkingBuffer[i+16] = g_grdChunkData.m3FlatRGB;
        g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] = g_grdChunkData.m1FlatA;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


// chunk processor: draws alpha into working buffer.
void SpanShade_FlatA(void)
{
    int     i;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] = g_grdChunkData.m1FlatA;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


// chunk processor: draws Gouraud alpha into working buffer.
void SpanShade_GouraudA(void)
{
    int         i;
    GOURAUD_A   ga = g_grdChunkData.ga_Chunk;
    GOURAUD_A   gaIncrement = g_grdChunkData.gaIncrement_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] = GOURAUD_A_TO_MUNGED1(ga);
        ga += gaIncrement;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


// chunk processor: multiplies flat color into working buffer.
void SpanShade_FlatRGBMul(void)
{
    int     i;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        MUNGED2     m2GB, m2R;

        m2GB = MUNGED3_TO_MUNGED2_GB(g_grdChunkData.rgm3WorkingBuffer[i+16]);
        m2R = MUNGED3_TO_MUNGED2_R(g_grdChunkData.rgm3WorkingBuffer[i+16]);

        g_grdChunkData.rgm3WorkingBuffer[i+16] =
                MUL_MUNGED2X_TIMES_MUNGED2_RGB_WITH_FIXUP(g_grdChunkData.m2xFlatGB, g_grdChunkData.m2xFlatAR, m2GB, m2R);
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


// chunk processor: multiplies Gouraud color into working buffer.
void SpanShade_GouraudRGBMul(void)
{
    int         i;
    GOURAUD_RGB grgb = g_grdChunkData.grgb_Chunk;
    GOURAUD_RGB grgbIncrement = g_grdChunkData.grgbIncrement_Chunk;

    // process as many pixels in pairs as possible, so we do
    // 1.5 rather than 2 MULs per pixel
    for (i=g_grdChunkData.cPixels_Chunk; i<-1; i += 2)
    {
        MUNGED2     m2GB, m2BR, m2RG;
        MUNGED2X    m2xGB, m2xBR, m2xRG;
        GOURAUD_RGB grgbTemp;

        m2GB = MUNGED3_TO_MUNGED2_GB(g_grdChunkData.rgm3WorkingBuffer[i+16]);
        m2BR = MUNGED3_PAIR_TO_MUNGED2_BR(g_grdChunkData.rgm3WorkingBuffer[i+16],
                                          g_grdChunkData.rgm3WorkingBuffer[i+16+1]);
        m2RG = MUNGED3_TO_MUNGED2_RG(g_grdChunkData.rgm3WorkingBuffer[i+16+1]);
        m2xGB = GOURAUD_RGB_TO_MUNGED2X_GB(grgb);
        grgbTemp = grgb;
        grgb += grgbIncrement;
        grgb &= GOURAUD_RGB_CARRY_MASK;
        m2xBR = GOURAUD_RGB_TO_MUNGED2X_BR(grgbTemp, grgb);
        m2xRG = GOURAUD_RGB_TO_MUNGED2X_RG(grgb);

        MUL_MUNGED2X_TRIO_TIMES_MUNGED2_TRIO_RGB_WITH_FIXUP(m2xGB, m2xBR, m2xRG,
                                                            m2GB, m2BR, m2RG,
                                                            &g_grdChunkData.rgm3WorkingBuffer[i+16],
                                                            &g_grdChunkData.rgm3WorkingBuffer[i+16+1]);
        grgb += grgbIncrement;
        grgb &= GOURAUD_RGB_CARRY_MASK;
    }

    // do the odd pixel, if there is one
    if (i == -1)
    {
        MUNGED2     m2GB, m2R;
        MUNGED2X    m2xGB, m2xR;

        m2GB = MUNGED3_TO_MUNGED2_GB(g_grdChunkData.rgm3WorkingBuffer[15]);
        m2R = MUNGED3_TO_MUNGED2_R(g_grdChunkData.rgm3WorkingBuffer[15]);
        m2xGB = GOURAUD_RGB_TO_MUNGED2X_GB(grgb);
        m2xR = GOURAUD_RGB_TO_MUNGED2X_R(grgb);

        g_grdChunkData.rgm3WorkingBuffer[15] =
                MUL_MUNGED2X_TIMES_MUNGED2_RGB_WITH_FIXUP(m2xGB, m2xR, m2GB, m2R);
    }

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


// chunk processor: multiplies Gouraud color and Gouraud alpha into working buffer.
void SpanShade_GouraudRGBAMul(void)
{
    int         i;
    GOURAUD_GB  ggb = g_grdChunkData.ggb_Chunk;
    GOURAUD_AR  gar = g_grdChunkData.gar_Chunk;
    GOURAUD_GB  ggbIncrement = g_grdChunkData.ggbIncrement_Chunk;
    GOURAUD_AR  garIncrement = g_grdChunkData.garIncrement_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        MUNGED2     m2GB, m2AR;
        MUNGED2X    m2xGB, m2xAR;

        m2GB = MUNGED3_TO_MUNGED2_GB(g_grdChunkData.rgm3WorkingBuffer[i+16]);
        m2AR = MUNGED3_AND_ALPHA_TO_MUNGED2_AR(g_grdChunkData.rgm3WorkingBuffer[i+16],
                                               g_grdChunkData.rgm1WorkingAlphaBuffer[i+16]);
        m2xGB = GOURAUD_GB_TO_MUNGED2X(ggb);
        m2xAR = GOURAUD_AR_TO_MUNGED2X(gar);

        MUL_MUNGED2X_TIMES_MUNGED2_RGBA_WITH_FIXUP(m2xGB, m2xAR, m2GB, m2AR,
                &g_grdChunkData.rgm3WorkingBuffer[i+16], &g_grdChunkData.rgm1WorkingAlphaBuffer[i+16]);
        ggb += ggbIncrement;
        ggb &= GOURAUD_GB_CARRY_MASK;
        gar += garIncrement;
        gar &= GOURAUD_AR_CARRY_MASK;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


// chunk processor: multiplies Gouraud intensity into working buffer.
void SpanShade_GouraudIMul(void)
{
    int     i;
    GOURAUD_I   gi = g_grdChunkData.gi_Chunk;
    GOURAUD_I   giIncrement = g_grdChunkData.giIncrement_Chunk;
    MUNGED1     m1;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        m1 = GOURAUD_I_TO_MUNGED1(gi);
        g_grdChunkData.rgm3WorkingBuffer[i+16] =
                MUL_MUNGED3_TIMES_MUNGED1_WITH_FIXUP(g_grdChunkData.rgm3WorkingBuffer[i+16], m1);
        gi += giIncrement;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


// chunk processor: multiplies flat intensity into working buffer.
void SpanShade_FlatIMul(void)
{
    int     i;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        g_grdChunkData.rgm3WorkingBuffer[i+16] =
                MUL_MUNGED3_TIMES_MUNGED1_WITH_FIXUP(g_grdChunkData.rgm3WorkingBuffer[i+16], g_grdChunkData.m1FlatI);
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


// chunk processor: multiplies flat intensity into working buffer, stores flat alpha.
void SpanShade_FlatIMulA(void)
{
    int     i;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        g_grdChunkData.rgm3WorkingBuffer[i+16] =
                MUL_MUNGED3_TIMES_MUNGED1_WITH_FIXUP(g_grdChunkData.rgm3WorkingBuffer[i+16], g_grdChunkData.m1FlatI);
        g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] = g_grdChunkData.m1FlatA;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


// chunk processor: multiplies Gouraud color into working buffer, stores Gouraud alpha.
void SpanShade_GouraudRGBMulA(void)
{
    int         i;
    GOURAUD_RGB grgb = g_grdChunkData.grgb_Chunk;
    GOURAUD_RGB grgbIncrement = g_grdChunkData.grgbIncrement_Chunk;
    GOURAUD_A   ga = g_grdChunkData.ga_Chunk;
    GOURAUD_A   gaIncrement = g_grdChunkData.gaIncrement_Chunk;

    // process as many pixels in pairs as possible, so we do
    // 1.5 rather than 2 MULs per pixel
    for (i=g_grdChunkData.cPixels_Chunk; i<-1; i += 2)
    {
        MUNGED2     m2GB, m2BR, m2RG;
        MUNGED2X    m2xGB, m2xBR, m2xRG;
        GOURAUD_RGB grgbTemp;

        m2GB = MUNGED3_TO_MUNGED2_GB(g_grdChunkData.rgm3WorkingBuffer[i+16]);
        m2BR = MUNGED3_PAIR_TO_MUNGED2_BR(g_grdChunkData.rgm3WorkingBuffer[i+16],
                                          g_grdChunkData.rgm3WorkingBuffer[i+16+1]);
        m2RG = MUNGED3_TO_MUNGED2_RG(g_grdChunkData.rgm3WorkingBuffer[i+16+1]);
        m2xGB = GOURAUD_RGB_TO_MUNGED2X_GB(grgb);
        grgbTemp = grgb;
        grgb += grgbIncrement;
        grgb &= GOURAUD_RGB_CARRY_MASK;
        m2xBR = GOURAUD_RGB_TO_MUNGED2X_BR(grgbTemp, grgb);
        m2xRG = GOURAUD_RGB_TO_MUNGED2X_RG(grgb);

        MUL_MUNGED2X_TRIO_TIMES_MUNGED2_TRIO_RGB_WITH_FIXUP(m2xGB, m2xBR, m2xRG,
                                                            m2GB, m2BR, m2RG,
                                                            &g_grdChunkData.rgm3WorkingBuffer[i+16],
                                                            &g_grdChunkData.rgm3WorkingBuffer[i+16+1]);
        grgb += grgbIncrement;
        grgb &= GOURAUD_RGB_CARRY_MASK;
        g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] = GOURAUD_A_TO_MUNGED1(ga);
        g_grdChunkData.rgm1WorkingAlphaBuffer[i+16+1] = GOURAUD_A_TO_MUNGED1(ga + gaIncrement);
        ga += gaIncrement << 1;
    }

    // do the odd pixel, if there is one
    if (i == -1)
    {
        MUNGED2     m2GB, m2R;
        MUNGED2X    m2xGB, m2xR;

        m2GB = MUNGED3_TO_MUNGED2_GB(g_grdChunkData.rgm3WorkingBuffer[15]);
        m2R = MUNGED3_TO_MUNGED2_R(g_grdChunkData.rgm3WorkingBuffer[15]);
        m2xGB = GOURAUD_RGB_TO_MUNGED2X_GB(grgb);
        m2xR = GOURAUD_RGB_TO_MUNGED2X_R(grgb);

        g_grdChunkData.rgm3WorkingBuffer[15] =
                MUL_MUNGED2X_TIMES_MUNGED2_RGB_WITH_FIXUP(m2xGB, m2xR, m2GB, m2R);
        g_grdChunkData.rgm1WorkingAlphaBuffer[15] = GOURAUD_A_TO_MUNGED1(ga);
    }

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


// chunk processor: multiplies Gouraud intensity into working buffer, stores Gouraud alpha.
void SpanShade_GouraudIMulA(void)
{
    int         i;
    GOURAUD_I   gi = g_grdChunkData.gi_Chunk;
    GOURAUD_I   giIncrement = g_grdChunkData.giIncrement_Chunk;
    GOURAUD_A   ga = g_grdChunkData.ga_Chunk;
    GOURAUD_A   gaIncrement = g_grdChunkData.gaIncrement_Chunk;
    MUNGED1     m1I;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        m1I = GOURAUD_I_TO_MUNGED1(gi);
        g_grdChunkData.rgm3WorkingBuffer[i+16] =
                MUL_MUNGED3_TIMES_MUNGED1_WITH_FIXUP(g_grdChunkData.rgm3WorkingBuffer[i+16], m1I);
        gi += giIncrement;
        g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] = GOURAUD_A_TO_MUNGED1(ga);
        ga += gaIncrement;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


// chunk processor: multiplies flat intensity and alpha into working buffer.
void SpanShade_FlatIAMul(void)
{
    int     i;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        g_grdChunkData.rgm3WorkingBuffer[i+16] =
                MUL_MUNGED3_TIMES_MUNGED1_WITH_FIXUP(g_grdChunkData.rgm3WorkingBuffer[i+16], g_grdChunkData.m1FlatI);
        g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] =
                MUL_MUNGED1_TIMES_MUNGED1_WITH_FIXUP(g_grdChunkData.rgm1WorkingAlphaBuffer[i+16], g_grdChunkData.m1FlatA);
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


// chunk processor: multiplies Gouraud intensity and alpha into working buffer.
void SpanShade_GouraudIAMul(void)
{
    int     i;
    GOURAUD_I   gi = g_grdChunkData.gi_Chunk;
    GOURAUD_I   giIncrement = g_grdChunkData.giIncrement_Chunk;
    GOURAUD_A   ga = g_grdChunkData.ga_Chunk;
    GOURAUD_A   gaIncrement = g_grdChunkData.gaIncrement_Chunk;
    MUNGED1     m1I, m1A;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        m1I = GOURAUD_I_TO_MUNGED1(gi);
        g_grdChunkData.rgm3WorkingBuffer[i+16] =
                MUL_MUNGED3_TIMES_MUNGED1_WITH_FIXUP(g_grdChunkData.rgm3WorkingBuffer[i+16], m1I);
        gi += giIncrement;
        m1A = GOURAUD_A_TO_MUNGED1(ga);
        g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] =
                MUL_MUNGED1_TIMES_MUNGED1_WITH_FIXUP(m1A, g_grdChunkData.rgm1WorkingAlphaBuffer[i+16]);
        ga += gaIncrement;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


// chunk processor: multiplies Gouraud alpha into working buffer.
void SpanShade_GouraudAMul(void)
{
    int     i;
    GOURAUD_A   ga = g_grdChunkData.ga_Chunk;
    GOURAUD_A   gaIncrement = g_grdChunkData.gaIncrement_Chunk;
    MUNGED1     m1A;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        m1A = GOURAUD_A_TO_MUNGED1(ga);
        g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] =
                MUL_MUNGED1_TIMES_MUNGED1_WITH_FIXUP(m1A, g_grdChunkData.rgm1WorkingAlphaBuffer[i+16]);
        ga += gaIncrement;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


// chunk processor: multiplies flat color and alpha into working buffer.
void SpanShade_FlatRGBAMul(void)
{
    int     i;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        MUNGED2 m2GB, m2AR;

        m2GB = MUNGED3_TO_MUNGED2_GB(g_grdChunkData.rgm3WorkingBuffer[i+16]);
        m2AR = MUNGED3_AND_ALPHA_TO_MUNGED2_AR(g_grdChunkData.rgm3WorkingBuffer[i+16],
                                             g_grdChunkData.rgm1WorkingAlphaBuffer[i+16]);

        MUL_MUNGED2X_TIMES_MUNGED2_RGBA_WITH_FIXUP(g_grdChunkData.m2xFlatGB, g_grdChunkData.m2xFlatAR, m2GB, m2AR,
                &g_grdChunkData.rgm3WorkingBuffer[i+16], &g_grdChunkData.rgm1WorkingAlphaBuffer[i+16]);
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


// chunk processor: multiplies alpha into working buffer.
void SpanShade_FlatAMul(void)
{
    int     i;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] =
                MUL_MUNGED1_TIMES_MUNGED1_WITH_FIXUP(g_grdChunkData.rgm1WorkingAlphaBuffer[i+16], g_grdChunkData.m1FlatA);
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


// chunk processor: multiplies flat color into working buffer, stores flat alpha.
void SpanShade_FlatRGBMulA(void)
{
    int     i;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        MUNGED2 m2GB, m2R;

        m2GB = MUNGED3_TO_MUNGED2_GB(g_grdChunkData.rgm3WorkingBuffer[i+16]);
        m2R = MUNGED3_TO_MUNGED2_R(g_grdChunkData.rgm3WorkingBuffer[i+16]);

        g_grdChunkData.rgm3WorkingBuffer[i+16] =
                MUL_MUNGED2X_TIMES_MUNGED2_RGB_WITH_FIXUP(g_grdChunkData.m2xFlatGB, g_grdChunkData.m2xFlatAR, m2GB, m2R);
        g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] = g_grdChunkData.m1FlatA;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_SHADING])();
}


//----------------------------------------------------------------------------
// Munge-pass chunk processors.
//----------------------------------------------------------------------------

// chunk processor: munges 1555 texels into working buffer.
void SpanMunge_1555(void)
{
    int         i;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] = FROM_1555_TO_ALPHA(g_grdChunkData.rgm3WorkingBuffer[i+16]);
        g_grdChunkData.rgm3WorkingBuffer[i+16] = FROM_555_TO_MUNGED3(g_grdChunkData.rgm3WorkingBuffer[i+16]);
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_MUNGING])();
}


// chunk processor: munges 555 texels into working buffer.
#if USE_C
void SpanMunge_555(void)
{
    int         i;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        g_grdChunkData.rgm3WorkingBuffer[i+16] = FROM_555_TO_MUNGED3(g_grdChunkData.rgm3WorkingBuffer[i+16]);
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_MUNGING])();
}
#endif


// chunk processor: munges 565 texels into working buffer.
#if USE_C
void SpanMunge_565(void)
{
    int         i;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        g_grdChunkData.rgm3WorkingBuffer[i+16] = FROM_565_TO_MUNGED3(g_grdChunkData.rgm3WorkingBuffer[i+16]);
    } while (++i<0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_MUNGING])();
}
#endif


// chunk processor: munges 4444 texels into working buffer.
void SpanMunge_4444(void)
{
    int         i;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        g_grdChunkData.rgm1WorkingAlphaBuffer[i+16] = FROM_4444_TO_ALPHA(g_grdChunkData.rgm3WorkingBuffer[i+16]);
        g_grdChunkData.rgm3WorkingBuffer[i+16] = FROM_444_TO_MUNGED3(g_grdChunkData.rgm3WorkingBuffer[i+16]);
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_MUNGING])();
}


//----------------------------------------------------------------------------
// Texture-pass chunk processors.
//----------------------------------------------------------------------------

// chunk processor: draws 16-bpp texels (any format) into working buffer, checking for wrap.
#if USE_C
void SpanTexture_Wrap(void)
{
    int         i;
    FIX16_16    fix16u = g_grdChunkData.fix16u_Chunk;
    FIX16_16    fix16v = g_grdChunkData.fix16v_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
		long u = (fix16u >> intSHIFT16_16) & g_grdChunkData.cxTextureMask;
		long v = (fix16v >> g_grdChunkData.cyTextureShift) & g_grdChunkData.cyTextureMask;

        g_grdChunkData.rgm3WorkingBuffer[i+16] = g_grdChunkData.pwTexture[u+v];

		fix16u += g_grdChunkData.fix16du_Chunk;
		fix16v += g_grdChunkData.fix16dv_Chunk;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_TEXTURING])();
}
#endif


// chunk processor: draws 16-bpp texels (any format) into working buffer, clamping.
void SpanTexture_Clamp(void)
{
    int         i;
    FIX16_16    fix16u = g_grdChunkData.fix16u_Chunk;
    FIX16_16    fix16v = g_grdChunkData.fix16v_Chunk;

#if defined(_DEBUG)
    if (ReportClamp)
    {
        OutputDebugString("Clamping occurred\n");
    }
#endif

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
		long u = fix16u >> intSHIFT16_16;
		long v = fix16v >> g_grdChunkData.cyTextureShift;

        if (u < 0)
        {
            u = 0;
        }
        else if (u > (int)g_grdChunkData.cxTextureMask)
        {
            u = (int)g_grdChunkData.cxTextureMask;
        }

        if (v < 0)
        {
            v = 0;
        }
        else if (v > (int)g_grdChunkData.cyTextureMask)
        {
            // keep low bits of v from interfering with u
            v = (int)g_grdChunkData.cyTextureMask;
        }
        else
        {
            v &=g_grdChunkData.cyTextureMask;
        }

        g_grdChunkData.rgm3WorkingBuffer[i+16] = g_grdChunkData.pwTexture[u+v];

		fix16u += g_grdChunkData.fix16du_Chunk;
		fix16v += g_grdChunkData.fix16dv_Chunk;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_TEXTURING])();
}


// chunk processor: draws 16-bpp texels (any format) into working buffer, clamping U, wrapping V.
void SpanTexture_ClampUWrapV(void)
{
    int         i;
    FIX16_16    fix16u = g_grdChunkData.fix16u_Chunk;
    FIX16_16    fix16v = g_grdChunkData.fix16v_Chunk;

#if defined(_DEBUG)
    if (ReportClamp)
    {
        OutputDebugString("Clamping occurred\n");
    }
#endif

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
		long u = fix16u >> intSHIFT16_16;
		long v = (fix16v >> g_grdChunkData.cyTextureShift) & g_grdChunkData.cyTextureMask;

        if (u < 0)
        {
            u = 0;
        }
        else if (u > (int)g_grdChunkData.cxTextureMask)
        {
            u = (int)g_grdChunkData.cxTextureMask;
        }

        g_grdChunkData.rgm3WorkingBuffer[i+16] = g_grdChunkData.pwTexture[u+v];

		fix16u += g_grdChunkData.fix16du_Chunk;
		fix16v += g_grdChunkData.fix16dv_Chunk;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_TEXTURING])();
}


// chunk processor: draws 16-bpp texels (any format) into working buffer, wrapping U, clamping V.
void SpanTexture_WrapUClampV(void)
{
    int         i;
    FIX16_16    fix16u = g_grdChunkData.fix16u_Chunk;
    FIX16_16    fix16v = g_grdChunkData.fix16v_Chunk;

#if defined(_DEBUG)
    if (ReportClamp)
    {
        OutputDebugString("Clamping occurred\n");
    }
#endif

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
		long u = (fix16u >> intSHIFT16_16) & g_grdChunkData.cxTextureMask;
		long v = fix16v >> g_grdChunkData.cyTextureShift;

        if (v < 0)
        {
            v = 0;
        }
        else if (v > (int)g_grdChunkData.cyTextureMask)
        {
            v = (int)g_grdChunkData.cyTextureMask;
        }
        else
        {
            // keep low bits of v from interfering with u
            v &=g_grdChunkData.cyTextureMask;
        }

        g_grdChunkData.rgm3WorkingBuffer[i+16] = g_grdChunkData.pwTexture[u+v];

		fix16u += g_grdChunkData.fix16du_Chunk;
		fix16v += g_grdChunkData.fix16dv_Chunk;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_TEXTURING])();
}


//----------------------------------------------------------------------------
// Fog-pass chunk processors.
//----------------------------------------------------------------------------
 
// chunk processor: fogs contents of working buffer with flat fog level.
void SpanFog_FlatIMul(void)
{
    int     i;
    MUNGED3 m3FogColorFlattened = g_grdChunkData.m3FogColorFlattened;
    DWORD   dwPix;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        dwPix = g_grdChunkData.rgm3WorkingBuffer[i+16];
        dwPix += m3FogColorFlattened;

        // saturate fog color+fragment color result. This is necessary because
        // we bumped both the fog and color interpolators up by 1/16th step,
        // which can cause the sum to overflow
        if (dwPix & MUNGED3_SATURATION_MASK)
        {
            if (dwPix & MUNGED3_SATURATION_MASK_BLUE)
                dwPix |= MUNGED3_SATURATED_BLUE;

            if (dwPix & MUNGED3_SATURATION_MASK_GREEN)
                dwPix |= MUNGED3_SATURATED_GREEN;

            if (dwPix & MUNGED3_SATURATION_MASK_RED)
                dwPix |= MUNGED3_SATURATED_RED;

            dwPix &= MUNGED3_CLEAR_PADS;
        }

        g_grdChunkData.rgm3WorkingBuffer[i+16] = dwPix;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_FOG])();
}


// chunk processor: fogs contents of working buffer with RGB Gouraud fog
void SpanFog_GouraudIMul(void)
{
    int         i;
    MUNGED3     m3FogColor = g_grdChunkData.m3FogColor;
    GOURAUD_I   giFog = g_grdChunkData.giFog_Chunk;
    GOURAUD_I   giFogIncrement = g_grdChunkData.giFogIncrement_Chunk;
    MUNGED1     m1;
    DWORD       dwPix;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        m1 = GOURAUD_I_TO_MUNGED1(giFog);
        dwPix = g_grdChunkData.rgm3WorkingBuffer[i+16];
        dwPix += MUL_MUNGED3_TIMES_MUNGED1_WITH_FIXUP(m3FogColor, m1);

        // saturate fog color+fragment color result. This is necessary because
        // we bumped both the fog and color interpolators up by 1/16th step,
        // which can cause the sum to overflow
        if (dwPix & MUNGED3_SATURATION_MASK)
        {
            if (dwPix & MUNGED3_SATURATION_MASK_BLUE)
                dwPix |= MUNGED3_SATURATED_BLUE;

            if (dwPix & MUNGED3_SATURATION_MASK_GREEN)
                dwPix |= MUNGED3_SATURATED_GREEN;

            if (dwPix & MUNGED3_SATURATION_MASK_RED)
                dwPix |= MUNGED3_SATURATED_RED;

            dwPix &= MUNGED3_CLEAR_PADS;
        }

        g_grdChunkData.rgm3WorkingBuffer[i+16] = dwPix;
        giFog += giFogIncrement;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_FOG])();
}


// chunk processor: fogs contents of working buffer with monochrome Gouraud fog
void SpanFog_MonoGouraudIMul(void)
{
    int         i;
    GOURAUD_I   giFog = g_grdChunkData.giFog_Chunk;
    GOURAUD_I   giFogIncrement = g_grdChunkData.giFogIncrement_Chunk;
    MUNGED1     m1;
    DWORD       dwPix;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        m1 = GOURAUD_I_TO_MUNGED1(giFog);
        dwPix = g_grdChunkData.rgm3WorkingBuffer[i+16];
        dwPix += m1 | (m1 << 10) | (m1 << 20);

        // saturate fog color+fragment color result. This is necessary because
        // we bumped both the fog and color interpolators up by 1/16th step,
        // which can cause the sum to overflow
        if (dwPix & MUNGED3_SATURATION_MASK)
        {
            if (dwPix & MUNGED3_SATURATION_MASK_BLUE)
                dwPix |= MUNGED3_SATURATED_BLUE;

            if (dwPix & MUNGED3_SATURATION_MASK_GREEN)
                dwPix |= MUNGED3_SATURATED_GREEN;

            if (dwPix & MUNGED3_SATURATION_MASK_RED)
                dwPix |= MUNGED3_SATURATED_RED;

            dwPix &= MUNGED3_CLEAR_PADS;
        }

        g_grdChunkData.rgm3WorkingBuffer[i+16] = dwPix;
        giFog += giFogIncrement;
    } while (++i < 0);

    (*g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_FOG])();
}


//----------------------------------------------------------------------------
// Multi-function-per-pass chunk processors.
//----------------------------------------------------------------------------

// chunk processor: draws 16-bpp texels (any format) directly to 16-bpp destination
// without any conversion, checking for wrap.
#if USE_C
void SpanTextureBackend_Wrap_Native_NoZ_10_NoAlphaTest(void)
{
    int         i;
    FIX16_16    fix16u = g_grdChunkData.fix16u_Chunk;
    FIX16_16    fix16v = g_grdChunkData.fix16v_Chunk;
    WORD        *pwPix = g_grdChunkData.pPix_Chunk;

    assert((int)((g_grdChunkData.cyTextureMask >> (16 - g_grdChunkData.cyTextureShift)) + 1) == (0x10000 >> g_grdChunkData.cyTextureShift));

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
		long u = (fix16u >> intSHIFT16_16) & g_grdChunkData.cxTextureMask;
		long v = (fix16v >> g_grdChunkData.cyTextureShift) & g_grdChunkData.cyTextureMask;

        pwPix[i] = g_grdChunkData.pwTexture[u+v];

		fix16u += g_grdChunkData.fix16du_Chunk;
		fix16v += g_grdChunkData.fix16dv_Chunk;
    } while (++i < 0);
}
#endif


// chunk processor: draws 16-bpp texels (any format) directly to pixel-doubled
// 16-bpp destination without any conversion, checking for wrap.
#if USE_C
void SpanTextureBackend2X_Wrap_Native_NoZ_10_NoAlphaTest(void)
{
    int         i, j;
    DWORD       *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;

    assert((int)((g_grdChunkData.cyTextureMask >> (16 - g_grdChunkData.cyTextureShift)) + 1) == (0x10000 >> g_grdChunkData.cyTextureShift));

    for (j=0; j<2; j++)
    {
        FIX16_16    fix16u = g_grdChunkData.fix16u_Chunk;
        FIX16_16    fix16v = g_grdChunkData.fix16v_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
		    long u = (fix16u >> intSHIFT16_16) & g_grdChunkData.cxTextureMask;
		    long v = (fix16v >> g_grdChunkData.cyTextureShift) & g_grdChunkData.cyTextureMask;

            DWORD   t = g_grdChunkData.pwTexture[u+v];
            pdwPix[i] = t | (t << 16);

		    fix16u += g_grdChunkData.fix16du_Chunk;
		    fix16v += g_grdChunkData.fix16dv_Chunk;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}
#endif


// chunk processor: draws a 16-bpp flat color directly to 16-bpp destination
// without any conversion.
#if USE_C
void SpanShadeBackend_Native_Flat_NoZ_10_NoAlphaTest(void)
{
    int         i;
    WORD        *pwPix = g_grdChunkData.pPix_Chunk;
    WORD        wColor;

    i = g_grdChunkData.cPixels_Chunk;
    wColor = (WORD)g_grdChunkData.dwNativeFlatRGB;

    do
    {
        pwPix[i] = wColor;
    } while (++i < 0);
}
#else
__declspec(naked) void SpanShadeBackend_Native_Flat_NoZ_10_NoAlphaTest(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    mov edi,[g_grdChunkData.pPix_Chunk]
    mov eax,[g_grdChunkData.dwNativeFlatRGB]
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov edx,eax
    shl eax,16
    lea edi,[edi+ecx*2]
    or  eax,edx
    test edi,2
    jz  DoAligned
    mov [edi],ax
    add edi,2
    inc ecx
    jz  Done
DoAligned:
    mov edx,ecx
    inc ecx
    sar ecx,1
    jz  DoLast
mloopz:
    mov [edi],eax
    add edi,4
    inc ecx
    jnz mloopz
DoLast:
    test edx,1
    jz  Done
    mov [edi],ax
Done:

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif

    ret
    }
}
#endif


// chunk processor: draws a 16-bpp flat color directly to pixel-doubled
// 16-bpp destination without any conversion.
#if USE_C
void SpanShadeBackend2X_Native_Flat_NoZ_10_NoAlphaTest(void)
{
    int         i, j;
    DWORD       *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    DWORD       dwColor;

    for (j=0; j<2; j++)
    {
        i = g_grdChunkData.cPixels_Chunk;
        dwColor = g_grdChunkData.dwNativeFlatRGB2X;

        do
        {
            pdwPix[i] = dwColor;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}
#else
__declspec(naked) void SpanShadeBackend2X_Native_Flat_NoZ_10_NoAlphaTest(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    mov edi,[g_grdChunkData.pPix_Chunk]
    mov ebp,2
dloop:
    mov eax,[g_grdChunkData.dwNativeFlatRGB2X]
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    lea edi,[edi+ecx*4]
mloopz:
    mov [edi],eax
    add edi,4
    inc ecx
    jnz mloopz

    mov edx,[g_grdChunkData.cbScanDoubleOffset]
    mov edi,[g_grdChunkData.pPix_Chunk]
    add edi,edx
    dec ebp
    jnz dloop

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif

    ret
    }
}
#endif


// chunk processor: draws 16-bpp Gouraud shading directly to 16-bpp destination
// without any conversion.
#if USE_C
void SpanShadeBackend_Native_Gouraud_NoZ_10_NoAlphaTest(void)
{
    int         i;
    WORD        *pwPix = g_grdChunkData.pPix_Chunk;
    GOURAUD_RGB grgb = g_grdChunkData.grgb_Chunk;
    GOURAUD_RGB grgbIncrement = g_grdChunkData.grgbIncrement_Chunk;

    i = g_grdChunkData.cPixels_Chunk;

    do
    {
        pwPix[i] = GOURAUD_RGB_TO_NATIVE(grgb);
        grgb += grgbIncrement;
        grgb &= GOURAUD_RGB_CARRY_MASK;
    } while (++i < 0);
}
#else
__declspec(naked) void SpanShadeBackend_Native_Gouraud_NoZ_10_NoAlphaTest(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov edx,[g_grdChunkData.grgb_Chunk]
    mov eax,[g_grdChunkData.cMunged3ToTargetShift0]
    mov ebp,[g_grdChunkData.grgbIncrement_Chunk]
    mov edi,[g_grdChunkData.pPix_Chunk]
    cmp eax,5
    jz  Do555
// 565 destination
mloop565:
    mov eax,edx
    mov ebx,edx
    shr eax,5
    mov esi,edx
    shr ebx,10
    and esi,0xF8000000
    shr esi,16
    and eax,0x0000001F
    and ebx,0x000007C0
    or  eax,esi
    add edx,ebp
    or  eax,ebx
    and edx,GOURAUD_RGB_CARRY_MASK
    mov [edi+ecx*2],ax
    inc ecx
    jnz mloop565

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif

    ret

Do555:
mloop555:
    mov eax,edx
    mov ebx,edx
    shr eax,5
    mov esi,edx
    shr ebx,11
    and esi,0xF8000000
    shr esi,17
    and eax,0x0000001F
    and ebx,0x000003E0
    or  eax,esi
    add edx,ebp
    or  eax,ebx
    and edx,GOURAUD_RGB_CARRY_MASK
    mov [edi+ecx*2],ax
    inc ecx
    jnz mloop555

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif

    ret
    }
}
#endif


// chunk processor: draws 16-bpp Gouraud shading directly to pixel-doubled
// 16-bpp destination without any conversion.
#if USE_C
void SpanShadeBackend2X_Native_Gouraud_NoZ_10_NoAlphaTest(void)
{
    int         i, j;
    DWORD   *pdwPix = (DWORD *)g_grdChunkData.pPix_Chunk;
    GOURAUD_RGB grgbIncrement = g_grdChunkData.grgbIncrement_Chunk;

    for (j=0; j<2; j++)
    {
        GOURAUD_RGB grgb = g_grdChunkData.grgb_Chunk;

        i = g_grdChunkData.cPixels_Chunk;

        do
        {
            DWORD t = GOURAUD_RGB_TO_NATIVE(grgb);

            pdwPix[i] = t | (t << 16);
            grgb += grgbIncrement;
            grgb &= GOURAUD_RGB_CARRY_MASK;
        } while (++i < 0);

        pdwPix = (DWORD *)((BYTE *)pdwPix + g_grdChunkData.cbScanDoubleOffset);
    }
}
#else
__declspec(naked) void SpanShadeBackend2X_Native_Gouraud_NoZ_10_NoAlphaTest(void)
{
    _asm
    {
// NOTE mikeab avoid problems when called from C code
#if defined(_DEBUG)
    push ebx
    push esi
    push edi
    push ebp
#endif
    mov ebp,2
    mov edi,[g_grdChunkData.pPix_Chunk]
    push ebp
dloop:
    mov ecx,[g_grdChunkData.cPixels_Chunk]
    mov edx,[g_grdChunkData.grgb_Chunk]
    mov eax,[g_grdChunkData.cMunged3ToTargetShift0]
    mov ebp,[g_grdChunkData.grgbIncrement_Chunk]
    cmp eax,5
    jz  Do555
// 565 destination
mloop565:
    mov eax,edx
    mov ebx,edx
    shr eax,5
    mov esi,edx
    shr ebx,10
    and esi,0xF8000000
    shr esi,16
    and eax,0x0000001F
    and ebx,0x000007C0
    or  eax,esi
    add edx,ebp
    or  eax,ebx
    and edx,GOURAUD_RGB_CARRY_MASK
    mov esi,eax
    shl eax,16
    or  eax,esi
    mov [edi+ecx*4],eax
    inc ecx
    jnz mloop565

    pop ebp
    dec ebp
    jz  Done
    mov edx,[g_grdChunkData.cbScanDoubleOffset]
    push ebp
    add edi,edx
    jmp dloop

Done:

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif

    ret

Do555:
mloop555:
    mov eax,edx
    mov ebx,edx
    shr eax,5
    mov esi,edx
    shr ebx,11
    and esi,0xF8000000
    shr esi,17
    and eax,0x0000001F
    and ebx,0x000003E0
    or  eax,esi
    add edx,ebp
    or  eax,ebx
    and edx,GOURAUD_RGB_CARRY_MASK
    mov esi,eax
    shl eax,16
    or  eax,esi
    mov [edi+ecx*4],eax
    inc ecx
    jnz mloop555

#if defined(_DEBUG)
    pop ebp
    pop edi
	pop esi
    pop ebx
#endif

    pop ebp
    dec ebp
    jz  Done
    mov edx,[g_grdChunkData.cbScanDoubleOffset]
    push ebp
    add edi,edx
    jmp dloop
    }
}
#endif

