/*--------------------------------------------------------------------------
 * File: dx.c
 * Written by: Alexander Boczar, 1997-03-30
 * Description: A DirectX driver for 8bit resolutions.
 *
 * Updates:
 * -- Date -- | ----- Name ----- |-- Did what....
 * 1997-04-01 | Alexander Boczar | Tog bort ModeX support pga av bristande information om lock()
 * 1997-04-01 | Alexander Boczar | Žndrade s† att ifall lPitch = Width, s† kopierar jag i ett svep ist„llet f”r rad f”r rad,
 * 1997-03-31 | Alexander Boczar | Fixade s† att copy() anv„nder lPitch f”r att skippa ev data efter varje rad.
 * 1997-06-06 | Alexander Boczar | Gjorde om drivern till det nya formatet
 *
 * Todo:
 *
 * Kolla vad h†rdvaran klarar ist„llet f”r k”ra rakt p† och faila..
 -------------------------------------------------------------------------------*/

#include <windows.h>
#include <ddraw.h>
#include "system/xstdio.h"
#include "drivers/drv8.h"
#include "draw8/draw8.h"

extern DRV dxDRV;

#define MAXKEYS 256

typedef enum
{
	ERR_NOERR,
	ERR_NOMEM,
	ERR_NODLL,
	ERR_INVDLL,
	ERR_FAILWIN,
	ERR_FAILDDRAW,
	ERR_FAILCOOPERATIVE,
	ERR_FAILENUM,
	ERR_FAILMODE,
	ERR_FAILSURFACE
} ERRORS;

/* ######################################################################### */

static PALETTEENTRY dxpal[256];

static int windowactive = 0;
static int keys = 0;
static char keystack[MAXKEYS];

static DWORD mousetimer = 0;

static int mouse_minx,mouse_maxx;
static int mouse_miny,mouse_maxy;
static int mousex,mousey;
static int mousexchange,mouseychange;
static int gmousexchange,gmouseychange;

static HINSTANCE dxDLL;
static HWND window;
static HINSTANCE process;
static LPDIRECTDRAW dd;
static LPDIRECTDRAWSURFACE showscreen;
//static LPDIRECTDRAWSURFACE workscreen;
static LPDIRECTDRAWPALETTE ddpal;

static FARPROC _DirectDrawCreate;
//static HRESULT WINAPI (*_DirectDrawCreate)( GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter );

static ERRORS error = ERR_NOERR;

/* ######################################################################### */

char scan2key[256] =
{
	0,	1,	2,	3,	4,	5,	6,	7,
	8,	9,	10,	11,	12,	13,	14,	15,
	16,	17,	18,	19,	20,	21,	22,	23,
	24,	25,	26,	'',28,	29,	30,	31,

	32,	33,	34,	35,	36,	37,	38,	39,
	40,	41,	42,	43,	44,	45,	46,	47,
	'0','1','2','3','4','5','6','7',
	'8','9',':',';','<','=','>','?',

	'@','A','B','C','D','E','F','G',
	'H','I','J','K','L','N','M','O',
	'P','Q','R','S','T','U','V','W',
	'X','Y','Z',	0,	0,	0,	0,	0,

	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	'+',0,  '-',0,  0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,

	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,

	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,

	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,

	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0
};
/* ######################################################################### */

static void checkmsg()
{
	MSG msg;

	while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
}

static long FAR PASCAL WindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
	POINT mousepos;

	switch( message )
	{
		case WM_ACTIVATEAPP:
//			printf("WM_ACTIVEAPP\n");
			windowactive = wParam;
			break;

		case WM_TIMER:
			if (wParam == mousetimer)
			{
				if	( windowactive)
				{
					GetCursorPos( &mousepos);
					mousexchange = mousepos.x - (dxDRV.width >> 1);
					mouseychange = mousepos.y - (dxDRV.height >> 1);
					gmousexchange += mousexchange;
					gmouseychange += mouseychange;
					mousex += mousexchange;
					mousey += mouseychange;
					if ( mousex > mouse_maxx)
						mousex = mouse_maxx;
					else if ( mousex < mouse_minx)
						mousex = mouse_minx;
					if ( mousey > mouse_maxy)
						mousey = mouse_maxy;
					else if ( mousey < mouse_miny)
						mousey = mouse_miny;

					SetCursorPos( (dxDRV.width >> 1), (dxDRV.height >> 1));
				}
			}
			else
			{
				printf("Unknown timer caught!\n");
			}

		case WM_CREATE:
//			printf("WM_CREATE\n");
			break;

		case WM_SETCURSOR:
//			printf("WM_SETCURSOR\n");
			SetCursor(NULL);
			return TRUE;

		case WM_KEYDOWN:
//			printf("WM_KEYDOWN (%d,'%c')\n", wParam, wParam);
			if ( keys < MAXKEYS)
			{
				keystack[keys] = wParam;
				keys++;
			}
			break;

		case WM_PAINT:
//			printf("WM_PAINT\n");

			break;

		case WM_DESTROY:
//			printf("WM_DESTROY\n");
			PostQuitMessage( 0 );
			break;
	}
	return DefWindowProc(hWnd, message, wParam, lParam);
}

