/*
	File	:	winmain.cpp
	Author	:	Richard Flower (c) 1998 Core Design
	----------------------------------------------------------------------------------
	Functions
	----------------------------------------------------------------------------------
	WinMain				-	Main Windows Entry Point
	WinAppExit			-	Windows Application Exit
	WinRegisterWindow	-	Register Window
	WinCreateWindow		-	Create Window
	WinAppProc			-	Application Window Proc
	WinUpdate			-	Window Update	
	WinDXInit			-	Initialise DirectX
	WinFreeDX			-	Free DirectX
	WinRender			-	Render Output
	WinFrameRate		-   Calculate Framerate
	WinDisplayString	-   Output Text To Screen
	----------------------------------------------------------------------------------
*/

#include "standard.h"
#include "global.h"
#include "template.h"
#include "directx.h"
#include "winmain.h"
#include "console.h"
#include "crtdbg.h"
#include "texture.h"
#include "drawprimitive.h"
#include "hwrender.h"
#include "utils.h"
#include "di.h"
#include "ds.h"
#include "time.h"
#include "spanbuffer.h"
#include "hwinsert.h"
#include "picture.h"

extern bool ThreadDone;
extern bool ThreadRender;

WINAPP	 App;
HWCONFIG HWConfig;


bool CD_Init(void);
int framedump;
extern bool bSoftwareDefault;



/*
	Function	:	WinMain
	Useage		:	Main Windows Entry Point
*/

int PASCAL WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
	int RetVal;
	int n;
	
	GpCmdLine=lpCmdLine;

	// Clear Application Structure
	memset(&App,0,sizeof(WINAPP));

	// Store Instance
	App.hInstance = hInstance;
	
	// Register Window Class
	if (!hPrevInstance)
	{
		RetVal = WinRegisterWindow(hInstance);
		if (!RetVal)
		{			
			MessageBox(NULL,"Unable To Register Window Class","",MB_OK);
			return FALSE;
		}	
	}
	

	// Create And Display Window
	App.WindowHandle = WinCreateWindow(hInstance,nCmdShow);
	if(!App.WindowHandle)
	{
		MessageBox(NULL,"Unable To Create Window","",MB_OK);
		return FALSE;
	}
	
	// Fill Device Info Structure
	DXGetDeviceInfo(&App.DeviceInfo,App.WindowHandle);

	
	if(UT_GetArg("sw",n))
	{
		if(n)
			bSoftwareDefault = true;
		else
			bSoftwareDefault = false;
	}

	
	// User Selection Dialog
	
	if(DXUserDialog(&App.DeviceInfo,&App.DXConfig,App.hInstance)==false)
	{
		DXFreeDeviceInfo(&App.DeviceInfo);
		return 0;
	}

	// DirectX Initialisation

	if(WinDXInit(&App.DeviceInfo,&App.DXConfig)==false)
	{
		WinFreeDX();
		DXFreeDeviceInfo(&App.DeviceInfo);
		return 0;
	}
	
	// Init Ptrs For Macros
	
	App.DXConfigPtr = &App.DXConfig;	
	App.DeviceInfoPtr = &App.DeviceInfo;


	// Initialise DrawPrimitive Ptr
	InitDrawPrimitive(App.lpD3DDevice,App.lpBackBuffer,DXD3D(App.DeviceInfoPtr,App.DXConfigPtr).bHardware);

	// Turn Rendering ON

	App.bRender = true;
	
	// Launch Console
//	CSLaunch(App.WindowHandle,App.lpDD,"console.bmp",App.lpBackBuffer);

	// Intialise HWConfig

	HWConfig.Perspective = true;
	HWConfig.Dither = true;
	HWConfig.Filter = D3DFILTER_LINEAR;
	HWConfig.nShadeMode = D3DSHADE_GOURAUD;
	HWConfig.nFillMode = D3DFILL_SOLID;



