///////////////////////////////////////////////////////////////////////////////
/// @file deWorldView.cpp
///
/// @brief Destiny3D Testing program
///
/// @author Assassin
///
/// This file is the intellectual property of Novus Delta, LLC.. Usage of the
/// contents of this file is subject to the Destiny3D Member License which
/// can be found at http://www.destiny3d.com.  Any other usage is prohibited.
///
/// This file is distributed "AS IS" without warranty of any kind.  Novus
/// Delta, LLC. does not guarantee the fitness of the contents of this file
/// for any particular purpose.
///
/// Copyright (C) 2001-2003 Novus Delta, LLC. All Rights Reserved.
///
/// <hr>
///                                 Change History
/// <hr>
///
/// @date Feb 2003
/// @author Assassin
/// @remarks Creation
///
///////////////////////////////////////////////////////////////////////////////

/**********************
Includes
**********************/
#include <cstdio>
#include <cmath>
#include <crtdbg.h>
#include <windows.h>
#include <ZMouse.h>

// automatic library usage

#include "Destiny3D.hpp"

#include "deBitmap.hpp"
#include "deBrush.hpp"
#include "deRender.hpp"
#include "deDriver.hpp"
#include "deWorld.hpp"
#include "deCamera.hpp"
#include "deResource.hpp"
#include "deConsole.hpp"
#include "de2D.hpp"
#include "deFont.hpp"
#include "deScene.hpp"
#include "deProfile.hpp"
#include "ResPicker.hpp"

#pragma message("Compiling under: " DESTINY3D_COMPILER)

#define DRIVER_NAME		("Direct3D9")
#define ONE_CAM			(1)
#define TEST_WORLD_LOAD	(1)
#define WINDOW_WIDTH	(800)
#define WINDOW_HEIGHT	(600)
#define VIEW_WIDTH		(800)
#define VIEW_HEIGHT		(600)
#define VIEW_FOV		(75)
#define VIEW_FULLSCREEN	(0)
#define VIEW_ADAPTER	(0)
#define VIEW_ASPECT		(4.0/3.0)
#define FRAMESCOUNTED	(50)
#define FOGCOLOR		(0x00000000)
#define TEST_ABT		(0)
#define SHOW_AABB		(1)
#define USE_FLASHLIGHT	(1)

const double piover180 = 0.0174532925;

HWND	WindowHandle;
int		FillVal;
int		CullVal;

IdeDriver::deDisplay m_Display;
deVec3d		m_vPosition;
deVec3d		m_vForward, m_vLeft;
float		m_fRotation;
BOOL		m_bMouseMove;
int			m_Wireframe;
POINT		m_ptMouse, m_ptOffset, m_ptDelta;
POINT		m_StartMove;
deVec3d		m_CamRotation = {0,0,0};
deFloat		m_SpeedMultiplier = 1;

IdeCamera	*m_Cam, *m_Cam2;
IdeWorldManager* m_pWorldManager;
deWorldID	m_WorldID;
IdeRender *	m_pRender;
IdeSceneGraph * pSG;
bool		m_bReset = false;
bool		m_bLostFocus = false;

Ide2DCollection * _2D = NULL;
IdeDriver*	m_pDriver;
IdeFont * Font = NULL;

IdeSceneLight* pLight = NULL;

double TotalTime = 0, FramesTime = 0;
double FrameTime = 0;
unsigned int TotalFrames = 0;

IdeRender::deRenderStats RenderStats;

void CheckMouse();
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