/* ######################################################################### */

static HRESULT WINAPI countmodes( LPDDSURFACEDESC ddsd, LPVOID lpContext)
{
	if( ddsd->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
		dxDRV.modes++;
	return( DDENUMRET_OK);
}

static HRESULT WINAPI addmodes( LPDDSURFACEDESC ddsd, LPVOID lpContext)
{
	if( ddsd->ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8)
	{
		dxDRV.modelist[dxDRV.modes].width = ddsd->dwWidth;
		dxDRV.modelist[dxDRV.modes].height = ddsd->dwHeight;
		dxDRV.modes++;
	}
	return( DDENUMRET_OK);
}

static int setup( void)
{
	WNDCLASS wc;

	if ( (dxDLL = LoadLibrary("ddraw.dll")) == NULL)
	{
		error = ERR_NODLL;
		return( FALSE);
	}

  if ( ( _DirectDrawCreate = GetProcAddress( dxDLL, "DirectDrawCreate")) == NULL)
	{
		FreeLibrary( dxDLL);
		error = ERR_INVDLL;
		return( FALSE);
	}

	process = GetModuleHandle( NULL);

	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WindowProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = process;
	wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
	wc.hCursor = LoadCursor( NULL, IDC_ARROW );
	wc.hbrBackground = NULL;
	wc.lpszMenuName = "Visual 3D";
	wc.lpszClassName = "Visual 3D";
	RegisterClass( &wc);

	window = CreateWindowEx( WS_EX_TOPMOST, "Visual 3D", "Visual 3D", WS_POPUP, 0, 0, GetSystemMetrics( SM_CXSCREEN ), GetSystemMetrics( SM_CYSCREEN ), NULL, NULL, process, NULL );
	if ( window == NULL)
	{
		FreeLibrary( dxDLL);
		error = ERR_FAILWIN;
		return( FALSE);
	}

	ShowWindow( window, SW_SHOWDEFAULT );
	UpdateWindow( window );

	if ( _DirectDrawCreate( NULL, &dd, NULL) != DD_OK)
	{
		FreeLibrary( dxDLL);
		error = ERR_FAILDDRAW;
		return( FALSE);
	}

	dxDRV.modes = 0;

	if( dd->lpVtbl->SetCooperativeLevel( dd, window, DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN) != DD_OK )
	{
		dd->lpVtbl->Release( dd);
		DestroyWindow( window);
		FreeLibrary( dxDLL);
		error = ERR_FAILCOOPERATIVE;
		return( FALSE);
	}

	if( dd->lpVtbl->EnumDisplayModes( dd, 0, NULL, NULL, countmodes) != DD_OK)
	{
		dd->lpVtbl->Release( dd);
		DestroyWindow( window);
		FreeLibrary( dxDLL);
		error = ERR_FAILENUM;
		return( FALSE);
	}

	printf("Found %d modes\n", dxDRV.modes);
	if( dxDRV.modes == 0)
	{
		dd->lpVtbl->Release( dd);
		DestroyWindow( window);
		FreeLibrary( dxDLL);
		return( FALSE);
	}

	dxDRV.modelist = (DRVMODE *)xmalloc( dxDRV.modes * sizeof( DRVMODE));
	dxDRV.modes = 0;
	dd->lpVtbl->EnumDisplayModes( dd, 0, NULL, NULL, addmodes);

	dd->lpVtbl->SetCooperativeLevel( dd, NULL, DDSCL_NORMAL);
	dd->lpVtbl->Release( dd);
	DestroyWindow( window);
	FreeLibrary( dxDLL);

	return( TRUE);
}

static int openscr( int width, int height, int config)
{
	WNDCLASS wc;
	DDSURFACEDESC ddsd;

	dxDRV.width = width;
	dxDRV.minx = 0;
	dxDRV.maxx = width - 1;

	dxDRV.height = height;
	dxDRV.miny = 0;
	dxDRV.maxy = height - 1;

	dxDRV.config = config;

	dxDRV.palette = (RGB *)xmalloc( 256 * sizeof( RGB));

	if ( (dxDLL = LoadLibrary("ddraw.dll")) == NULL)
	{
		error = ERR_NODLL;
		return( FALSE);
	}

	if ( (_DirectDrawCreate = GetProcAddress( dxDLL, "DirectDrawCreate")) == NULL)
	{
		FreeLibrary( dxDLL);
		error = ERR_INVDLL;
		return( FALSE);
	}

	process = GetModuleHandle( NULL);

	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WindowProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = process;
	wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
	wc.hCursor = LoadCursor( NULL, IDC_ARROW );
	wc.hbrBackground = NULL;
	wc.lpszMenuName = "Visual 3D";
	wc.lpszClassName = "Visual 3D";
	RegisterClass( &wc);

	window = CreateWindowEx( WS_EX_TOPMOST, "Visual 3D", "Visual 3D", WS_POPUP, 0, 0, GetSystemMetrics( SM_CXSCREEN ), GetSystemMetrics( SM_CYSCREEN ), NULL, NULL, process, NULL );
	if ( window == NULL)
	{
		FreeLibrary( dxDLL);
		error = ERR_FAILWIN;
		return( FALSE);
	}

	ShowWindow( window, SW_SHOWDEFAULT );
	UpdateWindow( window );

	if ( _DirectDrawCreate( NULL, &dd, NULL) != DD_OK)
	{
		DestroyWindow( window);
		FreeLibrary( dxDLL);
		error = ERR_FAILDDRAW;
		return( FALSE);
	}

	if( dd->lpVtbl->SetCooperativeLevel( dd, window, DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN ) != DD_OK )
	{
		dd->lpVtbl->Release( dd);
		DestroyWindow( window);
		FreeLibrary( dxDLL);
		error = ERR_FAILCOOPERATIVE;
		return( FALSE);
	}

	if( dd->lpVtbl->SetDisplayMode( dd, dxDRV.width, dxDRV.height, 8 ) != DD_OK )
	{
		dd->lpVtbl->Release( dd);
		DestroyWindow( window);
		FreeLibrary( dxDLL);
		error = ERR_FAILMODE;
		return( FALSE);
	}

	ddsd.dwSize = sizeof( ddsd );
	ddsd.dwFlags = DDSD_CAPS;
	ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
	if ( dd->lpVtbl->CreateSurface( dd, &ddsd, &showscreen, NULL ) != DD_OK )
	{
		dd->lpVtbl->Release( dd);
		DestroyWindow( window);
		FreeLibrary( dxDLL);
		error = ERR_FAILSURFACE;
		return( FALSE);
	}

	dxDRV.clearscr( 0);

	dd->lpVtbl->CreatePalette( dd, DDPCAPS_8BIT, dxpal, &ddpal, NULL);
	showscreen->lpVtbl->SetPalette( showscreen, ddpal);


	return( 1);
}

static int reopenscr( int width, int height)
{
	DDSURFACEDESC ddsd;

	showscreen->lpVtbl->Release( showscreen);

	if( dd->lpVtbl->SetDisplayMode( dd, width, height, 8 ) != DD_OK )
	{
		dd->lpVtbl->SetDisplayMode( dd, dxDRV.width, dxDRV.height, 8 );
		ddsd.dwSize = sizeof( ddsd );
		ddsd.dwFlags = DDSD_CAPS;
		ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
	 	dd->lpVtbl->CreateSurface( dd, &ddsd, &showscreen, NULL );
		dxDRV.clearscr( 0);
		dd->lpVtbl->CreatePalette( dd, DDPCAPS_8BIT, dxpal, &ddpal, NULL);
		showscreen->lpVtbl->SetPalette( showscreen, ddpal);
		error = ERR_FAILMODE;
		return( FALSE);
	}

	ddsd.dwSize = sizeof( ddsd );
	ddsd.dwFlags = DDSD_CAPS;
	ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
	if ( dd->lpVtbl->CreateSurface( dd, &ddsd, &showscreen, NULL ) != DD_OK )
	{
		dd->lpVtbl->SetDisplayMode( dd, dxDRV.width, dxDRV.height, 8 );
		ddsd.dwSize = sizeof( ddsd );
		ddsd.dwFlags = DDSD_CAPS;
		ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
	 	dd->lpVtbl->CreateSurface( dd, &ddsd, &showscreen, NULL );
		dxDRV.clearscr( 0);
		dd->lpVtbl->CreatePalette( dd, DDPCAPS_8BIT, dxpal, &ddpal, NULL);
		showscreen->lpVtbl->SetPalette( showscreen, ddpal);
		error = ERR_FAILSURFACE;
		return( FALSE);
	}

	dxDRV.width = width;
	dxDRV.minx = 0;
	dxDRV.maxx = width - 1;

	dxDRV.height = height;
	dxDRV.miny = 0;
	dxDRV.maxy = height - 1;

	dxDRV.clearscr( 0);

	dd->lpVtbl->CreatePalette( dd, DDPCAPS_8BIT, dxpal, &ddpal, NULL);
	showscreen->lpVtbl->SetPalette( showscreen, ddpal);

	return( TRUE);
}

static void closescr()
{
	if( mousetimer)
	{
		KillTimer( NULL, mousetimer);
		mousetimer = 0;
	}
	showscreen->lpVtbl->Release( showscreen);
	dd->lpVtbl->Release( dd);
	DestroyWindow( window);
	FreeLibrary( dxDLL);
}

static void setpalette( RGB *newpal)
{
	int i;

	memcpy( dxDRV.palette, newpal, sizeof(RGB) * 256);

	ddpal->lpVtbl->GetEntries( ddpal, 0, 0, 256, dxpal);
	for (i=0; i<256; i++)
	{
		dxpal[i].peRed = dxDRV.palette[i].r;
		dxpal[i].peGreen = dxDRV.palette[i].g;
		dxpal[i].peBlue = dxDRV.palette[i].b;
	}
	ddpal->lpVtbl->SetEntries( ddpal, 0, 0, 256, dxpal);

}

static void vsync()
{
	checkmsg();
	if ( windowactive)
		dd->lpVtbl->WaitForVerticalBlank( dd, DDWAITVB_BLOCKBEGIN, NULL);
}

static void clearscr( BYTE col)
{
	DDSURFACEDESC ddsd;
	HRESULT ddrval;
	BYTE *dest;
	int y;

	checkmsg();

	if ( windowactive)
	{
		ddsd.dwSize = sizeof( ddsd );
		ddrval = showscreen->lpVtbl->Lock( showscreen, NULL, &ddsd,  DDLOCK_WAIT, NULL);
		if ( ddrval == DDERR_SURFACELOST )
		{
			showscreen->lpVtbl->Restore( showscreen);
			ddrval = showscreen->lpVtbl->Lock( showscreen, NULL, &ddsd,  DDLOCK_WAIT, NULL);
		}
		if ( ddrval == DD_OK )
		{
			if ( ddsd.lPitch != dxDRV.width)
			{
				dest = ddsd.lpSurface;
				for (y=0; y<dxDRV.height; y++)
				{
					memset4( dest, (col | (col << 8) | (col << 16) | (col << 24)), dxDRV.width >> 2);
					dest += ddsd.lPitch;
				}
			}
			else
				memset4( ddsd.lpSurface, (col | (col << 8) | (col << 16) | (col << 24)), (dxDRV.width * dxDRV.height) >> 2);
			showscreen->lpVtbl->Unlock( showscreen, NULL);
		}
	}
}

/* ######################################################################### */

static BUFF *createbuff( int width, int height)
{
	BUFF *buff, *oldactive;
	int i;

	if( (buff = (BUFF *)xmalloc( sizeof(BUFF))) == NULL)
	{
		error = ERR_NOMEM;
		return( NULL);
	}

	buff->drv = &dxDRV;

	if( (buff->image = (BYTE *)xmalloc( sizeof( BYTE) * width * height)) == NULL)
	{
		xfree( buff);
		error = ERR_NOMEM;
		return( NULL);
	}

	if( (buff->ytab = (int *)xmalloc( sizeof( int) * height)) == NULL)
	{
		xfree( buff->image);
		xfree( buff);
		error = ERR_NOMEM;
		return( NULL);
	}

	if( dxDRV.config & DRVCFG_ZBUFFER)
	{
    if( (buff->zbuffer = (int *)xmalloc( sizeof( int) * width * height)) == NULL)
		{
			xfree( buff->ytab);
			xfree( buff->image);
			xfree( buff);
			error = ERR_NOMEM;
			return( NULL);
		}
	}

	for (i=0; i<height; i++)
		buff->ytab[i] = i * width;

	buff->width = width;
	buff->height = height;

	buff->xorigo = width/2;
	buff->yorigo = height/2;

	buff->minx = 0;
	buff->maxx = width - 1;
	buff->miny = 0;
	buff->maxy = height - 1;

	buff->lighttab = NULL;
	buff->transtab = NULL;

	oldactive = dxDRV.activebuff;
	dxDRV.activebuff = buff;
	dxDRV.clearbuff( 0);
	dxDRV.activebuff = oldactive;

	return( buff);
}

static void destroybuff( BUFF *buff)
{
	if( buff == dxDRV.activebuff)
		dxDRV.activebuff = NULL;

	if( buff != NULL)
	{
		if( buff->zbuffer != NULL) xfree( buff->zbuffer);
		if( buff->ytab != NULL) xfree( buff->ytab);
		if( buff->image != NULL) xfree( buff->image);
		xfree( buff);
	}
}

static void setbuff( BUFF *buff)
{
	dxDRV.activebuff = buff;
}

static void copybuff( int x, int y)
{
	DDSURFACEDESC ddsd;
	HRESULT ddrval;
	int i,j;

	checkmsg();

	if ( windowactive)
	{
		ddsd.dwSize = sizeof( ddsd );
		ddrval = showscreen->lpVtbl->Lock( showscreen, NULL, &ddsd,  DDLOCK_WAIT, NULL);
		if ( ddrval == DDERR_SURFACELOST )
		{
			showscreen->lpVtbl->Restore( showscreen);
			ddrval = showscreen->lpVtbl->Lock( showscreen, NULL, &ddsd,  DDLOCK_WAIT, NULL);
		}
		if ( ddrval == DD_OK )
		{
			if( (x == y == 0) && (dxDRV.activebuff->width == dxDRV.width) && (dxDRV.activebuff->height == dxDRV.height))
			{
				BYTE *image = dxDRV.activebuff->image;
				BYTE *screen = ddsd.lpSurface;

				for ( j=0; j<dxDRV.height; j++)
				{
					if( (dxDRV.width & 0x0f) == 0)
					{
						memcpy16( screen, image, dxDRV.width >> 4);
						image += dxDRV.width;
						screen += ddsd.lPitch;
					}
					else if( (dxDRV.width & 0x03) == 0)
					{
						memcpy4( screen, image, dxDRV.width >> 2);
						image += dxDRV.width;
						screen += ddsd.lPitch;
					}
					else
					{
						memcpy4( screen, image, dxDRV.width >> 2);
						image += dxDRV.width ^ 0x03;
						screen += dxDRV.width ^ 0x03;

						for ( i=0; i<(dxDRV.width & 0x03); i++)
							*(screen++) = *(image++);
						image += dxDRV.width & 0x03;
						screen += dxDRV.width & 0x03 + (ddsd.lPitch - dxDRV.width);
					}
				}
			}
			else
			{
				int sxs,ixs,xlen;
				int sys,iys,ylen;
				BYTE *image;
				BYTE *screen;

				// Check X

				if ( x >= dxDRV.minx )
				{
					sxs = x;
					ixs = 0;
					if ( (x + dxDRV.activebuff->width) <= dxDRV.maxx)
						xlen = dxDRV.activebuff->width;
					else
						xlen = dxDRV.maxx - x;
				}
				else
				{
					sxs = 0;
					ixs = dxDRV.minx - x;
					if ( (x + dxDRV.activebuff->width) <= dxDRV.maxx)
						xlen = (x + dxDRV.activebuff->width) - dxDRV.minx;
					else
						xlen = dxDRV.maxx - dxDRV.minx;
				}

				// Check Y

				if ( y >= dxDRV.miny )
				{
					sys = y;
					iys = 0;
					if ( (y + dxDRV.activebuff->height) <= dxDRV.maxy)
						ylen = dxDRV.activebuff->height;
					else
						ylen = dxDRV.maxy - y;
				}
				else
				{
					sys = 0;
					iys = dxDRV.miny - y;
					if ( (y + dxDRV.activebuff->height) <= dxDRV.maxy)
						ylen = (y + dxDRV.activebuff->height) - dxDRV.miny;
					else
						ylen = dxDRV.maxy - dxDRV.miny;
				}

				for ( j=0; j<ylen; j++)
				{
					image = &dxDRV.activebuff->image[ ixs + dxDRV.activebuff->ytab[j + iys]];
					screen = ddsd.lpSurface;
					screen += sxs + (ddsd.lPitch * (j + sys));
					for ( i=0; i<xlen; i++)
						*(screen++) = *(image++);
				}
			}

			showscreen->lpVtbl->Unlock( showscreen, NULL);
		}
	}
}

static void clearbuff( BYTE col)
{
	memset4( dxDRV.activebuff->image, (col | (col << 8) | (col << 16) | (col << 24)), (dxDRV.activebuff->width * dxDRV.activebuff->height) >> 2);
	if ( dxDRV.config & DRVCFG_ZBUFFER)
    memset4( dxDRV.activebuff->zbuffer, 0x7fffffff, (dxDRV.activebuff->width * dxDRV.activebuff->height));
}

static void movebuff( int x, int y, BYTE col)
{
	copybuff( x, y);
	clearbuff( col);
}

/* ######################################################################### */

static void _plot( XYZ p, BYTE col)
{
  plot( dxDRV.activebuff, p, col);
}

static void _line( XYZ p1, XYZ p2, BYTE col)
{
  line( dxDRV.activebuff, p1, p2, col);
}

static void _poly( XYZ p1, XYZ p2, XYZ p3, char col )
{
  poly( dxDRV.activebuff, p1, p2, p3, col);
}

static void _tpoly( XYZ p1, XYZ p2, XYZ p3, BYTE *data )
{
  tpoly( dxDRV.activebuff, p1, p2, p3, data);
}

static void _blit( XYZ p, BYTE *image, int *zimage, int width, int height)
{
  blit( dxDRV.activebuff, p, image, zimage, width, height);
}

/* ######################################################################### */

static int mouseinit( int minx, int miny, int maxx, int maxy)
{
  mouse_minx = minx;
  mouse_miny = miny;
  mouse_maxx = maxx;
  mouse_maxy = maxy;

  if( !mousetimer)
		mousetimer = SetTimer( window, 1, 20, NULL); //Start a mouse timer at 50hz

	return( mousetimer);
}

static int mousecallback( void ( *callback)( DRVMOUSE change))
{
	return( TRUE);
}

static void getmousepos( int *x, int *y)
{
  *x = mousex;
  *y = mousey;
}

static void setmousepos( int x, int y)
{
  mousex = x;
  mousey = y;
}

static void getmousediff( int *x, int *y)
{
  *x = gmousexchange;
  *y = gmouseychange;
  gmousexchange = 0;
  gmouseychange = 0;
}

/* ######################################################################### */

static int kbhit()
{
	return( keys);
}

static char getkey()
{
	int i;
	char key;

	if ( keys > 0)
	{
		key = keystack[0];
		keys--;
		for (i=0; i<keys; i++)
			keystack[i] = keystack[i+1];
		return( scan2key[key]);
	}
	else
	{
		while ( keys == 0)
			checkmsg();

		key = keystack[0];
		keys--;
		for (i=0; i<keys; i++)
			keystack[i] = keystack[i+1];
		return( scan2key[key]);
	}
}

/* ######################################################################### */

static char *geterror()
{
	ERRORS olderr = error;
	error = ERR_NOERR;
	switch( olderr)
	{
		case ERR_NOMEM: return("Unable allocate memory");
		case ERR_NODLL: return("Unable to load ddraw.dll");
		case ERR_INVDLL: return("Missing functions in ddraw.dll");
		case ERR_FAILWIN: return("Failed while opening window");
		case ERR_FAILDDRAW: return("Failed while create DirectDraw object");
		case ERR_FAILCOOPERATIVE: return("Unable to set cooperative mode");
		case ERR_FAILENUM: return("Failed while gathering mode information");
		case ERR_FAILMODE: return("Failed while setting mode");
		case ERR_FAILSURFACE: return("Unable to create surface");
		default : return( "Unknown error");
	}
}

/* ######################################################################### */

DRV dxDRV =
{
	"Windows 95/NT DirectDraw(tm) Driver",\

	0,
	NULL,

	640,480,
	0,639,0,479,
	1,1,

	0,/*config*/

	NULL,

	NULL,

	setup,
	openscr,
	reopenscr,
	closescr,

	setpalette,
	vsync,
	clearscr,

	createbuff,
	destroybuff,
	setbuff,

	NULL,
	NULL,
	copybuff,
	clearbuff,
	movebuff,

  _plot,
  _line,
  _poly,
  _tpoly,
  _blit,

	mouseinit,
	mousecallback,
  getmousepos,
  setmousepos,
  getmousediff,

	kbhit,
	getkey,

	geterror,
};

