#define NAME "WIPEOUT"
#define TITLE "WIPEOUT '95"
#define DBG				0

#define WINVER 0x0400
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
#include "c:\msdev\include\winuser.h"
#include "c:\msdev\include\mmsystem.h"
#include <direct.h>
#include <vfw.h>
#include <mciavi.h>
#include <ddraw.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "resource.h"
#include "winh.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <io.h>
#if USE_ATI
#include <math.h>

#include "ati3dcif.h"

#define	BLACK_NOT_DRAWN	1
#define	BLACK1_TRANSL	2
#define	BLACK2_TRANSL	3
#define	BLACK3_TRANSL	4
#define	BLACK4_TRANSL	5
#define	BLACK5_TRANSL	6
#define	BLACK6_TRANSL	7
#define	WHITE1_TRANSL	8
#define	WHITE2_TRANSL	9
#define	WHITE3_TRANSL	10
#define	WHITE4_TRANSL	11
#define	WHITE5_TRANSL	12
#define	WHITE6_TRANSL	13
#define	WHITE7_TRANSL	14
#define	WHITE8_TRANSL	15
#define	RED_TRANSL		16
#define	BRIGHT_RED_TRANSL	17
#define	YELLOW_TRANSL	18
#define	YELLOW_WHITE_TRANSL	19
#define	BLUE_TRANSL		20
#define	PURPLE_TRANSL	21
#define	UNUSED1_TRANSL	22
#define	UNUSED2_TRANSL	23
#define	UNUSED3_TRANSL	24
#define	UNUSED4_TRANSL	25

#define MCI_MCIAVI_PLAY_FULLSCREEN 0x02000000L

short dodump = 0;

//#pragma aux randy parm [eax] modify exact [ebx edx] value [eax];

typedef struct {
	LPDIRECTDRAWSURFACE	lpDDSTex;
	DDSURFACEDESC       ddsd;
	C3D_HTX				hTX;
} TEXTURE, * PTEXTURE;

TEXTURE gTex[25];

extern char JJSTextureTable[];

typedef struct
{
	unsigned long   tag;
	unsigned char   r0, g0, b0, code;
	short	   x0, y0;
	short	   x1, y1;
	short	   x2, y2;
	short	   x3, y3;
}	       POLY_F4;	/* Flat Quadrangle */


typedef struct
{
	unsigned long   tag;
	unsigned char   r0, g0, b0, code;
	short	   x0, y0;
	unsigned char   u0, v0;
	unsigned short  clut;
	short	   x1, y1;
	unsigned char   u1, v1;
	unsigned short  tpage;
	short	   x2, y2;
	unsigned char   u2, v2;
	unsigned short  pad1;
	short	   x3, y3;
	unsigned char   u3, v3;
	unsigned short  pad2;
}	       POLY_FT4;       /* Flat Textured Quadrangle */

typedef struct {
	unsigned long	tag;
	unsigned char	r0, g0, b0, code;
	short	x0, 	y0;
	unsigned char	r1, g1, b1, pad1;
	short	x1,	y1;
	unsigned char	r2, g2, b2, pad2;
	short	x2,	y2;
} POLY_G3;				/* Gouraud Triangle */

typedef struct {
	unsigned long	tag;
	unsigned char	r0, g0, b0, code;
	short	x0, 	y0;
	unsigned char	r1, g1, b1, pad1;
	short	x1,	y1;
	unsigned char	r2, g2, b2, pad2;
	short	x2,	y2;
	unsigned char	r3, g3, b3, pad3;
	short	x3,	y3;
} POLY_G4;				/* Gouraud Quadrangle */

typedef struct {
	unsigned long	tag;
	unsigned char	r0, g0, b0, code;
	short	x0, 	y0;
	unsigned char	u0, v0;	unsigned short	clut;
	unsigned char	r1, g1, b1, p1;
	short	x1,	y1;
	unsigned char	u1, v1;	unsigned short	tpage;
	unsigned char	r2, g2, b2, p2;
	short	x2,	y2;
	unsigned char	u2, v2;	unsigned short	pad2;
} POLY_GT3;				/* Gouraud Textured Triangle */

typedef struct {
	unsigned long	tag;
	unsigned char	r0, g0, b0, code;
	short	x0, 	y0;
	unsigned char	u0, v0;	unsigned short	clut;
	unsigned char	r1, g1, b1, p1;
	short	x1,	y1;
	unsigned char	u1, v1;	unsigned short	tpage;
	unsigned char	r2, g2, b2, p2;
	short	x2,	y2;
	unsigned char	u2, v2;	unsigned short	pad2;
	unsigned char	r3, g3, b3, p3;
	short	x3,	y3;
	unsigned char	u3, v3;	unsigned short	pad3;
} POLY_GT4;				/* Gouraud Textured Quadrangle */

typedef struct {
	unsigned long	tag;
	unsigned char	r0, g0, b0, code;
	short	x0, y0;
	unsigned char	u0, v0;
	unsigned short	clut;
	short	x1,	y1;
	unsigned char	u1, v1;
	unsigned short	tpage;
	short	x2,	y2;
	unsigned char	u2, v2;
	unsigned short	pad1;
} POLY_FT3;				/* Flat Textured Triangle */

typedef struct {
	unsigned long	tag;
	unsigned char	r0, g0, b0, code;
	short	x0, 	y0;
	unsigned char	u0, v0;	unsigned short	clut;
	short	w,	h;
} SPRT;					/* free size Sprite */

typedef struct {
	unsigned long	tag;
	unsigned char	r0, g0, b0, code;
	short	x0, 	y0;
	unsigned char	u0, v0;	unsigned short	clut;
} SPRT_8;				/* 8x8 Sprite */
	       
char	    gszErrMsg[64];
BOOL	    gbCIFInit;
C3D_HRC	 ghRC;

#define VBUFSIZE 40
#pragma pack(push)
#pragma pack (8)
C3D_VTCF	testarray[VBUFSIZE];
#pragma pack(pop);

C3D_PVTCF       testlist[VBUFSIZE];
C3D_EPRIM       quad = C3D_EPRIM_NUM;
C3D_ESHADE      shade = C3D_ESH_NUM;
C3D_ETLIGHT	light = C3D_ETL_NONE;
C3D_EADST eDstAlpha = C3D_EADST_ZERO;
C3D_EASRC eSrcAlpha = C3D_EASRC_ONE;
C3D_ETPERSPCOR ePerspCorOn = C3D_ETPC_NONE;
C3D_ETPERSPCOR ePerspCorOff = C3D_ETPC_THREE;
C3D_ETEXFILTER eTexFilter = C3D_ETFILT_MINPNT_MAGPNT;

short texpage=-1;
short numvert=0;
short tester=0;
typedef struct {
	unsigned short blue:5;
	unsigned short green:5;
	unsigned short red:5;
} BIT15;

BIT15 ATIpalette[256];
BOOL Rendering=FALSE;
BOOL bTexEn=FALSE;
#endif
BOOL trans = FALSE;
BOOL MPEGplaying;
HWND g_hwndMCIWnd;
DWORD dwMCIWndStyle;
HINSTANCE hinst;
HWND	    hwnd;

extern char DepthFadeTble,WhitePal;
extern short int CurrTrkNo;
short randlist[2000];
short *randnum;
short ctr;
char *SaveDirBase;
extern UINT wDeviceID;
//SJR

float joyModXVal;
float joyModYVal;
extern short JoyCentreX, JoyCentreY;
extern short	left_scale, right_scale;
extern float	left_scale_factor, right_scale_factor;
extern unsigned short JoyXVal, JoyYVal;
short JoyButton1, JoyButton2;

HANDLE gInstance;

#define	HIGH_SENS	8
#define	MEDIUM_SENS	16
#define	LOW_SENS	32

/* Type/Structure Definitions. */
typedef struct {
	unsigned short int	jX;
	unsigned short int	jY;
	unsigned short int	jDir;
	unsigned short int	jButton1;
	unsigned short int	jButton2;
} JOYSTICK;

typedef struct {
	unsigned short int	mX;
	unsigned short int	mY;
	unsigned short int	mDir;
	unsigned short int	mButton1;
	unsigned short int	mButton2;
	unsigned short int	mButton3;
} MOUSE;

typedef struct {
	long int	JoyUp;
	long int	JoyDown;
	long int	JoyLeft;
	long int	JoyRight;
	long int	JoyButton1;
	long int	JoyButton2;
	long int	JoyButton3;
	long int	JoyButton4;
} JOYSTICK_CONFIG;

typedef struct {
	long int	MouseUp;
	long int	MouseDown;
	long int	MouseLeft;
	long int	MouseRight;
	long int	MouseLeftButton;
	long int	MouseMiddleButton;
	long int	MouseRightButton;
	long int	MouseDummy;
} MOUSE_CONFIG;

#define _DEVICE_ON 1
#define OK 0
#define SONY_PAD 0x41
extern MOUSE etc_Mouse1;
extern JOYSTICK etc_Joy1;
extern unsigned long int etc_Mouse1Register;
extern unsigned long int etc_Joystick1Register;
extern MOUSE_CONFIG etc_Mouse1Config;
extern JOYSTICK_CONFIG etc_Joy1Config;
extern char *etc_TransferBuffer1;
extern char mouse_sensitivity;
extern unsigned char etc_Mouse1Switch;		/* id = 3 */
extern unsigned char etc_Joystick1Switch;
extern unsigned char etc_InputDeviceSelect;

#define TIMER_ID	1
#define TIMER_RATE      1

#define	GAME_WIDTH	320
#define GAME_HEIGHT	240

extern void     Set_Device(int tmp);
extern void     init3d(void);
extern void     oldmain(void);
extern void     QuitToDos(void);
extern void     pmkey(char);
extern void     ResetPitch(void);

extern int      WinPitch;
extern short    WinWidth;
extern short    WinHeight;
extern short    WinHeightX2;
int	     RealPitch;
int	     RealBackPitch;
char	   *DebugScreen, *RealScreen;

LPDIRECTDRAW    lpDD;	   // DirectDraw object
LPDIRECTDRAWSURFACE lpDDSPrimary;       // DirectDraw primary surface
LPDIRECTDRAWSURFACE lpDDSBack;  // DirectDraw back surface
#if !USE_ATI
LPDIRECTDRAWPALETTE lpDDPalette;
#endif
LPDIRECTDRAWSURFACE lpBack_Buffer;      // Directdraw 320X200 Surface for the  menu thing.
BOOL	    bActive;	// is application active?
BOOL backLocked=FALSE;
extern char    *CurBuffer, *CurBufferJ;
PALETTEENTRY    ddPalette[256];
char	   *backscreen;

extern long     NeedKeys;

extern void     finiSndObjects(void);


/*
 * finiObjects
 * 
 * finished with all objects we use; release them
 */
static void     finiObjects(void)
{
#if USE_ATI
	int i;
	
	CloseATI3DCIF();
#endif
	if (lpDD != NULL)
	{
		if (lpDDSPrimary != NULL)
		{
			lpDDSPrimary->lpVtbl->Release(lpDDSPrimary);
			lpDDSPrimary = NULL;
		}
		if (lpBack_Buffer != NULL)
		{
			lpBack_Buffer->lpVtbl->Release(lpBack_Buffer);
			lpBack_Buffer = NULL;
		}
#if USE_ATI
		for(i=0;i<25;++i)
			if (gTex[i].lpDDSTex != NULL)
			{
				gTex[i].lpDDSTex->lpVtbl->Release(gTex[i].lpDDSTex);
			}
#endif
		InvalidateRect(GetDesktopWindow(), NULL, TRUE);
		lpDD->lpVtbl->Release(lpDD);
		lpDD = NULL;
	}
}			       /* finiObjects */

