/////////////////////////////////////////////////////////////////////////////////////////
// ATI 3D RAGE                                                
//
// MipMapping and Texture Compositing Test Application
//
// This demo/test application is an interactive triangle draw program that
// allows the user to experiment with various ATI card options. In particular it
// is useful for experimenting with mip-mapping and texture compositing.
//
//                                                                            
// Copyright (c) 1997 ATI Technologies Inc.  All rights reserved.        
//
/////////////////////////////////////////////////////////////////////////////////////////


#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
#include <ddraw.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
#include <direct.h>
#include "resource.h"
#include "ati3dcif.h"
#include "exutil.h"
#include "glob.h"

#include <commctrl.h>
#include "resrc1.h"
#include <assert.h>
#include <crtdbg.h>



// If you are running on a chip that is earlier than a Rage3, you want to not
// define RAGE3. This indicates to the program that it cannot do things like
// texture compositing. This program should really check the caps bits for the chip
// to determine all this at run-time.
#define RAGE3


// The dialog box for entering vertice information assumes U,V values like D3D and does
// the multiply conversions on the fly before sending them to the hardware to make S,T values.
// Define Multiply as FALSE if you want to actually send U,V values to the hardware, not the
// S,T equivalents.
#define Multiply TRUE


#define NAME "RAGE Mip-Map and Texture Composite Tester"
#define TITLE "RAGE Mip-Map and Texture Composite Tester"
#define MAX_MAPS 11

// There may some bugs related to using more or less than 8 maps. So keep this at 8 for now.
// Instead of dynalically taking a single 128*128 map and calculating the equivalent smaller
// maps on the fly, we purposely want to load an entirely different texture for each of the mip
// levels.
#define MAPS 8

// The primary texture is mip mapped, however it is assumed that there are 8 individual
// textures for the primary, each one representing  a mip level and is a power of 2 in size.
// From 128*128 down to 1*1. The loading of these textures assumes the following format:
//	base1.bmp - 128*128
//	base2.bmp - 64*64
//	base3.bmp - 32*32
//	base4.bmp - 16*16
//	base5.bmp - 8*8
//	base6.bmp - 4*4
//	base7.bmp - 2*2
//	base8.bmp - 1*1
#define PRIMARY_BMP   "..\\bmpetc\\base"


// The secondary texture cannot be mipmapped. It is a single texture that is the same
// size as the largest primary. In this case 128*128.
#define SECONDARY_BMP   "..\\bmpetc\\lines.bmp"



#define MAXDELAY    2500.0f
#define MINDELAY    50.0f
#define DELTADELAY  10.0f


#define ID_TIMER 1
#ifdef EMU
#define WAIT_TIME 2500
#else
#define WAIT_TIME 150
#endif



// Prototype.
BOOL CALLBACK DlgVertPropProc(HWND, UINT, WPARAM, LPARAM);
void CloseApp (void);
void DrawFrame (void);
const char *ErrString(HRESULT err);
void STtoUV();
void UVtoST();
int DoCompositing(WPARAM, HMENU);

BOOL UnloadAllTexture (PPALTEXTURE pTex);
BOOL LoadAllTexture (const char* lpszTexFilename, PPALTEXTURE pTex, C3D_ETEXFMT texfmt);


#ifndef SETUP
// Primary Texture
// Support up to MAX_MAPS textures as Mip Mapped. Want to start numbering at 1, and 
// reserve the 0 element. Each texture is registered normally, Texture 1 is stored
// in element 1, and so on. Element 0, holds the same textures, all registered as a
// Mip Map.
PALTEXTURE gMipMapTex[MAX_MAPS + 1] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
#endif


// Secondary Texture


//TEXTURE gTex = {0};

PALTEXTURE gTex = {0};
PALTEXTURE gTex2 = {0};

static HWND g_hDlgVertProp;

// Window handle.
HWND    ghWnd;

// CIF Context States
BOOL			gbTMap = FALSE;
BOOL			gbComp = FALSE;
BOOL			gBorderState = TRUE;
BOOL			gHiResState = FALSE;
C3D_ETLIGHT		gLight = C3D_ETL_NONE;
C3D_COLOR		gColor = {0,0,0,0};
C3D_ETPERSPCOR	gTPerspCor = C3D_ETPC_NONE;
C3D_ESHADE		gShade = C3D_ESH_SOLID;
C3D_EASRC		gSrcABlend = C3D_EASRC_ONE;
C3D_EADST		gDstABlend = C3D_EADST_ZERO;
//C3D_BOOL		gbFog = FALSE;
C3D_ETEXOP		gTexOp = C3D_ETEXOP_NONE;
C3D_ETEXFILTER  gTexFilter = C3D_ETFILT_MINPNT_MAGPNT;
C3D_ETEXFILTER  gCombBlend = C3D_ETFILT_MINPNT_MAGPNT;

C3D_ETEXCOMPFCN gCombFcn = C3D_ETEXCOMPFCN_BLEND;
C3D_UINT32		gCombFactor = 8;
C3D_UINT32		gLODBias = 0;
C3D_UINT32		gCombAlphaState = FALSE;
C3D_ETEXFMT		g332 = C3D_ETF_RGB332;


// Menu States
static BOOL iRenderState = FALSE;
static BOOL iRenderTick = TRUE;
static int	iTexState = ID_TEXTURES_OFF;

static int	iCombFcnState = ID_COMPOSITING_COMBINEFUNCTION_BLEND;

static int	iLODBiasState = ID_MIPMAPPING_LODBIAS_0;
static int	iCombFactorState = ID_COMPOSITING_COMPOSITEFACTOR_8;
static int	iCompState = ID_COMP_OFF;
static int	iPCorrState = ID_PCORR_ONE;
static int	iTFilterState = ID_FILTERING_MINPNT_MAGPNT;
static BOOL iRenderOnlyTriangle = TRUE;
static int	iShadeState = ID_SHADING_SOLID;
static int	iColorState = ID_SOLIDCOLOR_RED;
static int	iLightState = ID_LIGHTING_NONE;
static int	iSrcABlend = ID_ALPHASRC_ONE;
static int	iDstABlend = ID_ALPHADST_ZERO;
static int	iTexOpState = ID_TEXTUREOPS_NONE;
static BOOL iBorderState = ID_RENDER_BORDER_ON;
static BOOL iHiResState = ID_RENDER_HIRESOFF;
static int  iCombBlendState = ID_COMPBLEND_FILTERING_MINPNT_MAGPNT;


//Other States
BOOL    gbDrawFrame = FALSE;
BOOL    gbDisplayFrameRate = FALSE;
float   gfMaxDelay = 1000.0f;
static BOOL options = FALSE;
static BOOL grid = FALSE;
static int mousex, mousey;
static int full = FALSE;
static int iCount = 0;
static int pitch_factor = 2;

#ifndef SETUP
// Vertice Definitions
C3D_PVTCF Src1[MAPS * 4];		// Primary Source
C3D_PVTCF Src2[MAPS * 4];		// Secondary Source
C3D_VTCF Src1List[MAPS * 4];	// Primary Source
C3D_VTCF Src2List[MAPS * 4];	// Secondary Source
#endif



// Rendered Triangle
C3D_VTCF Dst[3] = { 
    { 200.0f, 400.0f, 0.0f, 0.0f, 1.0f, 1.0f, 255.0f, 0.0f, 0.0f, 0.5f},  // v0
    { 540.0f, 400.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 255.0f, 0.0f, 0.5f},  // v1
    { 530.0f, 250.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 255.0f, 0.5f}   // v2
};


// GDI triangle
C3D_VTCF Border[3] = { 
    { 200.0f, 400.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.5f},  // v0
    { 540.0f, 400.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.5f},  // v1
    { 530.0f, 250.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.5f}   // v2
};


// Calculate vertices that the setup engine will use when detrmining fill.
// Caixia suggested using this calculation to ensure that the GDI border triangle
// used as a reference against the rendered one is more accurate.
float CalcVert(float val)
{
	div_t t;
	float u;
	int tmp;
	tmp = (int)(val * 4.0);
	t = div(tmp, 4);
	u = (float)t.quot + ((float)t.rem/4);
	return(u);
}



// Generate rectangle vertices of Primary Source. It is a series of rectangles set to
// the appropriate sixe for the MipMaps. These are used for rendering each of the source 
// MipMaps to the screen separately for viewing during test.
void BuildSrc1(int xoff, int yoff)
{
int map;
int rect;
int rect_addr;

for (rect=0; (rect < MAPS); rect++)
	{
	rect_addr = rect * 4;

	if (rect == 0)
		map = 1;
	else
		map = map * 2;

	Src1List[0+rect_addr].x = 0.0f  + (map * 2 + 5);
	Src1List[0+rect_addr].y = 0.0f  + (float)25.0;
	Src1List[0+rect_addr].s = 0.0f;
	Src1List[0+rect_addr].t = 0.0f;
	Src1List[0+rect_addr].w = 1.0f;
	Src1List[0+rect_addr].r = 255.0f;
//rc1List[0+rect_addr].g = 0.0f;
//rc1List[0+rect_addr].b = 0.0f;
	Src1List[0+rect_addr].g = 255.0f;
	Src1List[0+rect_addr].b = 255.0f;
	Src1List[0+rect_addr].a = 0.0f;

	Src1List[1+rect_addr].x = 0.0f  + (map * 2 + 5);
	Src1List[1+rect_addr].y = map  + (float)25.0;
	Src1List[1+rect_addr].s = 0.0f;
	Src1List[1+rect_addr].t = 1.0f;
	Src1List[1+rect_addr].w = 1.0f;
//	Src1List[1+rect_addr].r = 0.0f;
	Src1List[1+rect_addr].r = 255.0f;
	Src1List[1+rect_addr].g = 255.0f;
//	Src1List[1+rect_addr].b = 0.0f;
	Src1List[1+rect_addr].b = 255.0f;
	Src1List[1+rect_addr].a = 0.0f;

	Src1List[2+rect_addr].x = map  + (float)(map * 2.0 + 5.0);
	Src1List[2+rect_addr].y = map  + (float)25.0;
	Src1List[2+rect_addr].s = 1.0f;
	Src1List[2+rect_addr].t = 1.0f;
	Src1List[2+rect_addr].w = 1.0f;
//	Src1List[2+rect_addr].r = 0.0f;
//	Src1List[2+rect_addr].g = 0.0f;
	Src1List[2+rect_addr].r = 255.0f;
	Src1List[2+rect_addr].g = 255.0f;
	Src1List[2+rect_addr].b = 255.0f;
	Src1List[2+rect_addr].a = 0.0f;

	Src1List[3+rect_addr].x = map  + (float)(map * 2.0 + 5.0);
	Src1List[3+rect_addr].y = (float)0.0  + (float)25.0;
	Src1List[3+rect_addr].s = 1.0f;
	Src1List[3+rect_addr].t = 0.0f;
	Src1List[3+rect_addr].w = 1.0f;
//	Src1List[3+rect_addr].r = 0.0f;
//	Src1List[3+rect_addr].g = 0.0f;
	Src1List[3+rect_addr].r = 255.0f;
	Src1List[3+rect_addr].g = 255.0f;
	Src1List[3+rect_addr].b = 255.0f;
	Src1List[3+rect_addr].a = 0.0f;
	}
}