HWND CreateNewWindow(HINSTANCE hInstance)
{
	HWND		LocalHandle;
	WNDCLASSEX	wc;
	RECT		WindowRect;
	char		ClassName[] = "DWorldView";
	long		X;
	long		Y;

	//create a class
	wc.cbSize = sizeof(wc);
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = hInstance;
	wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
	wc.lpszMenuName = (const char*)NULL;
	wc.lpszClassName = ClassName;
	wc.hIcon = NULL; //LoadIcon(hInstance, IDI_APPLICATION);
	wc.hIconSm = NULL; //wc.hIcon;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	RegisterClassEx(&wc);

	//create the window and show it
	LocalHandle = CreateWindowEx(0, ClassName, "DWorldView", WS_POPUP|WS_CAPTION|WS_SYSMENU, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);

	//figure out the rect size for the area we want
	WindowRect.left = 0;
	WindowRect.top = 0;
	WindowRect.right = WINDOW_WIDTH - 1;
	WindowRect.bottom = WINDOW_HEIGHT - 1;
	GetWindowRect(LocalHandle, &WindowRect);

	//	AdjustWindowRect(&WindowRect, WS_POPUP, FALSE);

	//grab the screen with
	X = GetSystemMetrics(SM_CXSCREEN);
	Y = GetSystemMetrics(SM_CYSCREEN);
	
	//now modify the rect so that the window is centered and set it
	WindowRect.left = (X - WindowRect.right) / 2;
	WindowRect.top = (Y - WindowRect.bottom) / 2;
	m_ptOffset.x = WindowRect.left;
	m_ptOffset.y = WindowRect.top;
	SetWindowPos(LocalHandle, NULL, WindowRect.left, WindowRect.top, WindowRect.right, WindowRect.bottom, SWP_NOCOPYBITS);

	//go show and update the window
	ShowWindow(LocalHandle, SW_SHOWNORMAL);
//	UpdateWindow(LocalHandle);

	return LocalHandle;
}

void MoveNewWindow(HWND hWnd, int x, int y)
{
	RECT windowrect;
	int width, height;
	GetWindowRect(hWnd, &windowrect);
	width = windowrect.right - windowrect.left;
	height = windowrect.bottom - windowrect.top;
	MoveWindow(hWnd, x, y, width, height, TRUE);
}

bool InitEngine();
bool InitDisplay(HINSTANCE hInstance);
bool InitData();
bool StartDisplay();

int		WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprev, PSTR cmdline, int ishow)
{
#ifdef _DEBUG 
	int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); // Get current flag 
	flag |= _CRTDBG_LEAK_CHECK_DF;		// Turn on leak-checking bit 
	//flag |= _CRTDBG_CHECK_ALWAYS_DF;	// Turn on memory allocation checks (extremely slow)
	_CrtSetDbgFlag(flag); // Set flag to the new value 
#endif
	
	MSG		msg;

	if (!InitEngine())
		return -10;

	if (!InitData())
		return -20;

	if (!InitDisplay(hInstance))
		return -30;

	m_pRender->SetRenderFlag(IdeRender::Render_Fill);
	m_pRender->SetRenderFlag(IdeRender::Render_CullCW);
