//=================================================================
//
// 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"

#if defined(_DEBUG)
#include <stdio.h>
#endif


#define ASSERT assert

//------------------------------------------------------------
// Ideally, all data used by triangle and span processing goes
// in a single block here, to minimize cache contention.
//------------------------------------------------------------

// The render data contains all the information for the rasterization routines.
//   This includes the polygon data, texture information and so on.  It is in
//   a global variable so that it can be accessed faster from the assembly
//   routines.
GRFRENDERDATA   g_grdRenderData;

// contains all the data used by the chunk processors
// NOTE keep this and g_grdRenderData next to each other so they don't
// compete for cache lines
GRFCHUNKDATA    g_grdChunkData;

float   FloatShift16 = (float)0x10000;

DWORD Div_2_15_Table[14] = {
    0x100000000/15, 0x100000000/14, 0x100000000/13, 0x100000000/12,
    0x100000000/11, 0x100000000/10, 0x100000000/9, 0x100000000/8,
    0x100000000/7, 0x100000000/6, 0x100000000/5, 0x100000000/4,
    0x100000000/3, 0x100000000/2
};

inline void DRAW_SPAN(void)
{
#if USE_C
    (*g_grdRenderData.pspanfnEntry)();
#else
    _asm
    {
    push ebx
    push esi
    push edi
    push ebp
    call [g_grdRenderData.pspanfnEntry]
    pop ebp
    pop edi
    pop esi
    pop ebx
    }
#endif
}


// used for tracking which handlers get called
const int ITERATE_NOOP                              = 0;
const int ITERATE_Z                                 = 1;
const int ITERATE_TEXTUREZ                          = 2;
const int ITERATE_TEXTURE                           = 3;
const int ITERATE_ERROR                             = 4;
const int ITERATE_NOTHING                           = 5;
const int ITERATE_GOURAUDZ                          = 6;
const int ITERATE_PERSPECTIVETEXTUREGOURAUDZ        = 7;
const int ITERATE_AFFINETEXTUREGOURAUDZ             = 8;
const int ITERATE_ZFOG                              = 9;
const int ITERATE_GOURAUDZFOG                       = 10;
const int ITERATE_PERSPECTIVETEXTUREGOURAUDZFOG     = 11;
const int ITERATE_AFFINETEXTUREGOURAUDZFOG          = 12;

// state-based table of handler functions to do setup and dispatch to chunk processors
// table organization:
//
//    bit 4     bit 3       bit 2     bit 1    bit 0
//
//     fog   perspective   Gouraud   texture     z
//   (1-yes,   (1-yes,      (1-yes,  (1-yes,   (1-yes,
//    0-no)     0-affine)    0-no)    0-no)     0-no)
//
// C++ weirdness: class statics need to be defined in an implementation file.

// NOTE mikeab Many of these entries do more work than specifically required;
// they could be broken out more finely

const PTRIFN RenderDevice::m_rgphandlerfn[SIZE_M_RGPHANDLERFN] = {
// 0x00: !fog, !perspective, !Gouraud, !texture, !z
    RenderDevice::IterateZ,
// 0x01: !fog, !perspective, !Gouraud, !texture, z
    RenderDevice::IterateZ,
// 0x02: !fog, !perspective, !Gouraud, texture, !z
    RenderDevice::IterateTexture,
// 0x03: !fog, !perspective, !Gouraud, texture, z
    RenderDevice::IterateTextureZ,
// 0x04: !fog, !perspective, Gouraud, !texture, !z
    RenderDevice::IterateGouraudZ,
// 0x05: !fog, !perspective, Gouraud, !texture, z
    RenderDevice::IterateGouraudZ,
// 0x06: !fog, !perspective, Gouraud, texture, !z
    RenderDevice::IterateAffineTextureGouraudZ,
// 0x07: !fog, !perspective, Gouraud, texture, z
    RenderDevice::IterateAffineTextureGouraudZ,
// 0x08: !fog, perspective, !Gouraud, !texture, !z
    RenderDevice::IterateZ,
// 0x09: !fog, perspective, !Gouraud, !texture, z
    RenderDevice::IterateZ,
// 0x0A: !fog, perspective, !Gouraud, texture, !z
    RenderDevice::IterateTexture,
// 0x0B: !fog, perspective, !Gouraud, texture, z
    RenderDevice::IterateTextureZ,
// 0x0C: !fog, perspective, Gouraud, !texture, !z
    RenderDevice::IterateGouraudZ,
// 0x0D: !fog, perspective, Gouraud, !texture, z
    RenderDevice::IterateGouraudZ,
// 0x0E: !fog, perspective, Gouraud, texture, !z
    RenderDevice::IteratePerspectiveTextureGouraudZ,
// 0x0F: !fog, perspective, Gouraud, texture, z
    RenderDevice::IteratePerspectiveTextureGouraudZ,
// 0x10: fog, !perspective, !Gouraud, !texture, !z
    RenderDevice::IterateZFog,
// 0x11: fog, !perspective, !Gouraud, !texture, z
    RenderDevice::IterateZFog,
// 0x12: fog, !perspective, !Gouraud, texture, !z
    RenderDevice::IterateAffineTextureGouraudZFog,
// 0x13: fog, !perspective, !Gouraud, texture, z
    RenderDevice::IterateAffineTextureGouraudZFog,
// 0x14: fog, !perspective, Gouraud, !texture, !z
    RenderDevice::IterateGouraudZFog,
// 0x15: fog, !perspective, Gouraud, !texture, z
    RenderDevice::IterateGouraudZFog,
// 0x16: fog, !perspective, Gouraud, texture, !z
    RenderDevice::IterateAffineTextureGouraudZFog,
// 0x17: fog, !perspective, Gouraud, texture, z
    RenderDevice::IterateAffineTextureGouraudZFog,
// 0x18: fog, perspective, !Gouraud, !texture, !z
    RenderDevice::IterateZFog,
// 0x19: fog, perspective, !Gouraud, !texture, z
    RenderDevice::IterateZFog,
// 0x1A: fog, perspective, !Gouraud, texture, !z
    RenderDevice::IteratePerspectiveTextureGouraudZFog,
// 0x1B: fog, perspective, !Gouraud, texture, z
    RenderDevice::IteratePerspectiveTextureGouraudZFog,
// 0x1C: fog, perspective, Gouraud, !texture, !z
    RenderDevice::IterateGouraudZFog,
// 0x1D: fog, perspective, Gouraud, !texture, z
    RenderDevice::IterateGouraudZFog,
// 0x1E: fog, perspective, Gouraud, texture, !z
    RenderDevice::IteratePerspectiveTextureGouraudZFog,
// 0x1F: fog, perspective, Gouraud, texture, z
    RenderDevice::IteratePerspectiveTextureGouraudZFog,
};

#if defined(_DEBUG)
#define VERIFY_UV() VerifyUV()

unsigned int cHandlersIn[SIZE_M_RGPHANDLERFN];
unsigned int cHandlersDrawn[SIZE_M_RGPHANDLERFN];
unsigned int cStatesIn[SIZE_M_RGDTD];
unsigned int cStatesDrawn[SIZE_M_RGDTD];
unsigned int cBackendsIn[SIZE_M_RGTZAB];
unsigned int cBackendsDrawn[SIZE_M_RGTZAB];
#define AREA_COUNT_MAX  20
unsigned int cArea[AREA_COUNT_MAX];

#define IN_COUNT(i,j) cHandlersIn[i & MASTER_STATE_MASK]++;         \
                      cStatesIn[j & MASTER_STATE_MASK]++;           \
                      cBackendsIn[j >> TRIVIALZ_AND_BACKEND_SHIFT]++
#define DRAWN_COUNT(i,j) cHandlersDrawn[i & MASTER_STATE_MASK]++;   \
                         cStatesDrawn[j & MASTER_STATE_MASK]++;     \
                         cBackendsDrawn[j >> TRIVIALZ_AND_BACKEND_SHIFT]++

inline void AREA_COUNT(int area)
{

    if (area < 0)
        area = -area;

    area = (area >> 8) / 2;

    if (area >= (AREA_COUNT_MAX - 1))
    {
        cArea[AREA_COUNT_MAX - 1]++;
    }
    else
    {
        cArea[area]++;
    }
}

#define REPORT_IF_NO_FAST_PATH()  ReportIfNoFastPath()
#else

#define VERIFY_UV()
#define IN_COUNT(i,j)
#define DRAWN_COUNT(i,j)
#define AREA_COUNT(area)
#define REPORT_IF_NO_FAST_PATH()

#endif

// bytecodes for
// these must synchronize with the entries in rgpspanfn[].
const int SPAN_NOOP                     = 0;
const int SPAN_BACKEND                  = 1;
// defined in span.h because span.cpp needs access to it
//const int SPAN_MUNGE                    = 2;
#if SPAN_MUNGE !=2
#error Invalid SPAN_MUNGE value
#endif
const int SPAN_TEXTURE                  = 3;
const int SPAN_SHADE_FLATRGB            = 4;
const int SPAN_SHADE_FLATRGBA           = 5;
const int SPAN_SHADE_FLATRGBMUL         = 6;
const int SPAN_SHADE_FLATRGBAMUL        = 7;
const int SPAN_SHADE_FLATRGBMULA        = 8;
const int SPAN_SHADE_FLATA              = 9;
const int SPAN_SHADE_FLATAMUL           = 10;
const int SPAN_SHADE_FLATIMUL           = 11;
const int SPAN_SHADE_FLATIMULA          = 12;
const int SPAN_SHADE_FLATIAMUL          = 13;
const int SPAN_SHADE_GOURAUDRGB         = 14;
const int SPAN_SHADE_GOURAUDRGBA        = 15;
const int SPAN_SHADE_GOURAUDIMUL        = 16;
const int SPAN_SHADE_GOURAUDIAMUL       = 17;
const int SPAN_SHADE_GOURAUDIMULA       = 18;
const int SPAN_SHADE_GOURAUDRGBMUL      = 19;
const int SPAN_SHADE_GOURAUDRGBAMUL     = 20;
const int SPAN_SHADE_GOURAUDRGBMULA     = 21;
const int SPAN_SHADE_GOURAUDA           = 22;
const int SPAN_SHADE_GOURAUDAMUL        = 23;
const int SPAN_SHADE_FLATRGB_NATIVE     = 24;
const int SPAN_SHADE_GOURAUDRGB_NATIVE  = 25;
const int SPAN_BAD                      = 26;

// NOTE mikeab increase MAX_SPAN_FN when adding new entries above