// Generate rectangle vertices of Primary Source. It is a series of rectangles set to
// the appropriate sixe for the MipMaps. These are used for rendering each of the source 
// MipMaps to the screen separately for viewing during test.
// NOTE: since the Secondary source cannot be MipMapped, only the largest base is used.
void BuildSrc2(int xoff, int yoff)
{
int map;
int rect;
int rect_addr;

for (rect=0; (rect < MAPS); rect++)
	{
	rect_addr = rect * 4;

	if (rect == 0)
		map = 0;
	else if (rect == 1)
		map = 2;
	else
		map = map * 2;

	Src2List[0+rect_addr].x = 0.0f  + 225 + (map * 2 + 5);
	Src2List[0+rect_addr].y = 0.0f  + 25;
	Src2List[0+rect_addr].s = 0.0f;
	Src2List[0+rect_addr].t = 0.0f;
	Src2List[0+rect_addr].w = 1.0f;
	Src2List[0+rect_addr].r = 0.0f;
	Src2List[0+rect_addr].g = 0.0f;
	Src2List[0+rect_addr].b = 255.0f;
	Src2List[0+rect_addr].a = 0.0f;

	Src2List[1+rect_addr].x = 0  + (float)225.0 + (map * 2 + 5);
	Src2List[1+rect_addr].y = map  + (float)25.0;
	Src2List[1+rect_addr].s = 0.0f;
	Src2List[1+rect_addr].t = 1.0f;
	Src2List[1+rect_addr].w = 1.0f;
	Src2List[1+rect_addr].r = 0.0f;
	Src2List[1+rect_addr].g = 255.0f;
	Src2List[1+rect_addr].b = 0.0f;
	Src2List[1+rect_addr].a = 0.0f;

	Src2List[2+rect_addr].x = map  + (float)225.0 + (map * 2 + 5);
	Src2List[2+rect_addr].y = map  + (float)25.0;
	Src2List[2+rect_addr].s = 1.0f;
	Src2List[2+rect_addr].t = 1.0f;
	Src2List[2+rect_addr].w = 1.0f;
	Src2List[2+rect_addr].r = 255.0f;
	Src2List[2+rect_addr].g = 0.0f;
	Src2List[2+rect_addr].b = 0.0f;
	Src2List[2+rect_addr].a = 0.0f;

	Src2List[3+rect_addr].x = map  + (float)225.0 + (float)(map * 2.0 + 5.0);
	Src2List[3+rect_addr].y = 0  + (float)25.0;
	Src2List[3+rect_addr].s = 1.0f;
	Src2List[3+rect_addr].t = 0.0f;
	Src2List[3+rect_addr].w = 1.0f;
	Src2List[3+rect_addr].r = 0.0f;
	Src2List[3+rect_addr].g = 0.0f;
	Src2List[3+rect_addr].b = 0.0f;
	Src2List[3+rect_addr].a = 0.0f;
	}
}





// The vertices of the rendered triangle contain a value for S,T,W or  U,V,W. The 
// interpretation depends on whether or not the next two function are called to
// convert from one to the other. CIF always expects to get S,T,W, however calling
// UVtoST prior to rendering, and STtoUV after rendering will effectively treat the
// S,T,W as UV.

// Assumes that the s and t element of each vertice is really u and v
// and calculates the real u and v
void UVtoST()
{
if (!Multiply) return;

	Dst[0].s *= Dst[0].w;
	Dst[0].t *= Dst[0].w;

	Dst[1].s *= Dst[1].w;
	Dst[1].t *= Dst[1].w;

	Dst[2].s *= Dst[2].w;
	Dst[2].t *= Dst[2].w;

}

// Assumes that the s and t element of each vertice actually represents the s and t
// and will be converted back to represent u and v
void STtoUV()
{
if (!Multiply) return;

	Dst[0].s = Dst[0].s / Dst[0].w;
	Dst[0].t = Dst[0].t / Dst[0].w;

	Dst[1].s = Dst[1].s / Dst[1].w;
	Dst[1].t = Dst[1].t / Dst[1].w;

	Dst[2].s = Dst[2].s / Dst[2].w;
	Dst[2].t = Dst[2].t / Dst[2].w;

}




// Window procedure for the vertice property dialog bix
BOOL CALLBACK DlgVertPropProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
char s[20];
char t[20];
char w[20];
	switch (iMsg)
	{
	case WM_INITDIALOG:
		sprintf(s,"%.2f",Dst[0].s);
		sprintf(t,"%.2f",Dst[0].t);
		sprintf(w,"%.5f",Dst[0].w);
        SetDlgItemInt(hDlg, IDC_X1, (UINT)Dst[0].x, TRUE);
        SetDlgItemInt(hDlg, IDC_Y1, (UINT)Dst[0].y, TRUE);
        SetDlgItemInt(hDlg, IDC_Z1, (UINT)Dst[0].z, TRUE);
        SetDlgItemText(hDlg, IDC_S1, s);
        SetDlgItemText(hDlg, IDC_T1, t);
        SetDlgItemText(hDlg, IDC_W1, w);
		

		sprintf(s,"%.2f",Dst[1].s);
		sprintf(t,"%.2f",Dst[1].t);
		sprintf(w,"%.5f",Dst[1].w);
        SetDlgItemInt(hDlg, IDC_X2, (UINT)Dst[1].x, TRUE);
        SetDlgItemInt(hDlg, IDC_Y2, (UINT)Dst[1].y, TRUE);
        SetDlgItemInt(hDlg, IDC_Z2, (UINT)Dst[1].z, TRUE);
        SetDlgItemText(hDlg, IDC_S2, s);
        SetDlgItemText(hDlg, IDC_T2, t);
        SetDlgItemText(hDlg, IDC_W2, w);

		
		sprintf(s,"%.2f",Dst[2].s);
		sprintf(t,"%.2f",Dst[2].t);
		sprintf(w,"%.5f",Dst[2].w);
        SetDlgItemInt(hDlg, IDC_X3, (UINT)Dst[2].x, TRUE);
        SetDlgItemInt(hDlg, IDC_Y3, (UINT)Dst[2].y, TRUE);
        SetDlgItemInt(hDlg, IDC_Z3, (UINT)Dst[2].z, TRUE);
        SetDlgItemText(hDlg, IDC_S3, s);
        SetDlgItemText(hDlg, IDC_T3, t);
        SetDlgItemText(hDlg, IDC_W3, w);

		
		
		// Load values of vertices based on iCount
		return TRUE;

	case WM_MOUSEMOVE:
		if ((wParam) & MK_LBUTTON)
			{
			char s[20];
			char t[20];
			char w[20];

		switch (iCount)
		{
		case 0:
		sprintf(s,"%.2f",Dst[0].s);
		sprintf(t,"%.2f",Dst[0].t);
		sprintf(w,"%.5f",Dst[0].w);
        SetDlgItemInt(hDlg, IDC_X1, (UINT)Dst[0].x, TRUE);
        SetDlgItemInt(hDlg, IDC_Y1, (UINT)Dst[0].y, TRUE);
        SetDlgItemInt(hDlg, IDC_Z1, (UINT)Dst[0].z, TRUE);
        SetDlgItemText(hDlg, IDC_S1, s);
        SetDlgItemText(hDlg, IDC_T1, t);
        SetDlgItemText(hDlg, IDC_W1, w);
		break;


		case 1:
		sprintf(s,"%.2f",Dst[1].s);
		sprintf(t,"%.2f",Dst[1].t);
		sprintf(w,"%.5f",Dst[1].w);
        SetDlgItemInt(hDlg, IDC_X2, (UINT)Dst[1].x, TRUE);
        SetDlgItemInt(hDlg, IDC_Y2, (UINT)Dst[1].y, TRUE);
        SetDlgItemInt(hDlg, IDC_Z2, (UINT)Dst[1].z, TRUE);
        SetDlgItemText(hDlg, IDC_S2, s);
        SetDlgItemText(hDlg, IDC_T2, t);
        SetDlgItemText(hDlg, IDC_W2, w);
		break;
		
		case 2:
		sprintf(s,"%.2f",Dst[2].s);
		sprintf(t,"%.2f",Dst[2].t);
		sprintf(w,"%.5f",Dst[2].w);
        SetDlgItemInt(hDlg, IDC_X3, (UINT)Dst[2].x, TRUE);
        SetDlgItemInt(hDlg, IDC_Y3, (UINT)Dst[2].y, TRUE);
        SetDlgItemInt(hDlg, IDC_Z3, (UINT)Dst[2].z, TRUE);
        SetDlgItemText(hDlg, IDC_S3, s);
        SetDlgItemText(hDlg, IDC_T3, t);
        SetDlgItemText(hDlg, IDC_W3, w);
		break;
		
		}



			}
		break;
		
	case WM_COMMAND:
		switch(LOWORD(wParam))
		{
		case IDC_REFRESH:
		case IDOK:
			char s[20];
			char t[20];
			char w[20];


            Dst[0].x = (float)GetDlgItemInt(hDlg, IDC_X1, NULL, TRUE);
            Dst[0].y = (float)GetDlgItemInt(hDlg, IDC_Y1, NULL, TRUE);
            Dst[0].z = (float)GetDlgItemInt(hDlg, IDC_Z1, NULL, TRUE);
            GetDlgItemText(hDlg, IDC_S1, s, 20);
            GetDlgItemText(hDlg, IDC_T1, t, 20);
            GetDlgItemText(hDlg, IDC_W1, w, 20);
			Dst[0].s = (float)atof(s);
			Dst[0].t = (float)atof(t);
			Dst[0].w = (float)atof(w);
			Border[0].x = Dst[0].x;
			Border[0].y = Dst[0].y;
			Border[0].z = Dst[0].z;


			
		    Dst[1].x = (float)GetDlgItemInt(hDlg, IDC_X2, NULL, TRUE);
            Dst[1].y = (float)GetDlgItemInt(hDlg, IDC_Y2, NULL, TRUE);
            Dst[1].z = (float)GetDlgItemInt(hDlg, IDC_Z2, NULL, TRUE);
            GetDlgItemText(hDlg, IDC_S2, s, 20);
            GetDlgItemText(hDlg, IDC_T2, t, 20);
            GetDlgItemText(hDlg, IDC_W2, w, 20);
			Dst[1].s = (float)atof(s);
			Dst[1].t = (float)atof(t);
			Dst[1].w = (float)atof(w);
			Border[1].x = Dst[1].x;
			Border[1].y = Dst[1].y;
			Border[1].z = Dst[1].z;


            Dst[2].x = (float)GetDlgItemInt(hDlg, IDC_X3, NULL, TRUE);
            Dst[2].y = (float)GetDlgItemInt(hDlg, IDC_Y3, NULL, TRUE);
            Dst[2].z = (float)GetDlgItemInt(hDlg, IDC_Z3, NULL, TRUE);
            GetDlgItemText(hDlg, IDC_S3, s, 20);
            GetDlgItemText(hDlg, IDC_T3, t, 20);
            GetDlgItemText(hDlg, IDC_W3, w, 20);
			Dst[2].s = (float)atof(s);
			Dst[2].t = (float)atof(t);
			Dst[2].w = (float)atof(w);
			Border[2].x = Dst[2].x;
			Border[2].y = Dst[2].y;
			Border[2].z = Dst[2].z;


			
			
			if (LOWORD(wParam) == IDOK)
			{
			g_hDlgVertProp = NULL;
			EndDialog(hDlg, 0);
			}
			return TRUE;
		
		case IDCANCEL:
			g_hDlgVertProp = NULL;
			EndDialog(hDlg, 0);
			return TRUE;

		}
		break;
	}
	return FALSE;
}