//	m_pRender->SetMultiPassOptions(IdeRender::MultiPass_Disable);
	if (FOGCOLOR)
		m_pRender->SetBGColor(FOGCOLOR);
	else
		m_pRender->SetBGColor(0xffff80);
	m_Wireframe = 0;
	{
		long flags = ~IdeSceneGraph::deCullFarPlaneOptimize & IdeSceneGraph_GetSceneGraphPtr()->GetCullFlags();
		IdeSceneGraph_GetSceneGraphPtr()->SetCullFlags(flags);
	}

	// create a font
	Font = IdeFont_CreateFont();	
	Font->SetFont("Arial", 12, IdeFont::STYLE_BOLD);
	Font->SetScale(1.0f);

	if (TEST_WORLD_LOAD)
	{
		char currentdir[512];
		char filenamebuffer[512] = "\0";
		OPENFILENAME ofn;

		GetCurrentDirectory(511, currentdir);
		ZeroMemory(&ofn, sizeof(OPENFILENAME));
		ofn.lStructSize = sizeof(OPENFILENAME);
		ofn.hwndOwner = WindowHandle;
		ofn.lpstrFile = filenamebuffer;
		ofn.lpstrFilter = "DWorld\0*.dworld\0";
		ofn.nFilterIndex = 1;
		ofn.nMaxFile = 511;
		ofn.lpstrInitialDir = currentdir;
		ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR;

		// win32 file-open messagebox
		if (!GetOpenFileName(&ofn))
			goto end_main;

		StartDisplay();
		
		// print some loading text in the middle of the main camera
		{
			int SWidth, SHeight;
			Ide2DObject * object;
			Font->SetColor(0xff0000ff); // blue
			object = Font->Print2D(m_pDriver, NULL, VIEW_WIDTH/2, VIEW_HEIGHT/2, 0.91, &SWidth, &SHeight, 
				IdeFont::POSITION_HCENTER | IdeFont::POSITION_VCENTER, 
				"Loading...");
			if (object)
			{
				_2D->AddObject(object);
				object->MakeExpire();
				object->Release();
			}
			if (!m_pRender->Render(m_Cam, FramesTime/FRAMESCOUNTED, deTRUE, deTRUE, deTRUE, deTRUE))
			{
				MessageBox(NULL, "Render() Failed", "Error", MB_OK);
				goto end_main;
			}
		}

		// reset to FPS counter color
		Font->SetColor(0xff202020); // dark gray

		IdeResourceBase * rsc = IdeResourceManager_GetManager()->GetResource(filenamebuffer, NULL);
		IdeWorld * pWorld = (IdeWorld*)rsc->GetRscInterface(IdeWorld_GetManager()->GetRscInterfaceID());
		deWorldID ID = pWorld->GetWorldID();

		//pWorld->Release();
	}

	{
	PROFILE("Total");
	int PosX = 1;
	int PosY = 1;
	int polycount = 0;
	deTimer timer;
	timer.GrabStartTime();
	do	
	{													// Check if there was a message
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
        { 
			if(msg.message == WM_QUIT)					// If the message wasnt to quit
				break;
            TranslateMessage(&msg);						// Find out what the message does
            DispatchMessage(&msg);						// Execute the message
        }
		else if (m_bLostFocus)
		{
			WaitMessage();
		}
		else
		{
			if (m_bReset)
			{
				if (!m_pDriver->Reset(NULL))
				{
					MessageBox(NULL, "Reset() Failed", "Error", MB_OK);
					goto end_main;
				}
				m_bReset = false;
			}
			if (GetAsyncKeyState(VK_UP) & 0x8000)
			{
				// move camera forward
				deTransform M1,M2;
				M1.SetTranslation(deMake_Vec3d(0, 0, 1 * FrameTime * 10 * m_SpeedMultiplier));
				//M1.SetTranslation(deMake_Vec3d(0, 0, 0.05));
				M2 = m_Cam->Position();
				M1 = M2.Multiply(M1);
				m_Cam->Position() = M1;
			}
			else if (GetAsyncKeyState(VK_DOWN) & 0x8000)
			{
				// move camera backward
				deTransform M1,M2;
				M1.SetTranslation(deMake_Vec3d(0, 0, -1 * FrameTime * 10 * m_SpeedMultiplier));
				//M1.SetTranslation(deMake_Vec3d(0, 0, -0.05));
				M2 = m_Cam->Position();
				M1 = M2.Multiply(M1);
				m_Cam->Position() = M1;
			}
			if (GetAsyncKeyState(VK_SUBTRACT) & 0x8000)
			{
				// move camera up
				m_Cam->Position().Translation.y += (1 * FrameTime * 10 * m_SpeedMultiplier);
			}
			else if (GetAsyncKeyState(VK_ADD) & 0x8000)
			{
				// move camera down
				m_Cam->Position().Translation.y += (-1 * FrameTime * 10 * m_SpeedMultiplier);
			}
			if (GetAsyncKeyState(VK_LEFT) & 0x8000)
			{
				deTransform M1,M2;
				if (m_bMouseMove)
				{
					// in mouse move, we STRAFE
					M1.SetTranslation(deMake_Vec3d(-1 * FrameTime * 10 * m_SpeedMultiplier, 0, 0));
					M2 = m_Cam->Position();
					M1 = M2.Multiply(M1);
					m_Cam->Position() = M1;
				}
				else
				{
					// not in mousemove, so we turn
					deVec3d v;
					M2 = m_Cam->Position();
					v = M2.Translation;
					M2.RotateY(-1 * FrameTime * 1);
					m_CamRotation.x += -1 * FrameTime * 1;
					M2.Translation = v;
					m_Cam->Position() = M2;
				}
			}
			else if (GetAsyncKeyState(VK_RIGHT) & 0x8000)
			{
				deTransform M1,M2;
				if (m_bMouseMove)
				{
					// in mouse move, we STRAFE
					M1.SetTranslation(deMake_Vec3d(1 * FrameTime * 10 * m_SpeedMultiplier, 0, 0));
					M2 = m_Cam->Position();
					M1 = M2.Multiply(M1);
					m_Cam->Position() = M1;
				}
				else
				{
					// not in mousemove, so we turn
					deVec3d v;
					M2 = m_Cam->Position();
					v = M2.Translation;
					M2.RotateY(1 * FrameTime * 1);
					m_CamRotation.x += 1 * FrameTime * 1;
					M2.Translation = v;
					m_Cam->Position() = M2;
				}
			}

			CheckMouse();

			if (USE_FLASHLIGHT)
			{
				const deTransformInfo& campos = m_Cam->Position();
				IdeRenderLight::LightData ldata = *pLight->GetLightData();
				ldata.Position = deMake_Vertex(campos.Translation);
				ldata.Direction = deMake_Vertex(campos.I);
				pLight->SetLightData(ldata);
			}

			/**/
			Ide2DObject * object;
			double FrameRate = FRAMESCOUNTED/FramesTime;
			int SWidth, SHeight;
			if (1)
			{
				object = Font->Print2D(m_pDriver, NULL, 3, 0, 0.91, &SWidth, &SHeight, IdeFont::POSITION_DEFAULT, "%0.2f %d", FrameRate, TotalFrames);
				if (object)
				{
					object->MakeExpire();
					_2D->AddObject(object);
					object->Release();
				}
			}
			if (1)
			{
				object = Font->Print2D(m_pDriver, NULL, 3, 20, 0.92, &SWidth, &SHeight, IdeFont::POSITION_DEFAULT, "%d", polycount);
				object->MakeExpire();
				_2D->AddObject(object);
				object->Release();

				object = Font->Print2D(m_pDriver, NULL, 3, 40, 0.93, &SWidth, &SHeight, IdeFont::POSITION_DEFAULT, "%d", (int)(polycount*FrameRate));
				object->MakeExpire();
				_2D->AddObject(object);
				object->Release();
				
				object = Font->Print2D(m_pDriver, NULL, 3, 60, 0.93, &SWidth, &SHeight, IdeFont::POSITION_DEFAULT, "%f", m_Cam->GetFOV());
				object->MakeExpire();
				_2D->AddObject(object);
				object->Release();
			}
			if (1)
			{
				object = Font->Print2D(m_pDriver, NULL, 3, 80, 0.92, &SWidth, &SHeight, IdeFont::POSITION_DEFAULT, "%f", RenderStats.FarPlaneDistUsed);
				object->MakeExpire();
				_2D->AddObject(object);
				object->Release();
			}

			if (!ONE_CAM)
			{
				deTransform M, M2;
				deVec3d Trans = {0,0,-2};
				//M2.SetTranslation(Trans);
				M2.RotateY(DE_PI);
				M = m_Cam->Position();
				M = M.Multiply(M2);
				//M.FreeRotInPlace(0, SIN(TotalFrames/100.0)/2, 0);
				m_Cam2->Position() = M;
			}

			m_pRender->SetStatStruct(&RenderStats);

			if (!m_pRender->BeginFrame(WindowHandle, deTRUE))
			{
				MessageBox(NULL, "BeginFrame() Failed", "Error", MB_OK);
				goto end_main;
			}

			if (!m_pRender->Render(m_Cam, FramesTime/FRAMESCOUNTED, deTRUE, DE_FALSE, DE_FALSE, DE_FALSE))
			{
				MessageBox(NULL, "Render() Failed", "Error", MB_OK);
				goto end_main;
			}
			
#if !ONE_CAM
			if (!m_pRender->Render(m_Cam2, 0.05, deTRUE, DE_TRUE, DE_FALSE, DE_FALSE))
				return FALSE;
#endif
			if (!m_pRender->EndFrame(WindowHandle, 0.05))
			{
				MessageBox(NULL, "EndFrame() Failed", "Error", MB_OK);
				goto end_main;
			}
			{
				static double FrameTimes[FRAMESCOUNTED] = {0};
				FramesTime = 0;
				int i;
				for (i = 0; i < FRAMESCOUNTED-1; i++)
				{
					FramesTime += FrameTimes[i];
					FrameTimes[i] = FrameTimes[i+1];
				}
				timer.GrabStopTime();
				FrameTime = timer.DiffTime(1.0);
				timer.GrabStartTime();
				FramesTime += FrameTime;
				FrameTimes[FRAMESCOUNTED-1] = FrameTime;
				TotalTime += FrameTime;
				TotalFrames++;
			}
			polycount = RenderStats.PrimitiveRenders;
        }
	} while (1);
	}