// state-based table of triangle handlers and chunk processors
// C++ weirdness: class statics need to be defined in an implementation file.
//
//        bit 7      bit 6       bit 5       bit 4       bit 3        bit 2     bit 1      bit 0
//
//       native    texturemap  texalpha  shadealpha  shadecolor  shadegouraud  shadeI       z
//      (1-yes,     (1-yes,     (1-yes,     (1-yes,    (1-yes,     (1-Gouraud,  (1-I,     (1-yes,
//       0-no)       0-no)       0-no)       0-no)      0-no)       0-flat)      0-RGB)    0-no)
//
// NOTE mikeab ReevaluateState() will never set texalpha if there's no texture, therefore,
// all entries in this table for which (!texturemap && texalpha) == TRUE are errors.
// Likewise for cases for which (!shadecolor && shadergb) == TRUE.
// Likewise for cases for which ((!shadealpha && !shadecolor) && shadegouraud) == TRUE.
// Likewise for cases for which (!texture && !shadecolor) == TRUE.
// Cases for which !shadecolor don't really care about shadergb; those are arbitrarily
//  forced to RGB, and the I cases are error.
// !Shadergb is only allowed if there's a texture map; otherwise it's an error.
//
RenderDevice::DRAWTRIDESC RenderDevice::m_rgdtd[SIZE_M_RGDTD] = {
// 0x00: !native, !texturemap, !texalpha, !shadealpha, !shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x01: !native, !texturemap, !texalpha, !shadealpha, !shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x02: !native, !texturemap, !texalpha, !shadealpha, !shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x03: !native, !texturemap, !texalpha, !shadealpha, !shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x04: !native, !texturemap, !texalpha, !shadealpha, !shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x05: !native, !texturemap, !texalpha, !shadealpha, !shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x06: !native, !texturemap, !texalpha, !shadealpha, !shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x07: !native, !texturemap, !texalpha, !shadealpha, !shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x08: !native, !texturemap, !texalpha, !shadealpha, shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_SHADE_FLATRGB, SPAN_BAD, SPAN_BAD, SPAN_BACKEND},
// 0x09: !native, !texturemap, !texalpha, !shadealpha, shadecolor, !shadegouraud, !shadeI, z
	{SPAN_SHADE_FLATRGB, SPAN_BAD, SPAN_BAD, SPAN_BACKEND},
// 0x0A: !native, !texturemap, !texalpha, !shadealpha, shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x0B: !native, !texturemap, !texalpha, !shadealpha, shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x0C: !native, !texturemap, !texalpha, !shadealpha, shadecolor, shadegouraud, !shadeI, !z
    {SPAN_SHADE_GOURAUDRGB, SPAN_BAD, SPAN_BAD, SPAN_BACKEND},
// 0x0D: !native, !texturemap, !texalpha, !shadealpha, shadecolor, shadegouraud, !shadeI, z
    {SPAN_SHADE_GOURAUDRGB, SPAN_BAD, SPAN_BAD, SPAN_BACKEND},
// 0x0E: !native, !texturemap, !texalpha, !shadealpha, shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x0F: !native, !texturemap, !texalpha, !shadealpha, shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x10: !native, !texturemap, !texalpha, shadealpha, !shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x11: !native, !texturemap, !texalpha, shadealpha, !shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x12: !native, !texturemap, !texalpha, shadealpha, !shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x13: !native, !texturemap, !texalpha, shadealpha, !shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x14: !native, !texturemap, !texalpha, shadealpha, !shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x15: !native, !texturemap, !texalpha, shadealpha, !shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x16: !native, !texturemap, !texalpha, shadealpha, !shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x17: !native, !texturemap, !texalpha, shadealpha, !shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x18: !native, !texturemap, !texalpha, shadealpha, shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_SHADE_FLATRGBA, SPAN_BAD, SPAN_BAD, SPAN_BACKEND},
// 0x19: !native, !texturemap, !texalpha, shadealpha, shadecolor, !shadegouraud, !shadeI, z
	{SPAN_SHADE_FLATRGBA, SPAN_BAD, SPAN_BAD, SPAN_BACKEND},
// 0x1A: !native, !texturemap, !texalpha, shadealpha, shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x1B: !native, !texturemap, !texalpha, shadealpha, shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x1C: !native, !texturemap, !texalpha, shadealpha, shadecolor, shadegouraud, !shadeI, !z
    {SPAN_SHADE_GOURAUDRGBA, SPAN_BAD, SPAN_BAD, SPAN_BACKEND},
// 0x1D: !native, !texturemap, !texalpha, shadealpha, shadecolor, shadegouraud, !shadeI, z
    {SPAN_SHADE_GOURAUDRGBA, SPAN_BAD, SPAN_BAD, SPAN_BACKEND},
// 0x1E: !native, !texturemap, !texalpha, shadealpha, shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x1F: !native, !texturemap, !texalpha, shadealpha, shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x20: !native, !texturemap, texalpha, !shadealpha, !shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x21: !native, !texturemap, texalpha, !shadealpha, !shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x22: !native, !texturemap, texalpha, !shadealpha, !shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x23: !native, !texturemap, texalpha, !shadealpha, !shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x24: !native, !texturemap, texalpha, !shadealpha, !shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x25: !native, !texturemap, texalpha, !shadealpha, !shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x26: !native, !texturemap, texalpha, !shadealpha, !shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x27: !native, !texturemap, texalpha, !shadealpha, !shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x28: !native, !texturemap, texalpha, !shadealpha, shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x29: !native, !texturemap, texalpha, !shadealpha, shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x2A: !native, !texturemap, texalpha, !shadealpha, shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x2B: !native, !texturemap, texalpha, !shadealpha, shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x2C: !native, !texturemap, texalpha, !shadealpha, shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x2D: !native, !texturemap, texalpha, !shadealpha, shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x2E: !native, !texturemap, texalpha, !shadealpha, shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x2F: !native, !texturemap, texalpha, !shadealpha, shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x30: !native, !texturemap, texalpha, shadealpha, !shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x31: !native, !texturemap, texalpha, shadealpha, !shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x32: !native, !texturemap, texalpha, shadealpha, !shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x33: !native, !texturemap, texalpha, shadealpha, !shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x34: !native, !texturemap, texalpha, shadealpha, !shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x35: !native, !texturemap, texalpha, shadealpha, !shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x36: !native, !texturemap, texalpha, shadealpha, !shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x37: !native, !texturemap, texalpha, shadealpha, !shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x38: !native, !texturemap, texalpha, shadealpha, shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x39: !native, !texturemap, texalpha, shadealpha, shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x3A: !native, !texturemap, texalpha, shadealpha, shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x3B: !native, !texturemap, texalpha, shadealpha, shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x3C: !native, !texturemap, texalpha, shadealpha, shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x3D: !native, !texturemap, texalpha, shadealpha, shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x3E: !native, !texturemap, texalpha, shadealpha, shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x3F: !native, !texturemap, texalpha, shadealpha, shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x40: !native, texturemap, !texalpha, !shadealpha, !shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_BACKEND, SPAN_BAD},
// 0x41: !native, texturemap, !texalpha, !shadealpha, !shadecolor, !shadegouraud, !shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_BACKEND, SPAN_BAD},
// 0x42: !native, texturemap, !texalpha, !shadealpha, !shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x43: !native, texturemap, !texalpha, !shadealpha, !shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x44: !native, texturemap, !texalpha, !shadealpha, !shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x45: !native, texturemap, !texalpha, !shadealpha, !shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x46: !native, texturemap, !texalpha, !shadealpha, !shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x47: !native, texturemap, !texalpha, !shadealpha, !shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x48: !native, texturemap, !texalpha, !shadealpha, shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATRGBMUL, SPAN_BACKEND},
// 0x49: !native, texturemap, !texalpha, !shadealpha, shadecolor, !shadegouraud, !shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATRGBMUL, SPAN_BACKEND},
// 0x4A: !native, texturemap, !texalpha, !shadealpha, shadecolor, !shadegouraud, shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATIMUL, SPAN_BACKEND},
// 0x4B: !native, texturemap, !texalpha, !shadealpha, shadecolor, !shadegouraud, shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATIMUL, SPAN_BACKEND},
// 0x4C: !native, texturemap, !texalpha, !shadealpha, shadecolor, shadegouraud, !shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDRGBMUL, SPAN_BACKEND},
// 0x4D: !native, texturemap, !texalpha, !shadealpha, shadecolor, shadegouraud, !shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDRGBMUL, SPAN_BACKEND},
// 0x4E: !native, texturemap, !texalpha, !shadealpha, shadecolor, shadegouraud, shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDIMUL, SPAN_BACKEND},
// 0x4F: !native, texturemap, !texalpha, !shadealpha, shadecolor, shadegouraud, shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDIMUL, SPAN_BACKEND},
// 0x50: !native, texturemap, !texalpha, shadealpha, !shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATA, SPAN_BACKEND},
// 0x51: !native, texturemap, !texalpha, shadealpha, !shadecolor, !shadegouraud, !shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATA, SPAN_BACKEND},
// 0x52: !native, texturemap, !texalpha, shadealpha, !shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x53: !native, texturemap, !texalpha, shadealpha, !shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x54: !native, texturemap, !texalpha, shadealpha, !shadecolor, shadegouraud, !shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDA, SPAN_BACKEND},
// 0x55: !native, texturemap, !texalpha, shadealpha, !shadecolor, shadegouraud, !shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDA, SPAN_BACKEND},
// 0x56: !native, texturemap, !texalpha, shadealpha, !shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x57: !native, texturemap, !texalpha, shadealpha, !shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x58: !native, texturemap, !texalpha, shadealpha, shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATRGBMULA, SPAN_BACKEND},
// 0x59: !native, texturemap, !texalpha, shadealpha, shadecolor, !shadegouraud, !shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATRGBMULA, SPAN_BACKEND},
// 0x5A: !native, texturemap, !texalpha, shadealpha, shadecolor, !shadegouraud, shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATIMULA, SPAN_BACKEND},
// 0x5B: !native, texturemap, !texalpha, shadealpha, shadecolor, !shadegouraud, shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATIMULA, SPAN_BACKEND},
// 0x5C: !native, texturemap, !texalpha, shadealpha, shadecolor, shadegouraud, !shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDRGBMULA, SPAN_BACKEND},
// 0x5D: !native, texturemap, !texalpha, shadealpha, shadecolor, shadegouraud, !shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDRGBMULA, SPAN_BACKEND},
// 0x5E: !native, texturemap, !texalpha, shadealpha, shadecolor, shadegouraud, shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDIMULA, SPAN_BACKEND},
// 0x5F: !native, texturemap, !texalpha, shadealpha, shadecolor, shadegouraud, shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDIMULA, SPAN_BACKEND},
// 0x60: !native, texturemap, texalpha, !shadealpha, !shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_BACKEND, SPAN_BAD},
// 0x61: !native, texturemap, texalpha, !shadealpha, !shadecolor, !shadegouraud, !shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_BACKEND, SPAN_BAD},
// 0x62: !native, texturemap, texalpha, !shadealpha, !shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x63: !native, texturemap, texalpha, !shadealpha, !shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x64: !native, texturemap, texalpha, !shadealpha, !shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x65: !native, texturemap, texalpha, !shadealpha, !shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x66: !native, texturemap, texalpha, !shadealpha, !shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x67: !native, texturemap, texalpha, !shadealpha, !shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x68: !native, texturemap, texalpha, !shadealpha, shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATRGBMUL, SPAN_BACKEND},
// 0x69: !native, texturemap, texalpha, !shadealpha, shadecolor, !shadegouraud, !shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATRGBMUL, SPAN_BACKEND},
// 0x6A: !native, texturemap, texalpha, !shadealpha, shadecolor, !shadegouraud, shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATIMUL, SPAN_BACKEND},
// 0x6B: !native, texturemap, texalpha, !shadealpha, shadecolor, !shadegouraud, shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATIMUL, SPAN_BACKEND},
// 0x6C: !native, texturemap, texalpha, !shadealpha, shadecolor, shadegouraud, !shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDRGBMUL, SPAN_BACKEND},
// 0x6D: !native, texturemap, texalpha, !shadealpha, shadecolor, shadegouraud, !shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDRGBMUL, SPAN_BACKEND},
// 0x6E: !native, texturemap, texalpha, !shadealpha, shadecolor, shadegouraud, shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDIMUL, SPAN_BACKEND},
// 0x6F: !native, texturemap, texalpha, !shadealpha, shadecolor, shadegouraud, shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDIMUL, SPAN_BACKEND},
// 0x70: !native, texturemap, texalpha, shadealpha, !shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATAMUL, SPAN_BACKEND},
// 0x71: !native, texturemap, texalpha, shadealpha, !shadecolor, !shadegouraud, !shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATAMUL, SPAN_BACKEND},
// 0x72: !native, texturemap, texalpha, shadealpha, !shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x73: !native, texturemap, texalpha, shadealpha, !shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x74: !native, texturemap, texalpha, shadealpha, !shadecolor, shadegouraud, !shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDAMUL, SPAN_BACKEND},
// 0x75: !native, texturemap, texalpha, shadealpha, !shadecolor, shadegouraud, !shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDAMUL, SPAN_BACKEND},
// 0x76: !native, texturemap, texalpha, shadealpha, !shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x77: !native, texturemap, texalpha, shadealpha, !shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x78: !native, texturemap, texalpha, shadealpha, shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATRGBAMUL, SPAN_BACKEND},
// 0x79: !native, texturemap, texalpha, shadealpha, shadecolor, !shadegouraud, !shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATRGBAMUL, SPAN_BACKEND},
// 0x7A: !native, texturemap, texalpha, shadealpha, shadecolor, !shadegouraud, shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATIAMUL, SPAN_BACKEND},
// 0x7B: !native, texturemap, texalpha, shadealpha, shadecolor, !shadegouraud, shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_FLATIAMUL, SPAN_BACKEND},
// 0x7C: !native, texturemap, texalpha, shadealpha, shadecolor, shadegouraud, !shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDRGBAMUL, SPAN_BACKEND},
// 0x7D: !native, texturemap, texalpha, shadealpha, shadecolor, shadegouraud, !shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDRGBAMUL, SPAN_BACKEND},
// 0x7E: !native, texturemap, texalpha, shadealpha, shadecolor, shadegouraud, shadeI, !z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDIAMUL, SPAN_BACKEND},
// 0x7F: !native, texturemap, texalpha, shadealpha, shadecolor, shadegouraud, shadeI, z
	{SPAN_TEXTURE, SPAN_MUNGE, SPAN_SHADE_GOURAUDIAMUL, SPAN_BACKEND},
// 0x80: native, !texturemap, !texalpha, !shadealpha, !shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x81: native, !texturemap, !texalpha, !shadealpha, !shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x82: native, !texturemap, !texalpha, !shadealpha, !shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x83: native, !texturemap, !texalpha, !shadealpha, !shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x84: native, !texturemap, !texalpha, !shadealpha, !shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x85: native, !texturemap, !texalpha, !shadealpha, !shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x86: native, !texturemap, !texalpha, !shadealpha, !shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x87: native, !texturemap, !texalpha, !shadealpha, !shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x88: native, !texturemap, !texalpha, !shadealpha, shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BACKEND, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x89: native, !texturemap, !texalpha, !shadealpha, shadecolor, !shadegouraud, !shadeI, z
	{SPAN_SHADE_FLATRGB_NATIVE, SPAN_BAD, SPAN_BAD, SPAN_BACKEND},
// 0x8A: native, !texturemap, !texalpha, !shadealpha, shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x8B: native, !texturemap, !texalpha, !shadealpha, shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x8C: native, !texturemap, !texalpha, !shadealpha, shadecolor, shadegouraud, !shadeI, !z
    {SPAN_BACKEND, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x8D: native, !texturemap, !texalpha, !shadealpha, shadecolor, shadegouraud, !shadeI, z
    {SPAN_SHADE_GOURAUDRGB_NATIVE, SPAN_BAD, SPAN_BAD, SPAN_BACKEND},
// 0x8E: native, !texturemap, !texalpha, !shadealpha, shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x8F: native, !texturemap, !texalpha, !shadealpha, shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x90: native, !texturemap, !texalpha, shadealpha, !shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x91: native, !texturemap, !texalpha, shadealpha, !shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x92: native, !texturemap, !texalpha, shadealpha, !shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x93: native, !texturemap, !texalpha, shadealpha, !shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x94: native, !texturemap, !texalpha, shadealpha, !shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x95: native, !texturemap, !texalpha, shadealpha, !shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x96: native, !texturemap, !texalpha, shadealpha, !shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x97: native, !texturemap, !texalpha, shadealpha, !shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x98: native, !texturemap, !texalpha, shadealpha, shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x99: native, !texturemap, !texalpha, shadealpha, shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x9A: native, !texturemap, !texalpha, shadealpha, shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x9B: native, !texturemap, !texalpha, shadealpha, shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x9C: native, !texturemap, !texalpha, shadealpha, shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x9D: native, !texturemap, !texalpha, shadealpha, shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x9E: native, !texturemap, !texalpha, shadealpha, shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0x9F: native, !texturemap, !texalpha, shadealpha, shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xA0: native, !texturemap, texalpha, !shadealpha, !shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xA1: native, !texturemap, texalpha, !shadealpha, !shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xA2: native, !texturemap, texalpha, !shadealpha, !shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xA3: native, !texturemap, texalpha, !shadealpha, !shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xA4: native, !texturemap, texalpha, !shadealpha, !shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xA5: native, !texturemap, texalpha, !shadealpha, !shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xA6: native, !texturemap, texalpha, !shadealpha, !shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xA7: native, !texturemap, texalpha, !shadealpha, !shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xA8: native, !texturemap, texalpha, !shadealpha, shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xA9: native, !texturemap, texalpha, !shadealpha, shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xAA: native, !texturemap, texalpha, !shadealpha, shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xAB: native, !texturemap, texalpha, !shadealpha, shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xAC: native, !texturemap, texalpha, !shadealpha, shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xAD: native, !texturemap, texalpha, !shadealpha, shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xAE: native, !texturemap, texalpha, !shadealpha, shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xAF: native, !texturemap, texalpha, !shadealpha, shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xB0: native, !texturemap, texalpha, shadealpha, !shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xB1: native, !texturemap, texalpha, shadealpha, !shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xB2: native, !texturemap, texalpha, shadealpha, !shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xB3: native, !texturemap, texalpha, shadealpha, !shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xB4: native, !texturemap, texalpha, shadealpha, !shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xB5: native, !texturemap, texalpha, shadealpha, !shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xB6: native, !texturemap, texalpha, shadealpha, !shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xB7: native, !texturemap, texalpha, shadealpha, !shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xB8: native, !texturemap, texalpha, shadealpha, shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xB9: native, !texturemap, texalpha, shadealpha, shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xBA: native, !texturemap, texalpha, shadealpha, shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xBB: native, !texturemap, texalpha, shadealpha, shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xBC: native, !texturemap, texalpha, shadealpha, shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xBD: native, !texturemap, texalpha, shadealpha, shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xBE: native, !texturemap, texalpha, shadealpha, shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xBF: native, !texturemap, texalpha, shadealpha, shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xC0: native, texturemap, !texalpha, !shadealpha, !shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BACKEND, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xC1: native, texturemap, !texalpha, !shadealpha, !shadecolor, !shadegouraud, !shadeI, z
	{SPAN_TEXTURE, SPAN_BACKEND, SPAN_BAD, SPAN_BAD},
// 0xC2: native, texturemap, !texalpha, !shadealpha, !shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xC3: native, texturemap, !texalpha, !shadealpha, !shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xC4: native, texturemap, !texalpha, !shadealpha, !shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xC5: native, texturemap, !texalpha, !shadealpha, !shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xC6: native, texturemap, !texalpha, !shadealpha, !shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xC7: native, texturemap, !texalpha, !shadealpha, !shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xC8: native, texturemap, !texalpha, !shadealpha, shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xC9: native, texturemap, !texalpha, !shadealpha, shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xCA: native, texturemap, !texalpha, !shadealpha, shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xCB: native, texturemap, !texalpha, !shadealpha, shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xCC: native, texturemap, !texalpha, !shadealpha, shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xCD: native, texturemap, !texalpha, !shadealpha, shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xCE: native, texturemap, !texalpha, !shadealpha, shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xCF: native, texturemap, !texalpha, !shadealpha, shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xD0: native, texturemap, !texalpha, shadealpha, !shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xD1: native, texturemap, !texalpha, shadealpha, !shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xD2: native, texturemap, !texalpha, shadealpha, !shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xD3: native, texturemap, !texalpha, shadealpha, !shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xD4: native, texturemap, !texalpha, shadealpha, !shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xD5: native, texturemap, !texalpha, shadealpha, !shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xD6: native, texturemap, !texalpha, shadealpha, !shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xD7: native, texturemap, !texalpha, shadealpha, !shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xD8: native, texturemap, !texalpha, shadealpha, shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xD9: native, texturemap, !texalpha, shadealpha, shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xDA: native, texturemap, !texalpha, shadealpha, shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xDB: native, texturemap, !texalpha, shadealpha, shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xDC: native, texturemap, !texalpha, shadealpha, shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xDD: native, texturemap, !texalpha, shadealpha, shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xDE: native, texturemap, !texalpha, shadealpha, shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xDF: native, texturemap, !texalpha, shadealpha, shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xE0: native, texturemap, texalpha, !shadealpha, !shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xE1: native, texturemap, texalpha, !shadealpha, !shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xE2: native, texturemap, texalpha, !shadealpha, !shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xE3: native, texturemap, texalpha, !shadealpha, !shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xE4: native, texturemap, texalpha, !shadealpha, !shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xE5: native, texturemap, texalpha, !shadealpha, !shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xE6: native, texturemap, texalpha, !shadealpha, !shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xE7: native, texturemap, texalpha, !shadealpha, !shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xE8: native, texturemap, texalpha, !shadealpha, shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xE9: native, texturemap, texalpha, !shadealpha, shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xEA: native, texturemap, texalpha, !shadealpha, shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xEB: native, texturemap, texalpha, !shadealpha, shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xEC: native, texturemap, texalpha, !shadealpha, shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xED: native, texturemap, texalpha, !shadealpha, shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xEE: native, texturemap, texalpha, !shadealpha, shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xEF: native, texturemap, texalpha, !shadealpha, shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xF0: native, texturemap, texalpha, shadealpha, !shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xF1: native, texturemap, texalpha, shadealpha, !shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xF2: native, texturemap, texalpha, shadealpha, !shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xF3: native, texturemap, texalpha, shadealpha, !shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xF4: native, texturemap, texalpha, shadealpha, !shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xF5: native, texturemap, texalpha, shadealpha, !shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xF6: native, texturemap, texalpha, shadealpha, !shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xF7: native, texturemap, texalpha, shadealpha, !shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xF8: native, texturemap, texalpha, shadealpha, shadecolor, !shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xF9: native, texturemap, texalpha, shadealpha, shadecolor, !shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xFA: native, texturemap, texalpha, shadealpha, shadecolor, !shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xFB: native, texturemap, texalpha, shadealpha, shadecolor, !shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xFC: native, texturemap, texalpha, shadealpha, shadecolor, shadegouraud, !shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xFD: native, texturemap, texalpha, shadealpha, shadecolor, shadegouraud, !shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xFE: native, texturemap, texalpha, shadealpha, shadecolor, shadegouraud, shadeI, !z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
// 0xFF: native, texturemap, texalpha, shadealpha, shadecolor, shadegouraud, shadeI, z
	{SPAN_BAD, SPAN_BAD, SPAN_BAD, SPAN_BAD},
};

// These must synchronize with the entries in rgpspanfnTrivialZAndBackend[].

// NATIVE_SINGLE_PASS is in span.h, because span.cpp needs access to it
//const int NATIVE_SINGLE_PASS                            = 0;
const int TRIVIALZ_NOOP                                 = 1;
const int TRIVIALZ_CW                                   = 2;
const int TRIVIALZ_C                                    = 3;
const int TRIVIALZ_W                                    = 4;

const int BACKEND_BAD                                   = 5;

const int BACKEND_NOZ_10_NOALPHATEST                    = 6;
const int BACKEND_NOZ_10_ALPHATEST                      = 7;
const int BACKEND_NOZ_11_NOALPHATEST                    = 8;
const int BACKEND_NOZ_11_ALPHATEST                      = 9;
const int BACKEND_NOZ_1INVALPHA_NOALPHATEST             = 10;
const int BACKEND_NOZ_1INVALPHA_ALPHATEST               = 11;
const int BACKEND_NOZ_ALPHAINVALPHA_NOALPHATEST         = 12;
const int BACKEND_NOZ_ALPHAINVALPHA_ALPHATEST           = 13;

const int BACKEND_ZC_10_NOALPHATEST                     = 14;
const int BACKEND_ZC_10_ALPHATEST                       = 15;
const int BACKEND_ZC_11_NOALPHATEST                     = 16;
const int BACKEND_ZC_11_ALPHATEST                       = 17;
const int BACKEND_ZC_1INVALPHA_NOALPHATEST              = 18;
const int BACKEND_ZC_1INVALPHA_ALPHATEST                = 19;
const int BACKEND_ZC_ALPHAINVALPHA_NOALPHATEST          = 20;
const int BACKEND_ZC_ALPHAINVALPHA_ALPHATEST            = 21;

const int BACKEND_ZCCOND_10_NOALPHATEST                 = 22;
const int BACKEND_ZCCOND_10_ALPHATEST                   = 23;
const int BACKEND_ZCCOND_11_NOALPHATEST                 = 24;
const int BACKEND_ZCCOND_11_ALPHATEST                   = 25;
const int BACKEND_ZCCOND_1INVALPHA_NOALPHATEST          = 26;
const int BACKEND_ZCCOND_1INVALPHA_ALPHATEST            = 27;
const int BACKEND_ZCCOND_ALPHAINVALPHA_NOALPHATEST      = 28;
const int BACKEND_ZCCOND_ALPHAINVALPHA_ALPHATEST        = 29;

const int BACKEND_ZCW_10_NOALPHATEST                    = 30;
const int BACKEND_ZCW_10_ALPHATEST                      = 31;
const int BACKEND_ZCW_11_NOALPHATEST                    = 32;
const int BACKEND_ZCW_11_ALPHATEST                      = 33;
const int BACKEND_ZCW_1INVALPHA_NOALPHATEST             = 34;
const int BACKEND_ZCW_1INVALPHA_ALPHATEST               = 35;
const int BACKEND_ZCW_ALPHAINVALPHA_NOALPHATEST         = 36;
const int BACKEND_ZCW_ALPHAINVALPHA_ALPHATEST           = 37;

const int BACKEND_ZCWCOND_10_NOALPHATEST                = 38;
const int BACKEND_ZCWCOND_10_ALPHATEST                  = 39;
const int BACKEND_ZCWCOND_11_NOALPHATEST                = 40;
const int BACKEND_ZCWCOND_11_ALPHATEST                  = 41;
const int BACKEND_ZCWCOND_1INVALPHA_NOALPHATEST         = 42;
const int BACKEND_ZCWCOND_1INVALPHA_ALPHATEST           = 43;
const int BACKEND_ZCWCOND_ALPHAINVALPHA_NOALPHATEST     = 44;
const int BACKEND_ZCWCOND_ALPHAINVALPHA_ALPHATEST       = 45;

const int BACKEND_ZW_10_NOALPHATEST                     = 46;
const int BACKEND_ZW_10_ALPHATEST                       = 47;
const int BACKEND_ZW_11_NOALPHATEST                     = 48;
const int BACKEND_ZW_11_ALPHATEST                       = 49;
const int BACKEND_ZW_1INVALPHA_NOALPHATEST              = 50;
const int BACKEND_ZW_1INVALPHA_ALPHATEST                = 51;
const int BACKEND_ZW_ALPHAINVALPHA_NOALPHATEST          = 52;
const int BACKEND_ZW_ALPHAINVALPHA_ALPHATEST            = 53;

const int BACKEND_NATIVE_NOZ_10_NOALPHATEST             = 54;
const int BACKEND_NATIVE_ZC_10_NOALPHATEST              = 55;
const int BACKEND_NATIVE_ZCCOND_10_NOALPHATEST          = 56;
const int BACKEND_NATIVE_ZCW_10_NOALPHATEST             = 57;
const int BACKEND_NATIVE_ZCWCOND_10_NOALPHATEST         = 58;
const int BACKEND_NATIVE_ZW_10_NOALPHATEST              = 59;

const int TRIVIALZ_BAD                                  = 60;

const int TRIVIALZ_CW_NATIVE                            = 61;

const int BACKEND2X_NOZ_10_NOALPHATEST                  = 62;
const int BACKEND2X_NOZ_10_ALPHATEST                    = 63;
const int BACKEND2X_NOZ_11_NOALPHATEST                  = 64;
const int BACKEND2X_NOZ_11_ALPHATEST                    = 65;
const int BACKEND2X_NOZ_1INVALPHA_NOALPHATEST           = 66;
const int BACKEND2X_NOZ_1INVALPHA_ALPHATEST             = 67;
const int BACKEND2X_NOZ_ALPHAINVALPHA_NOALPHATEST       = 68;
const int BACKEND2X_NOZ_ALPHAINVALPHA_ALPHATEST         = 69;

const int BACKEND2X_ZC_10_NOALPHATEST                   = 70;
const int BACKEND2X_ZC_10_ALPHATEST                     = 71;
const int BACKEND2X_ZC_11_NOALPHATEST                   = 72;
const int BACKEND2X_ZC_11_ALPHATEST                     = 73;
const int BACKEND2X_ZC_1INVALPHA_NOALPHATEST            = 74;
const int BACKEND2X_ZC_1INVALPHA_ALPHATEST              = 75;
const int BACKEND2X_ZC_ALPHAINVALPHA_NOALPHATEST        = 76;
const int BACKEND2X_ZC_ALPHAINVALPHA_ALPHATEST          = 77;

const int BACKEND2X_ZCCOND_10_NOALPHATEST               = 78;
const int BACKEND2X_ZCCOND_10_ALPHATEST                 = 79;
const int BACKEND2X_ZCCOND_11_NOALPHATEST               = 80;
const int BACKEND2X_ZCCOND_11_ALPHATEST                 = 81;
const int BACKEND2X_ZCCOND_1INVALPHA_NOALPHATEST        = 82;
const int BACKEND2X_ZCCOND_1INVALPHA_ALPHATEST          = 83;
const int BACKEND2X_ZCCOND_ALPHAINVALPHA_NOALPHATEST    = 84;
const int BACKEND2X_ZCCOND_ALPHAINVALPHA_ALPHATEST      = 85;

const int BACKEND2X_ZCW_10_NOALPHATEST                  = 86;
const int BACKEND2X_ZCW_10_ALPHATEST                    = 87;
const int BACKEND2X_ZCW_11_NOALPHATEST                  = 88;
const int BACKEND2X_ZCW_11_ALPHATEST                    = 89;
const int BACKEND2X_ZCW_1INVALPHA_NOALPHATEST           = 90;
const int BACKEND2X_ZCW_1INVALPHA_ALPHATEST             = 91;
const int BACKEND2X_ZCW_ALPHAINVALPHA_NOALPHATEST       = 92;
const int BACKEND2X_ZCW_ALPHAINVALPHA_ALPHATEST         = 93;

const int BACKEND2X_ZCWCOND_10_NOALPHATEST              = 94;
const int BACKEND2X_ZCWCOND_10_ALPHATEST                = 95;
const int BACKEND2X_ZCWCOND_11_NOALPHATEST              = 96;
const int BACKEND2X_ZCWCOND_11_ALPHATEST                = 97;
const int BACKEND2X_ZCWCOND_1INVALPHA_NOALPHATEST       = 98;
const int BACKEND2X_ZCWCOND_1INVALPHA_ALPHATEST         = 99;
const int BACKEND2X_ZCWCOND_ALPHAINVALPHA_NOALPHATEST   = 100;
const int BACKEND2X_ZCWCOND_ALPHAINVALPHA_ALPHATEST     = 101;

const int BACKEND2X_ZW_10_NOALPHATEST                   = 102;
const int BACKEND2X_ZW_10_ALPHATEST                     = 103;
const int BACKEND2X_ZW_11_NOALPHATEST                   = 104;
const int BACKEND2X_ZW_11_ALPHATEST                     = 105;
const int BACKEND2X_ZW_1INVALPHA_NOALPHATEST            = 106;
const int BACKEND2X_ZW_1INVALPHA_ALPHATEST              = 107;
const int BACKEND2X_ZW_ALPHAINVALPHA_NOALPHATEST        = 108;
const int BACKEND2X_ZW_ALPHAINVALPHA_ALPHATEST          = 109;

const int BACKEND2X_NATIVE_NOZ_10_NOALPHATEST           = 110;
const int BACKEND2X_NATIVE_ZC_10_NOALPHATEST            = 111;
const int BACKEND2X_NATIVE_ZCCOND_10_NOALPHATEST        = 112;
const int BACKEND2X_NATIVE_ZCW_10_NOALPHATEST           = 113;
const int BACKEND2X_NATIVE_ZCWCOND_10_NOALPHATEST       = 114;
const int BACKEND2X_NATIVE_ZW_10_NOALPHATEST            = 115;

const int TRIVIALZ_W_NATIVE                             = 116;
const int TRIVIALZ_C_NATIVE                             = 117;


// state-based table of trivial z and backend processors
// C++ weirdness: class statics need to be defined in an implementation file.
//
//    bit 7          bit 6            bit 5       bit 4     bit 3     bit 2    bits 1-0
//
//                    use
// pixel doubled  native format  tex/shadealpha  zcompare  zwrite   alphatest  alphablend
//   (1-yes,         (1-yes,         (1-yes,       (1-LE,   (1-yes,  (1-yes,   (3-AlphaInvAlpha,
//    0-no)           0-no)           0-no)         0-no)    0-no)    0-no)     2-1InvAlpha,
//                                                                              1-11,
//                                                                              0-10)

const RenderDevice::TRIVIALZ_AND_BACKEND RenderDevice::m_rgtzab[SIZE_M_RGTZAB] = {
// 0x00: !pixdouble, !native, !tex/shadealpha, !zcompare, !zwrite, !alphatest, 10
	{TRIVIALZ_NOOP, BACKEND_NOZ_10_NOALPHATEST},
// 0x01: !pixdouble, !native, !tex/shadealpha, !zcompare, !zwrite, !alphatest, 11
	{TRIVIALZ_NOOP, BACKEND_NOZ_11_NOALPHATEST},
// 0x02: !pixdouble, !native, !tex/shadealpha, !zcompare, !zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_NOOP, BACKEND_NOZ_10_NOALPHATEST},
// 0x03: !pixdouble, !native, !tex/shadealpha, !zcompare, !zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_NOOP, BACKEND_NOZ_10_NOALPHATEST},
// 0x04: !pixdouble, !native, !tex/shadealpha, !zcompare, !zwrite, alphatest, 10
	{TRIVIALZ_NOOP, BACKEND_NOZ_10_NOALPHATEST},
// 0x05: !pixdouble, !native, !tex/shadealpha, !zcompare, !zwrite, alphatest, 11
	{TRIVIALZ_NOOP, BACKEND_NOZ_11_NOALPHATEST},
// 0x06: !pixdouble, !native, !tex/shadealpha, !zcompare, !zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_NOOP, BACKEND_NOZ_10_NOALPHATEST},
// 0x07: !pixdouble, !native, !tex/shadealpha, !zcompare, !zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_NOOP, BACKEND_NOZ_10_NOALPHATEST},
// 0x08: !pixdouble, !native, !tex/shadealpha, !zcompare, zwrite, !alphatest, 10
	{TRIVIALZ_W, BACKEND_NOZ_10_NOALPHATEST},
// 0x09: !pixdouble, !native, !tex/shadealpha, !zcompare, zwrite, !alphatest, 11
	{TRIVIALZ_W, BACKEND_NOZ_11_NOALPHATEST},
// 0x0A: !pixdouble, !native, !tex/shadealpha, !zcompare, zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_W, BACKEND_NOZ_10_NOALPHATEST},
// 0x0B: !pixdouble, !native, !tex/shadealpha, !zcompare, zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_W, BACKEND_NOZ_10_NOALPHATEST},
// 0x0C: !pixdouble, !native, !tex/shadealpha, !zcompare, zwrite, alphatest, 10
	{TRIVIALZ_W, BACKEND_NOZ_10_NOALPHATEST},
// 0x0D: !pixdouble, !native, !tex/shadealpha, !zcompare, zwrite, alphatest, 11
	{TRIVIALZ_W, BACKEND_NOZ_11_NOALPHATEST},
// 0x0E: !pixdouble, !native, !tex/shadealpha, !zcompare, zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_W, BACKEND_NOZ_10_NOALPHATEST},
// 0x0F: !pixdouble, !native, !tex/shadealpha, !zcompare, zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_W, BACKEND_NOZ_10_NOALPHATEST},
// 0x10: !pixdouble, !native, !tex/shadealpha, zcompare, !zwrite, !alphatest, 10
	{TRIVIALZ_C, BACKEND_ZCCOND_10_NOALPHATEST},
// 0x11: !pixdouble, !native, !tex/shadealpha, zcompare, !zwrite, !alphatest, 11
	{TRIVIALZ_C, BACKEND_ZCCOND_11_NOALPHATEST},
// 0x12: !pixdouble, !native, !tex/shadealpha, zcompare, !zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_C, BACKEND_ZCCOND_10_NOALPHATEST},
// 0x13: !pixdouble, !native, !tex/shadealpha, zcompare, !zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_C, BACKEND_ZCCOND_10_NOALPHATEST},
// 0x14: !pixdouble, !native, !tex/shadealpha, zcompare, !zwrite, alphatest, 10
	{TRIVIALZ_C, BACKEND_ZCCOND_10_NOALPHATEST},
// 0x15: !pixdouble, !native, !tex/shadealpha, zcompare, !zwrite, alphatest, 11
	{TRIVIALZ_C, BACKEND_ZCCOND_11_NOALPHATEST},
// 0x16: !pixdouble, !native, !tex/shadealpha, zcompare, !zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_C, BACKEND_ZCCOND_10_NOALPHATEST},
// 0x17: !pixdouble, !native, !tex/shadealpha, zcompare, !zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_C, BACKEND_ZCCOND_10_NOALPHATEST},
// 0x18: !pixdouble, !native, !tex/shadealpha, zcompare, zwrite, !alphatest, 10
	{TRIVIALZ_CW, BACKEND_ZCCOND_10_NOALPHATEST},
// 0x19: !pixdouble, !native, !tex/shadealpha, zcompare, zwrite, !alphatest, 11
	{TRIVIALZ_CW, BACKEND_ZCCOND_11_NOALPHATEST},
// 0x1A: !pixdouble, !native, !tex/shadealpha, zcompare, zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_CW, BACKEND_ZCCOND_10_NOALPHATEST},
// 0x1B: !pixdouble, !native, !tex/shadealpha, zcompare, zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_CW, BACKEND_ZCCOND_10_NOALPHATEST},
// 0x1C: !pixdouble, !native, !tex/shadealpha, zcompare, zwrite, alphatest, 10
	{TRIVIALZ_CW, BACKEND_ZCCOND_10_NOALPHATEST},
// 0x1D: !pixdouble, !native, !tex/shadealpha, zcompare, zwrite, alphatest, 11
	{TRIVIALZ_CW, BACKEND_ZCCOND_11_NOALPHATEST},
// 0x1E: !pixdouble, !native, !tex/shadealpha, zcompare, zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_CW, BACKEND_ZCCOND_10_NOALPHATEST},
// 0x1F: !pixdouble, !native, !tex/shadealpha, zcompare, zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_CW, BACKEND_ZCCOND_10_NOALPHATEST},
// 0x20: !pixdouble, !native, tex/shadealpha, !zcompare, !zwrite, !alphatest, 10
	{TRIVIALZ_NOOP, BACKEND_NOZ_10_NOALPHATEST},
// 0x21: !pixdouble, !native, tex/shadealpha, !zcompare, !zwrite, !alphatest, 11
	{TRIVIALZ_NOOP, BACKEND_NOZ_11_NOALPHATEST},
// 0x22: !pixdouble, !native, tex/shadealpha, !zcompare, !zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_NOOP, BACKEND_NOZ_1INVALPHA_NOALPHATEST},
// 0x23: !pixdouble, !native, tex/shadealpha, !zcompare, !zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_NOOP, BACKEND_NOZ_ALPHAINVALPHA_NOALPHATEST},
// 0x24: !pixdouble, !native, tex/shadealpha, !zcompare, !zwrite, alphatest, 10
	{TRIVIALZ_NOOP, BACKEND_NOZ_10_ALPHATEST},
// 0x25: !pixdouble, !native, tex/shadealpha, !zcompare, !zwrite, alphatest, 11
	{TRIVIALZ_NOOP, BACKEND_NOZ_11_ALPHATEST},
// 0x26: !pixdouble, !native, tex/shadealpha, !zcompare, !zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_NOOP, BACKEND_NOZ_1INVALPHA_ALPHATEST},
// 0x27: !pixdouble, !native, tex/shadealpha, !zcompare, !zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_NOOP, BACKEND_NOZ_ALPHAINVALPHA_ALPHATEST},
// 0x28: !pixdouble, !native, tex/shadealpha, !zcompare, zwrite, !alphatest, 10
	{TRIVIALZ_W, BACKEND_NOZ_10_NOALPHATEST},
// 0x29: !pixdouble, !native, tex/shadealpha, !zcompare, zwrite, !alphatest, 11
	{TRIVIALZ_W, BACKEND_NOZ_11_NOALPHATEST},
// 0x2A: !pixdouble, !native, tex/shadealpha, !zcompare, zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_W, BACKEND_NOZ_1INVALPHA_NOALPHATEST},
// 0x2B: !pixdouble, !native, tex/shadealpha, !zcompare, zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_W, BACKEND_NOZ_ALPHAINVALPHA_NOALPHATEST},
// 0x2C: !pixdouble, !native, tex/shadealpha, !zcompare, zwrite, alphatest, 10
	{TRIVIALZ_NOOP, BACKEND_ZW_10_ALPHATEST},
// 0x2D: !pixdouble, !native, tex/shadealpha, !zcompare, zwrite, alphatest, 11
	{TRIVIALZ_NOOP, BACKEND_ZW_11_ALPHATEST},
// 0x2E: !pixdouble, !native, tex/shadealpha, !zcompare, zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_NOOP, BACKEND_ZW_1INVALPHA_ALPHATEST},
// 0x2F: !pixdouble, !native, tex/shadealpha, !zcompare, zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_NOOP, BACKEND_ZW_ALPHAINVALPHA_ALPHATEST},
// 0x30: !pixdouble, !native, tex/shadealpha, zcompare, !zwrite, !alphatest, 10
	{TRIVIALZ_C, BACKEND_ZCCOND_10_NOALPHATEST},
// 0x31: !pixdouble, !native, tex/shadealpha, zcompare, !zwrite, !alphatest, 11
	{TRIVIALZ_C, BACKEND_ZCCOND_11_NOALPHATEST},
// 0x32: !pixdouble, !native, tex/shadealpha, zcompare, !zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_C, BACKEND_ZCCOND_1INVALPHA_NOALPHATEST},
// 0x33: !pixdouble, !native, tex/shadealpha, zcompare, !zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_C, BACKEND_ZCCOND_ALPHAINVALPHA_NOALPHATEST},
// 0x34: !pixdouble, !native, tex/shadealpha, zcompare, !zwrite, alphatest, 10
	{TRIVIALZ_C, BACKEND_ZCCOND_10_ALPHATEST},
// 0x35: !pixdouble, !native, tex/shadealpha, zcompare, !zwrite, alphatest, 11
	{TRIVIALZ_C, BACKEND_ZCCOND_11_ALPHATEST},
// 0x36: !pixdouble, !native, tex/shadealpha, zcompare, !zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_C, BACKEND_ZCCOND_1INVALPHA_ALPHATEST},
// 0x37: !pixdouble, !native, tex/shadealpha, zcompare, !zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_C, BACKEND_ZCCOND_ALPHAINVALPHA_ALPHATEST},
// 0x38: !pixdouble, !native, tex/shadealpha, zcompare, zwrite, !alphatest, 10
	{TRIVIALZ_CW, BACKEND_ZCCOND_10_NOALPHATEST},
// 0x39: !pixdouble, !native, tex/shadealpha, zcompare, zwrite, !alphatest, 11
	{TRIVIALZ_CW, BACKEND_ZCCOND_11_NOALPHATEST},
// 0x3A: !pixdouble, !native, tex/shadealpha, zcompare, zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_CW, BACKEND_ZCCOND_1INVALPHA_NOALPHATEST},
// 0x3B: !pixdouble, !native, tex/shadealpha, zcompare, zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_CW, BACKEND_ZCCOND_ALPHAINVALPHA_NOALPHATEST},
// 0x3C: !pixdouble, !native, tex/shadealpha, zcompare, zwrite, alphatest, 10
	{TRIVIALZ_C, BACKEND_ZCWCOND_10_ALPHATEST},
// 0x3D: !pixdouble, !native, tex/shadealpha, zcompare, zwrite, alphatest, 11
	{TRIVIALZ_C, BACKEND_ZCWCOND_11_ALPHATEST},
// 0x3E: !pixdouble, !native, tex/shadealpha, zcompare, zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_C, BACKEND_ZCWCOND_1INVALPHA_ALPHATEST},
// 0x3F: !pixdouble, !native, tex/shadealpha, zcompare, zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_C, BACKEND_ZCWCOND_ALPHAINVALPHA_ALPHATEST},
// 0x40: !pixdouble, native, !tex/shadealpha, !zcompare, !zwrite, !alphatest, 10
	{TRIVIALZ_NOOP, NATIVE_SINGLE_PASS},
// 0x41: !pixdouble, native, !tex/shadealpha, !zcompare, !zwrite, !alphatest, 11
	{TRIVIALZ_NOOP, BACKEND_NOZ_11_NOALPHATEST},
// 0x42: !pixdouble, native, !tex/shadealpha, !zcompare, !zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_NOOP, NATIVE_SINGLE_PASS},
// 0x43: !pixdouble, native, !tex/shadealpha, !zcompare, !zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_NOOP, NATIVE_SINGLE_PASS},
// 0x44: !pixdouble, native, !tex/shadealpha, !zcompare, !zwrite, alphatest, 10
	{TRIVIALZ_NOOP, NATIVE_SINGLE_PASS},
// 0x45: !pixdouble, native, !tex/shadealpha, !zcompare, !zwrite, alphatest, 11
	{TRIVIALZ_NOOP, BACKEND_NOZ_11_NOALPHATEST},
// 0x46: !pixdouble, native, !tex/shadealpha, !zcompare, !zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_NOOP, NATIVE_SINGLE_PASS},
// 0x47: !pixdouble, native, !tex/shadealpha, !zcompare, !zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_NOOP, NATIVE_SINGLE_PASS},
// 0x48: !pixdouble, native, !tex/shadealpha, !zcompare, zwrite, !alphatest, 10
	{TRIVIALZ_W_NATIVE, BACKEND_NATIVE_NOZ_10_NOALPHATEST},
// 0x49: !pixdouble, native, !tex/shadealpha, !zcompare, zwrite, !alphatest, 11
	{TRIVIALZ_W, BACKEND_NOZ_11_NOALPHATEST},
// 0x4A: !pixdouble, native, !tex/shadealpha, !zcompare, zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_W_NATIVE, BACKEND_NATIVE_NOZ_10_NOALPHATEST},
// 0x4B: !pixdouble, native, !tex/shadealpha, !zcompare, zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_W_NATIVE, BACKEND_NATIVE_NOZ_10_NOALPHATEST},
// 0x4C: !pixdouble, native, !tex/shadealpha, !zcompare, zwrite, alphatest, 10
	{TRIVIALZ_W_NATIVE, BACKEND_NATIVE_NOZ_10_NOALPHATEST},
// 0x4D: !pixdouble, native, !tex/shadealpha, !zcompare, zwrite, alphatest, 11
	{TRIVIALZ_W, BACKEND_NOZ_11_NOALPHATEST},
// 0x4E: !pixdouble, native, !tex/shadealpha, !zcompare, zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_W_NATIVE, BACKEND_NATIVE_NOZ_10_NOALPHATEST},
// 0x4F: !pixdouble, native, !tex/shadealpha, !zcompare, zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_W_NATIVE, BACKEND_NATIVE_NOZ_10_NOALPHATEST},
// 0x50: !pixdouble, native, !tex/shadealpha, zcompare, !zwrite, !alphatest, 10
	{TRIVIALZ_C_NATIVE, BACKEND_NATIVE_ZCCOND_10_NOALPHATEST},
// 0x51: !pixdouble, native, !tex/shadealpha, zcompare, !zwrite, !alphatest, 11
	{TRIVIALZ_C, BACKEND_ZCCOND_11_NOALPHATEST},
// 0x52: !pixdouble, native, !tex/shadealpha, zcompare, !zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_C_NATIVE, BACKEND_NATIVE_ZCCOND_10_NOALPHATEST},
// 0x53: !pixdouble, native, !tex/shadealpha, zcompare, !zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_C_NATIVE, BACKEND_NATIVE_ZCCOND_10_NOALPHATEST},
// 0x54: !pixdouble, native, !tex/shadealpha, zcompare, !zwrite, alphatest, 10
	{TRIVIALZ_C_NATIVE, BACKEND_NATIVE_ZCCOND_10_NOALPHATEST},
// 0x55: !pixdouble, native, !tex/shadealpha, zcompare, !zwrite, alphatest, 11
	{TRIVIALZ_C, BACKEND_ZCCOND_11_NOALPHATEST},
// 0x56: !pixdouble, native, !tex/shadealpha, zcompare, !zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_C_NATIVE, BACKEND_NATIVE_ZCCOND_10_NOALPHATEST},
// 0x57: !pixdouble, native, !tex/shadealpha, zcompare, !zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_C_NATIVE, BACKEND_NATIVE_ZCCOND_10_NOALPHATEST},
// 0x58: !pixdouble, native, !tex/shadealpha, zcompare, zwrite, !alphatest, 10
	{TRIVIALZ_CW_NATIVE, BACKEND_NATIVE_ZCCOND_10_NOALPHATEST},
// 0x59: !pixdouble, native, !tex/shadealpha, zcompare, zwrite, !alphatest, 11
	{TRIVIALZ_CW, BACKEND_ZCCOND_11_NOALPHATEST},
// 0x5A: !pixdouble, native, !tex/shadealpha, zcompare, zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_CW_NATIVE, BACKEND_NATIVE_ZCCOND_10_NOALPHATEST},
// 0x5B: !pixdouble, native, !tex/shadealpha, zcompare, zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_CW_NATIVE, BACKEND_NATIVE_ZCCOND_10_NOALPHATEST},
// 0x5C: !pixdouble, native, !tex/shadealpha, zcompare, zwrite, alphatest, 10
	{TRIVIALZ_CW_NATIVE, BACKEND_NATIVE_ZCCOND_10_NOALPHATEST},
// 0x5D: !pixdouble, native, !tex/shadealpha, zcompare, zwrite, alphatest, 11
	{TRIVIALZ_CW, BACKEND_ZCCOND_11_NOALPHATEST},
// 0x5E: !pixdouble, native, !tex/shadealpha, zcompare, zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_CW_NATIVE, BACKEND_NATIVE_ZCCOND_10_NOALPHATEST},
// 0x5F: !pixdouble, native, !tex/shadealpha, zcompare, zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_CW_NATIVE, BACKEND_NATIVE_ZCCOND_10_NOALPHATEST},
// 0x60: !pixdouble, native, tex/shadealpha, !zcompare, !zwrite, !alphatest, 10
	{TRIVIALZ_NOOP, NATIVE_SINGLE_PASS},
// 0x61: !pixdouble, native, tex/shadealpha, !zcompare, !zwrite, !alphatest, 11
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x62: !pixdouble, native, tex/shadealpha, !zcompare, !zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x63: !pixdouble, native, tex/shadealpha, !zcompare, !zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x64: !pixdouble, native, tex/shadealpha, !zcompare, !zwrite, alphatest, 10
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x65: !pixdouble, native, tex/shadealpha, !zcompare, !zwrite, alphatest, 11
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x66: !pixdouble, native, tex/shadealpha, !zcompare, !zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x67: !pixdouble, native, tex/shadealpha, !zcompare, !zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x68: !pixdouble, native, tex/shadealpha, !zcompare, zwrite, !alphatest, 10
	{TRIVIALZ_W_NATIVE, BACKEND_NATIVE_NOZ_10_NOALPHATEST},
// 0x69: !pixdouble, native, tex/shadealpha, !zcompare, zwrite, !alphatest, 11
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x6A: !pixdouble, native, tex/shadealpha, !zcompare, zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x6B: !pixdouble, native, tex/shadealpha, !zcompare, zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x6C: !pixdouble, native, tex/shadealpha, !zcompare, zwrite, alphatest, 10
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x6D: !pixdouble, native, tex/shadealpha, !zcompare, zwrite, alphatest, 11
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x6E: !pixdouble, native, tex/shadealpha, !zcompare, zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x6F: !pixdouble, native, tex/shadealpha, !zcompare, zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x70: !pixdouble, native, tex/shadealpha, zcompare, !zwrite, !alphatest, 10
	{TRIVIALZ_C_NATIVE, BACKEND_NATIVE_ZCCOND_10_NOALPHATEST},
// 0x71: !pixdouble, native, tex/shadealpha, zcompare, !zwrite, !alphatest, 11
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x72: !pixdouble, native, tex/shadealpha, zcompare, !zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x73: !pixdouble, native, tex/shadealpha, zcompare, !zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x74: !pixdouble, native, tex/shadealpha, zcompare, !zwrite, alphatest, 10
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x75: !pixdouble, native, tex/shadealpha, zcompare, !zwrite, alphatest, 11
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x76: !pixdouble, native, tex/shadealpha, zcompare, !zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x77: !pixdouble, native, tex/shadealpha, zcompare, !zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x78: !pixdouble, native, tex/shadealpha, zcompare, zwrite, !alphatest, 10
	{TRIVIALZ_CW_NATIVE, BACKEND_NATIVE_ZCCOND_10_NOALPHATEST},
// 0x79: !pixdouble, native, tex/shadealpha, zcompare, zwrite, !alphatest, 11
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x7A: !pixdouble, native, tex/shadealpha, zcompare, zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x7B: !pixdouble, native, tex/shadealpha, zcompare, zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x7C: !pixdouble, native, tex/shadealpha, zcompare, zwrite, alphatest, 10
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x7D: !pixdouble, native, tex/shadealpha, zcompare, zwrite, alphatest, 11
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x7E: !pixdouble, native, tex/shadealpha, zcompare, zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x7F: !pixdouble, native, tex/shadealpha, zcompare, zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0x80: pixdouble, !native, !tex/shadealpha, !zcompare, !zwrite, !alphatest, 10
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_10_NOALPHATEST},
// 0x81: pixdouble, !native, !tex/shadealpha, !zcompare, !zwrite, !alphatest, 11
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_11_NOALPHATEST},
// 0x82: pixdouble, !native, !tex/shadealpha, !zcompare, !zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_10_NOALPHATEST},
// 0x83: pixdouble, !native, !tex/shadealpha, !zcompare, !zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_10_NOALPHATEST},
// 0x84: pixdouble, !native, !tex/shadealpha, !zcompare, !zwrite, alphatest, 10
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_10_NOALPHATEST},
// 0x85: pixdouble, !native, !tex/shadealpha, !zcompare, !zwrite, alphatest, 11
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_11_NOALPHATEST},
// 0x86: pixdouble, !native, !tex/shadealpha, !zcompare, !zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_10_NOALPHATEST},
// 0x87: pixdouble, !native, !tex/shadealpha, !zcompare, !zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_10_NOALPHATEST},
// 0x88: pixdouble, !native, !tex/shadealpha, !zcompare, zwrite, !alphatest, 10
	{TRIVIALZ_W, BACKEND2X_NOZ_10_NOALPHATEST},