long FAR PASCAL WindowProc(HWND hWnd, UINT message,
					   WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT     ps;
	// RECT	rc;
	// SIZE	size;
	char	    keyhit;
	short DevID;
	long NotifyMsg;
	unsigned short buttons;
	unsigned long xpos, ypos;
	char temp;

	switch (message)
	{
	case WM_ACTIVATEAPP:
		bActive = wParam;
		break;

	case WM_CREATE:
		break;

	case WM_SETCURSOR:
		SetCursor(NULL);
		return TRUE;

	case WM_TIMER:
		break;

	case MM_JOY1MOVE:
		if (etc_Joystick1Switch == _DEVICE_ON)
		{

			xpos = LOWORD(lParam);
			ypos = HIWORD(lParam);
			buttons = wParam;
			etc_Joy1.jX = (short)((float)xpos * joyModXVal);
			etc_Joy1.jY = (short)((float)ypos * joyModYVal);
			etc_Joy1.jDir = 0;
			etc_Joy1.jButton1 = (buttons & JOY_BUTTON1) ? 1 : 0;
			etc_Joy1.jButton2 = (buttons & JOY_BUTTON2) ? 1 : 0;

			etc_Joystick1Register = 0;
			etc_Joystick1Register |= etc_Joy1.jDir;
			etc_Joystick1Register |= etc_Joy1.jButton1 << etc_Joy1Config.JoyButton1;
			etc_Joystick1Register |= etc_Joy1.jButton2 << etc_Joy1Config.JoyButton2;

			//Transmit data to buffer
			etc_TransferBuffer1[0] = OK;
			etc_TransferBuffer1[1] = SONY_PAD;
			etc_TransferBuffer1[2] = (char) ~(etc_Joystick1Register >> 8);

			temp = ~etc_TransferBuffer1[3];			// This lot preserves the
			temp &= 0x9F;					// brake bits, which get
			temp |= (char) (etc_Joystick1Register  & 0xFF);	// lost somehow otherwise
			etc_TransferBuffer1[3] = ~temp;
			return(0);
		}
		break;

	case MM_JOY1BUTTONDOWN:
	case MM_JOY2BUTTONDOWN:
		if (etc_Joystick1Switch == _DEVICE_ON)
		{

			xpos = LOWORD(lParam);
			ypos = HIWORD(lParam);
			buttons = wParam;
			etc_Joy1.jX = (short)((float)xpos * joyModXVal);
			etc_Joy1.jY = (short)((float)ypos * joyModYVal);
			etc_Joy1.jDir = 0;

			if (buttons & JOY_BUTTON1CHG)
				etc_Joy1.jButton1 = 1;
			else
				etc_Joy1.jButton2 = 1;


			etc_Joystick1Register = 0;
			etc_Joystick1Register |= etc_Joy1.jDir;
			etc_Joystick1Register |= etc_Joy1.jButton1 << etc_Joy1Config.JoyButton1;
			etc_Joystick1Register |= etc_Joy1.jButton2 << etc_Joy1Config.JoyButton2;

			//Transmit data to buffer
			etc_TransferBuffer1[0] = OK;
			etc_TransferBuffer1[1] = SONY_PAD;
			etc_TransferBuffer1[2] = (char) ~(etc_Joystick1Register >> 8);

			temp = ~etc_TransferBuffer1[3];			// This lot preserves the
			temp &= 0x9F;					// brake bits, which get
			temp |= (char) (etc_Joystick1Register  & 0xFF);	// lost somehow otherwise
			etc_TransferBuffer1[3] = ~temp;
			return(0);
		}
		break;

	case MM_JOY1BUTTONUP:
	case MM_JOY2BUTTONUP:
		if (etc_Joystick1Switch == _DEVICE_ON)
		{

			xpos = LOWORD(lParam);
			ypos = HIWORD(lParam);
			buttons = wParam;
			etc_Joy1.jX = (short)((float)xpos * joyModXVal);
			etc_Joy1.jY = (short)((float)ypos * joyModYVal);
			etc_Joy1.jDir = 0;

			if (buttons & JOY_BUTTON1CHG)
				etc_Joy1.jButton1 = 0;
			else
				etc_Joy1.jButton2 = 0;

			etc_Joystick1Register = 0;
			etc_Joystick1Register |= etc_Joy1.jDir;
			etc_Joystick1Register |= etc_Joy1.jButton1 << etc_Joy1Config.JoyButton1;
			etc_Joystick1Register |= etc_Joy1.jButton2 << etc_Joy1Config.JoyButton2;

			//Transmit data to buffer
			etc_TransferBuffer1[0] = OK;
			etc_TransferBuffer1[1] = SONY_PAD;
			etc_TransferBuffer1[2] = (char) ~(etc_Joystick1Register >> 8);

			temp = ~etc_TransferBuffer1[3];			// This lot preserves the
			temp &= 0x9F;					// brake bits, which get
			temp |= (char) (etc_Joystick1Register  & 0xFF);	// lost somehow otherwise
			etc_TransferBuffer1[3] = ~temp;
			return(0);
		}
		break;

	case WM_MOUSEMOVE:
		etc_Mouse1Register = 0;
		if(etc_Mouse1Switch == _DEVICE_ON)
		{
			short xtemp,fwKeys;
			char temp;

			xtemp=LOWORD(lParam);
			xtemp-=160;
			switch(mouse_sensitivity)
			{
				case MEDIUM_SENS:
					xtemp/=2;
					break;
				case LOW_SENS:
					xtemp/=4;
					break;
			}
			fwKeys = wParam;
			etc_Mouse1.mX = xtemp+160;

			etc_Mouse1.mDir = 0;
			etc_Mouse1.mButton1 = (fwKeys & MK_LBUTTON) ? 1 : 0;
			etc_Mouse1.mButton2 = (fwKeys & MK_MBUTTON) ? 1 : 0;
			etc_Mouse1.mButton3 = (fwKeys & MK_RBUTTON) ? 1 : 0;


			etc_Mouse1Register |= etc_Mouse1.mDir;
			etc_Mouse1Register |= etc_Mouse1.mButton1 << etc_Mouse1Config.MouseLeftButton;
			etc_Mouse1Register |= etc_Mouse1.mButton2 << etc_Mouse1Config.MouseMiddleButton;
			etc_Mouse1Register |= etc_Mouse1.mButton3 << etc_Mouse1Config.MouseRightButton;

			/* Transmit Data to data buffer. */
			etc_TransferBuffer1[0] = OK;
			etc_TransferBuffer1[1] = SONY_PAD;
	//		etc_TransferBuffer1[2] = (char) ~(etc_Mouse1Register >> 8);

			temp = ~etc_TransferBuffer1[3];			// This lot preserves the
			temp &= 0x9F;					// brake bits, which get
			temp |= (char) (etc_Mouse1Register & 0xFF);	// lost somehow otherwise
			etc_TransferBuffer1[3] = ~temp;
			return(0);
		}
		break;
	case WM_KEYUP:
	case WM_SYSKEYUP:
		if (HIWORD(lParam) & 0x100)
		{
			pmkey(0xe0);
		}
		keyhit = (char) (HIWORD(lParam) & 0x7f);
		keyhit |= 0x80;
		pmkey(keyhit);

		break;

	case WM_KEYDOWN:
	case WM_SYSKEYDOWN:
		if (HIWORD(lParam) & 0x100)
		{
			pmkey(0xe0);
		}
		keyhit = (char) (HIWORD(lParam) & 0x7f);
		keyhit &= 0x7f;
		pmkey(keyhit);

		switch (wParam)
		{
		case VK_F12:
			PostMessage(hWnd, WM_CLOSE, 0, 0);
			break;
		case VK_F11:
			dodump++;
			break;
		}

		if(MPEGplaying)
			MPEGplaying=FALSE;
		break;

	case WM_PAINT:
		BeginPaint(hWnd, &ps);
		/*
		 * GetClientRect(hWnd, &rc); GetTextExtentPoint( ps.hdc,
		 * szMsg, lstrlen(szMsg), &size ); SetBkColor( ps.hdc, RGB(
		 * 0, 0, 255 ) ); SetTextColor( ps.hdc, RGB( 255, 255, 0 ) );
		 * TextOut( ps.hdc, (rc.right - size.cx)/2, (rc.bottom -
		 * size.cy)/2, szMsg, sizeof( szMsg )-1 );
		 */
		EndPaint(hWnd, &ps);
		break;

	case WM_DESTROY:
		finiObjects();
		finiSndObjects();
		PostQuitMessage(0);
		QuitToDos();
		break;
#if USE_ATI
	case MM_MCINOTIFY:
	case MCIWNDM_NOTIFYMODE:
		DevID = LOWORD(lParam);
		NotifyMsg = wParam;
		MPEGplaying = FALSE;
		switch (NotifyMsg)
		{
			case MCI_NOTIFY_ABORTED://stopped for some reason
				break;
			case MCI_NOTIFY_FAILURE://device error
				break;
			case MCI_NOTIFY_SUCCESSFUL://horay!
				if (DevID == wDeviceID)//CD
				{
					CDPlay(CurrTrkNo);
				}
				break;
			case MCI_NOTIFY_SUPERSEDED://not needed any more
				break;
			default:
				break;
		}
		break;
#endif
	}

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

}			       /* WindowProc */


/*  SetSurfaceIntoATI3DCIF - sets direct draw surface to CIF
 *  Parameters : lpDDS long point to the direct draw surface to select
 */
#if USE_ATI
BOOL SetSurfaceIntoATI3DCIF(LPDIRECTDRAWSURFACE lpDDS)
{
	// set the pointer to the frame buffer address of the back surface
	// for the rendering context
	DDSURFACEDESC ddsd;
	HRESULT       ddretval;
	C3D_EPIXFMT ePixF = C3D_EPF_RGB565;

	ZeroMemory(&ddsd, sizeof(DDSURFACEDESC));
	ddsd.dwSize = sizeof (ddsd);
	ddsd.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );

	ddretval = lpDDS->lpVtbl->GetSurfaceDesc(lpDDS, &ddsd);
	ddretval = lpDDS->lpVtbl->Lock (lpDDS, NULL,
							&ddsd,
							DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,
							NULL);
	if (ddretval == DDERR_SURFACELOST) lpDDS->lpVtbl->Restore (lpDDS);
	
	ddretval = lpDDS->lpVtbl->Unlock (lpDDS, NULL);

	ATI3DCIF_ContextSetState (ghRC, C3D_ERS_SURF_DRAW_PTR, (C3D_PRSDATA) &(ddsd.lpSurface));
	switch(ddsd.ddpfPixelFormat.dwRGBBitCount)
	{ // select pixel format from bpp of surface!
		case 8:
			ePixF = C3D_EPF_RGB332;
			break;
		case 16:
			if ((((ddsd.ddpfPixelFormat.dwRBitMask) |
				  (ddsd.ddpfPixelFormat.dwGBitMask) |
				  (ddsd.ddpfPixelFormat.dwBBitMask)) &
				 (0x8000)) != 0)
			{ // check for 15 / 16 bpp through alpha bit!
				ePixF = C3D_EPF_RGB565;
			} else
			{
				ePixF = C3D_EPF_RGB1555;
			}
			break;
		case 32:
			ePixF = C3D_EPF_RGB8888;
			break;
		default:
			break;
	}
	
	ATI3DCIF_ContextSetState (ghRC, C3D_ERS_SURF_DRAW_PITCH, (C3D_PRSDATA)&(ddsd.dwWidth));
	ATI3DCIF_ContextSetState (ghRC, C3D_ERS_SURF_DRAW_PF, (C3D_PRSDATA)&(ePixF));

	return(TRUE);
}
#endif

/*
 * doInit - do work required for every instance of the application: create
 * the window, initialize data
 */