end_main:
	{
		__int64 rendertime, totaltime, frequency;
		totaltime = IdeProfile_GetTheManager()->TimeSpentIn("Total");
		rendertime = IdeProfile_GetTheManager()->TimeSpentIn_IDByName("Render");
		frequency = IdeProfile_GetTheManager()->EstimateFrequency();
		deDouble RenderPercent = ((deDouble)rendertime)/totaltime;
	}
	DE3D_SAFE_RELEASE(Font);
	m_Cam->Release();
	m_Cam2->Release();

	Destiny3D_ShutDown();
	
	return (int)(TotalFrames/TotalTime);
}

bool InitEngine()
{
	Destiny3D_Init();
	return true;
}

bool InitDisplay(HINSTANCE hInstance)
{
	WindowHandle = CreateNewWindow(hInstance);
	if(!WindowHandle)
	{
		return false;
	}

	m_pDriver = m_pRender->AttachToWindow(WindowHandle, DRIVER_NAME);
	if (!m_pDriver)
	{
		MessageBox(WindowHandle, "Failed to load driver - check your working directory", "ERROR!", MB_OK);
		return false;
	}
	deResPicker ResPicker;
	m_Display.IgnoreVSync = deTRUE;
	if (ResPicker.PickResolution(hInstance, WindowHandle, m_pDriver, &m_Display))
	{
		if (m_Display.Windowed)
		{
			m_Display.Width = VIEW_WIDTH;
			m_Display.Height = VIEW_HEIGHT;
			m_Display.RefreshRate = 0;
		}
		else
		{
			deRect r;
			r = m_Cam->GetRect();
			r.Left = 0;
			r.Top = 0;
			r.Right = m_Display.Width;
			r.Bottom = m_Display.Height;
			m_Cam->SetRect(r);
		}
	}
	else
	{
		return false;
	}
	if (0)
	{
		memset(&m_Display, 0, sizeof(IdeDriver::deDisplay));
		m_Display.Adapter = VIEW_ADAPTER;
		if (VIEW_FULLSCREEN)
		{
			int i=0;
			deBoolean RetVal;
			do
			{
				RetVal = m_pRender->GetResolution(m_pDriver, m_Display.Adapter, i, &m_Display.Width, &m_Display.Height, &m_Display.RefreshRate);
				i++;
			} while (RetVal && (m_Display.Width != VIEW_WIDTH || m_Display.Height != VIEW_HEIGHT || m_Display.RefreshRate < 60));
		}
		else
		{
			m_Display.Width = VIEW_WIDTH;
			m_Display.Height = VIEW_HEIGHT;
			m_Display.RefreshRate = 0;
		}
		m_Display.BackBpp = IdeDriver::BPP_A8R8G8B8;
		m_Display.FrontBpp = IdeDriver::BPP_X8R8G8B8;
		m_Display.ZDepth = 24;
		m_Display.StencilDepth = 0;
		m_Display.FSAASamples = 0;
		m_Display.TripleBuffer = deFALSE;
		m_Display.Windowed = !VIEW_FULLSCREEN;
	}
	if (!m_pRender->QueryFormat(m_pDriver, &m_Display, deTRUE))
	{
		MessageBox(WindowHandle, "QueryFormat returned false, using recommended format", "Warning", MB_OK);
	}
	m_pDriver->SetQualityFlag(IdeDriver::QUALITY_ALLOW_TEXTURE_MANGLING, 1);
	m_pDriver->SetQualityFlag(IdeDriver::QUALITY_ALLOW_INVALID_TEXTURES, 1);
	const IdeDriver::deDriverCaps * caps = m_pDriver->GetCaps(0);
	_2D = m_pRender->Get2DCollection(WindowHandle);
	
	return true;
}