// Window procedure for main window
LRESULT CALLBACK WindowProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
HMENU hMenu;
char Debug[128];

static HINSTANCE hInstance;

    switch (message)
    {
	case WM_TIMER:
		if (gbDrawFrame) 
			{
			DrawFrame();
			}
		return 0;

	case WM_CREATE:
			hInstance = ((LPCREATESTRUCT) lParam)->hInstance;
			return 0;
            break;

	case WM_COMMAND:

			hMenu = GetMenu(hWnd);
	
			switch (LOWORD(wParam))
				{
				case ID_COMP_ON:
				case ID_COMP_OFF:
					CheckMenuItem(hMenu, iCompState, MF_UNCHECKED);
					iCompState = LOWORD(wParam);
					CheckMenuItem(hMenu, iCompState, MF_CHECKED);
                    if (iCompState == ID_COMP_OFF)
						{
						gbComp = FALSE;

						}
					else
						{	
						gbComp = TRUE;
						}
					sprintf(Debug,"Set State: C3D_ERS_COMPOSITE_EN=%d\n",gbComp);
					OutputDebugString(Debug);

					return 0;

				case ID_COMPBLEND_FILTERING_MINPNT_MAGPNT:
				case ID_COMPBLEND_FILTERING_MINPNT_MAG2BY2:
				case ID_COMPBLEND_FILTERING_MIN2BY2_MAG2BY2:
				case ID_COMPBLEND_FILTERING_MIPLIN_MAGPNT:
					// Do nothing if the current state is the state we just selected
					if (iCombBlendState == LOWORD(wParam))
						return 0;
					CheckMenuItem(hMenu, iCombBlendState, MF_UNCHECKED);
					iCombBlendState = LOWORD(wParam);
					CheckMenuItem(hMenu, iCombBlendState, MF_CHECKED);
					switch (iCombBlendState)
						{
						case ID_COMPBLEND_FILTERING_MINPNT_MAGPNT:
							gCombBlend = C3D_ETFILT_MINPNT_MAGPNT;
							break;
						case ID_COMPBLEND_FILTERING_MINPNT_MAG2BY2:
							gCombBlend = C3D_ETFILT_MINPNT_MAG2BY2;
							break;
						case ID_COMPBLEND_FILTERING_MIN2BY2_MAG2BY2:
							gCombBlend = C3D_ETFILT_MIN2BY2_MAG2BY2;
							break;
						case ID_COMPBLEND_FILTERING_MIPLIN_MAGPNT:
							gCombBlend = C3D_ETFILT_MIPLIN_MAGPNT;
							break;
						}
					sprintf(Debug,"Set State: C3D_ERS_COMPOSITE_FILTER=%d\n",gCombBlend );
					OutputDebugString(Debug);
                    ATI3DCIF_ContextSetState (ghRC, C3D_ERS_COMPOSITE_FILTER, &gCombBlend);

					return 0;

				
				case ID_COMPOSITING_COMPOSITEFACTOR_0:
				case ID_COMPOSITING_COMPOSITEFACTOR_1:
				case ID_COMPOSITING_COMPOSITEFACTOR_2:
				case ID_COMPOSITING_COMPOSITEFACTOR_3:
				case ID_COMPOSITING_COMPOSITEFACTOR_4:
				case ID_COMPOSITING_COMPOSITEFACTOR_5:
				case ID_COMPOSITING_COMPOSITEFACTOR_6:
				case ID_COMPOSITING_COMPOSITEFACTOR_7:
				case ID_COMPOSITING_COMPOSITEFACTOR_8:
				case ID_COMPOSITING_COMPOSITEFACTOR_9:
				case ID_COMPOSITING_COMPOSITEFACTOR_10:
				case ID_COMPOSITING_COMPOSITEFACTOR_11:
				case ID_COMPOSITING_COMPOSITEFACTOR_12:
				case ID_COMPOSITING_COMPOSITEFACTOR_13:
				case ID_COMPOSITING_COMPOSITEFACTOR_14:
				case ID_COMPOSITING_COMPOSITEFACTOR_15:
					// Do nothing if the current state is the state we just selected
					if (iCombFactorState == LOWORD(wParam))
						return 0;
					CheckMenuItem(hMenu, iCombFactorState, MF_UNCHECKED);
					iCombFactorState = LOWORD(wParam);
					CheckMenuItem(hMenu, iCombFactorState, MF_CHECKED);

					gCombFactor = (iCombFactorState - ID_COMPOSITING_COMPOSITEFACTOR_0);
					sprintf(Debug,"Set State: C3D_ERS_COMPOSITE_FACTOR=%d\n",gCombFactor );
					OutputDebugString(Debug);
                    ATI3DCIF_ContextSetState (ghRC, C3D_ERS_COMPOSITE_FACTOR, &gCombFactor);


					// If we set a composite factor, than we do not want the chip to
					// use alpha, we want it to use th efactor we are setting here.
					gCombAlphaState = FALSE;
					sprintf(Debug,"Set State: C3D_ERS_COMPOSITE_FACTOR_ALPHA=0\n");
					OutputDebugString(Debug);
                    ATI3DCIF_ContextSetState (ghRC, C3D_ERS_COMPOSITE_FACTOR_ALPHA, &gCombAlphaState);


					return 0;




				case ID_MIPMAPPING_LODBIAS_0:
				case ID_MIPMAPPING_LODBIAS_1:
				case ID_MIPMAPPING_LODBIAS_2:
				case ID_MIPMAPPING_LODBIAS_3:
				case ID_MIPMAPPING_LODBIAS_4:
				case ID_MIPMAPPING_LODBIAS_5:
				case ID_MIPMAPPING_LODBIAS_6:
				case ID_MIPMAPPING_LODBIAS_7:
				case ID_MIPMAPPING_LODBIAS_8:
				case ID_MIPMAPPING_LODBIAS_9:
				case ID_MIPMAPPING_LODBIAS_10:
				case ID_MIPMAPPING_LODBIAS_11:
				case ID_MIPMAPPING_LODBIAS_12:
				case ID_MIPMAPPING_LODBIAS_13:
				case ID_MIPMAPPING_LODBIAS_14:
				case ID_MIPMAPPING_LODBIAS_15:
					// Do nothing if the current state is the state we just selected
					if (iLODBiasState == LOWORD(wParam))
						return 0;
					CheckMenuItem(hMenu, iLODBiasState, MF_UNCHECKED);
					iLODBiasState = LOWORD(wParam);
					CheckMenuItem(hMenu, iLODBiasState, MF_CHECKED);

					gLODBias = (iLODBiasState - ID_MIPMAPPING_LODBIAS_0);
					sprintf(Debug,"Set State: C3D_ERS_LOD_BIAS_ENABLE=%d\n",gLODBias );
					OutputDebugString(Debug);
                    ATI3DCIF_ContextSetState (ghRC, C3D_ERS_LOD_BIAS_LEVEL, &gLODBias);
					return 0;


					
				case ID_COMPOSITING_COMPOSITEFACTOR_ALPHA:
					// Do nothing if the current state is the state we just selected
					if (iCombFactorState == LOWORD(wParam))
						return 0;
					CheckMenuItem(hMenu, iCombFactorState, MF_UNCHECKED);
					iCombFactorState = LOWORD(wParam);
					CheckMenuItem(hMenu, ID_COMPOSITING_COMPOSITEFACTOR_ALPHA, MF_CHECKED);
					// Turning Alpha on.
					gCombAlphaState = TRUE;
					sprintf(Debug,"Set State: C3D_ERS_COMPOSITE_FACTOR_ALPHA=1\n");
					OutputDebugString(Debug);
                    ATI3DCIF_ContextSetState (ghRC, C3D_ERS_COMPOSITE_FACTOR_ALPHA, &gCombAlphaState);
					return 0;


				case ID_COMPOSITING_COMBINEFUNCTION_BLEND:
				case ID_COMPOSITING_COMBINEFUNCTION_MODULATE:
				case ID_COMPOSITING_COMBINEFUNCTION_ADDSPECULAR:

					// Do nothing if the current state is the state we just selected
					if (iCombFcnState == LOWORD(wParam))
						return 0;
					CheckMenuItem(hMenu, iCombFcnState, MF_UNCHECKED);
					iCombFcnState = LOWORD(wParam);
					CheckMenuItem(hMenu, iCombFcnState, MF_CHECKED);
					switch (iCombFcnState)
						{
						case ID_COMPOSITING_COMBINEFUNCTION_BLEND:
							gCombFcn = C3D_ETEXCOMPFCN_BLEND;
							break;
						case ID_COMPOSITING_COMBINEFUNCTION_MODULATE:
							gCombFcn = C3D_ETEXCOMPFCN_MOD;
							break;
						case ID_COMPOSITING_COMBINEFUNCTION_ADDSPECULAR:
							gCombFcn = C3D_ETEXCOMPFCN_ADD_SPEC;
							break;
						}
					sprintf(Debug,"Set State: C3D_ERS_COMPOSITE_FNC=%d\n",gCombFcn );
					OutputDebugString(Debug);
                    ATI3DCIF_ContextSetState (ghRC, C3D_ERS_COMPOSITE_FNC, &gCombFcn);

					return 0;
			
			
			
				case ID_RENDER_BORDER_ON:
				case ID_RENDER_BORDER_OFF:
					CheckMenuItem(hMenu, iBorderState, MF_UNCHECKED);
					iBorderState = LOWORD(wParam);
					CheckMenuItem(hMenu, iBorderState, MF_CHECKED);
					gBorderState = !gBorderState;
					sprintf(Debug,"Border State=%d\n",gBorderState);
					OutputDebugString(Debug);
					return 0;

					
				case ID_RENDER_HIRESON:
				case ID_RENDER_HIRESOFF:
					CheckMenuItem(hMenu, iHiResState, MF_UNCHECKED);
					iHiResState = LOWORD(wParam);
					CheckMenuItem(hMenu, iHiResState, MF_CHECKED);
					gHiResState = !gHiResState;
					sprintf(Debug,"HiRes State=%d\n",gHiResState);
					OutputDebugString(Debug);
					return 0;



				case ID_TEXTURES_OFF:
				case ID_TEXTURES_ON:
					CheckMenuItem(hMenu, iTexState, MF_UNCHECKED);
					iTexState = LOWORD(wParam);
					CheckMenuItem(hMenu, iTexState, MF_CHECKED);
                    if (iTexState == ID_TEXTURES_OFF)
						{
						gbTMap = FALSE;

						}
					else
						{	
						gbTMap = TRUE;
						}
					sprintf(Debug,"Set State: C3D_ERS_TMAP_EN=%d\n",gbTMap);
					OutputDebugString(Debug);
					ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_EN, &gbTMap);
					return 0;

				case ID_TEXTURES_ONLYTRIANGLE:
					iRenderOnlyTriangle = !iRenderOnlyTriangle;
					sprintf(Debug,"Render Only Triangle: %d\n",iRenderOnlyTriangle);
					OutputDebugString(Debug);
					if (iRenderOnlyTriangle)
						{
						CheckMenuItem(hMenu, ID_TEXTURES_ONLYTRIANGLE, MF_CHECKED);
						}
					else
						{
						CheckMenuItem(hMenu, ID_TEXTURES_ONLYTRIANGLE, MF_UNCHECKED);
						}
					return 0;

				case ID_RENDER_OFF:
					CheckMenuItem(hMenu, ID_RENDER_ON, MF_UNCHECKED);
					CheckMenuItem(hMenu, ID_RENDER_OFF, MF_CHECKED);
					iRenderState = FALSE;
					EnableMenuItem(hMenu, ID_RENDER_TICK, MF_ENABLED);  
					sprintf(Debug,"Render State: %d\n",iRenderState);
					OutputDebugString(Debug);
					return 0;


				case ID_RENDER_ON:
					CheckMenuItem(hMenu, ID_RENDER_OFF, MF_UNCHECKED);
					CheckMenuItem(hMenu, ID_RENDER_ON, MF_CHECKED);
					iRenderState = TRUE;
					EnableMenuItem(hMenu, ID_RENDER_TICK, MF_GRAYED);  
					sprintf(Debug,"Render State: %d\n",iRenderState);
					OutputDebugString(Debug);
					return 0;


				case ID_RENDER_TICK:
					iRenderTick = TRUE;
					sprintf(Debug,"Draw Frame State: %d\n",iRenderTick);
					OutputDebugString(Debug);
					return 0;

					
				

				case ID_PCORR_ONE:
				case ID_PCORR_TWO:
				case ID_PCORR_THREE:
				case ID_PCORR_FOUR:
				case ID_PCORR_FIVE:
				case ID_PCORR_SIX:
				case ID_PCORR_SEVEN:
				case ID_PCORR_EIGHT:
				case ID_PCORR_NINE:
				case ID_PCORR_NONE:
					// Do nothing if the current state is the state we just selected
					if (iPCorrState == LOWORD(wParam))
						return 0;
					CheckMenuItem(hMenu, iPCorrState, MF_UNCHECKED);
					iPCorrState = LOWORD(wParam);
					CheckMenuItem(hMenu, iPCorrState, MF_CHECKED);
					switch (iPCorrState)
						{
						case ID_PCORR_NONE:
							gTPerspCor = C3D_ETPC_NONE;
							break;
						case ID_PCORR_ONE:
							gTPerspCor = C3D_ETPC_ONE;
							break;
						case ID_PCORR_TWO:
							gTPerspCor = C3D_ETPC_TWO;
							break;
						case ID_PCORR_THREE:
							gTPerspCor = C3D_ETPC_THREE;
							break;
						case ID_PCORR_FOUR:
							gTPerspCor = C3D_ETPC_FOUR;
							break;
						case ID_PCORR_FIVE:
							gTPerspCor = C3D_ETPC_FIVE;
							break;
						case ID_PCORR_SIX:
							gTPerspCor = C3D_ETPC_SIX;
							break;
						case ID_PCORR_SEVEN:
							gTPerspCor = C3D_ETPC_SEVEN;
							break;
						case ID_PCORR_EIGHT:
							gTPerspCor = C3D_ETPC_EIGHT;
							break;
						case ID_PCORR_NINE:
							gTPerspCor = C3D_ETPC_NINE;
							break;
						}
					sprintf(Debug,"Set State: C3D_ERS_TMAP_PERSP_COR=%d\n",gTPerspCor );
					OutputDebugString(Debug);
                    ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_PERSP_COR, &gTPerspCor);
					return 0;

				case ID_FILTERING_MINPNT_MAGPNT:
				case ID_FILTERING_MINPNT_MAG2BY2:
				case ID_FILTERING_MIN2BY2_MAG2BY2:
				case ID_FILTERING_MIPLIN_MAGPNT:
				case ID_FILTERING_MIPLIN_MAG2BY2:
				case ID_FILTERING_MIPTRI_MAG2BY2: // New for Rage3
				case ID_FILTERING_MIN2BY2_MAGPNT:   // New for Rage3
					// Do nothing if the current state is the state we just selected
					if (iTFilterState == LOWORD(wParam))
						return 0;
					CheckMenuItem(hMenu, iTFilterState, MF_UNCHECKED);
					iTFilterState = LOWORD(wParam);
					CheckMenuItem(hMenu, iTFilterState, MF_CHECKED);
					switch (iTFilterState)
						{
						case ID_FILTERING_MINPNT_MAGPNT:
							gTexFilter = C3D_ETFILT_MINPNT_MAGPNT;
							break;
						case ID_FILTERING_MINPNT_MAG2BY2:
							gTexFilter = C3D_ETFILT_MINPNT_MAG2BY2;
							break;
						case ID_FILTERING_MIN2BY2_MAG2BY2:
							gTexFilter = C3D_ETFILT_MIN2BY2_MAG2BY2;
							break;
						case ID_FILTERING_MIPLIN_MAGPNT:
							gTexFilter = C3D_ETFILT_MIPLIN_MAGPNT;
							break;
						case ID_FILTERING_MIPLIN_MAG2BY2:
							gTexFilter = C3D_ETFILT_MIPLIN_MAG2BY2;
							break;
						case ID_FILTERING_MIPTRI_MAG2BY2: // New for Rage3
							gTexFilter = C3D_ETFILT_MIPTRI_MAG2BY2;
							break;
						case ID_FILTERING_MIN2BY2_MAGPNT:   // New for Rage3
							gTexFilter = C3D_ETFILT_MIN2BY2_MAGPNT;
							break;
						}
					sprintf(Debug,"Set State: C3D_ERS_TMAP_FILTER=%d\n",gTexFilter);
					OutputDebugString(Debug);
                    ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_FILTER, &gTexFilter);
                    return 0;

				case ID_TEXTUREOPS_NONE:
				case ID_TEXTUREOPS_CHROMAKEY:
				case ID_TEXTUREOPS_ALPHA:
				case ID_TEXTUREOPS_ALPHAMASK:
					// Do nothing if the current state is the state we just selected
					if (iTexOpState == LOWORD(wParam))
						return 0;
					CheckMenuItem(hMenu, iTexOpState, MF_UNCHECKED);
					iTexOpState = LOWORD(wParam);
					CheckMenuItem(hMenu, iTexOpState, MF_CHECKED);
					switch (iTexOpState)
						{
						// Texel op modes: determines how which operations are applied to texels as 
						//      they are read from the texture.  By design theses are orthogonal to 
						//      filtering modes. 
						//
						case ID_TEXTUREOPS_NONE:
							gTexOp = C3D_ETEXOP_NONE;
							break;
						case ID_TEXTUREOPS_CHROMAKEY:
							gTexOp = C3D_ETEXOP_CHROMAKEY; // select texels not equal to the chroma key
							break;
						case ID_TEXTUREOPS_ALPHA:
							gTexOp = C3D_ETEXOP_ALPHA;// pass texel alpha to the alpha blender
							break;
						case ID_TEXTUREOPS_ALPHAMASK:
							gTexOp = C3D_ETEXOP_ALPHA_MASK;// lw bit 0: tex not drawn otw: alpha int
							break;
						}
					sprintf(Debug,"Set State: C3D_ERS_TMAP_TEXOP=%d\n",gTexOp);
					OutputDebugString(Debug);
					ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_TEXOP, &gTexOp);
					return 0;

				case ID_LIGHTING_NONE:
				case ID_LIGHTING_MODULATE:
				case ID_LIGHTING_ALPHADECAL:
					// Do nothing if the current state is the state we just selected
					if (iLightState == LOWORD(wParam))
						return 0;
					CheckMenuItem(hMenu, iLightState, MF_UNCHECKED);
					iLightState = LOWORD(wParam);
					CheckMenuItem(hMenu, iLightState, MF_CHECKED);
					switch (iLightState)
						{
						case ID_LIGHTING_NONE:
							gLight = C3D_ETL_NONE;
							break;
						case ID_LIGHTING_MODULATE:
							gLight = C3D_ETL_MODULATE;
							break;
						case ID_LIGHTING_ALPHADECAL:
							gLight = C3D_ETL_ALPHA_DECAL;
							break;
						}
					sprintf(Debug,"Set State: C3D_ERS_TMAP_LIGHT=%d\n",gLight);
					OutputDebugString(Debug);
					ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_LIGHT, &gLight);
					return 0;

                case ID_SHADING_NONE:
                case ID_SHADING_SOLID:
                case ID_SHADING_FLAT:
                case ID_SHADING_SMOOTH:
					// Do nothing if the current state is the state we just selected
					if (iShadeState == LOWORD(wParam))
						return 0;
					CheckMenuItem(hMenu, iShadeState, MF_UNCHECKED);
					iShadeState = LOWORD(wParam);
					CheckMenuItem(hMenu, iShadeState, MF_CHECKED);
					switch (iShadeState)
						{
						case ID_SHADING_NONE:
							gShade = C3D_ESH_NONE;
							break;
						case ID_SHADING_SOLID:
							gShade = C3D_ESH_SOLID;
							break;
						case ID_SHADING_FLAT:
							gShade = C3D_ESH_FLAT;
							break;
						case ID_SHADING_SMOOTH:
							gShade = C3D_ESH_SMOOTH;
							break;
						}
					sprintf(Debug,"Set State: C3D_ERS_SHADE_MODE=%d\n",gShade);
					OutputDebugString(Debug);
       				ATI3DCIF_ContextSetState (ghRC, C3D_ERS_SHADE_MODE, &gShade);
					return 0;


                case ID_SOLIDCOLOR_WHITE:
                case ID_SOLIDCOLOR_RED:
                case ID_SOLIDCOLOR_GREEN:
                case ID_SOLIDCOLOR_BLUE:
					// Do nothing if the current state is the state we just selected
					if (iColorState == LOWORD(wParam))
						return 0;
					CheckMenuItem(hMenu, iColorState, MF_UNCHECKED);
					iColorState = LOWORD(wParam);
					CheckMenuItem(hMenu, iColorState, MF_CHECKED);
					switch (iColorState)
						{
						case ID_SOLIDCOLOR_WHITE:
							// White.
							SET_CIF_COLOR (gColor, 0xff, 0xff, 0xff, 0xff);
							break;
						case ID_SOLIDCOLOR_RED:
							// Red.
							SET_CIF_COLOR (gColor, 0xff, 0x00, 0x00, 0x00);
							break;
						case ID_SOLIDCOLOR_GREEN:
							// Green.
							SET_CIF_COLOR (gColor, 0x00, 0xff, 0x00, 0x00);
							break;
						case ID_SOLIDCOLOR_BLUE:
							// Blue.
							SET_CIF_COLOR (gColor, 0x00, 0x00, 0xff, 0x00);
							break;
						} // switch
					sprintf(Debug,"Set State: C3D_ERS_SOLID_CLR= r:%d b:%d g:%d a:%d\n",gColor.r,gColor.b,gColor.g,gColor.a);
					OutputDebugString(Debug);
                    ATI3DCIF_ContextSetState (ghRC, C3D_ERS_SOLID_CLR, &gColor);
                    return 0;


				case ID_ALPHASRC_ZERO:        
				case ID_ALPHASRC_ONE:             
				case ID_ALPHASRC_DESTINATION: 
				case ID_ALPHASRC_INVERSEDESTINATION:
				case ID_ALPHASRC_SOURCEALPHA:    
				case ID_ALPHASRC_INVERSESOURCEALPHA: 
					// Do nothing if the current state is the state we just selected
					if (iSrcABlend == LOWORD(wParam))
						return 0;
					CheckMenuItem(hMenu, iSrcABlend, MF_UNCHECKED);
					iSrcABlend = LOWORD(wParam);
					CheckMenuItem(hMenu, iSrcABlend, MF_CHECKED);
					switch (iSrcABlend)
						{
						case ID_ALPHASRC_ZERO:
							gSrcABlend = C3D_EASRC_ZERO;
							break;
						case ID_ALPHASRC_ONE:           
							gSrcABlend = C3D_EASRC_ONE;
							break;
						case ID_ALPHASRC_DESTINATION: 
							gSrcABlend = C3D_EASRC_DSTCLR;
							break;
						case ID_ALPHASRC_INVERSEDESTINATION:
							gSrcABlend = C3D_EASRC_INVDSTCLR;
							break;
						case ID_ALPHASRC_SOURCEALPHA:    
							gSrcABlend = C3D_EASRC_SRCALPHA;
							break;
						case ID_ALPHASRC_INVERSESOURCEALPHA: 
							gSrcABlend = C3D_EASRC_INVSRCALPHA;
							break;
						}
						sprintf(Debug,"Set State: C3D_ERS_ALPHA_SRC=%d\n",gSrcABlend);
						OutputDebugString(Debug);
                        ATI3DCIF_ContextSetState (ghRC, C3D_ERS_ALPHA_SRC, &gSrcABlend);
						return 0;


				case ID_ALPHADST_ZERO:          
				case ID_ALPHADST_ONE:              
				case ID_ALPHADST_SOURCE:          
				case ID_ALPHADST_INVERSESOURCE:
				case ID_ALPHADST_SOURCEALPHA:          
				case ID_ALPHADST_INVERSESOURCEALPHA:  

					// Do nothing if the current state is the state we just selected
					if (iDstABlend == LOWORD(wParam))
						return 0;
					CheckMenuItem(hMenu, iDstABlend, MF_UNCHECKED);
					iDstABlend = LOWORD(wParam);
					CheckMenuItem(hMenu, iDstABlend, MF_CHECKED);
					switch (iDstABlend)
						{
						case ID_ALPHADST_ZERO:
							gDstABlend = C3D_EADST_ZERO;
							break;
						case ID_ALPHADST_ONE:           
							gDstABlend = C3D_EADST_ONE;
							break;
						case ID_ALPHADST_SOURCE: 
							gDstABlend = C3D_EADST_SRCCLR;
							break;
						case ID_ALPHADST_INVERSESOURCE:
							gDstABlend = C3D_EADST_INVSRCCLR;
							break;
						case ID_ALPHADST_SOURCEALPHA: 
							gDstABlend = C3D_EADST_SRCALPHA;
							break;
						case ID_ALPHADST_INVERSESOURCEALPHA:    
							gDstABlend = C3D_EADST_INVSRCALPHA;
							break;
						}
						sprintf(Debug,"Set State: C3D_ERS_ALPHA_DST=%d\n",gDstABlend);
						OutputDebugString(Debug);
                        ATI3DCIF_ContextSetState (ghRC, C3D_ERS_ALPHA_DST, &gDstABlend);
						return 0;




				case ID_RENDER_SHOWSTATES:
					OutputDebugString("\n---Begin States---\n");
					sprintf(Debug,"Render State: %d\n",iRenderState);
					OutputDebugString(Debug);
					sprintf(Debug,"Render Only Triangle: %d\n",iRenderOnlyTriangle);
					OutputDebugString(Debug);
					sprintf(Debug,"Draw Frame State: %d\n",iRenderTick);
					OutputDebugString(Debug);
					sprintf(Debug,"State: C3D_ERS_TMAP_EN=%d\n",gbTMap);
					OutputDebugString(Debug);
					sprintf(Debug,"State: C3D_ERS_TMAP_PERSP_COR=%d\n",gTPerspCor );
					OutputDebugString(Debug);
					sprintf(Debug,"State: C3D_ERS_TMAP_FILTER=%d\n",gTexFilter);
					OutputDebugString(Debug);
					sprintf(Debug,"State: C3D_ERS_TMAP_LIGHT=%d\n",gLight);
					OutputDebugString(Debug);
					sprintf(Debug,"State: C3D_ERS_SHADE_MODE=%d\n",gShade);
					OutputDebugString(Debug);
					sprintf(Debug,"State: C3D_ERS_SOLID_CLR= r:%d b:%d g:%d a:%d\n",gColor.r,gColor.b,gColor.g,gColor.a);
					OutputDebugString(Debug);
					sprintf(Debug,"State: C3D_ERS_ALPHA_SRC=%d\n",gSrcABlend);
					OutputDebugString(Debug);
					sprintf(Debug,"State: C3D_ERS_ALPHA_DST=%d\n",gDstABlend);
					OutputDebugString(Debug);
					OutputDebugString("---End States---\n");
					return 0;
					
					
				case IDM_EXIT:
					KillTimer(hWnd, ID_TIMER);
                    DestroyWindow (hWnd);
                    return 0;
			
			
			
			} 			// switch (LOWORD(wParam))




		case WM_LBUTTONDOWN:
			if ((wParam) & MK_LBUTTON)
				{
				POINT point = {0,0};
				ClientToScreen(ghWnd, &point);
				SetCursorPos((int)Dst[iCount].x + point.x, (int)Dst[iCount].y + point.y);
				}
			break;


		case WM_RBUTTONDOWN:
			if ((wParam) & MK_RBUTTON)
				{
				iCount++;
				if (iCount == 3)
					iCount = 0;
				POINT point = {0,0};
				ClientToScreen(ghWnd, &point);
				SetCursorPos((int)Dst[iCount].x + point.x, (int)Dst[iCount].y + point.y);
				}
			sprintf(Debug,"RBUTTONDOWN: Vertice=%d\n",iCount);
			OutputDebugString(Debug);
			break;	

		case WM_MOUSEMOVE:
			{
			if ((wParam) & MK_LBUTTON)
				{

				Dst[iCount].x = (float)LOWORD(lParam);		
				Dst[iCount].y = (float)HIWORD(lParam);	
				Border[iCount].x = Dst[iCount].x;
				Border[iCount].y = Dst[iCount].y;
				// Tell the vert prop dialog about the mouse move
				if (g_hDlgVertProp != NULL)
					SendMessage(g_hDlgVertProp, WM_MOUSEMOVE, MK_LBUTTON, NULL);
				}
			break;
			}

			
		case WM_LBUTTONDBLCLK:
			{
			if (g_hDlgVertProp == NULL)
				g_hDlgVertProp = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_VERPROP), hWnd, (DLGPROC)DlgVertPropProc);
			}

			
		case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		ShowCursor(TRUE);
		EndPaint(hWnd, &ps);
		return 0;


        case WM_KEYDOWN:
            switch (wParam)
            {
                case VK_ESCAPE:
                    DestroyWindow (hWnd);
                    return 0;


   

                case VK_F11:
					full = !full;

					break;

                case VK_F12:
                    grid = !grid;
                    break;

				// Change the Pitch using arrow keys
					// BUG: corrupts textures in memory with VK_DOWN
				case VK_UP:
					if (pitch_factor == 1)
					{
						pitch_factor = 2;
						break;
					}
					if (pitch_factor == 2)
						pitch_factor = 4;
					break;

				case VK_DOWN:
					if (pitch_factor == 4)
					{
						pitch_factor = 2;
						break;
					}
					if (pitch_factor == 2)
						pitch_factor = 1;
					break;
				
				// BUG: want to do s and t separately usign a nice easy interface (sliders)
                case VK_SUBTRACT:
					if (Dst[iCount].s >= .01)
						{
						Dst[iCount].s = (float)(Dst[iCount].s - .01);
						Dst[iCount].t = (float)(Dst[iCount].t - .01);
					// Tell the vert prop dialog about the s and t change
					if (g_hDlgVertProp != NULL)
						SendMessage(g_hDlgVertProp, WM_MOUSEMOVE, MK_LBUTTON, NULL);
						}
					break;

                case VK_ADD:
					if (Dst[iCount].s < 1)
						{
						Dst[iCount].s = (float)(Dst[iCount].s + .01);
						Dst[iCount].t = (float)(Dst[iCount].t + .01);
					// Tell the vert prop dialog about the s and t change
					if (g_hDlgVertProp != NULL)
						SendMessage(g_hDlgVertProp, WM_MOUSEMOVE, MK_LBUTTON, NULL);
						}
  					break;
            } // switch
            break;

        case WM_SYSKEYDOWN:
            switch (wParam)
            {
                case 'F':
                case 'f':

                    // Toggle frame rate counter state.

                    gbDisplayFrameRate = !gbDisplayFrameRate;
                    if (gbDisplayFrameRate)
                    {
                        StartFrameCounter ();
                    }
                    else
                    {
                        EndFrameCounter ();
                    } // if
                    break;
            } // switch
            break;



        case WM_DESTROY:
            gbDrawFrame = FALSE;
            CloseApp ();
            PostQuitMessage (0);
            break;
    } // switch

    return DefWindowProc (hWnd, message, wParam, lParam);

} // WindowProc