static BOOL     doInit(HANDLE hInstance, int nCmdShow)
{
	WNDCLASS	wc;
	DDSURFACEDESC   ddsd;
	DDSCAPS	 ddscaps;
	DDCAPS	  ddcaps;
	DDCAPS	  ddcaps2;
	HRESULT	 ddrval,ddretval;
	// HDC		 hdc;
	// char		buf[256];
	int	     i;
	char	    StatBankSwitched;
	char	    StatBltStretch;
	char	    StatBlt;

	/*
	 * Initialise palette
	 */

	for (i = 0; i < 256; i++)
	{
		ddPalette[i].peRed = i;
		ddPalette[i].peGreen = i;
		ddPalette[i].peBlue = i;
		ddPalette[i].peFlags = 0;
	}

	/*
	 * set up and register window class
	 */
	wc.style = CS_HREDRAW | CS_VREDRAW;
	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
	 */

	//mpeganim();

	hwnd = CreateWindowEx(
			      WS_EX_TOPMOST,
			      NAME,
			      TITLE,
			      WS_POPUP,
			      0, 0,
			      GetSystemMetrics(SM_CXSCREEN),
			      GetSystemMetrics(SM_CYSCREEN),
			      NULL,
			      NULL,
			      hInstance,
			      NULL);

	if (!hwnd)
	{
		ShowErrorMessage(2000);
		return FALSE;
	}
	gInstance = hInstance;

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


	/*
	 * create the main DirectDraw object
	 */
	ddrval = DirectDrawCreate(NULL, &lpDD, NULL);
	if (ddrval == DD_OK)
	{
		// Get exclusive mode
#if USE_ATI
		ddrval = lpDD->lpVtbl->SetCooperativeLevel(lpDD, hwnd,
					DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
#else
		ddrval = lpDD->lpVtbl->SetCooperativeLevel(lpDD, hwnd,
			DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX );
#endif
		if (ddrval == DD_OK)
		{
#if USE_ATI
			ddrval = lpDD->lpVtbl->SetDisplayMode(lpDD, WinWidth, WinHeight, 16);
#else
			ddrval = lpDD->lpVtbl->SetDisplayMode(lpDD, WinWidth, WinHeight, 8);
#endif
			if (ddrval == DD_OK)
			{
#if !USE_ATI
				ddrval = lpDD->lpVtbl->CreatePalette(lpDD, DDPCAPS_8BIT, ddPalette, &lpDDPalette, NULL);
				if (ddrval == DD_OK)
				{
#endif
					// Create the primary surface with 1 back buffer
					memset(&ddsd, 0, sizeof(ddsd));
					ddsd.dwSize = sizeof(ddsd);
					ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
						//DDSD_PIXELFORMAT;
					//ddsd.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
					//ddsd.ddpfPixelFormat.dwRGBBitCount = 16;
					//ddsd.ddpfPixelFormat.dwFlags = DDPF_RGB;
					//ddsd.ddpfPixelFormat.dwRBitMask = 0x1f << 11;
					//ddsd.ddpfPixelFormat.dwGBitMask = 0x3f << 5;
					//ddsd.ddpfPixelFormat.dwBBitMask = 0x1f << 0;
					ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE |
						DDSCAPS_FLIP |
						DDSCAPS_VIDEOMEMORY |
						DDSCAPS_COMPLEX;
#if USE_ATI
					ddsd.dwBackBufferCount = 1;
#else
					ddsd.dwBackBufferCount = 2;
#endif
					ddrval = lpDD->lpVtbl->CreateSurface(lpDD, &ddsd, &lpDDSPrimary, NULL);

#if USE_ATI
				SetSurfaceIntoATI3DCIF(lpDDSPrimary);
#endif

#if !USE_ATI
					if (ddrval != DD_OK)
					{
						// Want at least 1 BackBuffer
						//   in VRAM
						ddsd.dwBackBufferCount = 1;
						ddrval = lpDD->lpVtbl->CreateSurface(lpDD, &ddsd, &lpDDSPrimary, NULL);
					}
					if (ddrval != DD_OK)
					{
						// Settle for what we can get
						ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY;
						ddrval = lpDD->lpVtbl->CreateSurface(lpDD, &ddsd, &lpDDSPrimary, NULL);
					}
#endif
					if (ddrval != DD_OK)
					{
						ShowErrorMessage(4001);
						QuitToDos();    // Sorry punter your cards shite
					}
#if !USE_ATI
					/* set palette for this surface */
					lpDDSPrimary->lpVtbl->SetPalette(lpDDSPrimary, lpDDPalette);
#endif
					memset(&ddcaps, 0, sizeof(ddcaps));
					ddcaps.dwSize = sizeof(ddcaps);
					if (lpDDSPrimary->lpVtbl->GetCaps(lpDDSPrimary, &ddcaps) == DD_OK)
					{
						StatBankSwitched = ((ddcaps.dwCaps & DDCAPS_BANKSWITCHED) ? 1 : 0);
						StatBltStretch = ((ddcaps.dwCaps & DDCAPS_BLTSTRETCH) ? 1 : 0);
						StatBlt = ((ddcaps.dwCaps & DDCAPS_BLT) ? 1 : 0);
					}
					// Get a pointer to the back buffer
					memset(&ddscaps, 0, sizeof(ddscaps));
					ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
					ddrval = lpDDSPrimary->lpVtbl->GetAttachedSurface(lpDDSPrimary,
								   &ddscaps,
								&lpDDSBack);
					memset(&ddcaps2, 0, sizeof(ddcaps2));
					ddcaps2.dwSize = sizeof(ddcaps2);
					if (lpDDSBack->lpVtbl->GetCaps(lpDDSBack, &ddcaps2) == DD_OK)
					{
						StatBankSwitched = ((ddcaps.dwCaps & DDCAPS_BANKSWITCHED) ? 1 : 0);
						StatBltStretch = ((ddcaps.dwCaps & DDCAPS_BLTSTRETCH) ? 1 : 0);
						StatBlt = ((ddcaps.dwCaps & DDCAPS_BLT) ? 1 : 0);
					}
					if (ddrval != DD_OK)
					{
						ShowErrorMessage(4002);
						return (FALSE);

					}
					memset(&ddsd, 0, sizeof(ddsd));
					ddsd.dwSize = sizeof(ddsd);
					ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
					ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
					ddsd.dwWidth = 320;
#if USE_ATI
					ddsd.dwHeight = 240;
#else
					ddsd.dwHeight = 200;
#endif
					ddrval = lpDD->lpVtbl->CreateSurface(lpDD, &ddsd, &lpBack_Buffer, NULL);
					if (ddrval != DD_OK)
					{
						ShowErrorMessage(4002);
						return (FALSE);
					}
#if USE_ATI
					// create 4 offscreen surfaces to cache the high res track
					for(i=0;i<4;++i)
					{
						ZeroMemory (&(gTex[i].ddsd), sizeof (gTex[i].ddsd));
						gTex[i].ddsd.dwSize = sizeof (gTex[i].ddsd);
						gTex[i].ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
						gTex[i].ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
						gTex[i].ddsd.dwWidth = 256;//SJR	// standard texture size
						gTex[i].ddsd.dwHeight = 256;//SJR	// standard height
						ddretval = lpDD->lpVtbl->CreateSurface (lpDD,&(gTex[i].ddsd), &gTex[i].lpDDSTex, NULL);
						if (ddretval != DD_OK)
						{
						ShowErrorMessage(4002);
							//wsprintf (gszErrMsg, "Could not create texture surface");
							return FALSE;
						}
					}
					// create 18 offscreen surfaces to cache the texture maps
					for(i=4;i<22;++i)
					{
						ZeroMemory (&(gTex[i].ddsd), sizeof (gTex[i].ddsd));
						gTex[i].ddsd.dwSize = sizeof (gTex[i].ddsd);
						gTex[i].ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
						gTex[i].ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
						gTex[i].ddsd.dwWidth = 128;//SJR	// standard texture size
						gTex[i].ddsd.dwHeight = 128;//SJR	// standard height
						ddretval = lpDD->lpVtbl->CreateSurface (lpDD,&(gTex[i].ddsd), &gTex[i].lpDDSTex, NULL);
						if (ddretval != DD_OK)
						{
							//wsprintf (gszErrMsg, "Could not create texture surface");
						ShowErrorMessage(4002);
							return FALSE;
						}
					}
					// create 3 offscreen surfaces to cache the sprite maps
					for(i=22;i<25;++i)
					{
						ZeroMemory (&(gTex[i].ddsd), sizeof (gTex[i].ddsd));
						gTex[i].ddsd.dwSize = sizeof (gTex[i].ddsd);
						gTex[i].ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
						gTex[i].ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
						gTex[i].ddsd.dwWidth = 256;//SJR	// standard texture size
						gTex[i].ddsd.dwHeight = 256;//SJR	// standard height
						ddretval = lpDD->lpVtbl->CreateSurface (lpDD,&(gTex[i].ddsd), &gTex[i].lpDDSTex, NULL);
						if (ddretval != DD_OK)
						{
						ShowErrorMessage(4002);
							//wsprintf (gszErrMsg, "Could not create texture surface");
							return FALSE;
						}
					}
#endif
#if !USE_ATI
				}
#endif
			}
		}
#if USE_ATI
		// create an ATI CIF redering context:
		if (!InitATI3DCIF())
		{
			ShowErrorMessage(5000);
			return FALSE;
		}
		{
			C3D_PVTCF *p;
			for (i = 0, p = testlist;i<VBUFSIZE;++i)
				*p++=&testarray[i];
		}	

		JJSLoadSprites();
#endif

	}

#if USE_ATI

	JJSLoadRage();
#endif
	return TRUE;
}			       /* doInit */

void	    CopyPal(char *palette, short start, short end)
{
	HRESULT	 ddrval;
	int	     i;

	for (i = start; i <= end; i++)
	{
		ddPalette[i].peRed = *palette++;
		ddPalette[i].peGreen = *palette++;
		ddPalette[i].peBlue = *palette++;
		ddPalette[i].peFlags = 0;
#if USE_ATI
		ATIpalette[i].red=(ddPalette[i].peRed)>>3;
		ATIpalette[i].green=(ddPalette[i].peGreen)>>3;
		ATIpalette[i].blue=(ddPalette[i].peBlue)>>3;
#endif
	}
#if !USE_ATI
	ddrval = lpDDPalette->lpVtbl->SetEntries(lpDDPalette,
						 DDSETPAL_IMMEDIATE,
						 start,
						 (end - start) + 1,
						 ddPalette);
#endif
}

void initrandy()
{
	short i;

	for (i = 0; i < 2000; i++)
		randlist[i] = rand() & 0x7FFF;

	randnum = &randlist[0];;
	ctr = 0;
}

int randy()
{
	short num;

	num = *randnum++;

	ctr++;
	if (ctr == 2000)
	{
		randnum = &randlist[0];;
		ctr = 0;
	}

	return num;

}

/*
 * WinMain - initialization, message loop
 */
int PASCAL      WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
					LPSTR lpCmdLine, int nCmdShow)
{
	long tmp;
	int retval;

	initrandy();
	tmp = randy();
	lpCmdLine = lpCmdLine;
	hPrevInstance = hPrevInstance;
	DebugScreen = (char *) malloc(640 * 480);
	WinWidth = GAME_WIDTH;
	WinHeight = GAME_HEIGHT;
	WinHeightX2 = WinHeight * 2;
	hinst = hInstance;
	// Initialise Direct Draw
	if (!doInit(hInstance, nCmdShow))
	{
		return FALSE;
	}

	SaveDirBase = (char *)malloc(120);
	retval = ShellGetGameDirectory(SaveDirBase);
	if (retval != ERROR_SUCCESS)
		strcpy(SaveDirBase, "c:\wipeout");

	CDStop();
	ShowCursor(FALSE);
	oldmain();
  	ShowCursor(TRUE);
  	joyReleaseCapture(JOYSTICKID1);
	DestroyWindow(hwnd);
	return (0);

}			       /* WinMain */

int	     ProcessMessages(void)
{
	MSG	     msg;
	while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))      // Clear all outstanding messages
	{
		if (GetMessage(&msg, NULL, 0, 0))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
			return (0);
		}
		else
		{
			return (1);
		}
	}
	return (0);
}

DDSURFACEDESC   ddsd;
DDSURFACEDESC   backDdsd;
int	     old_pitch = 0;

int	     LockBackBuffer(void)
{
	LPBYTE	  ptr;
	// int			i;
	HRESULT	 ddrval;
	if (bActive && !backLocked)
	{
		ZeroMemory(&ddsd, sizeof(ddsd));
		ddsd.dwSize = sizeof(ddsd);

		ddrval = lpDDSBack->lpVtbl->Lock(lpDDSBack, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);
#if DEBUG_LOCKED
		WinPitch = WinWidth;
		RealPitch = ddsd.lPitch;
#else
		WinPitch = ddsd.lPitch;
#endif
		if (WinPitch != old_pitch)      // pitch has changed
		{
			ResetPitch();
			old_pitch = WinPitch;
		}

		if (ddrval == DDERR_SURFACEBUSY)
		{
			MessageBeep(0);
			return (1);
		}
		if (ddrval == DDERR_SURFACELOST)
		{
			MessageBeep(0);
			lpDDSBack->lpVtbl->Restore(lpDDSBack);
			return (1);
		}

		ptr = (LPBYTE) ddsd.lpSurface;
		if (ptr == NULL)
			return (1);
		// Set my render buffers to the back screen
#if DEBUG_LOCKED
		CurBuffer = (char *) DebugScreen;
		CurBufferJ = (char *) DebugScreen;
		RealScreen = (char *) ptr;
#else
		CurBuffer = (char *) ptr;
		CurBufferJ = (char *) ptr;
#endif
		backLocked=TRUE;
	}

	return (0);

}

void	    WinBeep(void)
{
	MessageBeep(0);
}
void	    UnlockBackBuffer(void)
{
#if DEBUG_LOCKED
	RECT	    rect;

	rect.left = 0;
	rect.top = 0;
	rect.right = WinWidth;
	rect.bottom = WinHeight;

	// memcpy(RealScreen, (DebugScreen + (640*150)), ((WinHeight - 150) *	   WinWidth));
	PitchMemCpy(RealScreen, DebugScreen, &rect);
	memset(DebugScreen, 0, (WinHeight * WinWidth));
#endif
	if (bActive && backLocked)
	{
		lpDDSBack->lpVtbl->Unlock(lpDDSBack, ddsd.lpSurface);
		backLocked = FALSE;
	}
}


int	     LockClearBuffer(void)
{
	LPBYTE	  ptr;
	// int			i;
	HRESULT	 ddrval;
	if (bActive)
	{
		ZeroMemory(&backDdsd, sizeof(backDdsd));
		backDdsd.dwSize = sizeof(backDdsd);

		ddrval = lpBack_Buffer->lpVtbl->Lock(lpBack_Buffer, NULL, &backDdsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);

		if (ddrval == DDERR_SURFACEBUSY)
		{
			MessageBeep(0);
			return (1);
		}
		if (ddrval == DDERR_SURFACELOST)
		{
			MessageBeep(0);
			lpBack_Buffer->lpVtbl->Restore(lpBack_Buffer);
			return (1);
		}

		RealBackPitch = backDdsd.lPitch;
		ptr = (LPBYTE) backDdsd.lpSurface;
		if (ptr == NULL)
			return (1);
		// Set my render buffers to the back screen
#if DEBUG_LOCKED
		backscreen = (char *) DebugScreen;
#else
		backscreen = (char *) ptr;
#endif
	}

	return (0);

}