bool InitData()
{
	m_vPosition.x = 0;
	m_vPosition.y = 0;
	m_vPosition.z = 10;
	m_vForward.x = 0;
	m_vForward.y = 0;
	m_vForward.z = 1;
	m_vLeft.x = 1;
	m_vLeft.y = 0;
	m_vLeft.z = 0;
	m_fRotation = 0.0f;
	m_bMouseMove = FALSE;
	m_Wireframe = 0;
	
	m_pWorldManager = IdeWorld_GetManager();
	m_WorldID = 0;
	m_pRender = IdeRender_GetPtr();
	pSG = IdeSceneGraph_GetSceneGraphPtr();

	if (SHOW_AABB)
	{
		long x = pSG->GetDebugFlags();
		x |= IdeSceneGraph::deDrawAABB;
		pSG->SetDebugFlags(x);
	}

	{
		deDouble aspect;
		m_Cam = IdeCamera_CreateCamera();
		m_Cam2 = IdeCamera_CreateCamera();
		deRect rect;
		rect.Top = 0;
		rect.Left = 0;
		rect.Right = VIEW_WIDTH;
		rect.Bottom = VIEW_HEIGHT;
		m_Cam->SetRect(rect);
		//m_Cam->SetClip(1,2000);
		m_Cam->SetFOV(VIEW_FOV);
		m_Cam->SetOrthoWidth(8);
		m_Cam->EnableOrtho(deFALSE);
		if (FOGCOLOR)
		{
			deFloat Dist = 150;
			m_Cam->SetFog(10, Dist, FOGCOLOR, deTRUE);
			m_Cam->SetClip(0.1, Dist);
		}
		else
		{
			m_Cam->SetClip(0.1, 100000);
		}
		//m_Cam.Position.RotateY(DE_PI/2);
		rect.Top = 0;
		rect.Left = 0;
		rect.Bottom = 256;
		rect.Right = 256;
#if RENDER_TEXTURE
		rect.Bottom = RENDER_SIZE;
		rect.Right = RENDER_SIZE;
#endif
		m_Cam2->SetScreenAspect(rect.Right, rect.Bottom, 3.0/3.0);
		//m_Cam2->LockAspect(4.0/3.0);
		m_Cam2->SetRect(rect);
		m_Cam2->SetFOV(VIEW_FOV);
		aspect = ((deFloat)rect.Right)/rect.Bottom;
		m_Cam2->GetFOVy(aspect);
		deTransform M(m_Cam->Position());
		M.Translation.X = 0;
		M.Translation.Y = 1;
		M.Translation.Z = -5;
		m_Cam->Position() = M;
		M.RotateY(-DE_PI/2);
		M.Translation.X = 30;
		M.Translation.Y = 0;
		M.Translation.Z = -10;
		m_Cam2->Position() = M;
	}

	if (USE_FLASHLIGHT)
	{
		IdeRenderLight::LightData ldata;
		memset(&ldata, 0, sizeof(ldata));
		ldata.Position = deMake_Vertex(deZeroVec);
		ldata.Direction = deMake_Vertex(deVecZ);
		ldata.DiffuseColor = deMake_Color(0xffffffff);
		ldata.LightType = IdeRenderLight::LIGHTTYPE_POINT;
		ldata.MaxRange = 40;
		ldata.FallOff = 1.0;
		ldata.Attenuation[1] = 0.25;
		ldata.Phi = DE_PI/3;
		ldata.Theta = DE_PI/4;
		ldata.ID = 5;
		ldata.Status = deTRUE;
		pLight = IdeSceneObject_CreateSceneLight();
		pLight->SetLightData(ldata);
		pSG->AddSceneObject(pLight);
	}

	return true;
}