// 0x89: pixdouble, !native, !tex/shadealpha, !zcompare, zwrite, !alphatest, 11
	{TRIVIALZ_W, BACKEND2X_NOZ_11_NOALPHATEST},
// 0x8A: pixdouble, !native, !tex/shadealpha, !zcompare, zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_W, BACKEND2X_NOZ_10_NOALPHATEST},
// 0x8B: pixdouble, !native, !tex/shadealpha, !zcompare, zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_W, BACKEND2X_NOZ_10_NOALPHATEST},
// 0x8C: pixdouble, !native, !tex/shadealpha, !zcompare, zwrite, alphatest, 10
	{TRIVIALZ_W, BACKEND2X_NOZ_10_NOALPHATEST},
// 0x8D: pixdouble, !native, !tex/shadealpha, !zcompare, zwrite, alphatest, 11
	{TRIVIALZ_W, BACKEND2X_NOZ_11_NOALPHATEST},
// 0x8E: pixdouble, !native, !tex/shadealpha, !zcompare, zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_W, BACKEND2X_NOZ_10_NOALPHATEST},
// 0x8F: pixdouble, !native, !tex/shadealpha, !zcompare, zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_W, BACKEND2X_NOZ_10_NOALPHATEST},
// 0x90: pixdouble, !native, !tex/shadealpha, zcompare, !zwrite, !alphatest, 10
	{TRIVIALZ_C, BACKEND2X_ZCCOND_10_NOALPHATEST},
// 0x91: pixdouble, !native, !tex/shadealpha, zcompare, !zwrite, !alphatest, 11
	{TRIVIALZ_C, BACKEND2X_ZCCOND_11_NOALPHATEST},
// 0x92: pixdouble, !native, !tex/shadealpha, zcompare, !zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_C, BACKEND2X_ZCCOND_10_NOALPHATEST},
// 0x93: pixdouble, !native, !tex/shadealpha, zcompare, !zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_C, BACKEND2X_ZCCOND_10_NOALPHATEST},
// 0x94: pixdouble, !native, !tex/shadealpha, zcompare, !zwrite, alphatest, 10
	{TRIVIALZ_C, BACKEND2X_ZCCOND_10_NOALPHATEST},
// 0x95: pixdouble, !native, !tex/shadealpha, zcompare, !zwrite, alphatest, 11
	{TRIVIALZ_C, BACKEND2X_ZCCOND_11_NOALPHATEST},
// 0x96: pixdouble, !native, !tex/shadealpha, zcompare, !zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_C, BACKEND2X_ZCCOND_10_NOALPHATEST},
// 0x97: pixdouble, !native, !tex/shadealpha, zcompare, !zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_C, BACKEND2X_ZCCOND_10_NOALPHATEST},
// 0x98: pixdouble, !native, !tex/shadealpha, zcompare, zwrite, !alphatest, 10
	{TRIVIALZ_CW, BACKEND2X_ZCCOND_10_NOALPHATEST},
// 0x99: pixdouble, !native, !tex/shadealpha, zcompare, zwrite, !alphatest, 11
	{TRIVIALZ_CW, BACKEND2X_ZCCOND_11_NOALPHATEST},
// 0x9A: pixdouble, !native, !tex/shadealpha, zcompare, zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_CW, BACKEND2X_ZCCOND_10_NOALPHATEST},
// 0x9B: pixdouble, !native, !tex/shadealpha, zcompare, zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_CW, BACKEND2X_ZCCOND_10_NOALPHATEST},
// 0x9C: pixdouble, !native, !tex/shadealpha, zcompare, zwrite, alphatest, 10
	{TRIVIALZ_CW, BACKEND2X_ZCCOND_10_NOALPHATEST},
// 0x9D: pixdouble, !native, !tex/shadealpha, zcompare, zwrite, alphatest, 11
	{TRIVIALZ_CW, BACKEND2X_ZCCOND_11_NOALPHATEST},
// 0x9E: pixdouble, !native, !tex/shadealpha, zcompare, zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_CW, BACKEND2X_ZCCOND_10_NOALPHATEST},
// 0x9F: pixdouble, !native, !tex/shadealpha, zcompare, zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_CW, BACKEND2X_ZCCOND_10_NOALPHATEST},
// 0xA0: pixdouble, !native, tex/shadealpha, !zcompare, !zwrite, !alphatest, 10
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_10_NOALPHATEST},
// 0xA1: pixdouble, !native, tex/shadealpha, !zcompare, !zwrite, !alphatest, 11
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_11_NOALPHATEST},
// 0xA2: pixdouble, !native, tex/shadealpha, !zcompare, !zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_1INVALPHA_NOALPHATEST},
// 0xA3: pixdouble, !native, tex/shadealpha, !zcompare, !zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_ALPHAINVALPHA_NOALPHATEST},
// 0xA4: pixdouble, !native, tex/shadealpha, !zcompare, !zwrite, alphatest, 10
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_10_ALPHATEST},
// 0xA5: pixdouble, !native, tex/shadealpha, !zcompare, !zwrite, alphatest, 11
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_11_ALPHATEST},
// 0xA6: pixdouble, !native, tex/shadealpha, !zcompare, !zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_1INVALPHA_ALPHATEST},
// 0xA7: pixdouble, !native, tex/shadealpha, !zcompare, !zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_ALPHAINVALPHA_ALPHATEST},
// 0xA8: pixdouble, !native, tex/shadealpha, !zcompare, zwrite, !alphatest, 10
	{TRIVIALZ_W, BACKEND2X_NOZ_10_NOALPHATEST},
// 0xA9: pixdouble, !native, tex/shadealpha, !zcompare, zwrite, !alphatest, 11
	{TRIVIALZ_W, BACKEND2X_NOZ_11_NOALPHATEST},
// 0xAA: pixdouble, !native, tex/shadealpha, !zcompare, zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_W, BACKEND2X_NOZ_1INVALPHA_NOALPHATEST},
// 0xAB: pixdouble, !native, tex/shadealpha, !zcompare, zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_W, BACKEND2X_NOZ_ALPHAINVALPHA_NOALPHATEST},
// 0xAC: pixdouble, !native, tex/shadealpha, !zcompare, zwrite, alphatest, 10
	{TRIVIALZ_NOOP, BACKEND2X_ZW_10_ALPHATEST},
// 0xAD: pixdouble, !native, tex/shadealpha, !zcompare, zwrite, alphatest, 11
	{TRIVIALZ_NOOP, BACKEND2X_ZW_11_ALPHATEST},
// 0xAE: pixdouble, !native, tex/shadealpha, !zcompare, zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_NOOP, BACKEND2X_ZW_1INVALPHA_ALPHATEST},
// 0xAF: pixdouble, !native, tex/shadealpha, !zcompare, zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_NOOP, BACKEND2X_ZW_ALPHAINVALPHA_ALPHATEST},
// 0xB0: pixdouble, !native, tex/shadealpha, zcompare, !zwrite, !alphatest, 10
	{TRIVIALZ_C, BACKEND2X_ZCCOND_10_NOALPHATEST},
// 0xB1: pixdouble, !native, tex/shadealpha, zcompare, !zwrite, !alphatest, 11
	{TRIVIALZ_C, BACKEND2X_ZCCOND_11_NOALPHATEST},