void	    UnlockClearBuffer(void)
{
#if DEBUG_LOCKED
	memcpy(RealScreen, DebugScreen, 320 * 240);
#endif
	if (bActive)
	{
		lpBack_Buffer->lpVtbl->Unlock(lpBack_Buffer, backDdsd.lpSurface);
	}
}

void	    BltClearToScreen(void)
{
	RECT	    dest_rect, src_rect;
	DWORD	   dwFlags;
	DDBLTFX	 DDBltFX;
	HRESULT	 ddrval;

	dest_rect.top = dest_rect.left = 0;
#if USE_ATI
	dest_rect.bottom = 239; //WinHeight;
#else
	dest_rect.bottom = 199; //WinHeight;
#endif
	dest_rect.right = 319; //WinWidth;

	src_rect.top = src_rect.left = 0;
#if USE_ATI
	src_rect.bottom = 239;
#else
	src_rect.bottom = 199;
#endif
	src_rect.right = 319;

	DDBltFX.dwSize = sizeof(DDBltFX);

	dwFlags = DDBLT_WAIT;

	ddrval = lpDDSBack->lpVtbl->Blt(lpDDSBack, &dest_rect, lpBack_Buffer, &src_rect, dwFlags, &DDBltFX);
	if (ddrval != DD_OK)
	{
		// Msg("Blt copy failed err=%d", ddrval);
		switch (ddrval)
		{
		case DDERR_SURFACELOST:
			MessageBeep(0);
			break;
		case DDERR_SURFACEBUSY:
			MessageBeep(0);
			break;
		}
		;
	}
}

void	    DDSwap(void)
{
	if (bActive)
	{
		while (1)
		{
			HRESULT	 ddrval;
			ddrval = lpDDSPrimary->lpVtbl->Flip(lpDDSPrimary, NULL, 0);
			if (ddrval == DD_OK)
			{
				break;
			}
			if (ddrval == DDERR_SURFACELOST)
			{
				ddrval = lpDDSPrimary->lpVtbl->Restore(lpDDSPrimary);
				if (ddrval != DD_OK)
				{
					break;
				}
			}
			if (ddrval != DDERR_WASSTILLDRAWING)
			{
				break;
			}
		}
	}
}

void	    DrawIT(void)
{
	DDSURFACEDESC   ddsd;
	LPBYTE	  ptr;
	// int			i;
	HRESULT	 ddrval;
	static int      err_count = 0;

	// Flip surfaces
	if (bActive)
	{
		ZeroMemory(&ddsd, sizeof(ddsd));
		ddsd.dwSize = sizeof(ddsd);

		ddrval = lpDDSBack->lpVtbl->Lock(lpDDSBack, NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL);

		if (ddrval == DDERR_SURFACEBUSY)
		{
			err_count++;
		}
		if (ddrval == DDERR_SURFACELOST)
		{
			MessageBeep(0);
			lpDDSBack->lpVtbl->Restore(lpDDSBack);
		}

		ptr = (LPBYTE) ddsd.lpSurface;
		if (ptr == NULL)
			return;
		// Set my render buffers to the back screen
		CurBuffer = (char *) ptr;
		CurBufferJ = (char *) ptr;

		// Render_Triangles();
		// Move_Triangles();
		lpDDSBack->lpVtbl->Unlock(lpDDSBack, ddsd.lpSurface);

		while (1)
		{
			HRESULT	 ddrval;
			ddrval = lpDDSPrimary->lpVtbl->Flip(lpDDSPrimary, NULL, 0);
			if (ddrval == DD_OK)
			{
				break;
			}
			if (ddrval == DDERR_SURFACELOST)
			{
				ddrval = lpDDSPrimary->lpVtbl->Restore(lpDDSPrimary);
				if (ddrval != DD_OK)
				{
					break;
				}
			}
			if (ddrval != DDERR_WASSTILLDRAWING)
			{
				break;
			}
		}
	}




}

void	    WinQuit(void)
{
#if DEBUG_LOCKED
	free(DebugScreen);
#endif
	finiObjects();
	finiSndObjects();
	PostQuitMessage(0);
}

void	    WinClearScreen(char colour)
{
	DDBLTFX	 ddbltfx;

	memset(&ddbltfx,0,sizeof(ddbltfx));
	ddbltfx.dwSize = sizeof(ddbltfx);
	ddbltfx.dwFillColor = colour;
	lpDDSBack->lpVtbl->Blt(lpDDSBack, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx);
}

void	    PitchMemCpy(char *dest, char *source, RECT * rect)
{
	int	     loop;

	for (loop = 0; loop < (rect->bottom - rect->top); loop++)
	{
		memcpy(dest, source, (rect->right - rect->left));
		dest += RealPitch;
		source += (rect->right - rect->left);
	}
}

void	    PitchMemCpy320X200(char *dest, char *source)
{
	RECT	    rect;
	int	     loop;

	rect.left = 0;
	rect.right = 320;
	rect.top = 0;
	rect.bottom = 199;
	for (loop = 0; loop < (rect.bottom - rect.top); loop++)
	{
		memcpy(dest, source, (rect.right - rect.left));
		dest += RealBackPitch;
		source += (rect.right - rect.left);
	}
}

#if USE_ATI

void SetContext(void)
{
	ATI3DCIF_ContextSetState(ghRC, C3D_ERS_SURF_DRAW_PTR,
					   (C3D_PRSDATA) & CurBuffer);
}

/*
 *  CloseATI3DCIF - destroy the rendering context and unload the ATI3DCIF module
 */
void CloseATI3DCIF (void)
{
	// destroy ATI 3D rendering context
	if (ghRC) ATI3DCIF_ContextDestroy (ghRC);

	// terminate the ATI 3D driver
	if (gbCIFInit) ATI3DCIF_Term ();
}

/*
 * InitATI3DCIF - create and initialize the ATI 3D rendering context
 */
BOOL	    InitATI3DCIF(void)
{
	// initialize the CIF driver
	if (ATI3DCIF_Init() != C3D_EC_OK)
	{
		wsprintf(gszErrMsg, "Could not initialize 3D driver");
		return FALSE;
	}
	// set flag indicating driver is loaded
	gbCIFInit = TRUE;

	// create the rendering context
	ghRC = ATI3DCIF_ContextCreate();
	if (!ghRC)
	{
		wsprintf(gszErrMsg, "Could not create 3D rendering context");
		return FALSE;
	}
	return TRUE;
}

void setRenderBegin(void)
{
	if(!Rendering)
	{
		ATI3DCIF_RenderBegin(ghRC);
		Rendering=TRUE;
		ATI3DCIF_ContextSetState(ghRC, C3D_ERS_PRIM_TYPE,
						   &quad);
		ATI3DCIF_ContextSetState(ghRC, C3D_ERS_SHADE_MODE,
						   &shade);
		ATI3DCIF_ContextSetState(ghRC, C3D_ERS_TMAP_EN, &bTexEn);
	//	ATI3DCIF_ContextSetState (ghRC, C3D_ERS_ALPHA_DST, &eDstAlpha);
	//	ATI3DCIF_ContextSetState (ghRC, C3D_ERS_ALPHA_SRC, &eSrcAlpha);
		ATI3DCIF_ContextSetState(ghRC, C3D_ERS_TMAP_PERSP_COR, &ePerspCorOff);
		ATI3DCIF_ContextSetState(ghRC, C3D_ERS_TMAP_FILTER, &eTexFilter);
	}
}

void PersCorOn()
{
	ATI3DCIF_ContextSetState(ghRC, C3D_ERS_TMAP_PERSP_COR, &ePerspCorOn);
}

void PersCorOff()
{
	ATI3DCIF_ContextSetState(ghRC, C3D_ERS_TMAP_PERSP_COR, &ePerspCorOff);
}

void setRenderEnd(void)
{
	if(Rendering)
	{
		ATI3DCIF_RenderEnd();
		Rendering=FALSE;
	}
}

void sendList(void)
{

	if(numvert)
	{
		if(numvert>tester)
			tester=numvert;
		setRenderBegin();
		ATI3DCIF_RenderPrimList(
					  testlist,
					 numvert);
		
	numvert=0;
	}
}

short jjstestsrc=0,jjstestdst=0,jjstest3=128;


BOOL SetState(C3D_EPRIM Quad, C3D_ESHADE Shade, BOOL BTexEn, BOOL Trans, C3D_ETLIGHT Light)
{
	BOOL change=FALSE;
	C3D_PRSDATA chkey = C3D_ETEXOP_NONE;
	
	if(Quad!=quad)
	{
		sendList();
		quad = Quad;
		ATI3DCIF_ContextSetState(ghRC, C3D_ERS_PRIM_TYPE,
						   &quad);
		change = TRUE;
	}
	if(Shade != shade)
	{
		if(!change)
			sendList();
		shade = Shade;
		ATI3DCIF_ContextSetState(ghRC, C3D_ERS_SHADE_MODE,
						   &shade);
		change = TRUE;
	}
	if(BTexEn != bTexEn)
	{
		if(!change)
			sendList();
		bTexEn = BTexEn;
		ATI3DCIF_ContextSetState(ghRC, C3D_ERS_TMAP_EN, &bTexEn);
		change = TRUE;
	}
	if(Light != light)
	{
		if(!change)
			sendList();
		light = Light;
		ATI3DCIF_ContextSetState(ghRC, C3D_ERS_TMAP_LIGHT, &light);
		change = TRUE;
	}
	if(Trans != trans)
	{
		if(!change)
			sendList();
		trans = Trans;
		if(trans)
		{
			switch(trans)
			{
				case BLACK_NOT_DRAWN:
					chkey = C3D_ETEXOP_CHROMAKEY;//SJR - make 0,0,0 trans
					eDstAlpha = C3D_EADST_ZERO;
					eSrcAlpha = C3D_EASRC_ONE;
					break;
				case BLACK5_TRANSL:
				case BLACK1_TRANSL:
				case BLACK2_TRANSL:
				case BLACK3_TRANSL:
				case BLACK4_TRANSL:		
				case BLACK6_TRANSL:
				case RED_TRANSL:
					chkey = C3D_ETEXOP_CHROMAKEY;//SJR - make 0,0,0 trans
					eDstAlpha = C3D_EADST_ZERO;
					eSrcAlpha = C3D_EASRC_DSTCLR;
					break;
				case WHITE1_TRANSL:
				case WHITE2_TRANSL:
				case WHITE3_TRANSL:
				case WHITE4_TRANSL:
				case WHITE5_TRANSL:
				case WHITE6_TRANSL:
				case WHITE7_TRANSL:
				case WHITE8_TRANSL:
				default:
					eDstAlpha = C3D_EADST_ONE;
					eSrcAlpha = C3D_EASRC_INVDSTCLR;
					
					break;
			}
		}
		else
		{
			eDstAlpha = C3D_EADST_ZERO;
			eSrcAlpha = C3D_EASRC_ONE;
		}
		ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_TEXOP, &chkey);
		ATI3DCIF_ContextSetState (ghRC, C3D_ERS_ALPHA_DST, &eDstAlpha);
		ATI3DCIF_ContextSetState (ghRC, C3D_ERS_ALPHA_SRC, &eSrcAlpha);

		change = TRUE;
	}
	return(change);
}

void JJSDrawSprite(SPRT_8 *sp,short w, short h)
{
	C3D_PVTCF       v;
	//C3D_PRSDATA chkey;
	short tpage;
	short nu,nv;

	if(!SetState(C3D_EPRIM_QUAD,C3D_ESH_FLAT,TRUE,sp->b0==RED_TRANSL?RED_TRANSL:BLACK_NOT_DRAWN,C3D_ETL_NONE))
		if(numvert>(VBUFSIZE-4))
			sendList();
	tpage=JJSTextureTable[sp->clut&0x1f];
	switch(tpage)
	{
		case 12:
			tpage=22;
			break;
		case 15:
			tpage=23;
			break;
		default:
			tpage=24;
			break;
	}
	nu=sp->u0;
	nv=sp->v0;
	if(sp->g0 && tpage == 23)
	{
		tpage = 24;
		nv+=128;
	}
	if(texpage !=tpage)
	{
		sendList();
		texpage=tpage;
		ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_SELECT, &(gTex[texpage].hTX));
	}
	v = &testarray[numvert++];
	v->x = sp->x0;
	v->y = sp->y0;
	v->z = 0;
	v->s = nu/256.0;
	v->t = nv/256.0;
	v->w = 1.0;
	v = &testarray[numvert++];
	v->x = sp->x0+w;
	v->y = sp->y0;
	v->z = 0;
	v->s = (nu+w)/256.0;
	v->t = nv/256.0;
	v->w = 1.0;
	v = &testarray[numvert++];
	v->x = sp->x0+w;
	v->y = sp->y0+h;
	v->z = 0;
	v->s = (nu+w)/256.0;
	v->t = (nv+h)/256.0;
	v->w = 1.0;
	v = &testarray[numvert++];
	v->x = sp->x0;
	v->y = sp->y0+h;
	v->z = 0;
	v->s = nu/256.0;
	v->t = (nv+h)/256.0;
	v->w = 1.0;
}