//////////////////////////////////////////////////////////////////////////
//InitApp                                                                   
//	Function:	do work required for every instance of the application:         
//				create the window, initialize data                              
//  Inputs:		hInstance - instance handle of application                      
//				nCmdShow - current visibility state                             
//  Outputs:	TRUE - initialization was successful                            
//				FALSE - initialization failed                             
//////////////////////////////////////////////////////////////////////////
static BOOL InitApp (HANDLE hInstance, int nCmdShow)
{
    HWND        hwnd;
    WNDCLASS    wc;
    int         i;
    char        cExePath[_MAX_PATH], cExeDir[_MAX_DIR];
	RECT	rc;
	DWORD	dw_style;
	HMENU hMenu;


	// Generate vertices for Primary and Secondary sources
	BuildSrc1(0, 0);
	BuildSrc2(0, 0);

	
	for (i = 0 ; i < 32; i++)
		{
        Src1[i] = &(Src1List[i]);
        Src2[i] = &(Src2List[i]);
		}


    // Make sure we are in the right directory so relative paths will behave.
    GetModuleFileName (hInstance, cExePath, _MAX_PATH);
    _splitpath (cExePath, NULL, cExeDir, NULL, NULL);
    _chdir (cExeDir);

    // Set up and register window class.
    wc.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
    wc.lpfnWndProc = WindowProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon (hInstance, IDI_APPLICATION);
    wc.hCursor = LoadCursor (NULL, IDC_ARROW);
    wc.hbrBackground = NULL;
    wc.lpszMenuName = NAME;
    wc.lpszClassName = NAME;

    RegisterClass (&wc);

    // Create a window.
	rc.top = rc.left = 0;
	rc.bottom = SCREEN_HEIGHT;
	rc.right = SCREEN_WIDTH;
	dw_style = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU;

	AdjustWindowRectEx(&rc, dw_style, FALSE, WS_EX_APPWINDOW);

	hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU));

    ghWnd = hwnd = CreateWindowEx (WS_EX_APPWINDOW/*WS_EX_TOPMOST*/,
		NAME, TITLE, dw_style/*WS_POPUP*/, 50, 50,
                                   rc.right - rc.left,
                                   rc.bottom - rc.top, NULL, hMenu,
 //                                  GetSystemMetrics (SM_CXSCREEN),
 //                                  GetSystemMetrics (SM_CYSCREEN), NULL, NULL,
                                   hInstance, NULL);


	// Create DrawFrame() Timer
	if (!SetTimer(hwnd, ID_TIMER, WAIT_TIME, NULL))
		{
		MessageBox(hwnd,
				"Too Many clocks or timers!",
				"",
				MB_ICONEXCLAMATION | MB_OK);
		return FALSE;
		}	



    if (!hwnd)
    {
        return FALSE;
    }

    ShowWindow (hwnd, nCmdShow);
    UpdateWindow (hwnd);

    // Create and initialize the main DirectDraw object.
    if (!InitDirectDraw (hwnd, SCREEN_WIDTH, SCREEN_HEIGHT, 16, FALSE))
    {
        CloseApp ();
        MessageBox (hwnd, gszErrMsg, TITLE, MB_OK);
        DestroyWindow (hwnd);
        return FALSE;
    }


    
    // Create an ATI CIF redering context.

    if (!InitATI3DCIF ())
    {
        CloseApp ();
        MessageBox (hwnd, gszErrMsg, TITLE, MB_OK);
        DestroyWindow (hwnd);
        return FALSE;
    }