// 0xB2: pixdouble, !native, tex/shadealpha, zcompare, !zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_C, BACKEND2X_ZCCOND_1INVALPHA_NOALPHATEST},
// 0xB3: pixdouble, !native, tex/shadealpha, zcompare, !zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_C, BACKEND2X_ZCCOND_ALPHAINVALPHA_NOALPHATEST},
// 0xB4: pixdouble, !native, tex/shadealpha, zcompare, !zwrite, alphatest, 10
	{TRIVIALZ_C, BACKEND2X_ZCCOND_10_ALPHATEST},
// 0xB5: pixdouble, !native, tex/shadealpha, zcompare, !zwrite, alphatest, 11
	{TRIVIALZ_C, BACKEND2X_ZCCOND_11_ALPHATEST},
// 0xB6: pixdouble, !native, tex/shadealpha, zcompare, !zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_C, BACKEND2X_ZCCOND_1INVALPHA_ALPHATEST},
// 0xB7: pixdouble, !native, tex/shadealpha, zcompare, !zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_C, BACKEND2X_ZCCOND_ALPHAINVALPHA_ALPHATEST},
// 0xB8: pixdouble, !native, tex/shadealpha, zcompare, zwrite, !alphatest, 10
	{TRIVIALZ_CW, BACKEND2X_ZCCOND_10_NOALPHATEST},
// 0xB9: pixdouble, !native, tex/shadealpha, zcompare, zwrite, !alphatest, 11
	{TRIVIALZ_CW, BACKEND2X_ZCCOND_11_NOALPHATEST},
// 0xBA: pixdouble, !native, tex/shadealpha, zcompare, zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_CW, BACKEND2X_ZCCOND_1INVALPHA_NOALPHATEST},
// 0xBB: pixdouble, !native, tex/shadealpha, zcompare, zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_CW, BACKEND2X_ZCCOND_ALPHAINVALPHA_NOALPHATEST},
// 0xBC: pixdouble, !native, tex/shadealpha, zcompare, zwrite, alphatest, 10
	{TRIVIALZ_C, BACKEND2X_ZCWCOND_10_ALPHATEST},
// 0xBD: pixdouble, !native, tex/shadealpha, zcompare, zwrite, alphatest, 11
	{TRIVIALZ_C, BACKEND2X_ZCWCOND_11_ALPHATEST},
// 0xBE: pixdouble, !native, tex/shadealpha, zcompare, zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_C, BACKEND2X_ZCWCOND_1INVALPHA_ALPHATEST},
// 0xBF: pixdouble, !native, tex/shadealpha, zcompare, zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_C, BACKEND2X_ZCWCOND_ALPHAINVALPHA_ALPHATEST},
// 0xC0: pixdouble, native, !tex/shadealpha, !zcompare, !zwrite, !alphatest, 10
	{TRIVIALZ_NOOP, NATIVE_SINGLE_PASS},
// 0xC1: pixdouble, native, !tex/shadealpha, !zcompare, !zwrite, !alphatest, 11
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_11_NOALPHATEST},
// 0xC2: pixdouble, native, !tex/shadealpha, !zcompare, !zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_NOOP, NATIVE_SINGLE_PASS},
// 0xC3: pixdouble, native, !tex/shadealpha, !zcompare, !zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_NOOP, NATIVE_SINGLE_PASS},
// 0xC4: pixdouble, native, !tex/shadealpha, !zcompare, !zwrite, alphatest, 10
	{TRIVIALZ_NOOP, NATIVE_SINGLE_PASS},
// 0xC5: pixdouble, native, !tex/shadealpha, !zcompare, !zwrite, alphatest, 11
	{TRIVIALZ_NOOP, BACKEND2X_NOZ_11_NOALPHATEST},
// 0xC6: pixdouble, native, !tex/shadealpha, !zcompare, !zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_NOOP, NATIVE_SINGLE_PASS},
// 0xC7: pixdouble, native, !tex/shadealpha, !zcompare, !zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_NOOP, NATIVE_SINGLE_PASS},
// 0xC8: pixdouble, native, !tex/shadealpha, !zcompare, zwrite, !alphatest, 10
	{TRIVIALZ_W_NATIVE, BACKEND2X_NATIVE_NOZ_10_NOALPHATEST},
// 0xC9: pixdouble, native, !tex/shadealpha, !zcompare, zwrite, !alphatest, 11
	{TRIVIALZ_W, BACKEND2X_NOZ_11_NOALPHATEST},
// 0xCA: pixdouble, native, !tex/shadealpha, !zcompare, zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_W_NATIVE, BACKEND2X_NATIVE_NOZ_10_NOALPHATEST},
// 0xCB: pixdouble, native, !tex/shadealpha, !zcompare, zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_W_NATIVE, BACKEND2X_NATIVE_NOZ_10_NOALPHATEST},
// 0xCC: pixdouble, native, !tex/shadealpha, !zcompare, zwrite, alphatest, 10
	{TRIVIALZ_W_NATIVE, BACKEND2X_NATIVE_NOZ_10_NOALPHATEST},
// 0xCD: pixdouble, native, !tex/shadealpha, !zcompare, zwrite, alphatest, 11
	{TRIVIALZ_W, BACKEND2X_NOZ_11_NOALPHATEST},
// 0xCE: pixdouble, native, !tex/shadealpha, !zcompare, zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_W_NATIVE, BACKEND2X_NATIVE_NOZ_10_NOALPHATEST},
// 0xCF: pixdouble, native, !tex/shadealpha, !zcompare, zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_W_NATIVE, BACKEND2X_NATIVE_NOZ_10_NOALPHATEST},
// 0xD0: pixdouble, native, !tex/shadealpha, zcompare, !zwrite, !alphatest, 10
	{TRIVIALZ_C_NATIVE, BACKEND2X_NATIVE_ZCCOND_10_NOALPHATEST},
// 0xD1: pixdouble, native, !tex/shadealpha, zcompare, !zwrite, !alphatest, 11
	{TRIVIALZ_C, BACKEND2X_ZCCOND_11_NOALPHATEST},
// 0xD2: pixdouble, native, !tex/shadealpha, zcompare, !zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_C_NATIVE, BACKEND2X_NATIVE_ZCCOND_10_NOALPHATEST},
// 0xD3: pixdouble, native, !tex/shadealpha, zcompare, !zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_C_NATIVE, BACKEND2X_NATIVE_ZCCOND_10_NOALPHATEST},
// 0xD4: pixdouble, native, !tex/shadealpha, zcompare, !zwrite, alphatest, 10
	{TRIVIALZ_C_NATIVE, BACKEND2X_NATIVE_ZCCOND_10_NOALPHATEST},
// 0xD5: pixdouble, native, !tex/shadealpha, zcompare, !zwrite, alphatest, 11
	{TRIVIALZ_C, BACKEND2X_ZCCOND_11_NOALPHATEST},
// 0xD6: pixdouble, native, !tex/shadealpha, zcompare, !zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_C_NATIVE, BACKEND2X_NATIVE_ZCCOND_10_NOALPHATEST},
// 0xD7: pixdouble, native, !tex/shadealpha, zcompare, !zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_C_NATIVE, BACKEND2X_NATIVE_ZCCOND_10_NOALPHATEST},
// 0xD8: pixdouble, native, !tex/shadealpha, zcompare, zwrite, !alphatest, 10
	{TRIVIALZ_CW_NATIVE, BACKEND2X_NATIVE_ZCCOND_10_NOALPHATEST},
// 0xD9: pixdouble, native, !tex/shadealpha, zcompare, zwrite, !alphatest, 11
	{TRIVIALZ_CW, BACKEND2X_ZCCOND_11_NOALPHATEST},
// 0xDA: pixdouble, native, !tex/shadealpha, zcompare, zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_CW_NATIVE, BACKEND2X_NATIVE_ZCCOND_10_NOALPHATEST},
// 0xDB: pixdouble, native, !tex/shadealpha, zcompare, zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_CW_NATIVE, BACKEND2X_NATIVE_ZCCOND_10_NOALPHATEST},
// 0xDC: pixdouble, native, !tex/shadealpha, zcompare, zwrite, alphatest, 10
	{TRIVIALZ_CW_NATIVE, BACKEND2X_NATIVE_ZCCOND_10_NOALPHATEST},
// 0xDD: pixdouble, native, !tex/shadealpha, zcompare, zwrite, alphatest, 11
	{TRIVIALZ_CW, BACKEND2X_ZCCOND_11_NOALPHATEST},
// 0xDE: pixdouble, native, !tex/shadealpha, zcompare, zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_CW_NATIVE, BACKEND2X_NATIVE_ZCCOND_10_NOALPHATEST},
// 0xDF: pixdouble, native, !tex/shadealpha, zcompare, zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_CW_NATIVE, BACKEND2X_NATIVE_ZCCOND_10_NOALPHATEST},
// 0xE0: pixdouble, native, tex/shadealpha, !zcompare, !zwrite, !alphatest, 10
	{TRIVIALZ_NOOP, NATIVE_SINGLE_PASS},
// 0xE1: pixdouble, native, tex/shadealpha, !zcompare, !zwrite, !alphatest, 11
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xE2: pixdouble, native, tex/shadealpha, !zcompare, !zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xE3: pixdouble, native, tex/shadealpha, !zcompare, !zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xE4: pixdouble, native, tex/shadealpha, !zcompare, !zwrite, alphatest, 10
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xE5: pixdouble, native, tex/shadealpha, !zcompare, !zwrite, alphatest, 11
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xE6: pixdouble, native, tex/shadealpha, !zcompare, !zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xE7: pixdouble, native, tex/shadealpha, !zcompare, !zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xE8: pixdouble, native, tex/shadealpha, !zcompare, zwrite, !alphatest, 10
	{TRIVIALZ_W_NATIVE, BACKEND2X_NATIVE_NOZ_10_NOALPHATEST},
// 0xE9: pixdouble, native, tex/shadealpha, !zcompare, zwrite, !alphatest, 11
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xEA: pixdouble, native, tex/shadealpha, !zcompare, zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xEB: pixdouble, native, tex/shadealpha, !zcompare, zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xEC: pixdouble, native, tex/shadealpha, !zcompare, zwrite, alphatest, 10
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xED: pixdouble, native, tex/shadealpha, !zcompare, zwrite, alphatest, 11
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xEE: pixdouble, native, tex/shadealpha, !zcompare, zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xEF: pixdouble, native, tex/shadealpha, !zcompare, zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xF0: pixdouble, native, tex/shadealpha, zcompare, !zwrite, !alphatest, 10
	{TRIVIALZ_C_NATIVE, BACKEND2X_NATIVE_ZCCOND_10_NOALPHATEST},
// 0xF1: pixdouble, native, tex/shadealpha, zcompare, !zwrite, !alphatest, 11
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xF2: pixdouble, native, tex/shadealpha, zcompare, !zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xF3: pixdouble, native, tex/shadealpha, zcompare, !zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xF4: pixdouble, native, tex/shadealpha, zcompare, !zwrite, alphatest, 10
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xF5: pixdouble, native, tex/shadealpha, zcompare, !zwrite, alphatest, 11
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xF6: pixdouble, native, tex/shadealpha, zcompare, !zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xF7: pixdouble, native, tex/shadealpha, zcompare, !zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xF8: pixdouble, native, tex/shadealpha, zcompare, zwrite, !alphatest, 10
	{TRIVIALZ_CW_NATIVE, BACKEND2X_NATIVE_ZCCOND_10_NOALPHATEST},
// 0xF9: pixdouble, native, tex/shadealpha, zcompare, zwrite, !alphatest, 11
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xFA: pixdouble, native, tex/shadealpha, zcompare, zwrite, !alphatest, 1InvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xFB: pixdouble, native, tex/shadealpha, zcompare, zwrite, !alphatest, AlphaInvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xFC: pixdouble, native, tex/shadealpha, zcompare, zwrite, alphatest, 10
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xFD: pixdouble, native, tex/shadealpha, zcompare, zwrite, alphatest, 11
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xFE: pixdouble, native, tex/shadealpha, zcompare, zwrite, alphatest, 1InvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
// 0xFF: pixdouble, native, tex/shadealpha, zcompare, zwrite, alphatest, AlphaInvAlpha
	{TRIVIALZ_BAD, BACKEND_BAD},
};


#if defined(_DEBUG)

BOOL ReportNotFastPath = FALSE;


//-----------------------------------------------------------------------------
// Reports if native processing isn't set in state.
//----------------------------------------------------------------------------
void ReportIfNoFastPath(void)
{
    if (ReportNotFastPath && ((g_grdRenderData.dwState & STATE_USENATIVE) == 0))
        OutputDebugString("Fast path not taken\n");
}


//-----------------------------------------------------------------------------
// Resets counters.
//----------------------------------------------------------------------------
void ResetCounts(void)
{
    memset(cHandlersIn, 0, sizeof(cHandlersIn));
    memset(cHandlersDrawn, 0, sizeof(cHandlersDrawn));
    memset(cStatesIn, 0, sizeof(cStatesIn));
    memset(cStatesDrawn, 0, sizeof(cStatesDrawn));
    memset(cBackendsIn, 0, sizeof(cBackendsIn));
    memset(cBackendsDrawn, 0, sizeof(cBackendsDrawn));
    memset(cArea, 0, sizeof(cBackendsDrawn));
    cTrivialAccept = 0;
    cTrivialPartial = 0;
    cTrivialReject = 0;
}


//-----------------------------------------------------------------------------
// Converts a handler index to the handler's name.
//----------------------------------------------------------------------------
char *HandlerIndexToName(int i)
{
    char *rgchHandlerNames[] = {"ITERATE_NOOP", "ITERATE_Z", "ITERATE_TEXTUREZ",
                                "ITERATE_TEXTURE", "ITERATE_ERROR", "ITERATE_NOTHING",
                                "ITERATE_GOURAUDZ", "ITERATE_PERSPECTIVETEXTUREGOURAUDZ",
                                "ITERATE_AFFINETEXTUREGOURAUDZ",
                                "ITERATE_ZFOG", "ITERATE_GOURAUDZFOG",
                                "ITERATE_PERSPECTIVETEXTUREGOURAUDZFOG",
                                "ITERATE_AFFINETEXTUREGOURAUDZFOG"};

    assert(i < sizeof(rgchHandlerNames)/sizeof(rgchHandlerNames[0]));
    return rgchHandlerNames[i];
}


//-----------------------------------------------------------------------------
// Displays handlers, sorted for most frequent.
//----------------------------------------------------------------------------
void DisplayHandlerCounts(void)
{
    int i, j;
    int cHandlersIndex[sizeof(cHandlersIn)/sizeof(cHandlersIn[0])];

    OutputDebugString("\nHandlers called (per-triangle counts):\n");

    for (i=0; i<sizeof(cHandlersIn)/sizeof(cHandlersIn[0]); i++)
        cHandlersIndex[i] = i;

    for (i=0; i<sizeof(cHandlersIn)/sizeof(cHandlersIn[0]); i++)
    {
        for (j=i+1; j<sizeof(cHandlersIn)/sizeof(cHandlersIn[0]); j++)
        {
            if (cHandlersIn[cHandlersIndex[i]] < cHandlersIn[cHandlersIndex[j]])
            {
                int t;

                t = cHandlersIndex[i];
                cHandlersIndex[i] = cHandlersIndex[j];
                cHandlersIndex[j] = t;
            }
        }
    }

    for (i=0; i<sizeof(cHandlersIn)/sizeof(cHandlersIn[0]); i++)
    {
        if (cHandlersIn[cHandlersIndex[i]] == 0)
            break;

        char tch[1000];

        sprintf(tch, "%s: %d\n", HandlerIndexToName(cHandlersIndex[i]), cHandlersIn[cHandlersIndex[i]]);
        OutputDebugString(tch);
    }

    OutputDebugString("\nHandlers actually drawn after special-casing (per-triangle counts):\n");

    for (i=0; i<sizeof(cHandlersDrawn)/sizeof(cHandlersDrawn[0]); i++)
        cHandlersIndex[i] = i;

    for (i=0; i<sizeof(cHandlersDrawn)/sizeof(cHandlersDrawn[0]); i++)
    {
        for (j=i+1; j<sizeof(cHandlersDrawn)/sizeof(cHandlersDrawn[0]); j++)
        {
            if (cHandlersDrawn[cHandlersIndex[i]] < cHandlersDrawn[cHandlersIndex[j]])
            {
                int t;

                t = cHandlersIndex[i];
                cHandlersIndex[i] = cHandlersIndex[j];
                cHandlersIndex[j] = t;
            }
        }
    }

    for (i=0; i<sizeof(cHandlersDrawn)/sizeof(cHandlersDrawn[0]); i++)
    {
        if (cHandlersDrawn[cHandlersIndex[i]] == 0)
            break;

        char tch[1000];

        sprintf(tch, "%s: %d\n", HandlerIndexToName(cHandlersIndex[i]), cHandlersDrawn[cHandlersIndex[i]]);
        OutputDebugString(tch);
    }
}


//-----------------------------------------------------------------------------
// Displays master states, sorted for most frequent.
//----------------------------------------------------------------------------
void DisplayStateCounts(void)
{
    int i, j;
    int cStatesIndex[sizeof(cStatesIn)/sizeof(cStatesIn[0])];

    OutputDebugString("\nStates: (per-triangle counts)\n");

    for (i=0; i<sizeof(cStatesIn)/sizeof(cStatesIn[0]); i++)
        cStatesIndex[i] = i;

    for (i=0; i<sizeof(cStatesIn)/sizeof(cStatesIn[0]); i++)
    {
        for (j=i+1; j<sizeof(cStatesIn)/sizeof(cStatesIn[0]); j++)
        {
            if (cStatesIn[cStatesIndex[i]] < cStatesIn[cStatesIndex[j]])
            {
                int t;

                t = cStatesIndex[i];
                cStatesIndex[i] = cStatesIndex[j];
                cStatesIndex[j] = t;
            }
        }
    }

    for (i=0; i<sizeof(cStatesIn)/sizeof(cStatesIn[0]); i++)
    {
        if (cStatesIn[cStatesIndex[i]] == 0)
            break;

        char tch[1000];

        sprintf(tch, "%x: %d\n", cStatesIndex[i], cStatesIn[cStatesIndex[i]]);
        OutputDebugString(tch);
    }

    OutputDebugString("\nStates actually drawn after special-casing (per-triangle counts):\n");

    for (i=0; i<sizeof(cStatesDrawn)/sizeof(cStatesDrawn[0]); i++)
        cStatesIndex[i] = i;

    for (i=0; i<sizeof(cStatesDrawn)/sizeof(cStatesDrawn[0]); i++)
    {
        for (j=i+1; j<sizeof(cStatesDrawn)/sizeof(cStatesDrawn[0]); j++)
        {
            if (cStatesDrawn[cStatesIndex[i]] < cStatesDrawn[cStatesIndex[j]])
            {
                int t;

                t = cStatesIndex[i];
                cStatesIndex[i] = cStatesIndex[j];
                cStatesIndex[j] = t;
            }
        }
    }

    for (i=0; i<sizeof(cStatesDrawn)/sizeof(cStatesDrawn[0]); i++)
    {
        if (cStatesDrawn[cStatesIndex[i]] == 0)
            break;

        char tch[1000];

        sprintf(tch, "%x: %d\n", cStatesIndex[i], cStatesDrawn[cStatesIndex[i]]);
        OutputDebugString(tch);
    }
}


//-----------------------------------------------------------------------------
// Displays backend states, sorted for most frequent.
//----------------------------------------------------------------------------
void DisplayBackendCounts(void)
{
    int i, j;
    int cBackendsIndex[sizeof(cBackendsIn)/sizeof(cBackendsIn[0])];

    OutputDebugString("\nBackend states: (per-triangle counts)\n");

    for (i=0; i<sizeof(cBackendsIn)/sizeof(cBackendsIn[0]); i++)
        cBackendsIndex[i] = i;

    for (i=0; i<sizeof(cBackendsIn)/sizeof(cBackendsIn[0]); i++)
    {
        for (j=i+1; j<sizeof(cBackendsIn)/sizeof(cBackendsIn[0]); j++)
        {
            if (cBackendsIn[cBackendsIndex[i]] < cBackendsIn[cBackendsIndex[j]])
            {
                int t;

                t = cBackendsIndex[i];
                cBackendsIndex[i] = cBackendsIndex[j];
                cBackendsIndex[j] = t;
            }
        }
    }

    for (i=0; i<sizeof(cBackendsIn)/sizeof(cBackendsIn[0]); i++)
    {
        if (cBackendsIn[cBackendsIndex[i]] == 0)
            break;

        char tch[1000];

        sprintf(tch, "%x: %d\n", cBackendsIndex[i], cBackendsIn[cBackendsIndex[i]]);
        OutputDebugString(tch);
    }

    OutputDebugString("\nBackends actually drawn after special-casing (per-triangle counts):\n");

    for (i=0; i<sizeof(cBackendsDrawn)/sizeof(cBackendsDrawn[0]); i++)
        cBackendsIndex[i] = i;

    for (i=0; i<sizeof(cBackendsDrawn)/sizeof(cBackendsDrawn[0]); i++)
    {
        for (j=i+1; j<sizeof(cBackendsDrawn)/sizeof(cBackendsDrawn[0]); j++)
        {
            if (cBackendsDrawn[cBackendsIndex[i]] < cBackendsDrawn[cBackendsIndex[j]])
            {
                int t;

                t = cBackendsIndex[i];
                cBackendsIndex[i] = cBackendsIndex[j];
                cBackendsIndex[j] = t;
            }
        }
    }

    for (i=0; i<sizeof(cBackendsDrawn)/sizeof(cBackendsDrawn[0]); i++)
    {
        if (cBackendsDrawn[cBackendsIndex[i]] == 0)
            break;

        char tch[1000];

        sprintf(tch, "%x: %d\n", cBackendsIndex[i], cBackendsDrawn[cBackendsIndex[i]]);
        OutputDebugString(tch);
    }
}


//-----------------------------------------------------------------------------
// Displays area counts.
//----------------------------------------------------------------------------
void DisplayAreaCounts(void)
{
    int i, tot;

    OutputDebugString("\nTriangle areas:\n");

    tot = 0;

    for (i=0; i<AREA_COUNT_MAX; i++)
    {
        tot += cArea[i];
    }

    for (i=0; i<AREA_COUNT_MAX; i++)
    {
        char tch[1000];

        sprintf(tch, "Area %d: %d triangle(s) (%d percent)\n",
                i, cArea[i], (int)((float)cArea[i]*100/tot+0.5f));
        OutputDebugString(tch);
    }
}


//-----------------------------------------------------------------------------
// Displays trivial z accept/partial/reject counts.
//----------------------------------------------------------------------------
void DisplayTrivialZCounts(void)
{
    int tot;
    char tch[1000];

    tot = cTrivialAccept + cTrivialPartial + cTrivialReject;

    OutputDebugString("\nTrivial Z counts (per chunk):\n");

    sprintf(tch, " Trivial Z accept: %d chunks (%d percent)\n",
            cTrivialAccept, (int)((float)cTrivialAccept*100/tot+0.5f));
    OutputDebugString(tch);
    sprintf(tch, " Trivial Z partial: %d chunks (%d percent)\n",
            cTrivialPartial, (int)((float)cTrivialPartial*100/tot+0.5f));
    OutputDebugString(tch);
    sprintf(tch, " Trivial Z reject %d chunks (%d percent)\n",
            cTrivialReject, (int)((float)cTrivialReject*100/tot+0.5f));
    OutputDebugString(tch);
}