void JJS_Sprite(SPRT *sp)
{
	JJSDrawSprite((SPRT_8 *)sp,sp->w,sp->h);
}

void JJS_Sprite8(SPRT_8 *sp)
{
	JJSDrawSprite(sp,8,8);
}

void setColor(C3D_PVTCF v,char r, char g, char b)
{
	if(b)
	{
		switch(b)
		{
			case BLACK2_TRANSL:
				v->r=180;
				v->g=180;
				v->b=180;
				break;
			case WHITE2_TRANSL:
			default:
				v->r=100;
				v->g=100;
				v->b=100;
				break;
		}
	}
	else
	if(g)
	{
		int r;
		
		r=(&DepthFadeTble)[(g<<8) + WhitePal];
		v->r=ddPalette[r].peRed;
		v->g=ddPalette[r].peGreen;
		v->b=ddPalette[r].peBlue;
	}
	else
	{
		v->r=ddPalette[r].peRed;
		v->g=ddPalette[r].peGreen;
		v->b=ddPalette[r].peBlue;
		
	}
}
	
void	    JJSDrawPolyF4(POLY_F4 * p)
{
	C3D_PVTCF       v;

	if(!SetState(C3D_EPRIM_QUAD,C3D_ESH_FLAT,FALSE,p->b0,C3D_ETL_NONE))
		if(numvert>(VBUFSIZE-4))
			sendList();

	v = &testarray[numvert++];
	v->x = p->x0;
	v->y = p->y0;
	v->z = 0;
	v = &testarray[numvert++];
	v->x = p->x1;
	v->y = p->y1;
	v->z = 0;
	v = &testarray[numvert++];
	v->x = p->x3;
	v->y = p->y3;
	v->z = 0;
	v = &testarray[numvert++];
	v->x = p->x2;
	v->y = p->y2;
	v->z = 0;
	SetColor(v,p->r0,p->g0,p->b0);
}

void	    JJSDrawPolyG4(POLY_G4 * p)
{
	C3D_PVTCF       v;

	if(!SetState(C3D_EPRIM_QUAD,C3D_ESH_FLAT,FALSE,p->b0,C3D_ETL_NONE))
		if(numvert>(VBUFSIZE-4))
			sendList();
	v = &testarray[numvert++];
	v->x = p->x0;
	v->y = p->y0;
	v->z = 0;
	v = &testarray[numvert++];
	v->x = p->x1;
	v->y = p->y1;
	v->z = 0;
	v = &testarray[numvert++];
	v->x = p->x3;
	v->y = p->y3;
	v->z = 0;
	v = &testarray[numvert++];
	v->x = p->x2;
	v->y = p->y2;
	v->z = 0;
	SetColor(v,p->r0,p->g0,p->b0);
}

void	    JJSDrawPolyFT4(POLY_FT4 * p)
{
	C3D_PVTCF       v;
	//C3D_PRSDATA chkey;

	if(!SetState(C3D_EPRIM_QUAD,C3D_ESH_FLAT,FALSE,p->b0,p->g0?C3D_ETL_MODULATE:C3D_ETL_NONE))
//	if(!SetState(C3D_EPRIM_QUAD,C3D_ESH_FLAT,TRUE,p->b0,p->g0?C3D_ETL_MODULATE:C3D_ETL_NONE))
		if(numvert>(VBUFSIZE-4))
			sendList();
	if(texpage !=JJSTextureTable[p->tpage&0x1f])
	{
		sendList();
		texpage=JJSTextureTable[p->tpage&0x1f];
		ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_SELECT, &(gTex[texpage].hTX));
	}

	v = &testarray[numvert++];
	v->x = p->x0;
	v->y = p->y0;
	v->z = 0;
	v->s = p->u0/256.0;
	v->t = p->v0/256.0;
	v->w = 1.0;
	v = &testarray[numvert++];
	v->x = p->x1;
	v->y = p->y1;
	v->z = 0;
	v->s = p->u1/256.0;
	v->t = p->v1/256.0;
	v->w = 1.0;
	v = &testarray[numvert++];
	v->x = p->x3;
	v->y = p->y3;
	v->z = 0;
	v->s = p->u3/256.0;
	v->t = p->v3/256.0;
	v->w = 1.0;
	v = &testarray[numvert++];
	v->x = p->x2;
	v->y = p->y2;
	v->z = 0;
	v->s = p->u2/256.0;
	v->t = p->v2/256.0;
	v->w = 1.0;
	if (p->g0)
		SetColor(v,p->r0,p->g0,p->b0);
	else
		SetColor(v,255,255,0);
}

void	    JJSDrawPolyF3(POLY_F4 * p)
{
	C3D_PVTCF       v;

	if(!SetState(C3D_EPRIM_TRI,C3D_ESH_FLAT,FALSE,p->b0,C3D_ETL_NONE))
		if(numvert>(VBUFSIZE-4))
			sendList();

	v = &testarray[numvert++];
	v->x = p->x0;
	v->y = p->y0;
	v->z = 0;
	v = &testarray[numvert++];
	v->x = p->x1;
	v->y = p->y1;
	v->z = 0;
	v = &testarray[numvert++];
	v->x = p->x2;
	v->y = p->y2;
	v->z = 0;
	SetColor(v,p->r0,p->g0,p->b0);
}

void	    JJSDrawPolyG3(POLY_G3 * p)
{
	C3D_PVTCF       v;

	if(!SetState(C3D_EPRIM_TRI,C3D_ESH_FLAT,FALSE,p->b0,C3D_ETL_NONE))
		if(numvert>(VBUFSIZE-4))
			sendList();

	v = &testarray[numvert++];
	v->x = p->x0;
	v->y = p->y0;
	v->z = 0;
	v = &testarray[numvert++];
	v->x = p->x1;
	v->y = p->y1;
	v->z = 0;
	v = &testarray[numvert++];
	v->x = p->x2;
	v->y = p->y2;
	v->z = 0;
	SetColor(v,p->r0,p->g0,p->b0);
}

void	    JJSDrawPolyFT3(POLY_FT3 * p)
{
	C3D_PVTCF       v;

	if(!SetState(C3D_EPRIM_TRI,C3D_ESH_FLAT,FALSE,p->b0,p->g0?C3D_ETL_MODULATE:C3D_ETL_NONE))
//	if(!SetState(C3D_EPRIM_TRI,C3D_ESH_FLAT,TRUE,p->b0,p->g0?C3D_ETL_MODULATE:C3D_ETL_NONE))
		if(numvert>(VBUFSIZE-4))
			sendList();
	if(texpage!=JJSTextureTable[p->tpage&0x1f])
	{
		sendList();
		texpage=JJSTextureTable[p->tpage&0x1f];
		ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_SELECT, &(gTex[texpage].hTX));
	}

	v = &testarray[numvert++];
	v->x = p->x0;
	v->y = p->y0;
	v->z = 0;
	v->s = p->u0/256.0;
	v->t = p->v0/256.0;
	v->w = 1.0;
	v = &testarray[numvert++];
	v->x = p->x1;
	v->y = p->y1;
	v->z = 0;
	v->s = p->u1/256.0;
	v->t = p->v1/256.0;
	v->w = 1.0;
	v = &testarray[numvert++];
	v->x = p->x2;
	v->y = p->y2;
	v->z = 0;
	v->s = p->u2/256.0;
	v->t = p->v2/256.0;
	v->w = 1.0;

	if (p->g0)
		SetColor(v,p->r0,p->g0,p->b0);
	else
		SetColor(v,255,255,0);
}

void	    JJSDrawPolyGT3(POLY_GT3 * p)
{
	C3D_PVTCF       v;

	//p->b0
	if(!SetState(C3D_EPRIM_TRI,C3D_ESH_FLAT,FALSE,0,C3D_ETL_NONE))
//	if(!SetState(C3D_EPRIM_TRI,C3D_ESH_FLAT,TRUE,0,C3D_ETL_NONE))
		if(numvert>(VBUFSIZE-4))
			sendList();

	if(texpage!=JJSTextureTable[p->tpage&0x1f])
	{
		sendList();
		texpage=JJSTextureTable[p->tpage&0x1f];
		ATI3DCIF_ContextSetState (ghRC, C3D_ERS_TMAP_SELECT, &(gTex[texpage].hTX));
	}

	v = &testarray[numvert++];
	v->x = p->x0;
	v->y = p->y0;
	v->z = 0;
	v->s = p->u0/256.0;
	v->t = p->v0/256.0;
	v->w = 1.0;
	v = &testarray[numvert++];
	v->x = p->x1;
	v->y = p->y1;
	v->z = 0;
	v->s = p->u1/256.0;
	v->t = p->v1/256.0;
	v->w = 1.0;
	v = &testarray[numvert++];
	v->x = p->x2;
	v->y = p->y2;
	v->z = 0;
	v->s = p->u2/256.0;
	v->t = p->v2/256.0;
	v->w = 1.0;
	SetColor(v,255,255,0);
}

/*
 *  LoadTexture - load a texture map from a file into a texture surface
 */