#ifdef GAMEDEBUG
	framedump = 0;
	if(UT_GetArg("cut",n))
		SetCutscene(n);
	if(UT_GetArg("track",n))
		SetCutsceneTrack(n);
	if(UT_GetArg("angle",n))
		SetCutsceneAngle(n);
	if(UT_GetArg("framedump",n))
		framedump = 1;
#endif

	_CrtSetReportMode(_CRT_WARN,_CRTDBG_MODE_DEBUG);
	int temp=_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
	temp|=_CRTDBG_LEAK_CHECK_DF;
	_CrtSetDbgFlag(temp);
	
	CD_Init();

	UT_InitAccurateTimer();

	App.tJoystickEnabled = true;
	App.Joystick = 0;

	DXTextureInit(DXTextureList,DXPaletteList);
	
	DS_Init();
	DI_Init();

	TIME_Init();
	HWR_Init();
//	BGND_Init();

	DS_Start();
	DI_Start();

	HWR_InitState();

	setup_screen_size();

	GtWindowClosed=game_closedown=false;
	GtFullScreenClearNeeded = false;

	ThreadRender = false;

//	_beginthread(&DrawBucketsThread,0,0);

	GameMain();

	WinFreeDX();
	DXFreeDeviceInfo(&App.DeviceInfo);

	return 0;
}

// EOF : WinMain


/*
	Function	:	WinMessage
	Useage		:	Message Process

*/

int WinMessage()
{
	MSG msg;
	if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
	{
		TranslateMessage(&msg); 
        DispatchMessage(&msg);
 	}
	return msg.message;
}

// EOF : WinMessage



/*
	Function	:	WinAppExit
	Useage		:	Windows Application Exit
*/

void WinAppExit()
{
	App.bRender = false;
	DXSetCooperativeLevel(App.lpDD,App.WindowHandle,DDSCL_NORMAL);
	WinFreeDX();
	DXFreeDeviceInfo(&App.DeviceInfo);
}

// EOF : WinAppExit



/*
	Function	:	WinFreeDX
	Useage		:	Free DX
*/

void WinFreeDX()
{
	DXRelease(App.Palette);
	DXRelease(App.lpViewPort);
	DXRelease(App.lpD3DDevice);
	DXRelease(App.lpZBuffer);
	DXRelease(App.lpPictureBuffer);
	DXRelease(App.lpBackBuffer);
	DXRelease(App.lpFrontBuffer);
	DXRelease(App.lpD3D);
	DXRelease(App.lpDD);
}

// EOF : WinFreeDX


/*
	Function : WinRegisterWindow()
	Useage   : Register The Window Class
*/

BOOL WinRegisterWindow(HINSTANCE hInstance)
{
    App.WindowClass.hIcon			= LoadIcon(hInstance,"ICON");
    App.WindowClass.lpszMenuName	= NULL;
    App.WindowClass.lpszClassName	= WINDOWCLASS;
    App.WindowClass.hbrBackground	= (HBRUSH)GetStockObject(BLACK_BRUSH);
    App.WindowClass.hInstance       = hInstance;
    App.WindowClass.style           = CS_VREDRAW|CS_HREDRAW;
    App.WindowClass.lpfnWndProc     = (WNDPROC) WinAppProc;
    App.WindowClass.cbClsExtra      = 0;
    App.WindowClass.cbWndExtra      = 0;
	return RegisterClass(&App.WindowClass);
}

// EOF : WinRegisterWindow



/*
	Function : WinCreateWindow()
	Useage   : Create A Window, and return handle
*/

HWND WinCreateWindow(HINSTANCE hInstance,int nCmdShow)
{
	HWND Handle ;
	Handle = NULL ;
    Handle =  CreateWindowEx(WS_EX_APPWINDOW,
							 WINDOWCLASS,     
							 WINDOWNAME,      
				             WS_POPUP,
							 0,0,
							 0,0,
							 NULL,              
							 NULL,           
							 hInstance,          
							 NULL);


	
	if(Handle) 
	{
		ShowWindow(Handle,nCmdShow);
	    UpdateWindow(Handle);
	}
	

	return (Handle);
}


// EOF : WinCreateWindow