// Checks that u and v are in valid range.
void RenderDevice::VerifyUV(void)
{

    assert(((g_grdRenderData.gvVertices[0].tu / m_cxTextureWidth) < 128.0f) &&
           ((g_grdRenderData.gvVertices[0].tu / m_cxTextureWidth) > -128.0f));
    assert(((g_grdRenderData.gvVertices[1].tu / m_cxTextureWidth) < 128.0f) &&
           ((g_grdRenderData.gvVertices[1].tu / m_cxTextureWidth) > -128.0f));
    assert(((g_grdRenderData.gvVertices[2].tu / m_cxTextureWidth) < 128.0f) &&
           ((g_grdRenderData.gvVertices[2].tu / m_cxTextureWidth) > -128.0f));

    assert(((g_grdRenderData.gvVertices[0].tv / m_cyTextureHeight) < 128.0f) &&
           ((g_grdRenderData.gvVertices[0].tv / m_cyTextureHeight) > -128.0f));
    assert(((g_grdRenderData.gvVertices[1].tv / m_cyTextureHeight) < 128.0f) &&
           ((g_grdRenderData.gvVertices[1].tv / m_cyTextureHeight) > -128.0f));
    assert(((g_grdRenderData.gvVertices[2].tv / m_cyTextureHeight) < 128.0f) &&
           ((g_grdRenderData.gvVertices[2].tv / m_cyTextureHeight) > -128.0f));

    if (!(((g_grdRenderData.gvVertices[0].tu / m_cxTextureWidth) < 128.0f) &&
          ((g_grdRenderData.gvVertices[0].tu / m_cxTextureWidth) > -128.0f) &&
          ((g_grdRenderData.gvVertices[1].tu / m_cxTextureWidth) <= 128.0f) &&
          ((g_grdRenderData.gvVertices[1].tu / m_cxTextureWidth) >= -128.0f) &&
          ((g_grdRenderData.gvVertices[2].tu / m_cxTextureWidth) <= 128.0f) &&
          ((g_grdRenderData.gvVertices[2].tu / m_cxTextureWidth) >= -128.0f)))
    {
        OutputDebugString("u out of range -128 to +128, not inclusive\n");
    }

    if (!(((g_grdRenderData.gvVertices[0].tv / m_cxTextureWidth) < 128.0f) &&
          ((g_grdRenderData.gvVertices[0].tv / m_cxTextureWidth) > -128.0f) &&
          ((g_grdRenderData.gvVertices[1].tv / m_cxTextureWidth) <= 128.0f) &&
          ((g_grdRenderData.gvVertices[1].tv / m_cxTextureWidth) >= -128.0f) &&
          ((g_grdRenderData.gvVertices[2].tv / m_cxTextureWidth) <= 128.0f) &&
          ((g_grdRenderData.gvVertices[2].tv / m_cxTextureWidth) >= -128.0f)))
    {
        OutputDebugString("v out of range -128 to +128, not inclusive\n");
    }
}

#endif


// The RenderDevice has changed since the last drawing, so update global
// variables to match
void RenderDevice::UpdateRenderData(void)
{
    g_grdChunkData.pwTexture            = m_pwTexture;
    g_grdChunkData.cxTextureMask        = m_cxTextureMask;
    g_grdChunkData.cyTextureShift       = m_cyTextureShift;
    g_grdChunkData.cyTextureMask        = m_cyTextureMask;
    g_grdChunkData.cMunged3ToTargetShift0 = m_cMunged3ToTargetShift0;
    g_grdChunkData.cMunged3ToTargetShift1 = m_cMunged3ToTargetShift1;
    g_grdChunkData.pbScreen             = m_pbScreen;
    g_grdChunkData.m3FogColor           = FROM_888_TO_MUNGED3(m_pcd3dd->FogColor());
    g_grdChunkData.fSkipLastPixel       = m_pcd3dd->SkipLastPixel();

    // if the app wants to force monochrome fog, make the fog color monochrome
    if (m_pcd3dd->MonoFog())
    {
        MUNGED1 m1 = g_grdChunkData.m3FogColor;
        g_grdChunkData.m3FogColor = m1 | (m1 << 10) | (m1 << 20);
    }

    g_grdRenderData.fTargetIs555        = m_fTargetIs555;
    g_grdRenderData.cbZBufferPitch      = m_cbZBufferPitch;
    g_grdRenderData.pbZBuffer           = m_pbZBuffer;
    g_grdRenderData.pRenderDevice       = this;
}


//-----------------------------------------------------------------------------
// Sets up triangle vertices and branches to handler to draw triangle.
//----------------------------------------------------------------------------
void RenderDevice::DrawTri(D3DTLVERTEX *P0, D3DTLVERTEX *P1, D3DTLVERTEX *P2)
{

    assert(sizeof(cHandlersIn)/sizeof(cHandlersIn[0]) ==
           sizeof(m_rgphandlerfn)/sizeof(m_rgphandlerfn[0]));
    assert(sizeof(cHandlersDrawn)/sizeof(cHandlersDrawn[0]) ==
           sizeof(m_rgphandlerfn)/sizeof(m_rgphandlerfn[0]));
    assert(sizeof(cStatesIn)/sizeof(cStatesIn[0]) ==
           sizeof(m_rgdtd)/sizeof(m_rgdtd[0]));
    assert(sizeof(cStatesDrawn)/sizeof(cStatesDrawn[0]) ==
           sizeof(m_rgdtd)/sizeof(m_rgdtd[0]));
    assert(sizeof(cBackendsIn)/sizeof(cBackendsIn[0]) ==
           sizeof(m_rgtzab)/sizeof(m_rgtzab[0]));
    assert(sizeof(cBackendsDrawn)/sizeof(cBackendsDrawn[0]) ==
           sizeof(m_rgtzab)/sizeof(m_rgtzab[0]));

    assert((P0->sx >= 0) && (P0->sx <= GetScreenWidth()));
    assert((P1->sx >= 0) && (P1->sx <= GetScreenWidth()));
    assert((P2->sx >= 0) && (P2->sx <= GetScreenWidth()));

    assert((P0->sy >= 0) && (P0->sy <= GetScreenHeight()));
    assert((P1->sy >= 0) && (P1->sy <= GetScreenHeight()));
    assert((P2->sy >= 0) && (P2->sy <= GetScreenHeight()));

    // ASM code relies on the first entry being the current native-one-pass
    // chunk processor
    assert(NATIVE_SINGLE_PASS == 0);

	g_grdRenderData.gvVertices[0].x = FloatToFixed28_4NonNeg(P0->sx);
	g_grdRenderData.gvVertices[0].y = FloatToFixed28_4NonNeg(P0->sy);

	g_grdRenderData.gvVertices[1].x = FloatToFixed28_4NonNeg(P1->sx);
	g_grdRenderData.gvVertices[1].y = FloatToFixed28_4NonNeg(P1->sy);

	g_grdRenderData.gvVertices[2].x = FloatToFixed28_4NonNeg(P2->sx);
	g_grdRenderData.gvVertices[2].y = FloatToFixed28_4NonNeg(P2->sy);

    // Sanity checking - main program must call the Init function.
    ASSERT(m_dwStatus & GRF_SCREEN_INITIALIZED);

    // Sort vertices where top is the smallest Y.  Order is pTop, pMiddle, pBottom
    // if (bottom index follows top index in clockwise fashion then MiddleIsLeft)
    if (g_grdRenderData.gvVertices[1].y < g_grdRenderData.gvVertices[0].y) // Y1,Y0
    {
        if (g_grdRenderData.gvVertices[2].y < g_grdRenderData.gvVertices[1].y)  // Y2,Y1,Y0
        {
            g_grdRenderData.iTop    = 2;
            g_grdRenderData.iMiddle = 1;
            g_grdRenderData.iBottom = 0;
        }
        else // Y1,?,?
        {
            g_grdRenderData.iTop = 1;

            if (g_grdRenderData.gvVertices[2].y < g_grdRenderData.gvVertices[0].y) // Y1,Y2,Y0
            {
                g_grdRenderData.iMiddle = 2;
                g_grdRenderData.iBottom = 0;
            }
            else  // Y1,Y0,Y2
            {
                g_grdRenderData.iMiddle = 0;
                g_grdRenderData.iBottom = 2;
            }
        }
    }
    else  // Y0,Y1
    {
        if (g_grdRenderData.gvVertices[2].y < g_grdRenderData.gvVertices[0].y) // Y2,Y0,Y1
        {
            g_grdRenderData.iTop    = 2;
            g_grdRenderData.iMiddle = 0;
            g_grdRenderData.iBottom = 1;
        }
        else // Y0,?,?
        {
            g_grdRenderData.iTop = 0;

            if (g_grdRenderData.gvVertices[2].y < g_grdRenderData.gvVertices[1].y) // Y0,Y2,Y1
            {
                g_grdRenderData.iMiddle = 2;
                g_grdRenderData.iBottom = 1;
            }
            else // Y0,Y1,Y2
            {
                g_grdRenderData.iMiddle = 1;
                g_grdRenderData.iBottom = 2;
            }
        }
    }

    // figure winding direction and reject degenerate triangles
    g_grdRenderData.iTemp = ((g_grdRenderData.gvVertices[g_grdRenderData.iBottom].x -
                               g_grdRenderData.gvVertices[g_grdRenderData.iMiddle].x) *
                              (g_grdRenderData.gvVertices[g_grdRenderData.iMiddle].y -
                               g_grdRenderData.gvVertices[g_grdRenderData.iTop].y)) -
                             ((g_grdRenderData.gvVertices[g_grdRenderData.iBottom].y -
                               g_grdRenderData.gvVertices[g_grdRenderData.iMiddle].y) *
                              (g_grdRenderData.gvVertices[g_grdRenderData.iMiddle].x -
                               g_grdRenderData.gvVertices[g_grdRenderData.iTop].x));

    AREA_COUNT(g_grdRenderData.iTemp);

    // backface cull
    if (m_pcd3dd->Cull())
    {
	    if (m_pcd3dd->CullCCW())
	    {
            int i;

		    if (g_grdRenderData.iTemp <= 0)
		    {
                i = g_grdRenderData.iMiddle + 1;

                if (i > 2)
                    i = 0;
		    }
            else
		    {
                i = g_grdRenderData.iMiddle - 1;

                if (i < 0)
                    i = 2;
		    }

            if (g_grdRenderData.iTop == i)
            {
                return;
            }
	    }
	    else if (m_pcd3dd->CullCW())
	    {
            int i;

		    if (g_grdRenderData.iTemp >= 0)
		    {
                i = g_grdRenderData.iMiddle + 1;

                if (i > 2)
                    i = 0;
		    }
            else
		    {
                i = g_grdRenderData.iMiddle - 1;

                if (i < 0)
                    i = 2;
		    }

            if (g_grdRenderData.iTop == i)
            {
                return;
            }
	    }
    }

    if (g_grdRenderData.iTemp == 0)
    {
        return;
    }

    g_grdRenderData.fMiddleIsRight = g_grdRenderData.iTemp & 0x80000000;

#if defined(_DEBUG)
    if (m_pcd3dd->ZWrite() || m_pcd3dd->ZCompare())
    {
        assert((P0->sz >= 0.0f) && (P0->sz < 1.0f));
        assert((P1->sz >= 0.0f) && (P1->sz < 1.0f));
        assert((P2->sz >= 0.0f) && (P2->sz < 1.0f));
    }
#endif

    // NOTE mikeab this won't potentially cause stuff like NAN problems because the compiler does it as DWORD integer copies
	g_grdRenderData.gvVertices[0].z        = P0->sz;
	g_grdRenderData.gvVertices[1].z        = P1->sz;
	g_grdRenderData.gvVertices[2].z        = P2->sz;

	g_grdRenderData.gvVertices[0].color    = P0->color;
	g_grdRenderData.gvVertices[1].color    = P1->color;
	g_grdRenderData.gvVertices[2].color    = P2->color;

	g_grdRenderData.gvVertices[0].specular = P0->specular;
	g_grdRenderData.gvVertices[1].specular = P1->specular;
	g_grdRenderData.gvVertices[2].specular = P2->specular;

    // avoids problems when textures are disabled, because u,v's may be #SNANs
	if(m_pcd3dd->TextureMap())
	{
#if defined(_DEBUG)
        if (m_pcd3dd->Perspective())
        {
            assert((P0->rhw >= 0.0f) && (P0->rhw <= 1.0f));
            assert((P1->rhw >= 0.0f) && (P1->rhw <= 1.0f));
            assert((P2->rhw >= 0.0f) && (P2->rhw <= 1.0f));
        }
#endif

        // NOTE mikeab this won't potentially cause stuff like NAN problems because the compiler does it as DWORD integer copies
	    g_grdRenderData.gvVertices[0].rhw      = P0->rhw;
	    g_grdRenderData.gvVertices[1].rhw      = P1->rhw;
	    g_grdRenderData.gvVertices[2].rhw      = P2->rhw;

		g_grdRenderData.gvVertices[0].tu       = P0->tu * m_TextureWidth;
		g_grdRenderData.gvVertices[1].tu       = P1->tu * m_TextureWidth;
		g_grdRenderData.gvVertices[2].tu       = P2->tu * m_TextureWidth;

		g_grdRenderData.gvVertices[0].tv       = P0->tv * m_TextureHeight;
		g_grdRenderData.gvVertices[1].tv       = P1->tv * m_TextureHeight;
		g_grdRenderData.gvVertices[2].tv       = P2->tv * m_TextureHeight;
    }

    // update the cached render data if the active render device has changed
    if (g_grdRenderData.pRenderDevice != this)
	{
        UpdateRenderData();
	}

    // branch to handler to draw triangle
    g_grdRenderData.dwState = m_dwCurrentState;
    (this->*m_pfnDrawTri)();
}


//-----------------------------------------------------------------------------
// Recalculates the proper state word and handler for the current state
// configuration, then dispatches to that handler.
//
// NOTE mikeab this must stay in sync with ValidateDevice()
//-----------------------------------------------------------------------------
void RenderDevice::ReevaluateState(void)
{
    BOOL    fBackendAlpha = FALSE;;

    // determine current state & set state word and handler
    m_dwCurrentState = 0;

    if (m_pcd3dd->AlphaBlend())
    {
        if (m_pcd3dd->SrcBlend() == D3DBLEND_ONE)
        {
            if (m_pcd3dd->DestBlend() == D3DBLEND_ONE)
            {
                m_dwCurrentState |= STATE_ALPHABLEND_1_1 | STATE_CANT_USE_NATIVE | STATE_CANT_USE_NATIVE_NONFOG;
            }
            else if (m_pcd3dd->DestBlend() == D3DBLEND_INVSRCALPHA)
            {
                m_dwCurrentState |= STATE_ALPHABLEND_1_1MINUSA;
                fBackendAlpha = TRUE;
            }
            else
            {
                assert((m_pcd3dd->DestBlend() == D3DBLEND_ZERO));
            }
        }
        else if (m_pcd3dd->SrcBlend() == D3DBLEND_SRCALPHA)
        {
            if (m_pcd3dd->DestBlend() == D3DBLEND_INVSRCALPHA)
            {
                m_dwCurrentState |= STATE_ALPHABLEND_A_1MINUSA;
                fBackendAlpha = TRUE;
            }
            else
            {
                assert(0);
            }
        }
#ifdef USE_DX7_INTERFACE
        else if (m_pcd3dd->SrcBlend() == D3DBLEND_BOTHSRCALPHA)
        {
			m_dwCurrentState |= STATE_ALPHABLEND_A_1MINUSA;
			fBackendAlpha = TRUE;
        }
#endif
        else
        {
            assert(0);
        }
    }

    if (m_pcd3dd->AlphaTest())
    {
        m_dwCurrentState |= STATE_ALPHATEST;
        fBackendAlpha = TRUE;
    }

    if (m_pcd3dd->PixDouble())
    {
        g_grdChunkData.cPixDouble = 1;
        m_dwCurrentState |= STATE_PIXDOUBLE;
        g_grdChunkData.cbScanDoubleOffset = m_cbScreenPitch;
        g_grdChunkData.cbScreenPitch = m_cbScreenPitch << 1;
    }
    else
    {
        g_grdChunkData.cPixDouble = 0;
        g_grdChunkData.cbScreenPitch = m_cbScreenPitch;
    }

    if (m_pcd3dd->TextureMap())
    {
        assert(m_pwTexture != NULL);

        m_dwCurrentState |= STATE_TEXTURECOLOR | STATE_TEXTUREHANDLER;

        if (m_pcd3dd->Perspective())
            m_dwCurrentState |= STATE_PERSPECTIVE;

        switch (m_pcd3dd->TexelFormat())
        {
        case 4444:
            rgpspanfn[SPAN_MUNGE] = SpanMunge_4444;
            m_dwCurrentState |= STATE_TEXALPHA | STATE_TEXORSHADEALPHA | STATE_CANT_USE_NATIVE | STATE_CANT_USE_NATIVE_NONFOG;
            break;

        case 1555:
            m_dwCurrentState |= STATE_TEXALPHA | STATE_TEXORSHADEALPHA;
            rgpspanfn[SPAN_MUNGE] = SpanMunge_1555;

            if (!g_grdRenderData.fTargetIs555)
                m_dwCurrentState |= STATE_CANT_USE_NATIVE | STATE_CANT_USE_NATIVE_NONFOG;

            break;

        case 555:
            assert(g_grdRenderData.fTargetIs555);
            rgpspanfn[SPAN_MUNGE] = SpanMunge_555;
            break;

        case 565:
            assert(!g_grdRenderData.fTargetIs555);
            rgpspanfn[SPAN_MUNGE] = SpanMunge_565;
            break;

        default:
            assert(0);
            return;
        }

        // Fast-path texturing ASM code can only handle textures where texture width == texture pitch
        if ((int)m_cxTextureWidth != (0x10000 >> m_cyTextureShift))
        {
            m_dwCurrentState |= STATE_CANT_USE_NATIVE | STATE_CANT_USE_NATIVE_NONFOG;
        }

        // configure correct texture mapper for non-native cases (wrap or clamp)
        if (m_pcd3dd->TextureWrapU())
        {
            if (m_pcd3dd->TextureWrapV())
            {
                rgpspanfn[SPAN_TEXTURE] = SpanTexture_Wrap;
            }
            else
            {
                m_dwCurrentState |= STATE_CANT_USE_NATIVE | STATE_CANT_USE_NATIVE_NONFOG;
                rgpspanfn[SPAN_TEXTURE] = SpanTexture_WrapUClampV;
            }
        }
        else
        {
            if (m_pcd3dd->TextureWrapV())
            {
                m_dwCurrentState |= STATE_CANT_USE_NATIVE | STATE_CANT_USE_NATIVE_NONFOG;
                rgpspanfn[SPAN_TEXTURE] = SpanTexture_ClampUWrapV;
            }
            else
            {
                m_dwCurrentState |= STATE_CANT_USE_NATIVE | STATE_CANT_USE_NATIVE_NONFOG;
                rgpspanfn[SPAN_TEXTURE] = SpanTexture_Clamp;
            }
        }

        // configure correct native-single-pass chunk processor for unshaded texture mapping
        if (g_grdChunkData.cPixDouble)
        {
            rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] =
                SpanTextureBackend2X_Wrap_Native_NoZ_10_NoAlphaTest;
        }
        else
        {
            rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] =
                SpanTextureBackend_Wrap_Native_NoZ_10_NoAlphaTest;
        }
    }
    else
    {
        if (!m_pcd3dd->ShadeGouraud())
        {
            // configure correct native-single-pass chunk processor for flat untextured
            if (g_grdChunkData.cPixDouble)
            {
                rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] =
                    SpanShadeBackend2X_Native_Flat_NoZ_10_NoAlphaTest;
            }
            else
            {
                rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] =
                    SpanShadeBackend_Native_Flat_NoZ_10_NoAlphaTest;
            }
        }
        else
        {
            // configure correct native-single-pass chunk processor for Gouraud untextured
            if (g_grdChunkData.cPixDouble)
            {
                rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] =
                    SpanShadeBackend2X_Native_Gouraud_NoZ_10_NoAlphaTest;
            }
            else
            {
                rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] =
                    SpanShadeBackend_Native_Gouraud_NoZ_10_NoAlphaTest;
            }
        }
    }

    // if there's no texture map, we have no choice but to be in modulate alpha
    if (!(m_dwCurrentState & (STATE_TEXTURECOLOR | STATE_TEXALPHA)) ||
        (m_pcd3dd->TexBlendModulateAlpha()))
    {
        m_dwCurrentState |= STATE_SHADECOLOR | STATE_SHADEALPHA | STATE_TEXORSHADEALPHA;
    }
    else if (m_pcd3dd->TexBlendDecal())
    {
    }
    else if (m_pcd3dd->TexBlendModulateUseDiffuseAlpha())
    {
        m_dwCurrentState |= STATE_SHADECOLOR | STATE_SHADEALPHA | STATE_TEXORSHADEALPHA;
    }
    else if (m_pcd3dd->TexBlendModulateUseNoAlpha())
    {
        assert(m_dwCurrentState & STATE_TEXTURECOLOR);
        m_dwCurrentState &= ~(STATE_TEXALPHA | STATE_TEXORSHADEALPHA | STATE_ALPHATEST);
        fBackendAlpha = FALSE;

        if (((m_dwCurrentState & STATE_ALPHABLEND_MASK) == STATE_ALPHABLEND_1_1MINUSA) ||
            ((m_dwCurrentState & STATE_ALPHABLEND_MASK) == STATE_ALPHABLEND_A_1MINUSA))
        {
            m_dwCurrentState &= ~STATE_ALPHABLEND_MASK;
        }

        m_dwCurrentState |= STATE_SHADECOLOR;
    }
    else if (m_pcd3dd->TexBlendDecalUseNoAlpha())
    {
        assert(m_dwCurrentState & STATE_TEXTURECOLOR);
        m_dwCurrentState &= ~(STATE_TEXALPHA | STATE_TEXORSHADEALPHA | STATE_ALPHATEST);
        fBackendAlpha = FALSE;

        if (((m_dwCurrentState & STATE_ALPHABLEND_MASK) == STATE_ALPHABLEND_1_1MINUSA) ||
            ((m_dwCurrentState & STATE_ALPHABLEND_MASK) == STATE_ALPHABLEND_A_1MINUSA))
        {
            m_dwCurrentState &= ~STATE_ALPHABLEND_MASK;
        }
    }
    else if (m_pcd3dd->TexBlendModulateUseTextureAlpha())
    {
        if (m_dwCurrentState & STATE_TEXALPHA)
        {
            m_dwCurrentState |= STATE_SHADECOLOR;
        }
        else
        {
            m_dwCurrentState |= STATE_SHADECOLOR | STATE_SHADEALPHA | STATE_TEXORSHADEALPHA;
        }
    }
#ifdef USE_DX7_INTERFACE
    else if (m_pcd3dd->TexBlendAlphaOnly())
	{
	}
    else if (m_pcd3dd->TexBlendAlphaModulateOnly())
	{
	}
#endif
    else
    {
        assert(0);
    }

    // if there's no backend alpha, we never care about texture or shade alpha
    // because they can't have any effect. (Likewise, if there's no texture or
    // shade alpha we never care about backend alpha, but that's automatically
    // taken care of by the trivialz/backend table.)
    if (!fBackendAlpha)
    {
        m_dwCurrentState &= ~(STATE_SHADEALPHA | STATE_TEXALPHA | STATE_TEXORSHADEALPHA);
    }

    if (m_pcd3dd->MonoEnable())
    {
        // for cases where we don't shade color, RGB/I is irrelevant, so we
        // choose to use the RGB setting and make I an error
        // we only do intensity for shading texture maps; without a texture map
        // we're always RGB
        if ((m_dwCurrentState & STATE_SHADECOLOR) &&
            (m_dwCurrentState & STATE_TEXTURECOLOR))
        {
            m_dwCurrentState |= STATE_SHADEI;
        }
    }

    if (m_pcd3dd->ShadeGouraud())
    {
        if (m_dwCurrentState & (STATE_SHADEALPHA | STATE_SHADECOLOR))
        {
            m_dwCurrentState |= STATE_SHADEGOURAUD | STATE_GOURAUDHANDLER;
        }
    }

    if (m_pcd3dd->ZWrite())
    {
        assert(g_grdRenderData.pbZBuffer != NULL);
        m_dwCurrentState |= STATE_ZWRITE | STATE_Z | STATE_ZHANDLER;
    }

    if (m_pcd3dd->ZCompare())
    {
        assert(g_grdRenderData.pbZBuffer != NULL);
        m_dwCurrentState |= STATE_ZCOMPARE | STATE_Z | STATE_ZHANDLER;
    }

    if (m_pcd3dd->Fog())
    {
        m_dwCurrentState |= STATE_FOG | STATE_CANT_USE_NATIVE;
        g_grdChunkData.m3FogColor = FROM_888_TO_MUNGED3(m_pcd3dd->FogColor());

        // flag if fog color is monochrome or if the app wants to force monochrome fog,
        // and force the fog color to monochrome
        if (m_pcd3dd->MonoFog() ||
            ((g_grdChunkData.m3FogColor & 0x1F) == ((g_grdChunkData.m3FogColor >> 10) & 0x1F)) &&
            ((g_grdChunkData.m3FogColor & 0x1F) == (g_grdChunkData.m3FogColor >> 20)))
        {
            MUNGED1 m1 = g_grdChunkData.m3FogColor;
            g_grdChunkData.m3FogColor = m1 | (m1 << 10) | (m1 << 20);
            m_dwCurrentState |= STATE_MONO_FOG;
        }
    }

    // see if we can use native format to do either unshaded texture mapping,
    // untextured flat shading, or untextured Gouraud shading in a single pass,
    // with no munging
    if (!(m_dwCurrentState &
          (STATE_CANT_USE_NATIVE |
           STATE_SHADECOLOR |
           STATE_TEXORSHADEALPHA)))
    {
        // native texture mapping
        assert(m_dwCurrentState & STATE_TEXTURECOLOR);
        m_dwCurrentState |= STATE_USENATIVE;
    }
    else if (!(m_dwCurrentState &
               (STATE_CANT_USE_NATIVE |
                STATE_TEXTURECOLOR |
                STATE_TEXORSHADEALPHA)))
    {
        // native flat or Gouraud
        assert(m_dwCurrentState & STATE_SHADECOLOR);
        m_dwCurrentState |= STATE_USENATIVE;
    }

    assert(((m_dwCurrentState >> HANDLER_SHIFT) & HANDLER_MASK) < SIZE_M_RGPHANDLERFN);
    m_pfnDrawTri = m_rgphandlerfn[(m_dwCurrentState >> HANDLER_SHIFT) & HANDLER_MASK];

    // jump to the proper handler
    g_grdRenderData.dwState = m_dwCurrentState;
    (this->*m_pfnDrawTri)();
}