BOOL LoadTextureBMP (const char* lpszTexFilename, PTEXTURE pTex)
{
    HRESULT             ddretval;
	C3D_UINT32			log2X = 0L;
	C3D_UINT32			log2Y = 0L;
	C3D_TMAP			TMap;
	int					k, maxlog2;
	C3D_EC				ecRetVal;
	HANDLE				hTexFile;
	BITMAPFILEHEADER	bmfh;
	BITMAPINFOHEADER	bmih;
	C3D_UINT32			bufsize;
	void*				ptmap;
	void*				bmdata;
	C3D_UINT32			pitch;
	C3D_UINT8			r, g, b;
	C3D_UINT16			rgb565;
	DWORD				bytesread;
	int	x,y;

	// validate pTex
	if (!pTex)
	{
		wsprintf (gszErrMsg, "LoadTexture %s: invalid pointer", lpszTexFilename);
		return FALSE;
	}

	// open texture map file for reading
	hTexFile = CreateFile (
		lpszTexFilename,
		GENERIC_READ,
		FILE_SHARE_READ,
		NULL,
		OPEN_EXISTING,
		FILE_FLAG_SEQUENTIAL_SCAN,
		NULL);
	if (hTexFile == INVALID_HANDLE_VALUE)
	{
		wsprintf (gszErrMsg, "Could not open texture map file");
		return FALSE;
	}

	// read headers and bitmap data
	// first, determine buffer size required for BITMAPINFO and data
	bufsize = GetFileSize (hTexFile, NULL);
	if (bufsize == 0xFFFFFFFFL)
	{
		wsprintf (gszErrMsg, "Error getting texture file size");
		CloseHandle (hTexFile);
		return FALSE;
	}

	// adjust bufsize for BITMAFILEHEADER
	bufsize -= sizeof (bmfh);
	ptmap = (void*) HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, sizeof (char) * bufsize);
	if (!ptmap)
	{
		wsprintf (gszErrMsg, "Could not allocate memory for texture map data");
		CloseHandle (hTexFile);
		return FALSE;
	}

	// read BITMAPFILEHEADER
	if (!ReadFile (hTexFile, &bmfh, sizeof (bmfh), &bytesread, NULL) || 
		(bytesread != sizeof (bmfh)))
	{
		HeapFree (GetProcessHeap (), 0, ptmap);
		CloseHandle (hTexFile);
		wsprintf (gszErrMsg, "Error reading file header");
		return FALSE;
	}

	// read BITMAPINFO and bitmap data
	if (!ReadFile (hTexFile, ptmap, bufsize, &bytesread, NULL) || 
		(bytesread != bufsize))
	{
		HeapFree (GetProcessHeap (), 0, ptmap);
		CloseHandle (hTexFile);
		wsprintf (gszErrMsg, "Error reading bitmap header and data");
		return FALSE;
	}

	// close the texture file; we're done with it
	CloseHandle (hTexFile);

	// read BITMAPINFOHEADER
	memcpy (&bmih, ptmap, sizeof (BITMAPINFOHEADER));

	// ensure width is power of 2 <= 1024
	while (log2X <= 11)
	{
		if ((pow (2.0, (double)log2X)) == (double)bmih.biWidth) break;
		log2X++;
	}
	if (log2X == 11)
	{
		wsprintf (gszErrMsg, "Width of texture %s greater than 1024 or not a power of 2", 
			lpszTexFilename);
		HeapFree (GetProcessHeap (), 0, ptmap);
		return FALSE;
	}

	// ensure height is power of 2 <= 1024
	while (log2Y <= 11)
	{
		if ((pow (2.0, (double)log2Y)) == (double)bmih.biHeight) break;
		log2Y++;
	}
	if (log2Y == 11)
	{
		wsprintf (gszErrMsg, "Height of texture %s greater than 1024 or not a power of 2", 
			lpszTexFilename);
		HeapFree (GetProcessHeap (), 0, ptmap);
		return FALSE;
	}

	// create an offscreen surface to cache the texture map
	ZeroMemory (&(pTex->ddsd), sizeof (pTex->ddsd));
	pTex->ddsd.dwSize = sizeof (pTex->ddsd);
	pTex->ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
	pTex->ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
	pTex->ddsd.dwWidth = bmih.biWidth;
	pTex->ddsd.dwHeight = bmih.biHeight;
	ddretval = lpDD->lpVtbl->CreateSurface (lpDD,&(pTex->ddsd), &pTex->lpDDSTex, NULL);
	if (ddretval != DD_OK)
	{
		wsprintf (gszErrMsg, "Could not create texture surface for file %s", lpszTexFilename);
		HeapFree (GetProcessHeap (), 0, ptmap);
		return FALSE;
	}

	// get a pointer to the texture surface
	ZeroMemory (&(pTex->ddsd), sizeof (pTex->ddsd));
	pTex->ddsd.dwSize = sizeof (pTex->ddsd);
	// lock texture to fill ddsd member
	ddretval = pTex->lpDDSTex->lpVtbl->Lock (pTex->lpDDSTex,
		NULL,
		&(pTex->ddsd),
		DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,
		NULL);
	if (ddretval == DDERR_SURFACELOST) pTex->lpDDSTex->lpVtbl->Restore (pTex->lpDDSTex);
	// unlock surface
	ddretval = pTex->lpDDSTex->lpVtbl->Unlock (pTex->lpDDSTex,NULL);
	if (ddretval != DD_OK)
	{
		wsprintf (gszErrMsg, "Error unlocking texture surface for file %s", lpszTexFilename);
		HeapFree (GetProcessHeap (), 0, ptmap);
		pTex->lpDDSTex->lpVtbl->Release (pTex->lpDDSTex);
		pTex->lpDDSTex = NULL;
		return FALSE;
	}

	// pitch of each scan line
	if(bmih.biSizeImage)
	{
		pitch = bmih.biSizeImage / bmih.biHeight;
		// set pointer to start of bm data
		bmdata = (char*)ptmap + (bufsize - bmih.biSizeImage);
	}
	else
	{
		pitch = bmih.biWidth * 3;		// JJS for BMPs without biSizeImage
 		// set pointer to start of bm data
		bmdata = (char*)ptmap + (bufsize - pitch * bmih.biHeight);
	}

	// line counter
	for (y=((int)bmih.biHeight-1); y>=0; y--)
	{
		// scan line pixel counter
		for (x=0; x<(int)bmih.biWidth; x++)
		{
			// read RGB
			memcpy (&b, (char*)bmdata + (y*pitch)+(3*x), sizeof (C3D_UINT8));
			memcpy (&g, (char*)bmdata + (y*pitch)+(3*x)+1, sizeof (C3D_UINT8));
			memcpy (&r, (char*)bmdata + (y*pitch)+(3*x)+2, sizeof (C3D_UINT8));

			// pack color data in 16bpp format

//#define RGB_555
#ifndef RGB_555
			// pack data in RGB 555 format
			rgb565 = ((C3D_UINT32)r & 0xf8) << 8 |
					 ((C3D_UINT32)g & 0xfc) << 3 |
					 ((C3D_UINT32)b & 0xf8) >> 3;
#else
			// pack data in RGB 565 format
			rgb565 = ((C3D_UINT32)r & 0xf8) << 7 |
					 ((C3D_UINT32)g & 0xf8) << 2 |
					 ((C3D_UINT32)b & 0xf8) >> 3;
#endif
			// write texture data to texture cache
			memcpy ((char*)pTex->ddsd.lpSurface + ((bmih.biHeight-y-1)*(bmih.biWidth*2))+(2*x), &rgb565, sizeof (C3D_UINT16));
		}
	}

	// free the texture file buffer
		HeapFree (GetProcessHeap (), 0, ptmap);

	// fill a C3D_TMAP struct
	ZeroMemory (&TMap, sizeof (TMap));
	TMap.u32Size = sizeof (TMap);

	// determine the maximum log2 dimension
	maxlog2 = (int)(log2X >= log2Y? log2X : log2Y);
	for (k=0; k < maxlog2; k++)
		TMap.apvLevels[k] = pTex->ddsd.lpSurface;

	TMap.bMipMap = FALSE;
	TMap.u32MaxMapXSizeLg2 = log2X;
	TMap.u32MaxMapYSizeLg2 = log2Y;
	TMap.eTexFormat = C3D_ETF_RGB565;
//JJS	TMap.bTexTranspEnable = FALSE;
	SET_CIF_COLOR (TMap.clrTexChromaKey, 0, 0, 0, 0);

	// register the texture
	ecRetVal = ATI3DCIF_TextureReg (&TMap, &(pTex->hTX));
	if (ecRetVal != C3D_EC_OK)
	{
		wsprintf (gszErrMsg, "Error registering texture for file %s", lpszTexFilename);
		pTex->lpDDSTex->lpVtbl->Release (pTex->lpDDSTex);
		pTex->lpDDSTex = NULL;
		return FALSE;
	}

	return TRUE;
}


/*
 *  UnloadTexture - unregister texture and release its surface
 */
BOOL UnloadTexture (PTEXTURE pTex)
{
	if (!pTex)
	{
		wsprintf (gszErrMsg, "UnloadTexture: invalid pointer");
		return FALSE;
	}

	// unregister the texture if a non-NULL handle
	if (pTex->hTX)
	{
 		ATI3DCIF_TextureUnreg (pTex->hTX);
	}

	// unlock and release the texture surface
	if (pTex->lpDDSTex)
	{
		pTex->lpDDSTex->lpVtbl->Release (pTex->lpDDSTex);
		pTex->lpDDSTex = NULL;
	}

	return TRUE;;
}

/*
 *  LoadTexture - load a texture map from a file into a texture surface
 */

BOOL SJRLoadTextureBMP (const char* lpszTexFilename)
{
	int fp;
    HRESULT             ddretval;
	C3D_TMAP			TMap;
	int					i, k, maxlog2;
	C3D_EC				ecRetVal;
	//HANDLE				hTexFile;
	C3D_UINT32			bufsize;
	int	whichSurface;
	long 				texsize;
	char *			*ptr, *bmpdata, *p1;
	unsigned short *p2,*t2, t;

	
	texsize = 32768;//128*128 * sizeof (C3D_UINT16)

	fp = open(lpszTexFilename, O_RDONLY | O_BINARY);
	if (fp<0)
	{
		wsprintf (gszErrMsg, "Could not open texture map file");
		return FALSE;
	}

	bufsize = 18 * texsize + 4 * texsize * 4;

	bmpdata = (char *)malloc(bufsize);
	if( bmpdata == NULL ) {
		return FALSE;
    }
	read(fp, (void *)bmpdata, bufsize);
	close(fp);

	ptr = bmpdata;

	for (whichSurface=0; whichSurface< 22; whichSurface++)
	{
		// get a pointer to the texture surface
		ZeroMemory (&(gTex[whichSurface].ddsd), sizeof (gTex[whichSurface].ddsd));
		gTex[whichSurface].ddsd.dwSize = sizeof (gTex[whichSurface].ddsd);

		// lock texture to fill ddsd member
		ddretval = gTex[whichSurface].lpDDSTex->lpVtbl->Lock (gTex[whichSurface].lpDDSTex,
			NULL,
			&(gTex[whichSurface].ddsd),
			DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,
			NULL);
		if (ddretval == DDERR_SURFACELOST)
			gTex[whichSurface].lpDDSTex->lpVtbl->Restore (gTex[whichSurface].lpDDSTex);
		p1 = (char *)gTex[whichSurface].ddsd.lpSurface;

#if 1
		if(whichSurface<4)
			memcpy(p1, bmpdata, texsize*4);
		else
			memcpy(p1, bmpdata, texsize);
#else
		p2=(unsigned short *)p1;
		t2=(unsigned short *)bmpdata;
		for (k = 0; k < texsize/2; k++)
		{
			t=*t2++;
			*p2++=(t&0x1f)|((t&0xffe0)>>1);
		}
#endif
		if(whichSurface<4)
			bmpdata += texsize*4;
		else
			bmpdata += texsize;
		ddretval = gTex[whichSurface].lpDDSTex->lpVtbl->Unlock (gTex[whichSurface].lpDDSTex,NULL);
		if (ddretval != DD_OK)
		{
			wsprintf (gszErrMsg, "Error unlocking texture surface for file %s", lpszTexFilename);
			gTex[whichSurface].lpDDSTex->lpVtbl->Release (gTex[whichSurface].lpDDSTex);
			gTex[whichSurface].lpDDSTex = NULL;
			return FALSE;
		}

		// fill a C3D_TMAP struct
		ZeroMemory (&TMap, sizeof (TMap));
		TMap.u32Size = sizeof (TMap);

		// determine the maximum log2 dimension
		if(whichSurface<4)
			maxlog2 = 8;
		else
			maxlog2 = 7;
		for (k=0; k < maxlog2; k++)
		{
			TMap.apvLevels[k] = gTex[whichSurface].ddsd.lpSurface;
		}

		TMap.bMipMap = FALSE;
		TMap.u32MaxMapXSizeLg2 = maxlog2;
		TMap.u32MaxMapYSizeLg2 = maxlog2;
		TMap.eTexFormat = C3D_ETF_RGB1555;

		SET_CIF_COLOR (TMap.clrTexChromaKey, 0, 0, 0, 0);

		// register the texture
		ecRetVal = ATI3DCIF_TextureReg (&TMap, &(gTex[whichSurface].hTX));
		if (ecRetVal != C3D_EC_OK)
		{
			wsprintf (gszErrMsg, "Error registering texture for file %s", lpszTexFilename);
			gTex[i].lpDDSTex->lpVtbl->Release (gTex[i].lpDDSTex);
			gTex[i].lpDDSTex = NULL;
			return FALSE;
		}
	}
		
	free(ptr);
	return TRUE;
}

/*
 *  LoadTexture - load a texture map from a file into a texture surface
 */

BOOL JJSLoadSprites (void)
{
	int fp;
    HRESULT             ddretval;
	C3D_TMAP			TMap;
	int					k, maxlog2;
	C3D_EC				ecRetVal;
	//HANDLE				hTexFile;
	C3D_UINT32			bufsize;
	int	sp;
	long 				texsize;
	char *			*ptr, *bmpdata, *p1;
	static char* lpszTexFilename[3]={
		"wipeout\\newgraph\\menu\\page12.sjr",
		"wipeout\\newgraph\\menu\\page15.sjr",
		"wipeout\\newgraph\\menu\\page17.sjr"
	};

	texsize = 256 * 256 * sizeof (C3D_UINT16);

	bufsize = texsize;
	
	bmpdata = (char *)malloc(bufsize);
	if( bmpdata == NULL )
	{
		return FALSE;
	}

	for(sp=0;sp<3;++sp)
	{
		fp = open(lpszTexFilename[sp], O_RDONLY | O_BINARY);
		if (fp<0)
		{
			wsprintf (gszErrMsg, "Could not open texture map file");
			return FALSE;
		}
	
		read(fp, (void *)bmpdata, bufsize);
		close(fp);
	
		ptr = bmpdata;
	
		// get a pointer to the texture surface
		ZeroMemory (&(gTex[sp+22].ddsd), sizeof (gTex[sp+22].ddsd));
		gTex[sp+22].ddsd.dwSize = sizeof (gTex[sp+22].ddsd);
	
		// lock texture to fill ddsd member
		ddretval = gTex[sp+22].lpDDSTex->lpVtbl->Lock (gTex[sp+22].lpDDSTex,
			NULL,
			&(gTex[sp+22].ddsd),
			DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,
			NULL);
		if (ddretval == DDERR_SURFACELOST)
			gTex[sp+22].lpDDSTex->lpVtbl->Restore (gTex[sp+22].lpDDSTex);
		p1 = (char *)gTex[sp+22].ddsd.lpSurface;
	
		memcpy(p1, bmpdata, texsize);

		ddretval = gTex[sp+22].lpDDSTex->lpVtbl->Unlock (gTex[sp+22].lpDDSTex,NULL);
		if (ddretval != DD_OK)
		{
			wsprintf (gszErrMsg, "Error unlocking texture surface for file %s", lpszTexFilename);
			gTex[sp+22].lpDDSTex->lpVtbl->Release (gTex[sp+22].lpDDSTex);
			return FALSE;
		}

		// fill a C3D_TMAP struct

		ZeroMemory (&TMap, sizeof (TMap));
		TMap.u32Size = sizeof (TMap);

		// determine the maximum log2 dimension
		maxlog2 = 8;
		for (k=0; k < maxlog2; k++)
		{
			TMap.apvLevels[k] = gTex[sp+22].ddsd.lpSurface;
		}

		TMap.bMipMap = FALSE;
		TMap.u32MaxMapXSizeLg2 = 8;
		TMap.u32MaxMapYSizeLg2 = 8;
		TMap.eTexFormat = C3D_ETF_RGB1555;

		SET_CIF_COLOR (TMap.clrTexChromaKey, 0, 0, 0, 0);

		// register the texture
		ecRetVal = ATI3DCIF_TextureReg (&TMap, &(gTex[sp+22].hTX));
		if (ecRetVal != C3D_EC_OK)
		{
			wsprintf (gszErrMsg, "Error registering texture for file %s", lpszTexFilename[sp]);
			gTex[sp+22].lpDDSTex->lpVtbl->Release (gTex[sp+22].lpDDSTex);
			gTex[sp+22].lpDDSTex = NULL;
			return FALSE;
		}
	}
		
	free(ptr);
	return TRUE;
}