#ifdef SETUP
	// Load Texture into Secondary Source
    if (!LoadTexture (PRIMARY_BMP, &gTex))
//	if (!LoadCI8Texture (PRIMARY_BMP, &gTex))
//	if (!LoadCI4Texture (PRIMARY_BMP, &gTex, TRUE))
//    if (!LoadAllTexture (PRIMARY_BMP, &gTex, g332))
    {
        CloseApp ();
        MessageBox (hwnd, gszErrMsg, TITLE, MB_OK);
        DestroyWindow (hwnd);
        return FALSE;
    } // if

//DAG
/*	if (!LoadCI4Texture (SECONDARY_BMP, &gTex2, TRUE))
    {
        CloseApp ();
        MessageBox (hwnd, gszErrMsg, TITLE, MB_OK);
        DestroyWindow (hwnd);
        return FALSE;
    } // if
*/
#else
	// Load MipMapped Textures into Primary Source
	if (!LoadMipMapTexture (PRIMARY_BMP, gMipMapTex, MAPS))
    {
        CloseApp ();
        MessageBox (hwnd, gszErrMsg, TITLE, MB_OK);
        DestroyWindow (hwnd);
        return FALSE;
    } // if


	// Load Texture into Secondary Source
    if (!LoadTexture (SECONDARY_BMP, &gTex))