bool StartDisplay()
{
	if (!m_pDriver || !m_pRender->LoadDriver(WindowHandle, &m_Display, DRIVER_NAME))
	{
		MessageBox(WindowHandle, "No driver available", "ERROR!", MB_OK);
		return false;
	}
	
#if (WINVER >= 0x0501)
	// will only work with an updated version of windows platform SDK
	{
		MONITORINFO moninfo;
		int width, height;
		const IdeDriver::deDisplay * pDisplay;
		pDisplay = m_pDriver->GetDisplay();
		moninfo.cbSize = sizeof(MONITORINFO);
		GetMonitorInfo(pDisplay->MonitorHandle, &moninfo);
		width = moninfo.rcMonitor.right - moninfo.rcMonitor.left;
		height= moninfo.rcMonitor.bottom - moninfo.rcMonitor.top;
		m_Cam->SetScreenAspect(width, height, VIEW_ASPECT); // change to 16/9 if you have a widescreen monitor
		int x,y;
		if (pDisplay->Windowed)
		{
			x = (moninfo.rcMonitor.right + moninfo.rcMonitor.left)/2 - VIEW_WIDTH/2;
			y = (moninfo.rcMonitor.bottom + moninfo.rcMonitor.top)/2 - VIEW_HEIGHT/2;
		}
		else
		{
			x = moninfo.rcMonitor.left;
			y = moninfo.rcMonitor.top;
		}
		MoveNewWindow(WindowHandle, x, y);
	}
#endif

	m_Cam->SetWindow(WindowHandle);
	m_Cam2->SetWindow(WindowHandle);
	
	return true;
}