BOOL JJSLoadRage (void)
{
	int fp;
    HRESULT             ddretval;
	DDSURFACEDESC       ddsd;
	C3D_TMAP			TMap;
	int					 maxlog2;
	C3D_EC				ecRetVal;
	HANDLE				hTexFile;
	C3D_UINT32			bufsize;
	int	i,sp;
	long 				texsize;
	char *			*ptr, *bmpdata, *p1;
	static char* lpszTexFilename[2]={
		"wipeout\\newgraph\\legal.sjr",
		"wipeout\\newgraph\\rage.sjr"
	};

	texsize = 320 * 240 * sizeof (C3D_UINT16);

	bufsize = texsize;
	
	bmpdata = (char *)malloc(bufsize);
	if( bmpdata == NULL )
	{
		return FALSE;
	}

	for(sp=0;sp<2;++sp)
	{
		fp = open(lpszTexFilename[sp], O_RDONLY | O_BINARY);
		if (fp<0)
		{
			wsprintf (gszErrMsg, "Could not open texture map file");
			return FALSE;
		}
	
		read(fp, (void *)bmpdata, bufsize);
		close(fp);
	
		ptr = bmpdata;
	
		// get a pointer to the texture surface
		ZeroMemory (&ddsd, sizeof (ddsd));
		ddsd.dwSize = sizeof (ddsd);
	
		// lock texture to fill ddsd member
		ddretval = lpDDSBack->lpVtbl->Lock (lpDDSBack,
			NULL,
			&ddsd,
			DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,
			NULL);
		if (ddretval == DDERR_SURFACELOST)
			lpDDSBack->lpVtbl->Restore (lpDDSBack);
		p1 = (char *)ddsd.lpSurface;
	
		memcpy(p1, bmpdata, texsize);

		ddretval = lpDDSBack->lpVtbl->Unlock (lpDDSBack,NULL);
		if (ddretval != DD_OK)
		{
			wsprintf (gszErrMsg, "Error unlocking texture surface for file %s", lpszTexFilename);
			lpDDSBack->lpVtbl->Release (lpDDSBack);
			return FALSE;
		}
		DDSwap();
		WinClearScreen(0);
		sleep(3);
	}
	DDSwap();
		
	free(ptr);
	return TRUE;
}
/*
BOOL JJSLoadTextureBMP (const char* lpszTexFilename)
{
	int fp;
    HRESULT             ddretval;
	C3D_TMAP			TMap;
	int					k, maxlog2;
	C3D_EC				ecRetVal;
	HANDLE				hTexFile;
	BITMAPFILEHEADER	bmfh;
	BITMAPINFOHEADER	bmih;
	C3D_UINT32			bufsize;
	char*				bmdata;
	short*				p1;
	C3D_UINT32			pitch;
	C3D_UINT8			r, g, b;
	C3D_UINT16			rgb565;
	int	x,y,count,whichSurface,i;
	HANDLE           hFileMapping;
	LPBYTE           pBase;


	// open texture map file for reading
	hTexFile = CreateFile (
		lpszTexFilename,
		GENERIC_READ,
		FILE_SHARE_READ,
		NULL,
		OPEN_EXISTING,
		FILE_FLAG_RANDOM_ACCESS,
		NULL);
	if (hTexFile == INVALID_HANDLE_VALUE)
	{
		wsprintf (gszErrMsg, "Could not open texture map file");
		return FALSE;
	}

	// read headers and bitmap data
	// first, determine buffer size required for BITMAPINFO and data
	bufsize = GetFileSize (hTexFile, NULL);
	if (bufsize == 0xFFFFFFFFL)
	{
		wsprintf (gszErrMsg, "Error getting texture file size");
		CloseHandle (hTexFile);
		return FALSE;
	}

        hFileMapping = CreateFileMapping( hTexFile, NULL, PAGE_READONLY, 0, 0, NULL );
        if( hFileMapping == NULL ) {
            return FALSE;
        }

        pBase = MapViewOfFile( hFileMapping, FILE_MAP_READ, 0, 0, 0 );
        if( pBase == NULL ) {
             return FALSE;
        }
	// adjust bufsize for BITMAFILEHEADER
	bufsize -= sizeof (bmfh);

	// read BITMAPFILEHEADER
	memcpy(&bmfh,pBase,sizeof(bmfh));
	pBase+=sizeof(bmfh);

	// read BITMAPINFO and bitmap data
	memcpy (&bmih, pBase, sizeof (BITMAPINFOHEADER));
	pBase+=sizeof (BITMAPINFOHEADER);

	// unlock surface

	bmdata = pBase;
	// pitch of each scan line
	if(bmih.biSizeImage)
	{
		pitch = bmih.biSizeImage / bmih.biHeight;
	}
	else
	{
		pitch = bmih.biWidth * 3;		// JJS for BMPs without biSizeImage
	}

	whichSurface=-1;
	// line counter
	for (y=8192-1,count=0; y>=0; y-=2,count+=2)
	{
		if(count<1280 || ((count>=16*256) && (count < 21*256)))
			continue;
		if(count%256 == 0)
		{
			if(whichSurface>=0)
			{
				ddretval = gTex[whichSurface].lpDDSTex->lpVtbl->Unlock (gTex[whichSurface].lpDDSTex,NULL);
				if (ddretval != DD_OK)
				{
					wsprintf (gszErrMsg, "Error unlocking texture surface for file %s", lpszTexFilename);
					gTex[whichSurface].lpDDSTex->lpVtbl->Release (gTex[whichSurface].lpDDSTex);
					gTex[whichSurface].lpDDSTex = NULL;
					return FALSE;
				}
			}
			++whichSurface;
			// get a pointer to the texture surface
			ZeroMemory (&(gTex[whichSurface].ddsd), sizeof (gTex[whichSurface].ddsd));
			gTex[whichSurface].ddsd.dwSize = sizeof (gTex[whichSurface].ddsd);
			// lock texture to fill ddsd member
			ddretval = gTex[whichSurface].lpDDSTex->lpVtbl->Lock (gTex[whichSurface].lpDDSTex,
				NULL,
				&(gTex[whichSurface].ddsd),
				DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,
				NULL);
			if (ddretval == DDERR_SURFACELOST) gTex[whichSurface].lpDDSTex->lpVtbl->Restore (gTex[whichSurface].lpDDSTex);
			p1=(short*)gTex[whichSurface].ddsd.lpSurface;
		}
		// scan line pixel counter
		for (x=0; x<256; x+=2)
		{
			// read RGB
			memcpy (&b, (char*)bmdata + (y*pitch)+(3*x), sizeof (C3D_UINT8));
			memcpy (&g, (char*)bmdata + (y*pitch)+(3*x)+1, sizeof (C3D_UINT8));
			memcpy (&r, (char*)bmdata + (y*pitch)+(3*x)+2, sizeof (C3D_UINT8));

			// pack color data in 16bpp format

//#define RGB_555
//#ifndef RGB_555
			// pack data in RGB 555 format
			rgb565 = ((C3D_UINT32)r & 0xf8) << 8 |
					 ((C3D_UINT32)g & 0xfc) << 3 |
					 ((C3D_UINT32)b & 0xf8) >> 3;
//#else
			// pack data in RGB 565 format
			//rgb565 = ((C3D_UINT32)r & 0xf8) << 7 |
					 //((C3D_UINT32)g & 0xf8) << 2 |
					 //((C3D_UINT32)b & 0xf8) >> 3;
//#endif
			*p1++=rgb565;
			// write texture data to texture cache
		}
	}

	ddretval = gTex[whichSurface].lpDDSTex->lpVtbl->Unlock (gTex[whichSurface].lpDDSTex,NULL);
	if (ddretval != DD_OK)
	{
		wsprintf (gszErrMsg, "Error unlocking texture surface for file %s", lpszTexFilename);
		gTex[whichSurface].lpDDSTex->lpVtbl->Release (gTex[whichSurface].lpDDSTex);
		gTex[whichSurface].lpDDSTex = NULL;
		return FALSE;
	}
    if( hFileMapping != NULL && pBase ) {
        UnmapViewOfFile( pBase );
    }
    if( hFileMapping != NULL ) {
        CloseHandle( hFileMapping );
        hFileMapping = NULL;
    }
	// close the texture file; we're done with it
	CloseHandle (hTexFile);


	//fp = open("menus.sjr",O_RDWR|O_CREAT);
	for(i=0;i<22;++i)//SJR
	{
	
		// fill a C3D_TMAP struct
		ZeroMemory (&TMap, sizeof (TMap));
		TMap.u32Size = sizeof (TMap);

		// determine the maximum log2 dimension
		maxlog2 = 7;
		for (k=0; k < maxlog2; k++)
		{
			TMap.apvLevels[k] = gTex[i].ddsd.lpSurface;
		}

		TMap.bMipMap = FALSE;
		TMap.u32MaxMapXSizeLg2 = 7;
		TMap.u32MaxMapYSizeLg2 = 7;
		TMap.eTexFormat = C3D_ETF_RGB565;
//JJS	TMap.bTexTranspEnable = FALSE;

		SET_CIF_COLOR (TMap.clrTexChromaKey, 0, 0, 0, 0);

		//write(fp, (void *)&gTex[i], sizeof(TEXTURE));
		//write(fp, (void *)&gTex[i].ddsd, sizeof(DDSURFACEDESC));
		//write(fp, (void *)&gTex[i].ddsd.ddckCKDestOverlay, sizeof(gTex[1].ddsd.ddckCKDestOverlay));
		//write(fp, (void *)&gTex[i].ddsd.ddckCKDestBlt, sizeof(gTex[1].ddsd.ddckCKDestBlt));
		//write(fp, (void *)&gTex[i].ddsd.ddckCKSrcOverlay, sizeof(gTex[1].ddsd.ddckCKSrcOverlay));
		//write(fp, (void *)&gTex[i].ddsd.ddckCKSrcBlt, sizeof(gTex[1].ddsd.ddckCKSrcBlt));
		//write(fp, (void *)&gTex[i].ddsd.ddpfPixelFormat, sizeof(gTex[1].ddsd.ddpfPixelFormat));
		//write(fp, (void *)&gTex[i].ddsd.ddsCaps, sizeof(gTex[1].ddsd.ddsCaps));
		//write(fp, (void *)&TMap, sizeof(C3D_TMAP));
		//for (k = 0; k < 7;k++)
			//write(fp, (void *)&TMap.apvLevels[k], sizeof(TMap.apvLevels));
		// register the texture
		ecRetVal = ATI3DCIF_TextureReg (&TMap, &(gTex[i].hTX));
		if (ecRetVal != C3D_EC_OK)
		{
			wsprintf (gszErrMsg, "Error registering texture for file %s", lpszTexFilename);
			gTex[i].lpDDSTex->lpVtbl->Release (gTex[i].lpDDSTex);
			gTex[i].lpDDSTex = NULL;
			return FALSE;
		}
	}

	//close(fp);
	return TRUE;
}
*/
BOOL JJSLoadTextureBMP (const char* lpszTexFilename)
{
	int fp;
	C3D_TMAP			TMap;
	int					k, maxlog2;
	C3D_EC				ecRetVal;
	HANDLE				hTexFile;
	BITMAPFILEHEADER	bmfh;
	BITMAPINFOHEADER	bmih;
	C3D_UINT32			bufsize;
	char*				bmdata;
	HRESULT       ddretval;
	short*				p1;
	C3D_UINT32			pitch;
	C3D_UINT8			r, g, b;
	C3D_UINT16			rgb565;
	int	x,y,count,whichSurface,i;
	HANDLE           hFileMapping;
	LPBYTE           pBase;


	// open texture map file for reading
	hTexFile = CreateFile (
		lpszTexFilename,
		GENERIC_READ,
		FILE_SHARE_READ,
		NULL,
		OPEN_EXISTING,
		FILE_FLAG_RANDOM_ACCESS,
		NULL);
	if (hTexFile == INVALID_HANDLE_VALUE)
	{
		wsprintf (gszErrMsg, "Could not open texture map file");
		return FALSE;
	}

	// read headers and bitmap data
	// first, determine buffer size required for BITMAPINFO and data
	bufsize = GetFileSize (hTexFile, NULL);
	if (bufsize == 0xFFFFFFFFL)
	{
		wsprintf (gszErrMsg, "Error getting texture file size");
		CloseHandle (hTexFile);
		return FALSE;
	}

        hFileMapping = CreateFileMapping( hTexFile, NULL, PAGE_READONLY, 0, 0, NULL );
        if( hFileMapping == NULL ) {
            return FALSE;
        }

        pBase = MapViewOfFile( hFileMapping, FILE_MAP_READ, 0, 0, 0 );
        if( pBase == NULL ) {
             return FALSE;
        }
	// adjust bufsize for BITMAFILEHEADER
	bufsize -= sizeof (bmfh);

	// read BITMAPFILEHEADER
	memcpy(&bmfh,pBase,sizeof(bmfh));
	pBase+=sizeof(bmfh);

	// read BITMAPINFO and bitmap data
	memcpy (&bmih, pBase, sizeof (BITMAPINFOHEADER));
	pBase+=sizeof (BITMAPINFOHEADER);

	// unlock surface

	bmdata = pBase;
	// pitch of each scan line
	if(bmih.biSizeImage)
	{
		pitch = bmih.biSizeImage / bmih.biHeight;
	}
	else
	{
		pitch = bmih.biWidth * 3;		// JJS for BMPs without biSizeImage
	}

	whichSurface=-1;
	// line counter
	for (y=8192-1,count=0; y>=0; y-=1,count+=1)
	{
		if(count<2560 || ((count>=32*256) && (count < 42*256)))
			continue;
		if(count%256 == 0)
		{
			if(whichSurface>=0)
			{
				ddretval = gTex[whichSurface].lpDDSTex->lpVtbl->Unlock (gTex[whichSurface].lpDDSTex,NULL);
				if (ddretval != DD_OK)
				{
					wsprintf (gszErrMsg, "Error unlocking texture surface for file %s", lpszTexFilename);
					gTex[whichSurface].lpDDSTex->lpVtbl->Release (gTex[whichSurface].lpDDSTex);
					gTex[whichSurface].lpDDSTex = NULL;
					return FALSE;
				}
			}
			++whichSurface;
			// get a pointer to the texture surface
			ZeroMemory (&(gTex[whichSurface].ddsd), sizeof (gTex[whichSurface].ddsd));
			gTex[whichSurface].ddsd.dwSize = sizeof (gTex[whichSurface].ddsd);
			// lock texture to fill ddsd member
			ddretval = gTex[whichSurface].lpDDSTex->lpVtbl->Lock (gTex[whichSurface].lpDDSTex,
				NULL,
				&(gTex[whichSurface].ddsd),
				DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,
				NULL);
			if (ddretval == DDERR_SURFACELOST) gTex[whichSurface].lpDDSTex->lpVtbl->Restore (gTex[whichSurface].lpDDSTex);
			p1=(short*)gTex[whichSurface].ddsd.lpSurface;
		}
		// scan line pixel counter
		for (x=0; x<256; x+=1)
		{
			// read RGB
			memcpy (&b, (char*)bmdata + (y*pitch)+(3*x), sizeof (C3D_UINT8));
			memcpy (&g, (char*)bmdata + (y*pitch)+(3*x)+1, sizeof (C3D_UINT8));
			memcpy (&r, (char*)bmdata + (y*pitch)+(3*x)+2, sizeof (C3D_UINT8));

			// pack color data in 16bpp format

//#define RGB_555
//#ifndef RGB_555
			// pack data in RGB 555 format
			rgb565 = ((C3D_UINT32)r & 0xf8) << 8 |
					 ((C3D_UINT32)g & 0xfc) << 3 |
					 ((C3D_UINT32)b & 0xf8) >> 3;
//#else
			// pack data in RGB 565 format
			//rgb565 = ((C3D_UINT32)r & 0xf8) << 7 |
					 //((C3D_UINT32)g & 0xf8) << 2 |
					 //((C3D_UINT32)b & 0xf8) >> 3;
//#endif
			*p1++=rgb565;
			// write texture data to texture cache
		}
	}

	ddretval = gTex[whichSurface].lpDDSTex->lpVtbl->Unlock (gTex[whichSurface].lpDDSTex,NULL);
	if (ddretval != DD_OK)
	{
		wsprintf (gszErrMsg, "Error unlocking texture surface for file %s", lpszTexFilename);
		gTex[whichSurface].lpDDSTex->lpVtbl->Release (gTex[whichSurface].lpDDSTex);
		gTex[whichSurface].lpDDSTex = NULL;
		return FALSE;
	}
    if( hFileMapping != NULL && pBase ) {
        UnmapViewOfFile( pBase );
    }
    if( hFileMapping != NULL ) {
        CloseHandle( hFileMapping );
        hFileMapping = NULL;
    }
	// close the texture file; we're done with it
	CloseHandle (hTexFile);


	//fp = open("menus.sjr",O_RDWR|O_CREAT);
	for(i=0;i<22;++i)//SJR
	{
	
		// fill a C3D_TMAP struct
		ZeroMemory (&TMap, sizeof (TMap));
		TMap.u32Size = sizeof (TMap);

		// determine the maximum log2 dimension
		maxlog2 = 7;
		for (k=0; k < maxlog2; k++)
		{
			TMap.apvLevels[k] = gTex[i].ddsd.lpSurface;
		}

		TMap.bMipMap = FALSE;
		TMap.u32MaxMapXSizeLg2 = 7;
		TMap.u32MaxMapYSizeLg2 = 7;
		TMap.eTexFormat = C3D_ETF_RGB565;
//JJS	TMap.bTexTranspEnable = FALSE;

		SET_CIF_COLOR (TMap.clrTexChromaKey, 0, 0, 0, 0);

		// register the texture
		ecRetVal = ATI3DCIF_TextureReg (&TMap, &(gTex[i].hTX));
		if (ecRetVal != C3D_EC_OK)
		{
			wsprintf (gszErrMsg, "Error registering texture for file %s", lpszTexFilename);
			gTex[i].lpDDSTex->lpVtbl->Release (gTex[i].lpDDSTex);
			gTex[i].lpDDSTex = NULL;
			return FALSE;
		}
	}

	//close(fp);
	return TRUE;
}