//    if (!LoadAllTexture (SECONDARY_BMP, &gTex, g332))
    {
        CloseApp ();
        MessageBox (hwnd, gszErrMsg, TITLE, MB_OK);
        DestroyWindow (hwnd);
        return FALSE;
    } // if

#endif


    gbDrawFrame = TRUE;
    return TRUE;

}

///////////////////////////////////////////////////////////////////////////////
// WinMain                                                                    
//  Function: initialization, message loop                                    
//    Inputs: hInstance - handle for this instance of application             
//            hPrevInstance - handle for previous instance of application     
//            lpCmdLine - string containing remainder of commmand line        
//            nCmdShow - current visibility state                             
//   Outputs: varies                                                          
///////////////////////////////////////////////////////////////////////////////

int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    LPSTR lpCmdLine, int nCmdShow)
{
    MSG     msg;
    float   fDelayCounter = 0.0f;

    lpCmdLine = lpCmdLine;
    hPrevInstance = hPrevInstance;

    if (!InitApp (hInstance, nCmdShow))
    {
        return FALSE;
    } // if

    while (TRUE)
    {
            if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
            {
                if (!GetMessage (&msg, NULL, 0, 0))
                {
                    return msg.wParam;
                } // if
                TranslateMessage (&msg);
                DispatchMessage (&msg);
            } // if
//Use Timer        // Update object geomtery.
/*        if (gbDrawFrame)
        {
            DrawFrame ();
        } // if
*/
    } // while

    return msg.wParam;

} // WinMain


/******************************************************************************
 * CloseApp                                                                   *
 *  Function: unregister texture, close ATI 3D module, and destroy DirectDraw *
 *            object                                                          *
 *    Inputs: none                                                            *
 *   Outputs: none                                                            *
 ******************************************************************************/

void CloseApp (void)
{

    EndFrameCounter ();

#ifndef SETUP	
	// Unload any MipMap textures.
    if (gMipMapTex[0].hTX)
    {
        if (!UnloadMipMapTexture (gMipMapTex, MAPS))
        {
            MessageBox (ghWnd, gszErrMsg, TITLE, MB_OK);
        }
    }
#endif

	// Unload any MipMap textures.
    if (gTex.hTX)
    {
        if (!UnloadTexture (&gTex))
//      if (!UnloadCITexture (&gTex))
//       if (!UnloadAllTexture (&gTex))
        {
            MessageBox (ghWnd, gszErrMsg, TITLE, MB_OK);
        }
    }


    // Release surface.

    if (glpDDSScaled)
    {
        glpDDSScaled->Release ();
        glpDDSScaled = NULL;
    } // if

    // Destroy the ATI 3D rendering context and close the 3D Driver.

    CloseATI3DCIF ();

    // Destroy the DirectDraw object.

    CloseDirectDraw ();

} // CloseApp