//-----------------------------------------------------------------------------
// Miscellaneous RenderDevice functions that can't be inlined.
//-----------------------------------------------------------------------------
void RenderDevice::SetScreen(BYTE *pbScreen)
{
    m_pbScreen = pbScreen;
    g_grdChunkData.pbScreen = m_pbScreen;
}


void RenderDevice::SetScreenPitch(DWORD cbPitch)
{
    m_cbScreenPitch = cbPitch;

    if (m_pcd3dd->PixDouble())
    {
        g_grdChunkData.cbScanDoubleOffset = m_cbScreenPitch;
        g_grdChunkData.cbScreenPitch = m_cbScreenPitch << 1;
    }
    else
    {
        g_grdChunkData.cbScreenPitch = m_cbScreenPitch;
    }
}


void RenderDevice::SetZBuffer(BYTE *pbZBuffer)
{
    m_pbZBuffer = pbZBuffer;
    g_grdRenderData.pbZBuffer = m_pbZBuffer;
}


void RenderDevice::SetZBufferPitch(DWORD cbPitch)
{
    m_cbZBufferPitch = cbPitch;
    g_grdRenderData.cbZBufferPitch = m_cbZBufferPitch;
}


//-----------------------------------------------------------------------------
// Does nothing.
//-----------------------------------------------------------------------------
void RenderDevice::IterateNoOp(void)
{

    IN_COUNT(ITERATE_NOOP, g_grdRenderData.dwState);
    DRAWN_COUNT(ITERATE_Z, g_grdRenderData.dwState);

    // draw a visible flat color just to make the missing functionality apparent

    g_grdRenderData.dwState &= STATE_Z | STATE_ZWRITE | STATE_ZCOMPARE | STATE_ZHANDLER | STATE_PIXDOUBLE;
    g_grdRenderData.dwState = STATE_SHADECOLOR | STATE_USENATIVE;

    g_grdRenderData.gvVertices[0].color = 0x00FF00FF;

    // we're turning texture mapping off, which normally can't happen without
    // a state change, so we have to save and restore the normal single-pass
    // chunk processor for the current state
    PSPANFN tptr = rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS];

    // configure correct native-single-pass chunk processor for flat untextured
    if (g_grdChunkData.cPixDouble)
    {
        rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] =
            SpanShadeBackend2X_Native_Flat_NoZ_10_NoAlphaTest;
    }
    else
    {
        rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] =
            SpanShadeBackend_Native_Flat_NoZ_10_NoAlphaTest;
    }

    assert(((g_grdRenderData.dwState >> HANDLER_SHIFT) & HANDLER_MASK) < SIZE_M_RGPHANDLERFN);
    (this->*m_rgphandlerfn[(g_grdRenderData.dwState >> HANDLER_SHIFT) & HANDLER_MASK])();

    // restore normal single-pass chunk processor for the current state
    rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] = tptr;
}


//-----------------------------------------------------------------------------
// Asserts and returns.
//-----------------------------------------------------------------------------
void RenderDevice::IterateError(void)
{
	return;
}


//--------------------------------------------------------------------------------
// No Texture - Flat Shading with z
//--------------------------------------------------------------------------------
#define _ZBUFFER_
#define _ZBUFFER_READ_
#define _ZBUFFER_WRITE_

#define _CREATEEDGE_FN_NAME_        CreateEdgeFlatZGEW
#define _CREATEOTHEREDGE_FN_NAME_   CreateOtherEdgeFlatZGEW
#define _STEPEDGE_FN_NAME_          StepEdgeFlatZGEW
#define _INIT_FN_NAME_              InitFlatZGEW

#include "..\inc\createedge.h"
#include "..\inc\createotheredge.h"
#include "..\inc\stepedge.h"
#include "..\inc\init.h"

//-----------------------------------------------------------------------------
// Draws triangle, iterating z..
//-----------------------------------------------------------------------------
void RenderDevice::IterateZ(void)
{
    int     i, itzabState;
    const BYTE *  pbyte;

    IN_COUNT(ITERATE_Z, g_grdRenderData.dwState);

    // Patch entry vector and rgpspanfn[] for the proper trivialz and backend processors
    itzabState = g_grdRenderData.dwState >> TRIVIALZ_AND_BACKEND_SHIFT;
    assert(itzabState < SIZE_M_RGTZAB);

    // Set up the span vectors from the master table
    assert((g_grdRenderData.dwState & MASTER_STATE_MASK) < SIZE_M_RGDTD);
    pbyte = &m_rgdtd[g_grdRenderData.dwState & MASTER_STATE_MASK].bSpanProcessor[0];
    assert(m_rgtzab[itzabState].bBackend < SIZE_RGPSPANFNTRIVIALZANDBACKEND);
    rgpspanfn[SPAN_BACKEND] = rgpspanfnTrivialZAndBackend[m_rgtzab[itzabState].bBackend];

    for (i=0; i<NUM_TABLE_SPAN_VECTORS; i++)
    {
        assert(pbyte[i] <= MAX_SPAN_FN);
        g_grdChunkData.pspanfnWorking[i] = rgpspanfn[pbyte[i]];
    }

    rgpspanfnTrivialZAndBackend[TRIVIALZ_NOOP] = g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_TRIVIALZ];
    assert(m_rgtzab[itzabState].bTrivialZ < SIZE_RGPSPANFNTRIVIALZANDBACKEND);
    g_grdRenderData.pspanfnEntry = rgpspanfnTrivialZAndBackend[m_rgtzab[itzabState].bTrivialZ];

    DRAWN_COUNT(ITERATE_Z, g_grdRenderData.dwState);
    REPORT_IF_NO_FAST_PATH();

    // generate and draw spans

    // set flat color
    g_grdChunkData.m1FlatA = FROM_8888_TO_ALPHA(g_grdRenderData.gvVertices[0].color);
    g_grdChunkData.m3FlatRGB = FROM_888_TO_MUNGED3(g_grdRenderData.gvVertices[0].color);
    g_grdChunkData.dwNativeFlatRGB = FROM_MUNGED3_TO_TARGET(g_grdChunkData.m3FlatRGB);
    g_grdChunkData.dwNativeFlatRGB2X =
            g_grdChunkData.dwNativeFlatRGB | (g_grdChunkData.dwNativeFlatRGB << 16);

    InitFlatZGEW();

    if (!g_grdRenderData.fMiddleIsRight)
    {
        CreateEdgeFlatZGEW(g_grdRenderData.iTop, g_grdRenderData.iMiddle);
        CreateOtherEdgeFlatZGEW(g_grdRenderData.iTop, g_grdRenderData.iBottom);

        g_grdRenderData.cyHeight = g_grdRenderData.geEdge.cy;
    }
    else
    {
        CreateEdgeFlatZGEW(g_grdRenderData.iTop, g_grdRenderData.iBottom);
        CreateOtherEdgeFlatZGEW(g_grdRenderData.iTop, g_grdRenderData.iMiddle);

        g_grdRenderData.cyHeight = g_grdRenderData.geOtherEdge.cy;
    }

    g_grdRenderData.pbScreenLine  = g_grdChunkData.pbScreen  + g_grdRenderData.geEdge.y * g_grdChunkData.cbScreenPitch;
    assert(g_grdRenderData.pbScreenLine != NULL);
    g_grdRenderData.pbZBufferLine = g_grdRenderData.pbZBuffer + g_grdRenderData.geEdge.y * g_grdRenderData.cbZBufferPitch;

    g_grdChunkData.ZIncr_Chunk = FloatToZBUFFER2(g_grdRenderData.dZdx);

    for (i=0; ; )
    {
        while (g_grdRenderData.cyHeight--)
        {
            g_grdRenderData.cPixels = g_grdRenderData.geEdge.x - g_grdRenderData.geOtherEdge.x;

            if (g_grdRenderData.cPixels < 0)
            {
                // do this efficiently
                g_grdChunkData.pPix_Chunk =
                        (WORD *)g_grdRenderData.pbScreenLine + (g_grdRenderData.geEdge.x << g_grdChunkData.cPixDouble);
                g_grdChunkData.pZ_Chunk = (WORD *)g_grdRenderData.pbZBufferLine + g_grdRenderData.geEdge.x;
                g_grdChunkData.dwZ_Chunk = FloatToZBUFFER2(g_grdRenderData.geEdge.Z);

                goto ChunkLoopEntry;

                do
                {
                    g_grdChunkData.dwZ_Chunk += (g_grdChunkData.ZIncr_Chunk << 4);

ChunkLoopEntry:
                    g_grdChunkData.cPixels_Chunk = g_grdRenderData.cPixels;

                    if (g_grdRenderData.cPixels < -MAX_SPAN_BLOCK_LEN)
                        g_grdChunkData.cPixels_Chunk = -MAX_SPAN_BLOCK_LEN;

                    // point to rightmost pixel of span
                    g_grdChunkData.pPix_Chunk -= g_grdChunkData.cPixels_Chunk << g_grdChunkData.cPixDouble;
                    g_grdChunkData.pZ_Chunk -= g_grdChunkData.cPixels_Chunk;

                    DRAW_SPAN();

                    g_grdRenderData.cPixels -= g_grdChunkData.cPixels_Chunk;
                } while (g_grdRenderData.cPixels < 0);
            }

            // only happens when height==0 and i==1
            if (g_grdRenderData.cyHeight < i)
                goto Done;

            StepEdgeFlatZGEW();
            #include "..\inc\stepotheredge.h"

            g_grdRenderData.pbScreenLine  += g_grdChunkData.cbScreenPitch;
            g_grdRenderData.pbZBufferLine += g_grdRenderData.cbZBufferPitch;
        }

        // if the top two edges were the same length, there's no bottom and we're done
        if (g_grdRenderData.geEdge.cy == g_grdRenderData.geOtherEdge.cy)
            break;

        i++;

        if (!g_grdRenderData.fMiddleIsRight)
        {
            CreateEdgeFlatZGEW(g_grdRenderData.iMiddle, g_grdRenderData.iBottom);
            g_grdRenderData.cyHeight = g_grdRenderData.geEdge.cy;
        }
        else
        {
            CreateOtherEdgeFlatZGEW(g_grdRenderData.iMiddle, g_grdRenderData.iBottom);
            g_grdRenderData.cyHeight = g_grdRenderData.geOtherEdge.cy;
        }
    }
Done:;
}

#include "..\inc\undef.h"


//--------------------------------------------------------------------------------
// No Texture - Gouraud Shading with z
//--------------------------------------------------------------------------------
#define _ZBUFFER_
#define _ZBUFFER_READ_
#define _ZBUFFER_WRITE_
#define _GOURAUD_

#define _CREATEEDGE_FN_NAME_        CreateEdgeGouraudZGEW
#define _CREATEOTHEREDGE_FN_NAME_   CreateOtherEdgeGouraudZGEW
#define _STEPEDGE_FN_NAME_          StepEdgeGouraudZGEW
#define _INIT_FN_NAME_              InitGouraudZGEW

#include "..\inc\createedge.h"
#include "..\inc\createotheredge.h"
#include "..\inc\stepedge.h"
#include "..\inc\init.h"

//-----------------------------------------------------------------------------
// Draws triangle, iterating Gouraud and z.
//-----------------------------------------------------------------------------
void RenderDevice::IterateGouraudZ(void)
{
    int     i, itzabState;
    const BYTE *  pbyte;

    IN_COUNT(ITERATE_GOURAUDZ, g_grdRenderData.dwState);

    // check special cases

    // Patch entry vector and rgpspanfn[] for the proper trivialz and backend processors
    itzabState = g_grdRenderData.dwState >> TRIVIALZ_AND_BACKEND_SHIFT;
    assert(itzabState < SIZE_M_RGTZAB);

    // Set up the span vectors from the master table
    assert((g_grdRenderData.dwState & MASTER_STATE_MASK) < SIZE_M_RGDTD);
    pbyte = &m_rgdtd[g_grdRenderData.dwState & MASTER_STATE_MASK].bSpanProcessor[0];
    assert(m_rgtzab[itzabState].bBackend < SIZE_RGPSPANFNTRIVIALZANDBACKEND);
    rgpspanfn[SPAN_BACKEND] = rgpspanfnTrivialZAndBackend[m_rgtzab[itzabState].bBackend];

    for (i=0; i<NUM_TABLE_SPAN_VECTORS; i++)
    {
        assert(pbyte[i] <= MAX_SPAN_FN);
        g_grdChunkData.pspanfnWorking[i] = rgpspanfn[pbyte[i]];
    }

    rgpspanfnTrivialZAndBackend[TRIVIALZ_NOOP] = g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_TRIVIALZ];
    assert(m_rgtzab[itzabState].bTrivialZ < SIZE_RGPSPANFNTRIVIALZANDBACKEND);
    g_grdRenderData.pspanfnEntry = rgpspanfnTrivialZAndBackend[m_rgtzab[itzabState].bTrivialZ];

    DRAWN_COUNT(ITERATE_GOURAUDZ, g_grdRenderData.dwState);
    REPORT_IF_NO_FAST_PATH();

    // generate and draw spans

    InitGouraudZGEW();

    if (!g_grdRenderData.fMiddleIsRight)
    {
        CreateEdgeGouraudZGEW(g_grdRenderData.iTop, g_grdRenderData.iMiddle);
        CreateOtherEdgeGouraudZGEW(g_grdRenderData.iTop, g_grdRenderData.iBottom);

        g_grdRenderData.cyHeight = g_grdRenderData.geEdge.cy;
    }
    else
    {
        CreateEdgeGouraudZGEW(g_grdRenderData.iTop, g_grdRenderData.iBottom);
        CreateOtherEdgeGouraudZGEW(g_grdRenderData.iTop, g_grdRenderData.iMiddle);

        g_grdRenderData.cyHeight = g_grdRenderData.geOtherEdge.cy;
    }

    g_grdRenderData.pbScreenLine  = g_grdChunkData.pbScreen + g_grdRenderData.geEdge.y * g_grdChunkData.cbScreenPitch;
    assert(g_grdRenderData.pbScreenLine != NULL);
    g_grdRenderData.pbZBufferLine = g_grdRenderData.pbZBuffer + g_grdRenderData.geEdge.y * g_grdRenderData.cbZBufferPitch;

    g_grdChunkData.ZIncr_Chunk = FloatToZBUFFER2(g_grdRenderData.dZdx);

    for (i=0; ; )
    {
        while (g_grdRenderData.cyHeight--)
        {
            g_grdRenderData.cPixels = g_grdRenderData.geEdge.x - g_grdRenderData.geOtherEdge.x;

            if (g_grdRenderData.cPixels < 0)
            {
                // do this efficiently
                g_grdChunkData.pPix_Chunk =
                        (WORD *)g_grdRenderData.pbScreenLine + (g_grdRenderData.geEdge.x << g_grdChunkData.cPixDouble);
                g_grdChunkData.pZ_Chunk = (WORD *)g_grdRenderData.pbZBufferLine + g_grdRenderData.geEdge.x;
                g_grdChunkData.dwZ_Chunk = FloatToZBUFFER2(g_grdRenderData.geEdge.Z);

                FIX16_16 fix16Blue = g_grdRenderData.geEdge.f16Blue;
                FIX16_16 fix16Green = g_grdRenderData.geEdge.f16Green;
                FIX16_16 fix16Red = g_grdRenderData.geEdge.f16Red;
                FIX16_16 fix16Alpha = g_grdRenderData.geEdge.f16Alpha;

                goto ChunkLoopEntry;

                do
                {
                    g_grdChunkData.dwZ_Chunk += (g_grdChunkData.ZIncr_Chunk << 4);

                    fix16Blue += g_grdRenderData.f16dBdx << 4;
                    fix16Green += g_grdRenderData.f16dGdx << 4;
                    fix16Red += g_grdRenderData.f16dRdx << 4;
                    fix16Alpha += g_grdRenderData.f16dAdx << 4;

                    assert(((fix16Blue >> 19) >= 0) && ((fix16Blue >> 19) <= 0x1F));
                    assert((g_grdRenderData.dwState & STATE_SHADEI) | (((fix16Green >> 19) >= 0) && ((fix16Green >> 19) <= 0x1F)));
                    assert((g_grdRenderData.dwState & STATE_SHADEI) | (((fix16Red >> 19) >= 0) && ((fix16Red >> 19) <= 0x1F)));
                    assert(!(g_grdRenderData.dwState & STATE_SHADEALPHA) | (((fix16Alpha >> 19) >= 0) && ((fix16Alpha >> 19) <= 0x1F)));

ChunkLoopEntry:
                    DWORD dwBlue = fix16Blue >> 14;
                    DWORD dwGreen = fix16Green >> 14;
                    DWORD dwRed = fix16Red >> 14;
                    g_grdChunkData.grb_Chunk = BUILD_GRB(dwRed, dwBlue);
                    g_grdChunkData.grgb_Chunk = BUILD_GRGB(dwRed, dwGreen, dwBlue);

                    if (g_grdRenderData.dwState & STATE_SHADEALPHA)
                    {
                        DWORD dwAlpha = fix16Alpha >> 14;
                        g_grdChunkData.gag_Chunk = BUILD_GAG(dwAlpha, dwGreen);
                    }
                    else
                    {
                        g_grdChunkData.gag_Chunk = BUILD_GG(dwGreen);
                    }

                    g_grdChunkData.cPixels_Chunk = g_grdRenderData.cPixels;

                    if (g_grdRenderData.cPixels < -MAX_SPAN_BLOCK_LEN)
                        g_grdChunkData.cPixels_Chunk = -MAX_SPAN_BLOCK_LEN;

                    // point to rightmost pixel of span
                    g_grdChunkData.pPix_Chunk -= g_grdChunkData.cPixels_Chunk << g_grdChunkData.cPixDouble;
                    g_grdChunkData.pZ_Chunk -= g_grdChunkData.cPixels_Chunk;

                    DRAW_SPAN();

                    g_grdRenderData.cPixels -= g_grdChunkData.cPixels_Chunk;
                } while (g_grdRenderData.cPixels < 0);
            }

            // only happens when height==0 and i==1
            if (g_grdRenderData.cyHeight < i)
                goto Done;

            StepEdgeGouraudZGEW();
            #include "..\inc\stepotheredge.h"

            g_grdRenderData.pbScreenLine  += g_grdChunkData.cbScreenPitch;
            g_grdRenderData.pbZBufferLine += g_grdRenderData.cbZBufferPitch;
        }

        // if the top two edges were the same length, there's no bottom and we're done
        if (g_grdRenderData.geEdge.cy == g_grdRenderData.geOtherEdge.cy)
            break;

        i++;

        if (!g_grdRenderData.fMiddleIsRight)
        {
            CreateEdgeGouraudZGEW(g_grdRenderData.iMiddle, g_grdRenderData.iBottom);
            g_grdRenderData.cyHeight = g_grdRenderData.geEdge.cy;
        }
        else
        {
            CreateOtherEdgeGouraudZGEW(g_grdRenderData.iMiddle, g_grdRenderData.iBottom);
            g_grdRenderData.cyHeight = g_grdRenderData.geOtherEdge.cy;
        }
    }
Done:;
}

#include "..\inc\undef.h"


#define _ZBUFFER_
#define _ZBUFFER_READ_
#define _ZBUFFER_WRITE_
#define _TEXMAP_

//--------------------------------------------------------------------------------
// Affine Texture - no Gouraud, z
//--------------------------------------------------------------------------------
#define _AFFINE_

#define _CREATEEDGE_FN_NAME_        CreateEdgeAffineZGEW
#define _STEPEDGE_FN_NAME_          StepEdgeAffineZGEW
#define _INIT_FN_NAME_              InitAffineZGEW

#include "..\inc\createedge.h"
#include "..\inc\stepedge.h"
#include "..\inc\init.h"

#undef  _AFFINE_


//--------------------------------------------------------------------------------
// Perspective Texture - no shading, z
//--------------------------------------------------------------------------------
#define _PERSPECTIVE_

#undef  _CREATEEDGE_FN_NAME_
#define _CREATEEDGE_FN_NAME_        CreateEdgePerspectiveZGEW
#undef  _STEPEDGE_FN_NAME_
#define _STEPEDGE_FN_NAME_          StepEdgePerspectiveZGEW
#undef  _INIT_FN_NAME_
#define _INIT_FN_NAME_              InitPerspectiveZGEW

#include "..\inc\createedge.h"
#include "..\inc\stepedge.h"
#include "..\inc\init.h"

#undef  _PERSPECTIVE_

#define _CREATEOTHEREDGE_FN_NAME_   CreateOtherEdgeTextureZGEW

#include "..\inc\createotheredge.h"