BOOL JJSNewTexture(char *filename)
{
	return(JJSLoadTextureBMP (filename));
}

BOOL SJRNewTexture(char *filename)
{
	return(SJRLoadTextureBMP (filename));
}


HINSTANCE hInstance;
HWND hwndMCIWnd;

LRESULT FAR PASCAL VideoWndProc(HWND hWnd, UINT iMsg, WPARAM wParam, 
LPARAM lParam)
{
	switch(iMsg) {
		case MM_MCINOTIFY:
			switch(wParam) {				
				case MCI_NOTIFY_SUCCESSFUL:
				case MCI_NOTIFY_ABORTED:
				case MCI_NOTIFY_SUPERSEDED:
				case MCI_NOTIFY_FAILURE:
					MCIWndClose(hwndMCIWnd);
					MCIWndDestroy(hwndMCIWnd);
					DestroyWindow(hWnd);
					break;
			}
			return 1;
		case WM_DESTROY:
			PostQuitMessage(0);
			return 1;
/*		case MCIWNDM_NOTIFYMODE:
			if(lParam == MCI_MODE_STOP) {
				MCIWndOpen(hwndMCIWnd, "n:\\mmdata\\mpeg\\test.mpg", 0);
				MCIWndPlay(hwndMCIWnd);
			}
			return 1;*/
		default:
			return (DefWindowProc(hWnd, iMsg, wParam, lParam));
	}
}

void ShellMoviePlay(char *pName)
{
    WNDCLASS    wc;
	SIZE screenSz;
	DWORD dwMCIWndStyle;
	HWND m_hWnd;
	UINT id;
	DWORD dwErr;
	MCI_PLAY_PARMS playInfo;

    wc.style          = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc    = VideoWndProc;
    wc.cbClsExtra     = 0;
    wc.cbWndExtra     = 0;
    wc.hInstance      = hInstance;
    wc.hIcon          = NULL;
    wc.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground  = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName   = NULL;
    wc.lpszClassName  = "MpegVideoWindow";

    if (!RegisterClass(&wc))
        return;

	screenSz.cx = GetSystemMetrics(SM_CXSCREEN);
	screenSz.cy = GetSystemMetrics(SM_CYSCREEN);
	m_hWnd = CreateWindow("MpegVideoWindow", "Fullscreen MPEG Demo", 
			WS_POPUP, 0, 0, screenSz.cx, screenSz.cy,
			NULL, NULL, hInstance, NULL);
	
    if (NULL==m_hWnd) return;
	
	ShowWindow(m_hWnd, SW_SHOW);

	dwMCIWndStyle = WS_CHILD | WS_VISIBLE | MCIWNDF_NOPLAYBAR | 
//MCIWNDF_NOTIFYMODE |
		 CS_BYTEALIGNCLIENT | MCIWNDF_NOMENU | MCIWNDF_NOERRORDLG;

	hwndMCIWnd = MCIWndCreate(m_hWnd, hInstance, dwMCIWndStyle, pName);

	playInfo.dwCallback = MAKELONG(m_hWnd, 0);

	id = MCIWndGetDeviceID(hwndMCIWnd);
	
	SetWindowPos(hwndMCIWnd, HWND_TOP, 0, 0, screenSz.cx, screenSz.cy, 
NULL);
	dwErr = mciSendCommand(id, MCI_PLAY, MCI_NOTIFY, 
(DWORD)&playInfo);	
	DestroyWindow(hwndMCIWnd);
}




void mpeganim(void)
{
	int fp;
	char *mpegname;
	int namelen;
	char *cwd;
	char endchar;
	RECT prc;
	DWORD dwErr;
	static char ReturnString[80],command[80];
	UINT id;
	MCI_PLAY_PARMS playInfo;

	/*LPSTR lpszReturnString=ReturnString;
       	dwMCIWndStyle = WS_CHILD |		// child window
            WS_VISIBLE |			// visible
            MCIWNDF_NOTIFYMODE |		// notifies of mode changes
            MCIWNDF_NOPLAYBAR  |			// hides toolbar
		CS_BYTEALIGNCLIENT | MCIWNDF_NOMENU | MCIWNDF_NOERRORDLG;
		*/

	cwd = getcwd(NULL, 0);
	namelen = strlen(cwd) + 15;

	mpegname = (char *)malloc(namelen);

	endchar = *(cwd + strlen(cwd) - 1);
	if (endchar != '\\')
		sprintf(mpegname,"%s\\wipeout.mpg", cwd);
	else
		sprintf(mpegname,"%swipeout.mpg", cwd);

        	                                    
	//make sure the movie's there
	if ((fp = open(mpegname, O_RDONLY)) == -1)
		return;

	close(fp);

	ShellMoviePlay(mpegname);

	
	free(cwd);
	free(mpegname);

}
#endif

void centreMouse(void)
{

	mouse_event(MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE,32768,32768,0,0);
}

void JJSReadJoystick(void)
{
	JOYINFO myJoy;
	MMRESULT errVal;

	errVal = joyGetPos(JOYSTICKID1,&myJoy);

	JoyXVal = myJoy.wXpos >> 8;
	JoyYVal = myJoy.wYpos >> 8;

	JoyButton1 = myJoy.wButtons & 0x0001;
	JoyButton2 = myJoy.wButtons & 0x0002;
}

void JJSJoyConfig(void)
{
	JOYCAPS mycaps;
	UINT joyrange;
	MMRESULT theres;

	joyGetDevCaps(JOYSTICKID1,&mycaps,sizeof(mycaps));

	joyrange = mycaps.wXmax - mycaps.wXmin;
	joyModXVal = 256.0/(float)joyrange;

	joySetThreshold(JOYSTICKID1, joyrange/512);

	joyrange = mycaps.wYmax - mycaps.wYmin;
	joyModYVal = 256.0/(float)joyrange;

	theres = joySetCapture(hwnd, JOYSTICKID1, 0, TRUE);

	if (theres != JOYERR_NOERROR)
		switch(theres)
		{
			case MMSYSERR_NODRIVER:
				theres = 2;
				break;
			case JOYERR_NOCANDO:
				theres = 2;
				break;
			case JOYERR_UNPLUGGED:
				theres = 2;
				break;
		}

}


void ShowErrorMessage(UINT StrNum)
{
	char Msg[80];

	ShowCursor(TRUE);
	finiObjects();

	LoadString(hinst, StrNum, Msg, 80);
	MessageBox(hwnd, Msg, "Wipeout Error", MB_ICONHAND | MB_OK);
	DestroyWindow(hwnd);
	QuitToDos();
}

void ShowWarningMessage(LPCTSTR theMsg)
{
	ShowCursor(TRUE);
	MessageBox(hwnd, theMsg, "Wipeout Warning", MB_ICONHAND | MB_OK);
	ShowCursor(FALSE);
}