/******************************************************************************
 * DrawFrame                                                                  *
 *  Function: draw the animation frame and flip the double buffers            *
 *    Inputs: none                                                            *
 *   Outputs: none                                                            *
 ******************************************************************************/

void DrawFrame (void)
{
    HRESULT ddretval;
    C3D_EC ecRend;
    static BOOL phase = FALSE;
    int ytextoffset = 0;
    DDBLTFX			ddbltfx;
	C3D_UINT32		pitch;
    HDC hdcBack;
	POINT point = {0,0};
	RECT WindowSize;

#ifdef SETUP
    HDC hdcScaled;
	int ret;
#endif

	// point.x and point.y hold the starting locations of the DirectDraw program's
	// client window area relative to the top of the screen (primary surface)
	ClientToScreen(ghWnd, &point);

	// The WindowSize rectangle holds the size of the DirectDraw program's client window
	// relative to the beginning of the winodw (0,0,width,height). We can get our final
	// window size by adding point.x and point.y to WindowSize
	GetClientRect(ghWnd, &WindowSize);
		
	OffsetRect(&WindowSize, point.x, point.y);
	// ClipCursor Keeps cursor inside rect
	// ClipCursor(&WindowSize);

		
	if ((iRenderState) || (iRenderTick))
		{


	// Clear Back Buffer
	ZeroMemory (&ddbltfx, sizeof (ddbltfx));
	ddbltfx.dwSize = sizeof (ddbltfx);
	ddbltfx.dwFillColor = RGB (10, 20, 10);
	RECT r;
	r.top = 0;
	r.left = 0;
	r.right = SCREEN_WIDTH;
	r.bottom = SCREEN_HEIGHT;
	ddretval = glpDDSBack->Blt (&r, NULL, NULL, DDBLT_DDFX | DDBLT_WAIT | DDBLT_COLORFILL,&ddbltfx);





		// Get ptr to Back Buffer
		DDSURFACEDESC ddsd;
		ZeroMemory (&ddsd, sizeof (ddsd));
		ddsd.dwSize = sizeof (ddsd);
		ddretval = glpDDSBack->Lock (NULL, &ddsd,DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
		if (ddretval == DDERR_SURFACELOST) 
			glpDDSBack->Restore ();
		ddretval = glpDDSBack->Unlock (NULL);


		// Render onto Back Buffer
		ecRend = ATI3DCIF_RenderBegin (ghRC);
		assert(ecRend == C3D_EC_OK);



		ATI3DCIF_ContextSetState (ghRC, C3D_ERS_SURF_DRAW_PTR,(C3D_PRSDATA) &(ddsd.lpSurface));
		// pitch is a pointer to a C3D_UINT32 specifying the pitch of the drawing
		// surface region in pixels. The pitch must be an integer multiple of 8 pixels.
		// Set to pitch of on-screen desktop region on rendering context creation.
		pitch = ddsd.lPitch / pitch_factor;
		//pitch = SCREEN_WIDTH / scale;
		ATI3DCIF_ContextSetState (ghRC, C3D_ERS_SURF_DRAW_PITCH,&pitch);

		if (!iRenderOnlyTriangle)
			{
			C3D_EPRIM quad = C3D_EPRIM_QUAD;
			ATI3DCIF_ContextSetState (ghRC, C3D_ERS_PRIM_TYPE, &quad);

#ifdef RAGE3
			// If compositing is on, we do not want to use it here for display of the textures
			// we are using in the test. We just want to use it later when we draw the triangle.
			if (gbComp)
				{
				gbComp = !gbComp; // turn off
				ATI3DCIF_ContextSetState (ghRC, C3D_ERS_COMPOSITE_EN, &gbComp);	
				gbComp = !gbComp; // turn back on
				}
#endif		
			// render primary texture(s)
			// want to render individual rectangles with each individual texture map
			ecRend = ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_SELECT, &gMipMapTex[8].hTX);
			assert( ecRend == C3D_EC_OK);
			ecRend = ATI3DCIF_RenderPrimList ((C3D_VLIST)&Src1[0], 4);
			assert( ecRend == C3D_EC_OK);
			ecRend = ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_SELECT, &gMipMapTex[7].hTX);
			assert( ecRend == C3D_EC_OK);
			ecRend = ATI3DCIF_RenderPrimList ((C3D_VLIST)&Src1[4], 4);
			assert( ecRend == C3D_EC_OK);
			ecRend = ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_SELECT, &gMipMapTex[6].hTX);
			assert( ecRend == C3D_EC_OK);
			ecRend = ATI3DCIF_RenderPrimList ((C3D_VLIST)&Src1[8], 4);
			assert( ecRend == C3D_EC_OK);
			ecRend = ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_SELECT, &gMipMapTex[5].hTX);
			assert( ecRend == C3D_EC_OK);
			ecRend = ATI3DCIF_RenderPrimList ((C3D_VLIST)&Src1[12], 4);
			assert( ecRend == C3D_EC_OK);
			ecRend = ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_SELECT, &gMipMapTex[4].hTX);
			assert( ecRend == C3D_EC_OK);
			ecRend = ATI3DCIF_RenderPrimList ((C3D_VLIST)&Src1[16], 4);
			assert( ecRend == C3D_EC_OK);
			ecRend = ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_SELECT, &gMipMapTex[3].hTX);
			assert( ecRend == C3D_EC_OK);
			ecRend = ATI3DCIF_RenderPrimList ((C3D_VLIST)&Src1[20], 4);
			assert( ecRend == C3D_EC_OK);
			ecRend = ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_SELECT, &gMipMapTex[2].hTX);
			assert( ecRend == C3D_EC_OK);
			ecRend = ATI3DCIF_RenderPrimList ((C3D_VLIST)&Src1[24], 4);
			assert( ecRend == C3D_EC_OK);
			ecRend = ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_SELECT, &gMipMapTex[1].hTX);
			assert( ecRend == C3D_EC_OK);
			ecRend = ATI3DCIF_RenderPrimList ((C3D_VLIST)&Src1[28], 4);
			assert( ecRend == C3D_EC_OK);

			// Render secondary texture
			ecRend = ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_SELECT, &gTex.hTX);
			assert( ecRend == C3D_EC_OK);
			ecRend = ATI3DCIF_RenderPrimList ((C3D_VLIST)&Src2[28], 4);
			}				

#ifdef RAGE3

		// Always select secondary texture in case we are compositing
		ecRend = ATI3DCIF_ContextSetState (ghRC, C3D_ERS_COMPOSITE_SELECT, &gTex.hTX);	
		assert( ecRend == C3D_EC_OK);
		// Enable or disable compositing
		ecRend = ATI3DCIF_ContextSetState (ghRC, C3D_ERS_COMPOSITE_EN, &gbComp);	
		assert( ecRend == C3D_EC_OK);

#endif
		
		// Enable or disable compositing ALPHA
        //ecRend = ATI3DCIF_ContextSetState (ghRC, C3D_ERS_COMPOSITE_FACTOR_ALPHA, &gCombAlphaState);
		//assert( ecRend == C3D_EC_OK);
		
		
		// Select MipMapped texture
		ecRend = ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_SELECT, &gMipMapTex[0].hTX);	
		assert( ecRend == C3D_EC_OK);

		
		C3D_EPRIM tri = C3D_EPRIM_TRI;
		ATI3DCIF_ContextSetState (ghRC, C3D_ERS_PRIM_TYPE, &tri);

		// Convert u and v to ST, render, then convert back again
		UVtoST();
		ecRend = ATI3DCIF_RenderPrimStrip ((C3D_VSTRIP)Dst, 3);
		ecRend = ATI3DCIF_RenderPrimStrip ((C3D_VSTRIP)Dst, 3);
		assert(ecRend == C3D_EC_OK);
		STtoUV();
		
		ecRend = ATI3DCIF_RenderEnd();