//-----------------------------------------------------------------------------
// Draws triangle, iterating texture coordinates and z..
//-----------------------------------------------------------------------------
void RenderDevice::IterateTextureZ(void)
{
    int     i, itzabState;
    const BYTE *  pbyte;

    VERIFY_UV();
    IN_COUNT(ITERATE_TEXTUREZ, g_grdRenderData.dwState);

    if (g_grdRenderData.dwState & (STATE_SHADECOLOR | STATE_SHADEALPHA))
    {
        // set flat color
        // There are two forms, one used for RGBA shading and one used for IA shading.
        // We'll set both.

        // RGBA shading uses a shade color/alpha format in which GB is in g_grdChunkData.m2xFlatGB,
        // and AR is in g_grdChunkData.m2xFlatAR, so they're in the correct format for the 2 RGB
        // multiplies
        g_grdChunkData.m2xFlatGB = FROM_888_TO_GBX(g_grdRenderData.gvVertices[0].color);
        g_grdChunkData.m2xFlatAR = FROM_8888_TO_ARX(g_grdRenderData.gvVertices[0].color);

        // IA shading stores separate right-justified I and A values
        g_grdChunkData.m1FlatI = FROM_888_TO_B(g_grdRenderData.gvVertices[0].color);
        g_grdChunkData.m1FlatA = FROM_8888_TO_ALPHA(g_grdRenderData.gvVertices[0].color);
    }

    // Patch entry vector and rgpspanfn[] for the proper trivialz and backend processors
    itzabState = g_grdRenderData.dwState >> TRIVIALZ_AND_BACKEND_SHIFT;
    assert(itzabState < SIZE_M_RGTZAB);

    // Set up the span vectors from the master table
    assert((g_grdRenderData.dwState & MASTER_STATE_MASK) < SIZE_M_RGDTD);
    pbyte = &m_rgdtd[g_grdRenderData.dwState & MASTER_STATE_MASK].bSpanProcessor[0];
    assert(m_rgtzab[itzabState].bBackend < SIZE_RGPSPANFNTRIVIALZANDBACKEND);
    rgpspanfn[SPAN_BACKEND] = rgpspanfnTrivialZAndBackend[m_rgtzab[itzabState].bBackend];

    for (i=0; i<NUM_TABLE_SPAN_VECTORS; i++)
    {
        assert(pbyte[i] <= MAX_SPAN_FN);
        g_grdChunkData.pspanfnWorking[i] = rgpspanfn[pbyte[i]];
    }

    rgpspanfnTrivialZAndBackend[TRIVIALZ_NOOP] = g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_TRIVIALZ];
    assert(m_rgtzab[itzabState].bTrivialZ < SIZE_RGPSPANFNTRIVIALZANDBACKEND);
    g_grdRenderData.pspanfnEntry = rgpspanfnTrivialZAndBackend[m_rgtzab[itzabState].bTrivialZ];

    DRAWN_COUNT(ITERATE_TEXTUREZ, g_grdRenderData.dwState);
    REPORT_IF_NO_FAST_PATH();

    if (g_grdRenderData.dwState & STATE_PERSPECTIVE)
    {
        InitPerspectiveZGEW();
    }
    else
    {
        InitAffineZGEW();
    }

    if (!g_grdRenderData.fMiddleIsRight)
    {
        if (g_grdRenderData.dwState & STATE_PERSPECTIVE)
        {
            CreateEdgePerspectiveZGEW(g_grdRenderData.iTop, g_grdRenderData.iMiddle);
        }
        else
        {
            CreateEdgeAffineZGEW(g_grdRenderData.iTop, g_grdRenderData.iMiddle);
        }

        CreateOtherEdgeTextureZGEW(g_grdRenderData.iTop, g_grdRenderData.iBottom);

        g_grdRenderData.cyHeight = g_grdRenderData.geEdge.cy;
    }
    else
    {
        if (g_grdRenderData.dwState & STATE_PERSPECTIVE)
        {
            CreateEdgePerspectiveZGEW(g_grdRenderData.iTop, g_grdRenderData.iBottom);
        }
        else
        {
            CreateEdgeAffineZGEW(g_grdRenderData.iTop, g_grdRenderData.iBottom);
        }

        CreateOtherEdgeTextureZGEW(g_grdRenderData.iTop, g_grdRenderData.iMiddle);

        g_grdRenderData.cyHeight = g_grdRenderData.geOtherEdge.cy;
    }

    g_grdRenderData.pbScreenLine  = g_grdChunkData.pbScreen + g_grdRenderData.geEdge.y * g_grdChunkData.cbScreenPitch;
    assert(g_grdRenderData.pbScreenLine != NULL);
    g_grdRenderData.pbZBufferLine = g_grdRenderData.pbZBuffer + g_grdRenderData.geEdge.y * g_grdRenderData.cbZBufferPitch;

    g_grdChunkData.ZIncr_Chunk = FloatToZBUFFER2(g_grdRenderData.dZdx);

    for (i=0; ; )
    {
        if (g_grdRenderData.dwState & STATE_PERSPECTIVE)
        {
            while (g_grdRenderData.cyHeight--)
            {
                g_grdRenderData.cPixels = g_grdRenderData.geEdge.x - g_grdRenderData.geOtherEdge.x;

                if (g_grdRenderData.cPixels < 0)
                {
                    float       oow;
                    float       uow;
                    float       vow;
                    FIX16_16    fix16uNext, fix16vNext;
                    float       w;

                    // do this efficiently
                    g_grdChunkData.pPix_Chunk =
                            (WORD *)g_grdRenderData.pbScreenLine + (g_grdRenderData.geEdge.x << g_grdChunkData.cPixDouble);
                    g_grdChunkData.pZ_Chunk = (WORD *)g_grdRenderData.pbZBufferLine + g_grdRenderData.geEdge.x;
                    g_grdChunkData.dwZ_Chunk = FloatToZBUFFER2(g_grdRenderData.geEdge.Z);

                    oow = g_grdRenderData.geEdge.oow;
                    uow = g_grdRenderData.geEdge.uow;
                    vow = g_grdRenderData.geEdge.vow;

                    w = (float)1.0 / oow;

                    fix16uNext = FloatToFixed16_16(uow * w);
                    fix16vNext = FloatToFixed16_16(vow * w);

                    fix16uNext += g_grdRenderData.f16dudxModifier;
                    fix16vNext += g_grdRenderData.f16dvdxModifier;

                    if (g_grdRenderData.cPixels < -MAX_SPAN_BLOCK_LEN)
                    {
                        // the next chunk isn't the last, just blast ahead a full chunk
                        oow += g_grdRenderData.doowdx16;
                        uow += g_grdRenderData.duowdx16;
                        vow += g_grdRenderData.dvowdx16;
                    }
                    else
                    {
                        // the next chunk is the last, calc the required
                        // length (but land right on the last pixel, because
                        // there may not even be valid u and v for pixels
                        // off the triangle
                        oow -= g_grdRenderData.doowdx * (g_grdRenderData.cPixels + 1);
                        uow -= g_grdRenderData.duowdx * (g_grdRenderData.cPixels + 1);
                        vow -= g_grdRenderData.dvowdx * (g_grdRenderData.cPixels + 1);
                    }

#if USE_C
                    w = (float)1.0 / oow;
#else
                    // overlap FDIV with other work
                    _asm
                    {
                        fld  dword ptr [g_grdRenderData.Const1]
                        fdiv dword ptr [oow]
                    }
#endif

                    goto ChunkLoopEntry;

                    do
                    {
                        g_grdChunkData.dwZ_Chunk += (g_grdChunkData.ZIncr_Chunk << 4);

ChunkLoopEntry:
                        g_grdChunkData.cPixels_Chunk = g_grdRenderData.cPixels;

                        g_grdChunkData.fix16u_Chunk = fix16uNext;
                        g_grdChunkData.fix16v_Chunk = fix16vNext;

#if !USE_C
                        // pick up results from overlapped FDIV
                        _asm
                        {
                            fstp dword ptr [w]
                        }
#endif

	                    fix16uNext = FloatToFixed16_16(uow * w);
	                    fix16vNext = FloatToFixed16_16(vow * w);

                        fix16uNext += g_grdRenderData.f16dudxModifier;
                        fix16vNext += g_grdRenderData.f16dvdxModifier;

                        if (g_grdRenderData.cPixels < -MAX_SPAN_BLOCK_LEN)
                        {
                            g_grdChunkData.cPixels_Chunk = -MAX_SPAN_BLOCK_LEN;

                            // use a shift to divide for max chunks
                            g_grdChunkData.fix16du_Chunk =
                                    (fix16uNext - g_grdChunkData.fix16u_Chunk) >> MAX_SPAN_BLOCK_SHIFT;
                            g_grdChunkData.fix16dv_Chunk =
                                    (fix16vNext - g_grdChunkData.fix16v_Chunk) >> MAX_SPAN_BLOCK_SHIFT;

                            // calculate w for next time (potentially FDIV can overlap)
                            int cNextChunk = g_grdRenderData.cPixels - g_grdChunkData.cPixels_Chunk;

                            if (cNextChunk < -MAX_SPAN_BLOCK_LEN)
                            {
                                // the next chunk isn't the last, just blast ahead a full chunk
                                oow += g_grdRenderData.doowdx16;
                                uow += g_grdRenderData.duowdx16;
                                vow += g_grdRenderData.dvowdx16;
                            }
                            else
                            {
                                // the next chunk is the last, calc the required
                                // length (but land right on the last pixel, because
                                // there may not even be valid u and v for pixels
                                // off the triangle
                                oow -= g_grdRenderData.doowdx * (cNextChunk + 1);
                                uow -= g_grdRenderData.duowdx * (cNextChunk + 1);
                                vow -= g_grdRenderData.dvowdx * (cNextChunk + 1);
                            }

#if USE_C
                            w = (float)1.0 / oow;
#else
                            // overlap FDIV with other work
                            _asm
                            {
                                fld  dword ptr [g_grdRenderData.Const1]
                                fdiv dword ptr [oow]
                            }
#endif
                        }
                        else
                        {
                            // we have to divide the variable-length last chunk
                            // -g_grdRenderData.cPixels - 1 because for the last chunk, the
                            // end of the span is on the last pixel, not one pixel
                            // after it, as is the case for full chunks
                            if (g_grdRenderData.cPixels >= -2)
                            {
                                if (g_grdRenderData.cPixels == -2)
                                {
                                    g_grdChunkData.fix16du_Chunk = (fix16uNext - g_grdChunkData.fix16u_Chunk);
                                    g_grdChunkData.fix16dv_Chunk = (fix16vNext - g_grdChunkData.fix16v_Chunk);
                                }
                            }
                            else
                            {
#if USE_C
                                g_grdChunkData.fix16du_Chunk =
                                        (g_grdChunkData.fix16u_Chunk - fix16uNext) / (g_grdRenderData.cPixels + 1);
                                g_grdChunkData.fix16dv_Chunk =
                                        (g_grdChunkData.fix16v_Chunk - fix16vNext) / (g_grdRenderData.cPixels + 1);
#else
                                assert(g_grdRenderData.cPixels >= -16);

                                _asm {
                                    mov ecx,[g_grdRenderData.cPixels]
                                    mov eax,[fix16uNext]
                                    sub eax,[g_grdChunkData.fix16u_Chunk]
                                    jns  X1
                                    neg eax
                                    mul [Div_2_15_Table+16*4+ecx*4]
                                    neg edx
                                    jmp X2
X1:
                                    mul [Div_2_15_Table+16*4+ecx*4]
X2:
                                    mov [g_grdChunkData.fix16du_Chunk],edx

                                    mov eax,[fix16vNext]
                                    sub eax,[g_grdChunkData.fix16v_Chunk]
                                    jns  X3
                                    neg eax
                                    mul [Div_2_15_Table+16*4+ecx*4]
                                    neg edx
                                    jmp X4
X3:
                                    mul [Div_2_15_Table+16*4+ecx*4]
X4:
                                    mov [g_grdChunkData.fix16dv_Chunk],edx
                                }
#endif
                            }
                        }
                        // point to rightmost pixel of span
                        g_grdChunkData.pPix_Chunk -= g_grdChunkData.cPixels_Chunk << g_grdChunkData.cPixDouble;
                        g_grdChunkData.pZ_Chunk -= g_grdChunkData.cPixels_Chunk;

                        DRAW_SPAN();

                        g_grdRenderData.cPixels -= g_grdChunkData.cPixels_Chunk;
                    } while (g_grdRenderData.cPixels < 0);
                }

                // only happens when height==0 and i==1
                if (g_grdRenderData.cyHeight < i)
                    goto Done;

                StepEdgePerspectiveZGEW();

                #include "..\inc\stepotheredge.h"

                g_grdRenderData.pbScreenLine  += g_grdChunkData.cbScreenPitch;
                g_grdRenderData.pbZBufferLine += g_grdRenderData.cbZBufferPitch;

            }
        }
        else    // affine
        {
            while (g_grdRenderData.cyHeight--)
            {
                g_grdRenderData.cPixels = g_grdRenderData.geEdge.x - g_grdRenderData.geOtherEdge.x;

                if (g_grdRenderData.cPixels < 0)
                {
                    g_grdChunkData.pPix_Chunk =
                            (WORD *)g_grdRenderData.pbScreenLine + (g_grdRenderData.geEdge.x << g_grdChunkData.cPixDouble);
                    g_grdChunkData.pZ_Chunk = (WORD *)g_grdRenderData.pbZBufferLine + g_grdRenderData.geEdge.x;
                    g_grdChunkData.dwZ_Chunk = FloatToZBUFFER2(g_grdRenderData.geEdge.Z);

	                g_grdChunkData.fix16u_Chunk = FloatToFixed16_16(g_grdRenderData.geEdge.u);
	                g_grdChunkData.fix16v_Chunk = FloatToFixed16_16(g_grdRenderData.geEdge.v);
                    g_grdChunkData.fix16u_Chunk += g_grdRenderData.f16dudxModifier;
                    g_grdChunkData.fix16v_Chunk += g_grdRenderData.f16dvdxModifier;

                    goto ChunkLoopEntry2;

                    do
                    {
                        g_grdChunkData.dwZ_Chunk += (g_grdChunkData.ZIncr_Chunk << 4);
                        g_grdChunkData.fix16u_Chunk += g_grdRenderData.fix16du_Chunk_X16;
                        g_grdChunkData.fix16v_Chunk += g_grdRenderData.fix16dv_Chunk_X16;

ChunkLoopEntry2:
                        g_grdChunkData.cPixels_Chunk = g_grdRenderData.cPixels;

                        if (g_grdRenderData.cPixels < -MAX_SPAN_BLOCK_LEN)
                            g_grdChunkData.cPixels_Chunk = -MAX_SPAN_BLOCK_LEN;

                        // point to rightmost pixel of span
                        g_grdChunkData.pPix_Chunk -= g_grdChunkData.cPixels_Chunk << g_grdChunkData.cPixDouble;
                        g_grdChunkData.pZ_Chunk -= g_grdChunkData.cPixels_Chunk;

                        DRAW_SPAN();

                        g_grdRenderData.cPixels -= g_grdChunkData.cPixels_Chunk;
                    } while (g_grdRenderData.cPixels < 0);
                }

                // only happens when height==0 and i==1
                if (g_grdRenderData.cyHeight < i)
                    goto Done;

                StepEdgeAffineZGEW();

                #include "..\inc\stepotheredge.h"

                g_grdRenderData.pbScreenLine  += g_grdChunkData.cbScreenPitch;
                g_grdRenderData.pbZBufferLine += g_grdRenderData.cbZBufferPitch;

            }
        }

        // if the top two edges were the same length, there's no bottom and we're done
        if (g_grdRenderData.geEdge.cy == g_grdRenderData.geOtherEdge.cy)
            break;

        i++;

        if (!g_grdRenderData.fMiddleIsRight)
        {
            if (g_grdRenderData.dwState & STATE_PERSPECTIVE)
                CreateEdgePerspectiveZGEW(g_grdRenderData.iMiddle, g_grdRenderData.iBottom);
            else
                CreateEdgeAffineZGEW(g_grdRenderData.iMiddle, g_grdRenderData.iBottom);

            g_grdRenderData.cyHeight = g_grdRenderData.geEdge.cy;
        }
        else
        {
            CreateOtherEdgeTextureZGEW(g_grdRenderData.iMiddle, g_grdRenderData.iBottom);

            g_grdRenderData.cyHeight = g_grdRenderData.geOtherEdge.cy;
        }
    }
Done:;
}

#include "..\inc\undef.h"

//--------------------------------------------------------------------------------
// Texture, no Gouraud, no Z
//--------------------------------------------------------------------------------
#define _TEXMAP_

#define _AFFINE_

#define _CREATEEDGE_FN_NAME_        CreateEdgeAffine
#define _CREATEEDGE_AFFINE_FN_NAME_ CreateEdgeAffine
#define _STEPEDGE_FN_NAME_          StepEdgeAffine
#define _STEPEDGE_AFFINE_FN_NAME_   StepEdgeAffine
#define _INIT_FN_NAME_              InitAffine
#define _INIT_AFFINE_FN_NAME_       InitAffine

#include "..\inc\createedge.h"
#include "..\inc\stepedge.h"
#include "..\inc\init.h"

#undef  _AFFINE_

#define _PERSPECTIVE_

#undef  _CREATEEDGE_FN_NAME_
#define _CREATEEDGE_FN_NAME_        CreateEdgePerspective
#define _CREATEEDGE_PERSP_FN_NAME_  CreateEdgePerspective
#undef  _STEPEDGE_FN_NAME_
#define _STEPEDGE_FN_NAME_          StepEdgePerspective
#define _STEPEDGE_PERSP_FN_NAME_    StepEdgePerspective
#undef  _INIT_FN_NAME_
#define _INIT_FN_NAME_              InitPerspective
#define _INIT_PERSP_FN_NAME_        InitPerspective

#include "..\inc\createedge.h"
#include "..\inc\stepedge.h"
#include "..\inc\init.h"

#undef  _PERSPECTIVE_

#define _CREATEOTHEREDGE_FN_NAME_   CreateOtherEdgeTexture

#include "..\inc\createotheredge.h"

void RenderDevice::IterateTexture(void)
{
    int     i, itzabState;
    const BYTE *  pbyte;

    VERIFY_UV();
    IN_COUNT(ITERATE_TEXTURE, g_grdRenderData.dwState);

    if (g_grdRenderData.dwState & (STATE_SHADECOLOR | STATE_SHADEALPHA))
    {
        // set flat color
        // There are two forms, one used for RGBA shading and one used for IA shading.
        // We'll set both.

        // RGBA shading uses a shade color/alpha format in which GB is in g_grdChunkData.m2xFlatGB,
        // and AR is in g_grdChunkData.m2xFlatAR, so they're in the correct format for the 2 RGB
        // multiplies
        g_grdChunkData.m2xFlatGB = FROM_888_TO_GBX(g_grdRenderData.gvVertices[0].color);
        g_grdChunkData.m2xFlatAR = FROM_8888_TO_ARX(g_grdRenderData.gvVertices[0].color);

        // IA shading stores separate right-justified I and A values
        g_grdChunkData.m1FlatI = FROM_888_TO_B(g_grdRenderData.gvVertices[0].color);
        g_grdChunkData.m1FlatA = FROM_8888_TO_ALPHA(g_grdRenderData.gvVertices[0].color);
    }

    // Patch entry vector and rgpspanfn[] for the proper trivialz and backend processors
    itzabState = g_grdRenderData.dwState >> TRIVIALZ_AND_BACKEND_SHIFT;
    assert(itzabState < SIZE_M_RGTZAB);

    // Set up the span vectors from the master table
    assert((g_grdRenderData.dwState & MASTER_STATE_MASK) < SIZE_M_RGDTD);
    pbyte = &m_rgdtd[g_grdRenderData.dwState & MASTER_STATE_MASK].bSpanProcessor[0];
    assert(m_rgtzab[itzabState].bBackend < SIZE_RGPSPANFNTRIVIALZANDBACKEND);
    rgpspanfn[SPAN_BACKEND] = rgpspanfnTrivialZAndBackend[m_rgtzab[itzabState].bBackend];

    for (i=0; i<NUM_TABLE_SPAN_VECTORS; i++)
    {
        assert(pbyte[i] <= MAX_SPAN_FN);
        g_grdChunkData.pspanfnWorking[i] = rgpspanfn[pbyte[i]];
    }

    rgpspanfnTrivialZAndBackend[TRIVIALZ_NOOP] = g_grdChunkData.pspanfnWorking[PSPANFN_AFTER_TRIVIALZ];
    assert(m_rgtzab[itzabState].bTrivialZ < SIZE_RGPSPANFNTRIVIALZANDBACKEND);
    g_grdRenderData.pspanfnEntry = rgpspanfnTrivialZAndBackend[m_rgtzab[itzabState].bTrivialZ];

    DRAWN_COUNT(ITERATE_TEXTURE, g_grdRenderData.dwState);
    REPORT_IF_NO_FAST_PATH();

    if (g_grdRenderData.dwState & STATE_PERSPECTIVE)
    {
        InitPerspective();
    }
    else
    {
        InitAffine();
    }

    if (!g_grdRenderData.fMiddleIsRight)
    {
        if (g_grdRenderData.dwState & STATE_PERSPECTIVE)
        {
            CreateEdgePerspective(g_grdRenderData.iTop, g_grdRenderData.iMiddle);
        }
        else
        {
            CreateEdgeAffine(g_grdRenderData.iTop, g_grdRenderData.iMiddle);
        }

        CreateOtherEdgeTexture(g_grdRenderData.iTop, g_grdRenderData.iBottom);

        g_grdRenderData.cyHeight = g_grdRenderData.geEdge.cy;
    }
    else
    {
        if (g_grdRenderData.dwState & STATE_PERSPECTIVE)
        {
            CreateEdgePerspective(g_grdRenderData.iTop, g_grdRenderData.iBottom);
        }
        else
        {
            CreateEdgeAffine(g_grdRenderData.iTop, g_grdRenderData.iBottom);
        }

        CreateOtherEdgeTexture(g_grdRenderData.iTop, g_grdRenderData.iMiddle);

        g_grdRenderData.cyHeight = g_grdRenderData.geOtherEdge.cy;
    }

    g_grdRenderData.pbScreenLine  = g_grdChunkData.pbScreen + g_grdRenderData.geEdge.y * g_grdChunkData.cbScreenPitch;
    assert(g_grdRenderData.pbScreenLine != NULL);

    for (i=0; ; )
    {
        if (g_grdRenderData.dwState & STATE_PERSPECTIVE)
        {
            while (g_grdRenderData.cyHeight--)
            {
                g_grdRenderData.cPixels = g_grdRenderData.geEdge.x - g_grdRenderData.geOtherEdge.x;

                if (g_grdRenderData.cPixels < 0)
                {
                    float       oow;
                    float       uow;
                    float       vow;
                    FIX16_16    fix16uNext, fix16vNext;
                    float       w;

                    g_grdChunkData.pPix_Chunk =
                            (WORD *)g_grdRenderData.pbScreenLine + (g_grdRenderData.geEdge.x << g_grdChunkData.cPixDouble);

                    oow = g_grdRenderData.geEdge.oow;
                    uow = g_grdRenderData.geEdge.uow;
                    vow = g_grdRenderData.geEdge.vow;

                    w = (float)1.0 / oow;

                    fix16uNext = FloatToFixed16_16(uow * w);
                    fix16vNext = FloatToFixed16_16(vow * w);

                    fix16uNext += g_grdRenderData.f16dudxModifier;
                    fix16vNext += g_grdRenderData.f16dvdxModifier;

                    if (g_grdRenderData.cPixels < -MAX_SPAN_BLOCK_LEN)
                    {
                        // the next chunk isn't the last, just blast ahead a full chunk
                        oow += g_grdRenderData.doowdx16;
                        uow += g_grdRenderData.duowdx16;
                        vow += g_grdRenderData.dvowdx16;
                    }
                    else
                    {
                        // the next chunk is the last, calc the required
                        // length (but land right on the last pixel, because
                        // there may not even be valid u and v for pixels
                        // off the triangle
                        oow -= g_grdRenderData.doowdx * (g_grdRenderData.cPixels + 1);
                        uow -= g_grdRenderData.duowdx * (g_grdRenderData.cPixels + 1);
                        vow -= g_grdRenderData.dvowdx * (g_grdRenderData.cPixels + 1);
                    }

#if USE_C
                    w = (float)1.0 / oow;
#else
                    // overlap FDIV with other work
                    _asm
                    {
                        fld  dword ptr [g_grdRenderData.Const1]
                        fdiv dword ptr [oow]
                    }
#endif

                    do
                    {
                        g_grdChunkData.cPixels_Chunk = g_grdRenderData.cPixels;

                        g_grdChunkData.fix16u_Chunk = fix16uNext;
                        g_grdChunkData.fix16v_Chunk = fix16vNext;

#if !USE_C
                        // pick up results from overlapped FDIV
                        _asm
                        {
                            fstp dword ptr [w]
                        }
#endif

	                    fix16uNext = FloatToFixed16_16(uow * w);
	                    fix16vNext = FloatToFixed16_16(vow * w);

                        fix16uNext += g_grdRenderData.f16dudxModifier;
                        fix16vNext += g_grdRenderData.f16dvdxModifier;

                        if (g_grdRenderData.cPixels < -MAX_SPAN_BLOCK_LEN)
                        {
                            g_grdChunkData.cPixels_Chunk = -MAX_SPAN_BLOCK_LEN;

                            // use a shift to divide for max chunks
                            g_grdChunkData.fix16du_Chunk =
                                    (fix16uNext - g_grdChunkData.fix16u_Chunk) >> MAX_SPAN_BLOCK_SHIFT;
                            g_grdChunkData.fix16dv_Chunk =
                                    (fix16vNext - g_grdChunkData.fix16v_Chunk) >> MAX_SPAN_BLOCK_SHIFT;

                            // calculate w for next time (potentially FDIV can overlap)
                            int cNextChunk = g_grdRenderData.cPixels - g_grdChunkData.cPixels_Chunk;

                            if (cNextChunk < -MAX_SPAN_BLOCK_LEN)
                            {
                                // the next chunk isn't the last, just blast ahead a full chunk
                                oow += g_grdRenderData.doowdx16;
                                uow += g_grdRenderData.duowdx16;
                                vow += g_grdRenderData.dvowdx16;
                            }
                            else
                            {
                                // the next chunk is the last, calc the required
                                // length (but land right on the last pixel, because
                                // there may not even be valid u and v for pixels
                                // off the triangle
                                oow -= g_grdRenderData.doowdx * (cNextChunk + 1);
                                uow -= g_grdRenderData.duowdx * (cNextChunk + 1);
                                vow -= g_grdRenderData.dvowdx * (cNextChunk + 1);
                            }

#if USE_C
                            w = (float)1.0 / oow;
#else
                            // overlap FDIV with other work
                            _asm
                            {
                                fld  dword ptr [g_grdRenderData.Const1]
                                fdiv dword ptr [oow]
                            }
#endif
                        }
                        else
                        {
                            // we have to divide the variable-length last chunk
                            // -g_grdRenderData.cPixels - 1 because for the last chunk, the
                            // end of the span is on the last pixel, not one pixel
                            // after it, as is the case for full chunks
                            if (g_grdRenderData.cPixels >= -2)
                            {
                                if (g_grdRenderData.cPixels == -2)
                                {
                                    g_grdChunkData.fix16du_Chunk = (fix16uNext - g_grdChunkData.fix16u_Chunk);
                                    g_grdChunkData.fix16dv_Chunk = (fix16vNext - g_grdChunkData.fix16v_Chunk);
                                }
                            }
                            else
                            {
#if USE_C
                                g_grdChunkData.fix16du_Chunk =
                                        (g_grdChunkData.fix16u_Chunk - fix16uNext) / (g_grdRenderData.cPixels + 1);
                                g_grdChunkData.fix16dv_Chunk =
                                        (g_grdChunkData.fix16v_Chunk - fix16vNext) / (g_grdRenderData.cPixels + 1);
#else
                                assert(g_grdRenderData.cPixels >= -16);

                                _asm {
                                    mov ecx,[g_grdRenderData.cPixels]
                                    mov eax,[fix16uNext]
                                    sub eax,[g_grdChunkData.fix16u_Chunk]
                                    jns  X1
                                    neg eax
                                    mul [Div_2_15_Table+16*4+ecx*4]
                                    neg edx
                                    jmp X2
X1:
                                    mul [Div_2_15_Table+16*4+ecx*4]
X2:
                                    mov [g_grdChunkData.fix16du_Chunk],edx

                                    mov eax,[fix16vNext]
                                    sub eax,[g_grdChunkData.fix16v_Chunk]
                                    jns  X3
                                    neg eax
                                    mul [Div_2_15_Table+16*4+ecx*4]
                                    neg edx
                                    jmp X4
X3:
                                    mul [Div_2_15_Table+16*4+ecx*4]
X4:
                                    mov [g_grdChunkData.fix16dv_Chunk],edx
                                }
#endif
                            }
                        }

                        // point to rightmost pixel of span
                        g_grdChunkData.pPix_Chunk -= g_grdChunkData.cPixels_Chunk << g_grdChunkData.cPixDouble;

                        DRAW_SPAN();

                        g_grdRenderData.cPixels -= g_grdChunkData.cPixels_Chunk;
                    } while (g_grdRenderData.cPixels < 0);
                }

                // only happens when height==0 and i==1
                if (g_grdRenderData.cyHeight < i)
                    goto Done;

                StepEdgePerspective();

                #include "..\inc\stepotheredge.h"

                g_grdRenderData.pbScreenLine  += g_grdChunkData.cbScreenPitch;
            }
        }
        else    // affine
        {
            while (g_grdRenderData.cyHeight--)
            {
                g_grdRenderData.cPixels = g_grdRenderData.geEdge.x - g_grdRenderData.geOtherEdge.x;

                if (g_grdRenderData.cPixels < 0)
                {
                    g_grdChunkData.pPix_Chunk =
                            (WORD *)g_grdRenderData.pbScreenLine + (g_grdRenderData.geEdge.x << g_grdChunkData.cPixDouble);

	                g_grdChunkData.fix16u_Chunk = FloatToFixed16_16(g_grdRenderData.geEdge.u);
	                g_grdChunkData.fix16v_Chunk = FloatToFixed16_16(g_grdRenderData.geEdge.v);
                    g_grdChunkData.fix16u_Chunk += g_grdRenderData.f16dudxModifier;
                    g_grdChunkData.fix16v_Chunk += g_grdRenderData.f16dvdxModifier;

                    goto ChunkLoopEntry;

                    do
                    {
                        g_grdChunkData.fix16u_Chunk += g_grdRenderData.fix16du_Chunk_X16;
                        g_grdChunkData.fix16v_Chunk += g_grdRenderData.fix16dv_Chunk_X16;

ChunkLoopEntry:
                        g_grdChunkData.cPixels_Chunk = g_grdRenderData.cPixels;

                        if (g_grdRenderData.cPixels < -MAX_SPAN_BLOCK_LEN)
                            g_grdChunkData.cPixels_Chunk = -MAX_SPAN_BLOCK_LEN;

                        // point to rightmost pixel of span
                        g_grdChunkData.pPix_Chunk -= g_grdChunkData.cPixels_Chunk << g_grdChunkData.cPixDouble;

                        DRAW_SPAN();

                        g_grdRenderData.cPixels -= g_grdChunkData.cPixels_Chunk;
                    } while (g_grdRenderData.cPixels < 0);
                }

                // only happens when height==0 and i==1
                if (g_grdRenderData.cyHeight < i)
                    goto Done;

                StepEdgeAffine();

                #include "..\inc\stepotheredge.h"

                g_grdRenderData.pbScreenLine  += g_grdChunkData.cbScreenPitch;
            }
        }

        // if the top two edges were the same length, there's no bottom and we're done
        if (g_grdRenderData.geEdge.cy == g_grdRenderData.geOtherEdge.cy)
            break;

        i++;

        if (!g_grdRenderData.fMiddleIsRight)
        {
            if (g_grdRenderData.dwState & STATE_PERSPECTIVE)
                CreateEdgePerspective(g_grdRenderData.iMiddle, g_grdRenderData.iBottom);
            else
                CreateEdgeAffine(g_grdRenderData.iMiddle, g_grdRenderData.iBottom);

            g_grdRenderData.cyHeight = g_grdRenderData.geEdge.cy;
        }
        else
        {
            CreateOtherEdgeTexture(g_grdRenderData.iMiddle, g_grdRenderData.iBottom);

            g_grdRenderData.cyHeight = g_grdRenderData.geOtherEdge.cy;
        }
    }
Done:;
}