void CheckMouse()
{
	/**************************
	Polls the current mouse position and rotates the camera based on
	relative cursor position to a null zone in center of window.
	This routine currently only rotates left/right
	*****************************/

	// save old position
	m_ptDelta = m_ptMouse;
	GetCursorPos(&m_ptMouse);

	static LastMode = FALSE;
	if (LastMode != m_bMouseMove)
	{
		if (m_bMouseMove)
		{
			while(ShowCursor(FALSE) >= 0)
			{
			}
		}
		else
		{
			while(ShowCursor(TRUE) < 0)
			{
			}
		}
		LastMode = m_bMouseMove;
	}
	if (!m_bMouseMove)
		return;

	m_ptDelta.x = m_ptMouse.x - m_ptDelta.x;
	m_ptDelta.y = m_ptMouse.y - m_ptDelta.y;
	m_ptMouse.x -= m_ptDelta.x;
	m_ptMouse.y -= m_ptDelta.y;
	SetCursorPos(m_ptMouse.x, m_ptMouse.y);

	{
		deDouble FOV = m_Cam->GetFOV();
		FOV /= 90;
		deTransform* tform = &((deTransform&)m_Cam->Position());
		deVec3d pos = tform->Translation;
		m_CamRotation.x += FOV*(m_ptDelta.x) * 0.0025;
		m_CamRotation.y += FOV*(m_ptDelta.y) * 0.002;
		while (m_CamRotation.x > DE_PI)
			m_CamRotation.x -= DE_PI*2;
		while (m_CamRotation.x < -DE_PI)
			m_CamRotation.x += DE_PI*2;
		m_CamRotation.y = min(m_CamRotation.y, DE_PI*0.49);
		m_CamRotation.y = max(m_CamRotation.y, -DE_PI*0.49);
		tform->Reset();
		tform->FreeRotInPlace(m_CamRotation.y, m_CamRotation.x, 0);
		tform->Translation = pos;
	}
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    LONG			lRet = 1; 
//	deVec3d			vPos;

//	deVec3d position1 = {10,0,10};
//	deVec3d position2 = {0,0,-10};
    switch (message)
	{ 
	case WM_ACTIVATE:
		{
			int fActive = LOWORD(wParam);           // activation flag 
			BOOL fMinimized = (BOOL) HIWORD(wParam); // minimized flag 
			HWND hwndPrevious = (HWND) lParam;       // window handle 
			
			m_bLostFocus = (fActive == WA_INACTIVE) ? true : false;
		}
	case WM_ACTIVATEAPP:
		{
			BOOL fActive = (BOOL) wParam; // minimized flag 
			
			m_bLostFocus = (fActive) ? false : true;
		}
	case WM_SIZE:
		//m_cWorld.ResizeWindow(LOWORD(lParam),HIWORD(lParam));
        break; 
	case WM_RBUTTONDOWN:
		if (m_bMouseMove)
		{
			// already in mousemove, so leave it
			m_bMouseMove = FALSE;
			ShowCursor(TRUE);
		}
		else
		{
			// enter mousemove
			m_bMouseMove = TRUE;
			ShowCursor(TRUE);
		}
		break;
	case WM_MOUSEWHEEL:
		{
			deDouble FOV = m_Cam->GetFOV();
			short zDelta = (short) HIWORD(wParam);    // wheel rotation

			FOV -= 5 * ((deDouble)zDelta/120);

			if (FOV >= 120)
				FOV = 120;
			else if (FOV <= 5)
				FOV = 5;
			
			m_Cam->SetFOV(FOV);
		}
		break;
	case WM_KEYDOWN:						

		switch(wParam) 
		{					
#if (WINVER >= 0x0501)
		case VK_OEM_MINUS:
			m_SpeedMultiplier /= 2;
			if (m_SpeedMultiplier < 0.000001f)
				m_SpeedMultiplier = 0.000001f;
			break;
		case VK_OEM_PLUS:
			m_SpeedMultiplier *= 2;
			if (m_SpeedMultiplier > 100000)
				m_SpeedMultiplier = 100000;
			break;
		case VK_OEM_5:
			m_SpeedMultiplier = 1.0f;
			break;
#endif
		case VK_ESCAPE:			
			PostQuitMessage(0);		
			break;
		case VK_SPACE:
			m_Wireframe = (m_Wireframe+1)%3;
			switch (m_Wireframe)
			{
			default:
			case 0:
				m_pRender->SetRenderFlag(IdeRender::Render_Fill);
				break;
			case 1:
				m_pRender->SetRenderFlag(IdeRender::Render_Mesh);
				break;
			case 2:
				m_pRender->SetRenderFlag(IdeRender::Render_DepthMesh);
				break;
			}
			break;
		case VK_F5:
			m_bReset = true;
			break;
		case VK_F6:
			{
				static fullscreen = VIEW_FULLSCREEN;
				fullscreen = !fullscreen;
				IdeDriver::deDisplay display;
				display = *m_pDriver->GetDisplay();
				display.Width = VIEW_WIDTH;
				display.Height = VIEW_HEIGHT;
				display.Windowed = !fullscreen;
				if (fullscreen)
				{
					display.FSAASamples = 0;
					display.RefreshRate = 75;
				}
				else
				{
					display.FSAASamples = 0;
					display.RefreshRate = 0;
				}
				m_pRender->LoadDriver(WindowHandle, &display, DRIVER_NAME);
				if (!m_pDriver)
				{
					MessageBox(NULL, "Reset", "Error", MB_OK);
				}
				_2D = m_pRender->Get2DCollection(WindowHandle);
				if (FOGCOLOR)
				{
					m_pRender->SetBGColor(FOGCOLOR);
				}
				else
				{
					if (fullscreen)
						m_pRender->SetBGColor(0x0000ffff);
					else
						m_pRender->SetBGColor(0x00ffff00);
				}
				if (fullscreen)
				{
					m_Cam->SetScreenAspect(display.Width, display.Height, 4.0/3.0);
				}
				else
				{
					int width=800, height=600;
#if (WINVER >= 0x0501)
					HMONITOR hmon;
					MONITORINFO moninfo;
					moninfo.cbSize = sizeof(moninfo);
					hmon = MonitorFromWindow(WindowHandle, MONITOR_DEFAULTTOPRIMARY);
					GetMonitorInfo(hmon, &moninfo);
					width = moninfo.rcMonitor.right - moninfo.rcMonitor.left;
					height= moninfo.rcMonitor.bottom - moninfo.rcMonitor.top;
#endif
					m_Cam->SetScreenAspect(width, height, 4.0/3.0);
				}
			}
			break;
		case VK_F7:
			m_pRender->EnableTexturing(DE_TRUE);
			break;
		case VK_F8:
			m_pRender->EnableTexturing(DE_FALSE);
			break;
		case VK_F11:
			{
				int width=800, height=600;
#if (WINVER >= 0x0501)
				HMONITOR hmon;
				MONITORINFO moninfo;
				HDC dc = GetDC(WindowHandle);
				int wmm = GetDeviceCaps(dc, HORZSIZE);
				int hmm = GetDeviceCaps(dc, VERTSIZE);
				int blahx = GetDeviceCaps(dc, ASPECTX);
				int blahy = GetDeviceCaps(dc, ASPECTY);
				float screenAspect = ((float)wmm)/hmm;
				moninfo.cbSize = sizeof(moninfo);
				hmon = MonitorFromWindow(WindowHandle, MONITOR_DEFAULTTOPRIMARY);
				GetMonitorInfo(hmon, &moninfo);
				width = moninfo.rcMonitor.right - moninfo.rcMonitor.left;
				height= moninfo.rcMonitor.bottom - moninfo.rcMonitor.top;
				m_Cam->SetScreenAspect(width, height, screenAspect);
#else
				static bool WideScreen = false;
				WideScreen = !WideScreen;
				deDouble Aspect = (WideScreen) ? 16.0/9.0 : 4.0/3.0;
				m_Cam->SetScreenAspect(width, height, Aspect);
#endif
			}
			break;
		case VK_F12:
			{
				m_pRender->Screenshot(WindowHandle, "!screen.bmp");
			}
			break;
		}
		break;
    case WM_CLOSE:										// If the window is being closed
        PostQuitMessage(0);								// Send a QUIT Message to the window
        break; 
    default:											
        lRet = DefWindowProc (hwnd, message, wParam, lParam); 
        break; 
    } 
 
    return lRet;										
}