if (gHiResState)		// Render large directly onto the back	
		{
		ZeroMemory (&ddsd, sizeof (ddsd));
		ddsd.dwSize = sizeof (ddsd);
		ddretval = glpDDSBack->Lock (NULL, &ddsd,
									 DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
	    if (ddretval == DDERR_SURFACELOST) 
		{
			glpDDSBack->Restore ();
			OutputDebugString("Surface Lost!\n");
		}
		ddretval = glpDDSBack->Unlock (NULL);
		if ((ecRend = ATI3DCIF_RenderBegin (ghRC)) == C3D_EC_OK)
			{

			
//DAG-ci4s
		// render primary texture(s)
		// want to render individual rectangles with each individual texture map
//		ecRend = ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_SELECT, &gTex2.hTX);
//		assert( ecRend == C3D_EC_OK);
			
			
			
			ATI3DCIF_ContextSetState (ghRC, C3D_ERS_SURF_DRAW_PTR,
									  (C3D_PRSDATA) &(ddsd.lpSurface));
			pitch = ddsd.lPitch / pitch_factor;
			ATI3DCIF_ContextSetState (ghRC, C3D_ERS_SURF_DRAW_PITCH,
									  &pitch);

			UVtoST();
			ecRend = ATI3DCIF_RenderPrimStrip ((C3D_VSTRIP) Dst, 3);
			assert(ecRend == C3D_EC_OK);
			STtoUV();

			ecRend = ATI3DCIF_RenderEnd ();
			if (ecRend != C3D_EC_OK) OutputDebugString("RenderEnd Failed!\n");
			}
		else
			OutputDebugString("RenderBegin Failed!\n");
		}


}


	// Show border triangle whenever we are not rendering
	//if ((!iRenderState) && (!iRenderTick))
	if (gBorderState)
		{
		HPEN hpen1;
		HPEN hpen2;
		hpen1 = CreatePen(PS_SOLID, 0, RGB(255,255,255));
		hpen2 = CreatePen(PS_SOLID, 0, RGB(255,255,255));
		C3D_VTCF tmp[3] = { 
			{ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},  // v0
			{ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},  // v1
			{ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}   // v2
		};
		// We draw the border lines onto the primary surface, and must adjust
		// them based on the Offset rect, or they will be off by that much
		tmp[0].x = Border[0].x;// + point.x;
		tmp[0].y = Border[0].y;// + point.y;
		tmp[1].x = Border[1].x;// + point.x;
		tmp[1].y = Border[1].y;// + point.y;
		tmp[2].x = Border[2].x;// + point.x;
		tmp[2].y = Border[2].y;// + point.y;

		if (glpDDSBack->GetDC (&hdcBack) == DD_OK)
			{
			switch (iCount)
				{
				case 2:
					SelectObject(hdcBack, hpen1);
					MoveToEx(hdcBack, (int)tmp[0].x, (int)tmp[0].y, NULL);
					LineTo(hdcBack, (int)tmp[1].x, (int)tmp[1].y);
					SelectObject(hdcBack, hpen2);
					MoveToEx(hdcBack, (int)tmp[1].x, (int)tmp[1].y, NULL);
					LineTo(hdcBack, (int)tmp[2].x, (int)tmp[2].y);
					MoveToEx(hdcBack, (int)tmp[2].x, (int)tmp[2].y, NULL);
					LineTo(hdcBack, (int)tmp[0].x, (int)tmp[0].y);
					break;
				case 0:
					SelectObject(hdcBack, hpen2);
					MoveToEx(hdcBack, (int)tmp[0].x, (int)tmp[0].y, NULL);
					LineTo(hdcBack, (int)tmp[1].x, (int)tmp[1].y);
					SelectObject(hdcBack, hpen1);
					MoveToEx(hdcBack, (int)tmp[1].x, (int)tmp[1].y, NULL);
					LineTo(hdcBack, (int)tmp[2].x, (int)tmp[2].y);
					SelectObject(hdcBack, hpen2);
					MoveToEx(hdcBack, (int)tmp[2].x, (int)tmp[2].y, NULL);
					LineTo(hdcBack, (int)tmp[0].x, (int)tmp[0].y);
					break;
				case 1:
					SelectObject(hdcBack, hpen2);
					MoveToEx(hdcBack, (int)tmp[0].x, (int)tmp[0].y, NULL);
					LineTo(hdcBack, (int)tmp[1].x, (int)tmp[1].y);
					MoveToEx(hdcBack, (int)tmp[1].x, (int)tmp[1].y, NULL);
					LineTo(hdcBack, (int)tmp[2].x, (int)tmp[2].y);
					SelectObject(hdcBack, hpen1);
					MoveToEx(hdcBack, (int)tmp[2].x, (int)tmp[2].y, NULL);
					LineTo(hdcBack, (int)tmp[0].x, (int)tmp[0].y);
					break;
				}
			ddretval = glpDDSBack->ReleaseDC(hdcBack);
			assert(ddretval == DD_OK);
			}
		DeleteObject(hpen1);
		DeleteObject(hpen2);
		}




	
    PageFlip (glpDDSPrimary, WindowSize, ghWnd);
	

	if (iRenderTick)
		iRenderTick = !iRenderTick;



	ShowCursor(TRUE);	
	//InvalidateRect(ghWnd, NULL, TRUE);

}





const char *ErrString(HRESULT err)
{
	switch(err)
	{
#define REGISTER_ERROR(e) case e : return #e
		REGISTER_ERROR(DD_OK);
		REGISTER_ERROR(DDERR_ALREADYINITIALIZED);
		REGISTER_ERROR(DDERR_CANNOTATTACHSURFACE);
		REGISTER_ERROR(DDERR_CANNOTDETACHSURFACE);
		REGISTER_ERROR(DDERR_CURRENTLYNOTAVAIL);
		REGISTER_ERROR(DDERR_EXCEPTION);
		REGISTER_ERROR(DDERR_GENERIC);
		REGISTER_ERROR(DDERR_HEIGHTALIGN);
		REGISTER_ERROR(DDERR_INCOMPATIBLEPRIMARY);
		REGISTER_ERROR(DDERR_INVALIDCAPS);
		REGISTER_ERROR(DDERR_INVALIDCLIPLIST);
		REGISTER_ERROR(DDERR_INVALIDMODE);
		REGISTER_ERROR(DDERR_INVALIDOBJECT);
		REGISTER_ERROR(DDERR_INVALIDPARAMS);
		REGISTER_ERROR(DDERR_INVALIDPIXELFORMAT);
		REGISTER_ERROR(DDERR_INVALIDRECT);
		REGISTER_ERROR(DDERR_LOCKEDSURFACES);
		REGISTER_ERROR(DDERR_NO3D);
		REGISTER_ERROR(DDERR_NOALPHAHW);
		REGISTER_ERROR(DDERR_NOCLIPLIST);
		REGISTER_ERROR(DDERR_NOCOLORCONVHW);
		REGISTER_ERROR(DDERR_NOCOOPERATIVELEVELSET);
		REGISTER_ERROR(DDERR_NOCOLORKEY);
		REGISTER_ERROR(DDERR_NOCOLORKEYHW);
		REGISTER_ERROR(DDERR_NODIRECTDRAWSUPPORT);
		REGISTER_ERROR(DDERR_NOEXCLUSIVEMODE);
		REGISTER_ERROR(DDERR_NOFLIPHW);
		REGISTER_ERROR(DDERR_NOGDI);
		REGISTER_ERROR(DDERR_NOMIRRORHW);
		REGISTER_ERROR(DDERR_NOTFOUND);
		REGISTER_ERROR(DDERR_NOOVERLAYHW);
		REGISTER_ERROR(DDERR_NORASTEROPHW);
		REGISTER_ERROR(DDERR_NOROTATIONHW);
		REGISTER_ERROR(DDERR_NOSTRETCHHW);
		REGISTER_ERROR(DDERR_NOT4BITCOLOR);
		REGISTER_ERROR(DDERR_NOT4BITCOLORINDEX);
		REGISTER_ERROR(DDERR_NOT8BITCOLOR);
		REGISTER_ERROR(DDERR_NOTEXTUREHW);
		REGISTER_ERROR(DDERR_NOVSYNCHW);
		REGISTER_ERROR(DDERR_NOZBUFFERHW);
		REGISTER_ERROR(DDERR_NOZOVERLAYHW);
		REGISTER_ERROR(DDERR_OUTOFCAPS);
		REGISTER_ERROR(DDERR_OUTOFMEMORY);
		REGISTER_ERROR(DDERR_OUTOFVIDEOMEMORY);
		REGISTER_ERROR(DDERR_OVERLAYCANTCLIP);
		REGISTER_ERROR(DDERR_OVERLAYCOLORKEYONLYONEACTIVE);
		REGISTER_ERROR(DDERR_PALETTEBUSY);
		REGISTER_ERROR(DDERR_COLORKEYNOTSET);
		REGISTER_ERROR(DDERR_SURFACEALREADYATTACHED);
		REGISTER_ERROR(DDERR_SURFACEALREADYDEPENDENT);
		REGISTER_ERROR(DDERR_SURFACEBUSY);
		REGISTER_ERROR(DDERR_CANTLOCKSURFACE);
		REGISTER_ERROR(DDERR_SURFACEISOBSCURED);
		REGISTER_ERROR(DDERR_SURFACELOST);
		REGISTER_ERROR(DDERR_SURFACENOTATTACHED);
		REGISTER_ERROR(DDERR_TOOBIGHEIGHT);
		REGISTER_ERROR(DDERR_TOOBIGSIZE);
		REGISTER_ERROR(DDERR_TOOBIGWIDTH);
		REGISTER_ERROR(DDERR_UNSUPPORTED);
		REGISTER_ERROR(DDERR_UNSUPPORTEDFORMAT);
		REGISTER_ERROR(DDERR_UNSUPPORTEDMASK);
		REGISTER_ERROR(DDERR_VERTICALBLANKINPROGRESS);
		REGISTER_ERROR(DDERR_WASSTILLDRAWING);
		REGISTER_ERROR(DDERR_XALIGN);
		REGISTER_ERROR(DDERR_INVALIDDIRECTDRAWGUID);
		REGISTER_ERROR(DDERR_DIRECTDRAWALREADYCREATED);
		REGISTER_ERROR(DDERR_NODIRECTDRAWHW);
		REGISTER_ERROR(DDERR_PRIMARYSURFACEALREADYEXISTS);
		REGISTER_ERROR(DDERR_NOEMULATION);
		REGISTER_ERROR(DDERR_REGIONTOOSMALL);
		REGISTER_ERROR(DDERR_CLIPPERISUSINGHWND);
		REGISTER_ERROR(DDERR_NOCLIPPERATTACHED);
		REGISTER_ERROR(DDERR_NOHWND);
		REGISTER_ERROR(DDERR_HWNDSUBCLASSED);
		REGISTER_ERROR(DDERR_HWNDALREADYSET);
		REGISTER_ERROR(DDERR_NOPALETTEATTACHED);
		REGISTER_ERROR(DDERR_NOPALETTEHW);
		REGISTER_ERROR(DDERR_BLTFASTCANTCLIP);
		REGISTER_ERROR(DDERR_NOBLTHW);
		REGISTER_ERROR(DDERR_NODDROPSHW);
		REGISTER_ERROR(DDERR_OVERLAYNOTVISIBLE);
		REGISTER_ERROR(DDERR_NOOVERLAYDEST);
		REGISTER_ERROR(DDERR_INVALIDPOSITION);
		REGISTER_ERROR(DDERR_NOTAOVERLAYSURFACE);
		REGISTER_ERROR(DDERR_EXCLUSIVEMODEALREADYSET);
		REGISTER_ERROR(DDERR_NOTFLIPPABLE);
		REGISTER_ERROR(DDERR_CANTDUPLICATE);
		REGISTER_ERROR(DDERR_NOTLOCKED);
		REGISTER_ERROR(DDERR_CANTCREATEDC);
		REGISTER_ERROR(DDERR_NODC);
		REGISTER_ERROR(DDERR_WRONGMODE);
		REGISTER_ERROR(DDERR_IMPLICITLYCREATED);
		REGISTER_ERROR(DDERR_NOTPALETTIZED);
		REGISTER_ERROR(DDERR_UNSUPPORTEDMODE);
		REGISTER_ERROR(DDERR_NOMIPMAPHW);
		REGISTER_ERROR(DDERR_INVALIDSURFACETYPE);
		REGISTER_ERROR(DDERR_DCALREADYCREATED);
		REGISTER_ERROR(DDERR_CANTPAGELOCK);
		REGISTER_ERROR(DDERR_CANTPAGEUNLOCK);
		REGISTER_ERROR(DDERR_NOTPAGELOCKED);
//		REGISTER_ERROR(DDERR_NOTINITIALIZED);
#undef REGISTER_ERROR
	default:
		return "CDirectDraw::DDErrString(): Unknown Error Number";
	}
}