/*
	Function : AppWinProc
	Useage   : Application Window Procedure
*/

long FAR PASCAL WinAppProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
	switch(msg)
	{
	case WM_CREATE:
		ShowCursor(FALSE);
		break;

	case WM_DESTROY:
		 WinAppExit();
  		 PostQuitMessage(0);
		 break;
	

	case WM_CHAR:
//		KeyToConsole(wParam);
		break;


	case WM_KEYDOWN:
		switch(wParam)
		{
		case VK_F1:
//			ToggleConsole();
			break;
		}
		break;	

	case WM_KEYUP:
		break;


	case WM_ACTIVATE:
		switch(LOWORD(wParam))
		{
			case WA_ACTIVE:
			case WA_CLICKACTIVE:
			App.bFocus = TRUE;
			break;
			
			case WA_INACTIVE:
			App.bFocus = FALSE;
			break;
		}

	}
	return DefWindowProc(hWnd,msg,wParam,lParam);
}

// EOF : AppWinProc



/*
	Function : WinDXInit
	Useage	 : Initialise DirectX

*/


bool WinDXInit(DEVICEINFO* DeviceInfo,DXCONFIG* DXConfig)
{
	DDSURFACEDESC ddsd;
	DDSCAPS	ddscaps;
	

	//if(DXD3D(DeviceInfo,DXConfig).bHardware)
		App.nRenderMode = RENDERER_HAL;
	//else
	//	App.nRenderMode = RENDERER_INTERNAL;


	// Create Direct Draw
	
	if(DXCreateDirectDraw(DeviceInfo,DXConfig,&App.lpDD)==false)
		return false;
	
	// Create Direct3D
	
	if(DXCreateDirect3D(App.lpDD,&App.lpD3D)==false)
		return false;
		
	
	// Set Coopertative Level
	
	if(DXSetCooperativeLevel(App.lpDD,App.WindowHandle,DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN)==false)
		return false;	
	

	// Set The Videomode	
	
	if(DXSetVideoMode(App.lpDD,DXDisplayMode(DeviceInfo,DXConfig).w,
							   DXDisplayMode(DeviceInfo,DXConfig).h,
							   DXDisplayMode(DeviceInfo,DXConfig).bpp)==false)
		return false;	
	
	// Create Flippable Primary Surface
	
	DXInit(ddsd);
	
	if(DXD3D(DeviceInfo,DXConfig).bHardware)
	{
		ddsd.dwBackBufferCount = 1;
		ddsd.dwFlags		   = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
		ddsd.ddsCaps.dwCaps    = DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP|DDSCAPS_3DDEVICE|DDSCAPS_COMPLEX;
	}
	else
	{
		ddsd.dwFlags			     = DDSD_CAPS;
		ddsd.ddsCaps.dwCaps			 = DDSCAPS_PRIMARYSURFACE;
	}

	if(DXCreateSurface(App.lpDD,&ddsd,&App.lpFrontBuffer)==false)
		return false;	
	
	// Get Attached Back Buffer
	
	if(DXD3D(DeviceInfo,DXConfig).bHardware)
	{
		ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
		if(DXGetAttachedSurface(App.lpFrontBuffer,&ddscaps,&App.lpBackBuffer)==false)
			return false;
	}
	else
	{
		DXInit(ddsd);
		ddsd.dwFlags  = DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS;
		ddsd.dwWidth  = DXDisplayMode(DeviceInfo,DXConfig).w;
		ddsd.dwHeight = DXDisplayMode(DeviceInfo,DXConfig).h;
		ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN|DDSCAPS_3DDEVICE;
		DXCreateSurface(App.lpDD,&ddsd,&App.lpBackBuffer);
	}


	// Create Z Buffer And Add To Surface Chain

	if(DXConfig->bZBuffer)
	{
		DXInit(ddsd);
		ddsd.dwFlags = DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_ZBUFFERBITDEPTH;

		if(DXD3D(DeviceInfo,DXConfig).bHardware)
			ddsd.ddsCaps.dwCaps		= DDSCAPS_ZBUFFER|DDSCAPS_VIDEOMEMORY;
		else
			ddsd.ddsCaps.dwCaps		= DDSCAPS_ZBUFFER|DDSCAPS_SYSTEMMEMORY;
	
		ddsd.dwWidth			= DXDisplayMode(DeviceInfo,DXConfig).w;
		ddsd.dwHeight			= DXDisplayMode(DeviceInfo,DXConfig).h;
		ddsd.dwZBufferBitDepth	= 16;
		
		if(DXCreateSurface(App.lpDD,&ddsd,&App.lpZBuffer)==false)
			return false;
		
		if(DXAddAttachedSurface(App.lpBackBuffer,App.lpZBuffer)==false)
			return false;
	}
	else
		App.lpZBuffer = 0;

		
	// Create A Palette
/*
	if(!DXD3D(DeviceInfo,DXConfig).bHardware)
	{
		DWORD dwFlags=DDPCAPS_8BIT;
		ZeroArray(App.PaletteEntries);
		for (int i=0;i<256;++i)
			App.PaletteEntries[i].peFlags=D3DPAL_READONLY;
		
		dwFlags|=DDPCAPS_ALLOW256;
		App.lpDD->CreatePalette(dwFlags,App.PaletteEntries,&App.Palette,NULL);
		
		App.lpFrontBuffer->SetPalette(App.Palette);
		App.lpBackBuffer->SetPalette(App.Palette);
	}
*/	

	// Create Direct3D Device
	
	if(DXCreateDirect3DDevice(App.lpD3D,DXD3DGuid(DeviceInfo,DXConfig),
							  App.lpBackBuffer,&App.lpD3DDevice)==false)
							  return false;
	
	// Create Viewport

	if(DXCreateViewPort(App.lpD3D,App.lpD3DDevice,
					 DXDisplayMode(DeviceInfo,DXConfig).w,
					 DXDisplayMode(DeviceInfo,DXConfig).h,
					 &App.lpViewPort)==false)
					 return false;


	// Viewport Material (Black)

	D3DMATERIAL mat;
	D3DMATERIALHANDLE handle;
	DXInit(mat);
	App.lpD3D->CreateMaterial(&App.lpViewPortMaterial,NULL);
	App.lpViewPortMaterial->SetMaterial(&mat);
	App.lpViewPortMaterial->GetHandle(App.lpD3DDevice,&handle);
	App.lpViewPort->SetBackground(handle);

	// Create Picture Buffer 
	
	DXInit(ddsd);
	ddsd.dwWidth=640;
	ddsd.dwHeight=480;
	ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
    DXCreateSurface(App.lpDD,&ddsd,&App.lpPictureBuffer);
	
	return true;
}