#include "..\inc\undef.h"

//--------------------------------------------------------------------------------
// Texture, Gouraud/Flat, Z
//--------------------------------------------------------------------------------
#define _ZBUFFER_
#define _ZBUFFER_READ_
#define _ZBUFFER_WRITE_
#define _GOURAUD_
#define _FLAT_
#define _TEXMAP_

#define _AFFINE_

#define _CREATEEDGE_FN_NAME_        CreateEdgeAffineGouraudZGEW
#define _CREATEEDGE_AFFINE_FN_NAME_ CreateEdgeAffineGouraudZGEW
#define _STEPEDGE_FN_NAME_          StepEdgeAffineGouraudZGEW
#define _STEPEDGE_AFFINE_FN_NAME_   StepEdgeAffineGouraudZGEW
#define _INIT_FN_NAME_              InitAffineGouraudZGEW
#define _INIT_AFFINE_FN_NAME_       InitAffineGouraudZGEW

#include "..\inc\createedge.h"
#include "..\inc\stepedge.h"
#include "..\inc\init.h"

#undef  _AFFINE_

#define _PERSPECTIVE_

#undef  _CREATEEDGE_FN_NAME_
#define _CREATEEDGE_FN_NAME_        CreateEdgePerspectiveGouraudZGEW
#define _CREATEEDGE_PERSP_FN_NAME_  CreateEdgePerspectiveGouraudZGEW
#undef  _STEPEDGE_FN_NAME_
#define _STEPEDGE_FN_NAME_          StepEdgePerspectiveGouraudZGEW
#define _STEPEDGE_PERSP_FN_NAME_    StepEdgePerspectiveGouraudZGEW
#undef  _INIT_FN_NAME_
#define _INIT_FN_NAME_              InitPerspectiveGouraudZGEW
#define _INIT_PERSP_FN_NAME_        InitPerspectiveGouraudZGEW

#include "..\inc\createedge.h"
#include "..\inc\stepedge.h"
#include "..\inc\init.h"

#undef  _PERSPECTIVE_

#define _CREATEOTHEREDGE_FN_NAME_   CreateOtherEdgeTextureGouraudZGEW

#include "..\inc\createotheredge.h"

#define _STEPOTHEREDGE_INC_NAME_  "..\inc\stepotheredge.h"

void RenderDevice::IteratePerspectiveTextureGouraudZ(void)
{

    assert(g_grdRenderData.dwState & STATE_PERSPECTIVE);

    VERIFY_UV();
    IN_COUNT(ITERATE_PERSPECTIVETEXTUREGOURAUDZ, g_grdRenderData.dwState);

#define _DRAWN_COUNTER_   ITERATE_PERSPECTIVETEXTUREGOURAUDZ

#define _PERSPECTIVE_
    // generate and draw spans
    #include "..\inc\drawspans.h"
#undef _PERSPECTIVE_
}


void RenderDevice::IterateAffineTextureGouraudZ(void)
{

    assert(!(g_grdRenderData.dwState & STATE_PERSPECTIVE));

    VERIFY_UV();
    IN_COUNT(ITERATE_AFFINETEXTUREGOURAUDZ, g_grdRenderData.dwState);

#undef _DRAWN_COUNTER_
#define _DRAWN_COUNTER_   ITERATE_AFFINETEXTUREGOURAUDZ

#define _AFFINE_
    // generate and draw spans
    #include "..\inc\drawspans.h"
#undef _AFFINE_
}

#include "..\inc\undef.h"


//-----------------------------------------------------------------------------
// Draws triangle, iterating z and fog.
// Always converted into Gouraud, so the fog effect on the shade color can be
// rolled into the Gouraud iterators.
//-----------------------------------------------------------------------------
void RenderDevice::IterateZFog(void)
{

    // copy the flat color to all vertices for use in Gouraud
    g_grdRenderData.gvVertices[1].color = g_grdRenderData.gvVertices[0].color;
    g_grdRenderData.gvVertices[2].color = g_grdRenderData.gvVertices[0].color;

    g_grdRenderData.dwState |= STATE_SHADEGOURAUD;

    IterateGouraudZFog();
}


//-----------------------------------------------------------------------------
// Draws triangle, iterating Gouraud, z, and fog.
//-----------------------------------------------------------------------------

#define _ZBUFFER_
#define _ZBUFFER_READ_
#define _ZBUFFER_WRITE_
#define _GOURAUD_
#define _FOG_

#define _CREATEEDGE_FN_NAME_        CreateEdgeGouraudZGEWFog
#define _CREATEOTHEREDGE_FN_NAME_   CreateOtherEdgeGouraudZGEWFog
#define _STEPEDGE_FN_NAME_          StepEdgeGouraudZGEWFog
#define _INIT_FN_NAME_              InitGouraudZGEWFog

#include "..\inc\createedge.h"
#include "..\inc\createotheredge.h"
#include "..\inc\stepedge.h"
#include "..\inc\init.h"

#define _STEPOTHEREDGE_INC_NAME_  "..\inc\stepotheredge.h"

void RenderDevice::IterateGouraudZFog(void)
{

    IN_COUNT(ITERATE_GOURAUDZ, g_grdRenderData.dwState);

    // special-case zero-intensity fog, which is the same as no fog, by turning fog off
    if (((g_grdRenderData.gvVertices[0].specular &
          g_grdRenderData.gvVertices[1].specular &
          g_grdRenderData.gvVertices[2].specular) >> 27) == 0x1F)
    {
        g_grdRenderData.dwState &= ~STATE_FOG;

        // allow possibility of native mode if fog was all that was preventing it
        if (!(g_grdRenderData.dwState & STATE_CANT_USE_NATIVE_NONFOG))
            g_grdRenderData.dwState &= ~STATE_CANT_USE_NATIVE;

        // see whether we can now use native format
        // NOTE mikeab since texturing can't be special-cased into existence, we don't
        // need to check the textured native cases here
        if (!(g_grdRenderData.dwState &
              (STATE_CANT_USE_NATIVE |
               STATE_TEXTURECOLOR |
               STATE_TEXORSHADEALPHA)))
        {
            assert(g_grdRenderData.dwState & STATE_SHADECOLOR);
            g_grdRenderData.dwState |= STATE_USENATIVE;
        }

        assert(((g_grdRenderData.dwState >> HANDLER_SHIFT) & HANDLER_MASK) < SIZE_M_RGPHANDLERFN);
        (this->*m_rgphandlerfn[(g_grdRenderData.dwState >> HANDLER_SHIFT) & HANDLER_MASK])();

        return;
    }
    else if (!(g_grdRenderData.dwState & (STATE_TEXORSHADEALPHA | STATE_ALPHABLEND_MASK)) &&
             (((g_grdRenderData.gvVertices[0].specular |
                g_grdRenderData.gvVertices[1].specular |
                g_grdRenderData.gvVertices[2].specular) >> 27) == 0x00))
    {
        // special-case full-intensity non-alpha non-11 fog, which is the same as a flat fill with the fog color
        // NOTE mikeab 11 could be passed through here, if native is turned off, but it's possible there are
        // complications that would need to be addressed
        g_grdRenderData.dwState &= STATE_Z | STATE_ZWRITE | STATE_ZCOMPARE | STATE_ZHANDLER | STATE_PIXDOUBLE;
        g_grdRenderData.dwState |= STATE_SHADECOLOR | STATE_USENATIVE;
        g_grdRenderData.gvVertices[0].color = FROM_MUNGED3_TO_888(g_grdChunkData.m3FogColor);

        // we're turning texture mapping off, which normally can't happen without
        // a state change, so we have to save and restore the normal single-pass
        // chunk processor for the current state
        PSPANFN tptr = rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS];

        // configure correct native-single-pass chunk processor for flat untextured
        if (g_grdChunkData.cPixDouble)
        {
            rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] =
                SpanShadeBackend2X_Native_Flat_NoZ_10_NoAlphaTest;
        }
        else
        {
            rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] =
                SpanShadeBackend_Native_Flat_NoZ_10_NoAlphaTest;
        }

        assert(((g_grdRenderData.dwState >> HANDLER_SHIFT) & HANDLER_MASK) < SIZE_M_RGPHANDLERFN);
        (this->*m_rgphandlerfn[(g_grdRenderData.dwState >> HANDLER_SHIFT) & HANDLER_MASK])();

        // restore normal single-pass chunk processor for the current state
        rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] = tptr;

        return;
    }

    assert(!(g_grdRenderData.dwState & (STATE_TEXTURECOLOR | STATE_TEXALPHA)));

#define _DRAWN_COUNTER_   ITERATE_GOURAUDZFOG

#include "..\inc\drawspans.h"
}

#include "..\inc\undef.h"


//-----------------------------------------------------------------------------
// Draws triangle, iterating perspective texture, Gouraud, z, and fog.
//-----------------------------------------------------------------------------
#define _ZBUFFER_
#define _ZBUFFER_READ_
#define _ZBUFFER_WRITE_
#define _GOURAUD_
#define _FLAT_
#define _TEXMAP_
#define _FOG_

#define _AFFINE_

#define _CREATEEDGE_FN_NAME_        CreateEdgeAffineGouraudZGEWFog
#define _CREATEEDGE_AFFINE_FN_NAME_ CreateEdgeAffineGouraudZGEWFog
#define _STEPEDGE_FN_NAME_          StepEdgeAffineGouraudZGEWFog
#define _STEPEDGE_AFFINE_FN_NAME_   StepEdgeAffineGouraudZGEWFog
#define _INIT_FN_NAME_              InitAffineGouraudZGEWFog
#define _INIT_AFFINE_FN_NAME_       InitAffineGouraudZGEWFog

#include "..\inc\createedge.h"
#include "..\inc\stepedge.h"
#include "..\inc\init.h"

#undef  _AFFINE_

#define _PERSPECTIVE_

#undef  _CREATEEDGE_FN_NAME_
#define _CREATEEDGE_FN_NAME_        CreateEdgePerspectiveGouraudZGEWFog
#define _CREATEEDGE_PERSP_FN_NAME_  CreateEdgePerspectiveGouraudZGEWFog
#undef  _STEPEDGE_FN_NAME_
#define _STEPEDGE_FN_NAME_          StepEdgePerspectiveGouraudZGEWFog
#define _STEPEDGE_PERSP_FN_NAME_    StepEdgePerspectiveGouraudZGEWFog
#undef  _INIT_FN_NAME_
#define _INIT_FN_NAME_              InitPerspectiveGouraudZGEWFog
#define _INIT_PERSP_FN_NAME_        InitPerspectiveGouraudZGEWFog

#include "..\inc\createedge.h"
#include "..\inc\stepedge.h"
#include "..\inc\init.h"

#undef  _PERSPECTIVE_

#define _CREATEOTHEREDGE_FN_NAME_   CreateOtherEdgeTextureGouraudZGEWFog

#include "..\inc\createotheredge.h"

void RenderDevice::IteratePerspectiveTextureGouraudZFog(void)
{

    VERIFY_UV();
    IN_COUNT(ITERATE_PERSPECTIVETEXTUREGOURAUDZFOG, g_grdRenderData.dwState);

    // special-case zero-intensity fog, which is the same as no fog, by turning fog off
    if (((g_grdRenderData.gvVertices[0].specular &
          g_grdRenderData.gvVertices[1].specular &
          g_grdRenderData.gvVertices[2].specular) >> 27) == 0x1F)
    {
        g_grdRenderData.dwState &= ~STATE_FOG;

        // allow possibility of native mode if fog was all that was preventing it
        if (!(g_grdRenderData.dwState & STATE_CANT_USE_NATIVE_NONFOG))
            g_grdRenderData.dwState &= ~STATE_CANT_USE_NATIVE;

        // see whether we can now use native format
        // NOTE mikeab since texturing can't be special-cased away, we don't
        // need to check the shaded native cases here
        if (!(g_grdRenderData.dwState &
              (STATE_CANT_USE_NATIVE |
               STATE_SHADECOLOR |
               STATE_TEXORSHADEALPHA)))
        {
            assert(g_grdRenderData.dwState & STATE_TEXTURECOLOR);
            g_grdRenderData.dwState |= STATE_USENATIVE;
        }

        assert(((g_grdRenderData.dwState >> HANDLER_SHIFT) & HANDLER_MASK) < SIZE_M_RGPHANDLERFN);
        (this->*m_rgphandlerfn[(g_grdRenderData.dwState >> HANDLER_SHIFT) & HANDLER_MASK])();

        return;
    }
    else if (!(g_grdRenderData.dwState & (STATE_TEXORSHADEALPHA | STATE_ALPHABLEND_MASK)) &&
             (((g_grdRenderData.gvVertices[0].specular |
                g_grdRenderData.gvVertices[1].specular |
                g_grdRenderData.gvVertices[2].specular) >> 27) == 0x00))
    {
        // special-case full-intensity non-alpha non-11 fog, which is the same as a flat fill with the fog color
        // NOTE mikeab 11 could be passed through here, if native is turned off, but it's possible there are
        // complications that would need to be addressed
        g_grdRenderData.dwState &= STATE_Z | STATE_ZWRITE | STATE_ZCOMPARE | STATE_ZHANDLER | STATE_PIXDOUBLE;
        g_grdRenderData.dwState |= STATE_SHADECOLOR | STATE_USENATIVE;
        g_grdRenderData.gvVertices[0].color = FROM_MUNGED3_TO_888(g_grdChunkData.m3FogColor);

        // we're turning texture mapping off, which normally can't happen without
        // a state change, so we have to save and restore the normal single-pass
        // chunk processor for the current state
        PSPANFN tptr = rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS];

        // configure correct native-single-pass chunk processor for flat untextured
        if (g_grdChunkData.cPixDouble)
        {
            rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] =
                SpanShadeBackend2X_Native_Flat_NoZ_10_NoAlphaTest;
        }
        else
        {
            rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] =
                SpanShadeBackend_Native_Flat_NoZ_10_NoAlphaTest;
        }

        assert(((g_grdRenderData.dwState >> HANDLER_SHIFT) & HANDLER_MASK) < SIZE_M_RGPHANDLERFN);
        (this->*m_rgphandlerfn[(g_grdRenderData.dwState >> HANDLER_SHIFT) & HANDLER_MASK])();

        // restore normal single-pass chunk processor for the current state
        rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] = tptr;

        return;
    }

    assert(g_grdRenderData.dwState & STATE_PERSPECTIVE);

    if (!(g_grdRenderData.dwState & STATE_SHADECOLOR))
    {
        // if there's no shading, mock up intensity Gouraud so there's something to scale down
        g_grdRenderData.gvVertices[0].color |= 0x00FFFFFF;
        g_grdRenderData.gvVertices[1].color |= 0x00FFFFFF;
        g_grdRenderData.gvVertices[2].color |= 0x00FFFFFF;
        g_grdRenderData.dwState |= STATE_SHADECOLOR | STATE_SHADEGOURAUD | STATE_SHADEI;
    }
    else if (!(g_grdRenderData.dwState & STATE_SHADEGOURAUD))
    {
        // copy the flat color to all vertices for use in Gouraud
        g_grdRenderData.gvVertices[1].color = g_grdRenderData.gvVertices[0].color;
        g_grdRenderData.gvVertices[2].color = g_grdRenderData.gvVertices[0].color;
        g_grdRenderData.dwState |= STATE_SHADEGOURAUD;
    }

#define _DRAWN_COUNTER_   ITERATE_PERSPECTIVETEXTUREGOURAUDZFOG

#define _PERSPECTIVE_
    // generate and draw spans
    #include "..\inc\drawspans.h"
#undef _PERSPECTIVE_
}


//-----------------------------------------------------------------------------
// Draws triangle, iterating affine texture, Gouraud, z, and fog.
//-----------------------------------------------------------------------------
void RenderDevice::IterateAffineTextureGouraudZFog(void)
{

    VERIFY_UV();
    IN_COUNT(ITERATE_AFFINETEXTUREGOURAUDZ, g_grdRenderData.dwState);

    // special-case zero-intensity fog, which is the same as no fog, by turning fog off
    if (((g_grdRenderData.gvVertices[0].specular &
          g_grdRenderData.gvVertices[1].specular &
          g_grdRenderData.gvVertices[2].specular) >> 27) == 0x1F)
    {
        g_grdRenderData.dwState &= ~STATE_FOG;

        // allow possibility of native mode if fog was all that was preventing it
        if (!(g_grdRenderData.dwState & STATE_CANT_USE_NATIVE_NONFOG))
            g_grdRenderData.dwState &= ~STATE_CANT_USE_NATIVE;

        // see whether we can now use native format
        // NOTE mikeab since texturing can't be special-cased away, we don't
        // need to check the shaded native cases here
        if (!(g_grdRenderData.dwState &
              (STATE_CANT_USE_NATIVE |
               STATE_SHADECOLOR |
               STATE_TEXORSHADEALPHA)))
        {
            assert(g_grdRenderData.dwState & STATE_TEXTURECOLOR);
            g_grdRenderData.dwState |= STATE_USENATIVE;
        }

        assert(((g_grdRenderData.dwState >> HANDLER_SHIFT) & HANDLER_MASK) < SIZE_M_RGPHANDLERFN);
        (this->*m_rgphandlerfn[(g_grdRenderData.dwState >> HANDLER_SHIFT) & HANDLER_MASK])();

        return;
    }
    else if (!(g_grdRenderData.dwState & (STATE_TEXORSHADEALPHA | STATE_ALPHABLEND_MASK)) &&
             (((g_grdRenderData.gvVertices[0].specular |
                g_grdRenderData.gvVertices[1].specular |
                g_grdRenderData.gvVertices[2].specular) >> 27) == 0x00))
    {
        // special-case full-intensity non-alpha non-11 fog, which is the same as a flat fill with the fog color
        // NOTE mikeab 11 could be passed through here, if native is turned off, but it's possible there are
        // complications that would need to be addressed
        g_grdRenderData.dwState &= STATE_Z | STATE_ZWRITE | STATE_ZCOMPARE | STATE_ZHANDLER | STATE_PIXDOUBLE;
        g_grdRenderData.dwState |= STATE_SHADECOLOR | STATE_USENATIVE;
        g_grdRenderData.gvVertices[0].color = FROM_MUNGED3_TO_888(g_grdChunkData.m3FogColor);

        // we're turning texture mapping off, which normally can't happen without
        // a state change, so we have to save and restore the normal single-pass
        // chunk processor for the current state
        PSPANFN tptr = rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS];

        // configure correct native-single-pass chunk processor for flat untextured
        if (g_grdChunkData.cPixDouble)
        {
            rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] =
                SpanShadeBackend2X_Native_Flat_NoZ_10_NoAlphaTest;
        }
        else
        {
            rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] =
                SpanShadeBackend_Native_Flat_NoZ_10_NoAlphaTest;
        }

        assert(((g_grdRenderData.dwState >> HANDLER_SHIFT) & HANDLER_MASK) < SIZE_M_RGPHANDLERFN);
        (this->*m_rgphandlerfn[(g_grdRenderData.dwState >> HANDLER_SHIFT) & HANDLER_MASK])();

        // restore normal single-pass chunk processor for the current state
        rgpspanfnTrivialZAndBackend[NATIVE_SINGLE_PASS] = tptr;

        return;
    }

    assert(!(g_grdRenderData.dwState & STATE_PERSPECTIVE));

    if (!(g_grdRenderData.dwState & STATE_SHADECOLOR))
    {
        // if there's no shading, mock up intensity Gouraud so there's something to scale down
        g_grdRenderData.gvVertices[0].color |= 0x00FFFFFF;
        g_grdRenderData.gvVertices[1].color |= 0x00FFFFFF;
        g_grdRenderData.gvVertices[2].color |= 0x00FFFFFF;
        g_grdRenderData.dwState |= STATE_SHADECOLOR | STATE_SHADEGOURAUD | STATE_SHADEI;
    }
    else if (!(g_grdRenderData.dwState & STATE_SHADEGOURAUD))
    {
        // copy the flat color to all vertices for use in Gouraud
        g_grdRenderData.gvVertices[1].color = g_grdRenderData.gvVertices[0].color;
        g_grdRenderData.gvVertices[2].color = g_grdRenderData.gvVertices[0].color;
        g_grdRenderData.dwState |= STATE_SHADEGOURAUD;
    }

#undef _DRAWN_COUNTER_
#define _DRAWN_COUNTER_   ITERATE_AFFINETEXTUREGOURAUDZFOG

#define _AFFINE_
    // generate and draw spans
    #include "..\inc\drawspans.h"
#undef _AFFINE_
}

#include "..\inc\undef.h"