// EOF : WinDXInit




/*
	Function : WinFrameRate
	Useage	 : Calculate Averate Framerate
*/

float WinFrameRate(void)
{
	static int last_time = clock();
	static int count = 0;
	static float fps = 0.0f;
	
	count++;
    if(count == 10)
	{
        double t;
        time_t this_time;
        this_time = clock();
        t = (this_time - last_time)/(double)CLOCKS_PER_SEC;
        last_time = this_time;
        fps = (float)(count/t);
		count = 0;
	}

	App.fps = fps;
	
	return fps;
}

// EOF : WinFrameRate




/*
	Function : WinDisplayString
	Useage	 : Out Text To Screen
*/

void WinDisplayString (int x,int y,char *String,...)
{
	HDC hdc;
	App.lpBackBuffer->GetDC(&hdc);
	SetBkColor(hdc,RGB(0,0,0));
	SetTextColor(hdc,RGB(128,128,128));
	SetBkMode(hdc,OPAQUE);

	va_list	argptr;
	char msg[4096];
	va_start(argptr,String);
	vsprintf(msg,String,argptr);
	va_end(argptr);
	TextOut(hdc,x+phd_winxmin,(y*16)+phd_winymin,msg,strlen(msg));
	App.lpBackBuffer->ReleaseDC(hdc);
}

// EOF : WinDisplayString






