///////////////////////////////////////////////////////////////////////////////
/// @file deWorldTest.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 2002
/// @author Assassin
/// @remarks Creation
///
/// @date May 2003
/// @author Assassin
/// @remarks Renamed from main.cpp to dWorldTest.cpp
///
///////////////////////////////////////////////////////////////////////////////

/**********************
Includes
**********************/
#include <cstdio>
#include <cmath>

#ifndef __GNUC__
#include <crtdbg.h>
#endif

#include <windows.h>
#include <ZMouse.h>

// automatic library usage

#include "Destiny3D.hpp"

#include "de2D.hpp"
#include "deAnimatedMesh.hpp"
#include "deBitmap.hpp"
#include "deBrush.hpp"
#include "deCamera.hpp"
#include "deConsole.hpp"
#include "deDriver.hpp"
#include "deFile.hpp"
#include "deFileSystem.hpp"
#include "deFont.hpp"
#include "deFunctors.hpp"
#include "deIDServer.hpp"
#include "deLine.hpp"
#include "deList.hpp"
#include "deMachine.hpp"
#include "deMath.hpp"
//#include "deMemory.hpp"
//#include "deMemoryMacros.hpp"
#include "deMesh.hpp"
#include "deMeshOpt.hpp"
#include "dePortal.hpp"
#include "deProfile.hpp"
#include "deRedBlack.hpp"
#include "deRender.hpp"
#include "deResource_Helper.hpp"
#include "deRenderStates.hpp"
#include "deScene.hpp"
#include "deSound.hpp"
#include "deString.hpp"
#include "deWorld.hpp"
#include "deThread.hpp"
#include "deByteOrder.hpp"

#include "ResPicker.hpp"

#pragma message("Compiling under: " DESTINY3D_COMPILER)

#define DRIVER_NAME		("Direct3D9")
#define ONE_CAM			(1)
#define TEST_WORLD		(0)
#define TEST_WORLD_LOAD	(!TEST_WORLD && 0)
#define WINDOW_WIDTH	(800)
#define WINDOW_HEIGHT	(600)
#define VIEW_WIDTH		(800)
#define VIEW_HEIGHT		(600)
#define VIEW_FOV		(90)
#define VIEW_FULLSCREEN	(0)
#define VIEW_ADAPTER	(0)
#define VIEW_ASPECT		(4.0/3.0)
#define BRUSH_IDENT		(c)
#define FRAMESCOUNTED	(50)
#define FOGCOLOR		(0x00404080)
#define FAST_KEYS		(1)
#define FPS_CAMERA		(1)
#define RENDER_TEXTURE	(0)
#define RENDER_SIZE		(256)
#define TEST_DOT3		(0)
#define TEST_COLLISION	(0)
#define TEST_XLOADER	(0)
#define TEST_TPORTAL	(0)
#define TEST_SKY		(1)
#define TEST_CUBEMAP	(0)
#define TEST_Q3LOADER	(0)
#define TEST_TERRAIN	(1)
#define TEST_ABT		(0)
#define TEST_SOUND		(0)

const double piover180 = 0.0174532925;

HWND	WindowHandle;
int		FillVal;
int		CullVal;

//CDWorld		m_cWorld;
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;

IDestiny3DFactory*	m_pDe3DFactory = NULL;
IdeCamera	*m_Cam, *m_Cam2;
IdeWorldManager* m_pWorldManager;
deWorldID	m_WorldID;
IdeWorld *	m_pWorld;
IdeRender *	m_pRender;
IdeSceneGraph* pSG = NULL;
IdeAnimatedMesh* m_pMD2 = NULL;
IdeSceneTerrain* m_pTerrain = NULL;
IdeSceneRoom* m_pRoom = NULL;
int			m_LOD1, m_LOD2;
bool		m_SetLOD = false;
bool		m_bReset = false;
bool		m_bLostFocus = false;

IdeSceneObject* m_pCylinder = NULL;

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

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

IdeRender::deRenderStats RenderStats;
deResPicker* m_ResPicker = NULL;

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[] = "DWorldTest";
	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, "DWorldTest", 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);
}

class CTestResource : public deResourceBase
{
public:
	static int count;
	CTestResource(const char * filename) : deResourceBase(filename) {count++;}
	~CTestResource()
	{
		count--;
	}

	void * GetRscInterface(long /*interface_id*/)
	{
		return (CTestResource*)(this);
	}

	IdeResourceBase * MakeCopy() {return NULL;}
};
int CTestResource::count = 0;

IdeResourceBase * MakeTest(const char * filename, IdeFile * /*file*/, deBoolean /*isThreaded*/)
{
	return new CTestResource(filename);
}

// an example of tail-recursion (I think)
int fib_helper(int num, int & prev)
{
	int ret;
	if (num > 2)
	{
		ret = fib_helper(num-1, prev);
		ret += prev;
		prev = ret-prev;
	}
	else if (num == 2 || num == 1)
	{
		ret = 1;
		prev = 1;
	}
	return ret;
}
int fibonacci(int num)
{
	int ret;
	ret = fib_helper(num, ret);
	return ret;
}

bool InitEngine();
bool InitDisplay(HINSTANCE hInstance);
bool InitData();
bool TestStuff_1();
bool TestStuff_2();

struct dostuff_t
{
	int val;
	deBoolean operator()(int* x) { *x = val; return deTRUE; }
};
int		WINAPI WinMain(HINSTANCE hInstance, 
					   HINSTANCE /*hprev*/, 
					   PSTR /*cmdline*/, 
					   int /*ishow*/)
{
	MSG		msg;
	IdeBitmap * RenderBitmap = NULL;

	if (!InitEngine())
		return -10;

	if (!InitData())
		return -10;

	if (!TestStuff_1())
		return -20;

	if (!TestStuff_2())
		return -30;
	
	IdeBrush * testBrush = NULL;
	IdeBrush * LineB = IdeBrush_CreateBrush(IdeBrush::Brush_Line);
	
	m_pRender->SetRenderFlag(IdeRender::Render_Fill);
	m_pRender->SetRenderFlag(IdeRender::Render_CullCW);
	if (FOGCOLOR)
		m_pRender->SetBGColor(FOGCOLOR);
	else
		m_pRender->SetBGColor(0x80ffff00);
//	m_pRender->SetBGColor(0x00404040);
	m_Wireframe = 0;
//	IdeSceneGraph_GetSceneGraphPtr()->SetDebugFlags(0);
//	IdeSceneGraph_GetSceneGraphPtr()->SetDebugFlags(IdeSceneGraph::deDrawAABB);
	{
		long flags = (~IdeSceneGraph::deCullFarPlaneOptimize) & IdeSceneGraph_GetSceneGraphPtr()->GetCullFlags();
		IdeSceneGraph_GetSceneGraphPtr()->SetCullFlags(flags);
	}

#if 0
	{
		LineB->AddCV(deMake_Vec3d(0,0,0));
		LineB->AddCV(deMake_Vec3d(1,0,1));
	//	m_pWorld->AddBrushExclusive(LineB);
	}
#endif
	{
		dostuff_t dostuff = { 2 };
		deTArray<int*> intarr;
		int i = 0;
		intarr.push_back(&i);
		intarr.push_back(&i);
		intarr.push_back(&i);
		intarr.push_back(&i);
		deIter_All(intarr.begin(), intarr.end(), dostuff);
	}

/*
	IdeFSReal *FSR;
	IdeSoundSystem * SS = NULL;
	IdeSoundBuffer * S;
	if (0)
	{
		char filename[] = "battle.mid";
		SS = IdeSoundSystem_CreateDirectSound(WindowHandle);

		IdeSoundSystem * m_pSoundSys;
		IdeSoundData * m_pSndData;
		m_pSoundSys = IdeSoundSystem_CreateDirectSound(WindowHandle);

		FSR = IdeFileSystem_CreateFSReal();
		
		m_pSndData = (IdeSoundData*)IdeResourceManager_GetManager()->GetResource("Alien Antfarm - Smooth Criminal.ogg", NULL);

		m_pSndBuff = m_pSoundSys->CreateSoundBuffer(m_pSndData);
		m_pSndBuff->Play(deTRUE);
		
		S2->Release();
		FSR->Release();
	}
*/
	IdeRenderLight * Light = m_pDe3DFactory->CreateIdeRenderLight();
	IdeRenderLight * Light2 = m_pDe3DFactory->CreateIdeRenderLight();
	IdeRenderMaterial  * Material = m_pDe3DFactory->CreateIdeRenderMaterial();
	IdeRenderTexture * TextureState = m_pDe3DFactory->CreateIdeRenderTexture();

	IdeFSReal *FSR = NULL;
	IdeSoundSystem	*m_pSoundSys = NULL;
	IdeSoundBuffer	*m_pOGGBuff = NULL;
	IdeSoundBuffer	*m_pWAVBuff[10] = {NULL};
	{
		if (!InitDisplay(hInstance))
			goto end_main;
		
		IdeSoundData	*m_pSndData = NULL;
		if (TEST_SOUND)
		{
			char filename[] = "blaster.wav";
			m_pSoundSys = IdeSoundSystem_CreateDirectSound(WindowHandle);
			
			//FSR = IdeFileSystem_CreateFSReal();
			FSR = m_pDe3DFactory->CreateIdeFSReal();
			IdeResourceManager * manager = m_pDe3DFactory->GetIdeResourceManager();
			IdeResourceBase *resbase;
			
			if (0)
			{
				resbase = manager->GetResource("Alien Antfarm - Smooth Criminal.ogg", NULL);
				m_pSndData = (IdeSoundData*)resbase->GetRscInterface(IdeSoundData_GetInterfaceID());
				
				m_pOGGBuff = m_pSoundSys->CreateSoundBuffer(m_pSndData);
				m_pOGGBuff->Play(deTRUE);
			}
			
			if (1)
			{
				resbase = manager->GetResource(filename, NULL);
				m_pSndData = (IdeSoundData*)resbase->GetRscInterface(IdeSoundData_GetInterfaceID());
				
				m_pWAVBuff[0] = m_pSoundSys->CreateSoundBuffer(m_pSndData);
				m_pWAVBuff[0]->Play(deTRUE);
			}
		}

		m_pDriver->SetRenderState(IdeDriver::RENDER_HWLIGHTINGENABLE, DE_TRUE);
		// lighting
		if (0)
		{
			deColor color = deMake_Color(0x00000000);
			deVertex down = {0, -1, 0};
			Light->Lock();
			Light->SetDirection(&down);
			down.y = 30;
			Light->SetPosition(&down);
			color = deMake_Color(0xFF606060);
			Light->SetAmbientColor(&color);
			color = deMake_Color(0xFF004000);
			Light->SetDiffuseColor(&color);
			color = deMake_Color(0xFF006000);
			Light->SetSpecularColor(&color);
			Light->SetLightType(IdeRenderLight::LIGHTTYPE_DIRECTIONAL);
			Light->SetRange(1000);
			Light->SetFallOff(10);
			Light->Unlock();
			Light2->Lock();
			Light2->SetID(1);
			down.y = 1;
			Light2->SetDirection(&down);
			down.y = -30;
			Light2->SetPosition(&down);
			color = deMake_Color(0xFF000000);
			Light2->SetAmbientColor(&color);
			color = deMake_Color(0xFF400000);
			Light2->SetDiffuseColor(&color);
			color = deMake_Color(0xFF006000);
			Light2->SetSpecularColor(&color);
			Light2->SetLightType(IdeRenderLight::LIGHTTYPE_DIRECTIONAL);
			Light2->SetRange(1000);
			Light2->SetFallOff(10);
			Light2->Unlock();
			Material->Lock();
			color = deMake_Color(0xFF808080);
			Material->SetAmbientColor(&color);
			Material->SetDiffuseColor(&color);
			color = deMake_Color(0xFF202020);
			Material->SetSpecularColor(&color);
			//Material.SetEmissiveColor(&color);
			Material->Unlock();
			//m_pDriver->SetRenderState(IdeDriver::RENDER_SPECULARENABLE, deTRUE);

			if (0 && !TEST_WORLD)
			{
				m_pDriver->SetRenderState(Light);
				m_pDriver->SetRenderState(Light2);
			}
		}

		if (0)
		{
			// an interesting demo of the eye's ability to distinguish more than 256 shades of green
			IdeBitmap * BMP;
			deARGB color;
			int width, height, x, y;
			width = 256*4;
			height = 256;
			BMP = m_pDe3DFactory->CreateIdeBitmapWithInfo(width, height, IdeDriver::BPP_X8R8G8B8);
			for (y = 0; y < height; ++y)
			{
				for (x = 0; x < width; ++x)
				{
					color = ARGB(0,0,x/32+90,0);
					BMP->SetColorAt(x, y, color);
				}
			}
			BMP->SaveToFileSystem(NULL, "greenscale.bmp");
			BMP->Release();
		}

		{
		IdeBitmap * BMP = NULL;
#if RENDER_TEXTURE
		BMP = m_pDe3DFactory->CreateIdeBitmap();
		BMP->SetWidth(RENDER_SIZE);
		BMP->SetHeight(RENDER_SIZE);
		BMP->SetFormat(IdeDriver::BPP_A8R8G8B8);
		BMP->SetRenderTarget(deTRUE);
		RenderBitmap = BMP;
#else
		RenderBitmap = NULL;
		if (!TEST_DOT3)
		{
#endif
			IdeResourceBase * rsc = NULL;
#if !RENDER_TEXTURE
			rsc = IdeResourceManager_GetManager()->GetResource("base0.bmp", NULL);
			if (rsc)
				BMP = (IdeBitmap*)rsc->GetRscInterface(IdeBitmap_GetRscInterfaceID());
			else
			{
				BMP = NULL;
				deConsoleOut("Unable to load texture\n");
			}
#if 0
				// test our blitting
				IdeBitmap* BMP2;
				deRect SrcRect = {128,128,256+128,256+128};
				rsc = IdeResourceManager_GetManager()->GetResource("b&w8.bmp", NULL);
				BMP2 = (IdeBitmap*)rsc->GetRscInterface(IdeBitmap_GetRscInterfaceID());
				BMP2->CopyRect(BMP, NULL, 128,128);
				BMP->Release();
				BMP = BMP2;
			}
#endif
#endif

			TextureState->Lock();
			TextureState->SetColorArg(0,1,IdeRenderTexture::TEXTUREARG_TEXTURE);
			TextureState->SetColorArg(0,2,IdeRenderTexture::TEXTUREARG_DIFFUSE);
			TextureState->SetColorOperation(0, IdeRenderTexture::TEXTUREOP_SELECTARG1);

			TextureState->SetAlphaOperation(0, IdeRenderTexture::TEXTUREOP_DISABLE);

			TextureState->SetColorOperation(1, IdeRenderTexture::TEXTUREOP_DISABLE);
			TextureState->SetAlphaOperation(1, IdeRenderTexture::TEXTUREOP_DISABLE);
#if RENDER_TEXTURE
			TextureState->SetTextureMinFilter(0, IdeRenderTexture::TEXTUREFILTER_POINT);
			//TextureState->SetTextureMagFilter(0, IdeRenderTexture::TEXTUREFILTER_POINT);
#else
			if (0)
			{
				// do a little alpha-blending
				IdeBitmap* BMP2 = NULL;
				rsc = IdeResourceManager_GetManager()->GetResource("bump0.bmp", NULL);
				if (rsc)
					BMP2 = (IdeBitmap*)rsc->GetRscInterface(IdeBitmap_GetRscInterfaceID());
 				BMP->BindGrayScaleAsAlphaMap(BMP2);
				if (BMP2)
					BMP2->Release();
				TextureState->SetAlphaArg(0,1,IdeRenderTexture::TEXTUREARG_TEXTURE);
				TextureState->SetAlphaOperation(0, IdeRenderTexture::TEXTUREOP_SELECTARG1);
			}
#endif
			m_pDriver->SetQualityFlag(IdeDriver::QUALITY_ALLOW_TEXTURE_MANGLING, 1);
			m_pDriver->SetQualityFlag(IdeDriver::QUALITY_ALLOW_INVALID_TEXTURES, 1);
			m_pDriver->AddBitmap(BMP);
			if (0)
				m_pDriver->GetVideoTexture(BMP);
			{
				IdeBitmapProxy* proxy = m_pDe3DFactory->CreateIdeBitmapProxy(BMP);
				if (BMP)
					BMP->Release();
				BMP = NULL;
				TextureState->SetBitmap(0,proxy);
				if (proxy)
					proxy->Release();
			}

			if (TEST_CUBEMAP)
			{
				// some cube-mapping perhaps
				rsc = IdeResourceManager_GetManager()->GetResource("snow/snow.cmap", NULL);
				if (rsc)
					BMP = (IdeBitmap*)rsc->GetRscInterface(IdeBitmap_GetRscInterfaceID());
				m_pDriver->AddBitmap(BMP);
				{
					IdeBitmapProxy* proxy = m_pDe3DFactory->CreateIdeBitmapProxy(BMP);
					if (BMP)
						BMP->Release();
					BMP = NULL;
					TextureState->SetBitmap(1,proxy);
					if (proxy)
						proxy->Release();
				}
				TextureState->SetTexCoordGen(1, IdeRenderTexture::TEXCOORD_VIEWSPACE_REFLECTIONVECTOR);
				m_pDriver->SetRenderState(IdeDriver::RENDER_SPECULARPERSPECTIVE, deTRUE);
				TextureState->SetAlphaArg(0,1,IdeRenderTexture::TEXTUREARG_TEXTURE);
				TextureState->SetAlphaOperation(0, IdeRenderTexture::TEXTUREOP_SELECTARG1);
				TextureState->SetColorArg(1,1,IdeRenderTexture::TEXTUREARG_PREVIOUS);
				TextureState->SetColorArg(1,2,IdeRenderTexture::TEXTUREARG_TEXTURE);
				TextureState->SetColorOperation(1, IdeRenderTexture::TEXTUREOP_BLENDPREVIOUSALPHA);
				TextureState->SetAlphaArg(1,1,IdeRenderTexture::TEXTUREARG_PREVIOUS);
				TextureState->SetAlphaOperation(1, IdeRenderTexture::TEXTUREOP_SELECTARG1);
				TextureState->SetColorOperation(2, IdeRenderTexture::TEXTUREOP_DISABLE);
				TextureState->SetAlphaOperation(2, IdeRenderTexture::TEXTUREOP_DISABLE);
			}

			TextureState->Unlock();
#if !RENDER_TEXTURE
		}
		else //if (TEST_DOT3)
		{
			IdeResourceBase * rsc;
			TextureState->Lock();

			rsc = IdeResourceManager_GetManager()->GetResource("bump0.bmp", NULL);
			BMP = (IdeBitmap*)rsc->GetRscInterface(IdeBitmap_GetRscInterfaceID());
			if (BMP)
			{
				if (0)
				{
					// a sphere-map
					deVec3d vec;
					int x, y, width, height;
					deDouble ax, ay;
					deARGB * colors;
					colors = (deARGB*)(BMP->GetData());
					width = BMP->GetWidth();
					height = BMP->GetHeight();
					for (y = 0; y < height; ++y)
					{
						ay = DE_PI/2 - (DE_PI * y)/(height-1);
						for (x = 0; x < width; ++x)
						{
							ax = (DE_PI * 2 * x)/(width-1);
							vec.x = -COS(ay) * SIN(ax);
							vec.y = SIN(ay);
							vec.z = COS(ay) * COS(ax);

							//Vec3d_Normalize(vec);

							colors[x + y*width] = Vec3d_ConvertToDot3(vec, 0);
						}
					}
				}
				else if (1)
				{
					BMP->SetFormat(IdeDriver::BPP_X8R8G8B8);
					BMP->ConvertGrayScaleToDot3(7, 1);
					if (0)
						BMP->SaveToFileSystem(NULL, "normalmap.bmp");
				}
				m_pDriver->AddBitmap(BMP);
				{
					IdeBitmapProxy* proxy = m_pDe3DFactory->CreateIdeBitmapProxy(BMP);
					if (BMP)
						BMP->Release();
					BMP = NULL;
					TextureState->SetBitmap(0,proxy);
					if (proxy)
						proxy->Release();
				}
			}

			rsc = IdeResourceManager_GetManager()->GetResource("base0.bmp", NULL);
			if (rsc)
				BMP = (IdeBitmap*)rsc->GetRscInterface(IdeBitmap_GetRscInterfaceID());
			if (BMP)
			{
				if (0)
				{
					BMP->SetFormat(IdeDriver::BPP_X8R8G8B8);
					BMP->ConvertGrayScaleToDot3(7, 2);
				}
				m_pDriver->AddBitmap(BMP);
				{
					IdeBitmapProxy* proxy = m_pDe3DFactory->CreateIdeBitmapProxy(BMP);
					if (BMP)
						BMP->Release();
					BMP = NULL;
					TextureState->SetBitmap(1,proxy);
					if (proxy)
						proxy->Release();
				}
			}

			if (0)
			{
				if (0)
				{
					rsc = IdeResourceManager_GetManager()->GetResource("Attenuate2D.tga", NULL);
					BMP = (IdeBitmap*)rsc->GetRscInterface(IdeBitmap_GetRscInterfaceID());
				}
				else
				{
					BMP = m_pDe3DFactory->CreateIdeBitmapWithInfo(512,512,IdeDriver::BPP_A8R8G8B8);
					//generate our own attenuation function
					// d^2
					int x, y, width, height, clampint;
					float halfwidth, halfheight, xvalue, yvalue;
					deARGB color;
					width = BMP->GetWidth();
					height = BMP->GetHeight();
					halfwidth = width * 0.5f;
					halfheight = height * 0.5f;
					for (y = 0; y < height; ++y)
					{
						for (x = 0; x < width; ++x)
						{
							xvalue = (x - halfwidth)/halfwidth;
							xvalue = (xvalue*xvalue);
							//xvalue *= xvalue;
							xvalue *= 255;
							
							yvalue = (y - halfheight)/halfheight;
							yvalue = (yvalue*yvalue);
							//yvalue *= yvalue;
							yvalue *= 255;
							
							clampint = (int)(xvalue + yvalue + 0.5f);
							if (clampint < 0)
								clampint = 0;
							if (clampint > 255)
								clampint = 255;
							color = ((clampint<<24)&0xff000000) | ((clampint<<16)&0x00ff0000) | 
								((clampint<<8)&0x0000ff00) | ((clampint)&0x000000ff);
							BMP->SetColorAt(x,y,color);
						}
					}
				}
				if (BMP)
				{
					BMP->SetMipLevels(0);
					m_pDriver->AddBitmap(BMP);
					{
						IdeBitmapProxy* proxy = m_pDe3DFactory->CreateIdeBitmapProxy(BMP);
						BMP->Release();
						BMP = NULL;
						TextureState->SetBitmap(1,proxy);
						if (proxy)
							proxy->Release();
					}
				}
			}

			TextureState->SetTexCoordSource(0, 0);
			TextureState->SetTexCoordSource(1, 0);

			TextureState->SetColorArg(0,1,IdeRenderTexture::TEXTUREARG_TEXTURE);
			TextureState->SetColorArg(0,2,IdeRenderTexture::TEXTUREARG_TFACTOR);
			TextureState->SetColorOperation(0, IdeRenderTexture::TEXTUREOP_DOTPRODUCT3);
			TextureState->SetAlphaArg(0,1,IdeRenderTexture::TEXTUREARG_TEXTURE);
			TextureState->SetAlphaArg(0,2,IdeRenderTexture::TEXTUREARG_TFACTOR);
			TextureState->SetAlphaOperation(0, IdeRenderTexture::TEXTUREOP_DOTPRODUCT3);

			TextureState->SetColorArg(1,1,IdeRenderTexture::TEXTUREARG_TEXTURE);
			TextureState->SetColorArg(1,2,IdeRenderTexture::TEXTUREARG_PREVIOUS);
			TextureState->SetColorOperation(1, IdeRenderTexture::TEXTUREOP_MODULATE);
			TextureState->SetAlphaArg(1,1,IdeRenderTexture::TEXTUREARG_TEXTURE);
			TextureState->SetAlphaArg(1,2,IdeRenderTexture::TEXTUREARG_PREVIOUS);
			TextureState->SetAlphaOperation(1, IdeRenderTexture::TEXTUREOP_SELECTARG1);
			
			TextureState->SetColorArg(2,1,IdeRenderTexture::TEXTUREARG_TFACTOR);
			TextureState->SetColorArg(2,2,IdeRenderTexture::TEXTUREARG_PREVIOUS);
			TextureState->SetColorOperation(2, IdeRenderTexture::TEXTUREOP_DISABLE);
			TextureState->SetAlphaOperation(2, IdeRenderTexture::TEXTUREOP_DISABLE);

			TextureState->SetColorOperation(3, IdeRenderTexture::TEXTUREOP_DISABLE);
			TextureState->SetAlphaOperation(3, IdeRenderTexture::TEXTUREOP_DISABLE);
			// you can blend two dot3's together using
			// texture, whatever, selectarg1
			// texture, previous, blendtexturealpha
			// previous tfactor, dotproduct3

			TextureState->Unlock();
			}
#endif
		}

		// test our world (de)serialization stuff
		if (1)
		{
			Light->SetWorldID(m_WorldID);
			Light2->SetWorldID(m_WorldID);
			Material->SetWorldID(m_WorldID);
			TextureState->SetWorldID(m_WorldID);
			
			IdeFSReal * WorldFS;
			IdeFile *	WorldFile;
			if (0)
			{
				WorldFS = m_pDe3DFactory->CreateIdeFSReal();
				if (WorldFS)
				{
					WorldFile = WorldFS->Open("testworld.dworld", deFile_Open_CreateAlways | deFile_Open_Write);
					if (WorldFile)
					{
						m_pWorld->Serialize(WorldFile);
						WorldFile->Close();
						WorldFile->Release();
						WorldFS->Release();
					}
				}
			}
			if (0)
			{
				WorldFS = m_pDe3DFactory->CreateIdeFSReal();
				if (WorldFS)
				{
					deWorldID NewID = m_pWorldManager->CreateWorld();
					IdeWorld* pNewWorld = m_pWorldManager->GetWorld(NewID);
					WorldFile = WorldFS->Open("testworld.dworld", deFile_Open_Existing | deFile_Open_Read);
					if (WorldFile)
					{
						pNewWorld->DeSerialize(WorldFile);
						WorldFile->Close();
						WorldFile->Release();
						WorldFS->Release();
					}
					if (pNewWorld)
					{
						Light->Release();
						Light2->Release();
						Material->Release();
						TextureState->Release();
						
						m_pWorld->Release();
						
						void * ptr;
						deObjectID ObjID;
						int RenderStateID = IdeRenderState_GetWOInterfaceID();
						IdeWorldObject* pObj;
						IdeRenderState *state;
						
						ptr = NULL;
						ObjID = pNewWorld->GetNextObjectOfType("deRenderLight", ptr);
						pObj = pNewWorld->GetWorldObject(ObjID);
						state = (IdeRenderState*)(pObj->GetWOInterface(RenderStateID));
						Light = (IdeRenderLight*)state->GetRSInterface(IdeRenderState::TYPE_LIGHT);
						
						ObjID = pNewWorld->GetNextObjectOfType("deRenderLight", ptr);
						pObj = pNewWorld->GetWorldObject(ObjID);
						state = (IdeRenderState*)(pObj->GetWOInterface(RenderStateID));
						Light2 = (IdeRenderLight*)state->GetRSInterface(IdeRenderState::TYPE_LIGHT);
						
						ptr = NULL;
						ObjID = pNewWorld->GetNextObjectOfType("deRenderMaterial", ptr);
						pObj = pNewWorld->GetWorldObject(ObjID);
						state = (IdeRenderState*)(pObj->GetWOInterface(RenderStateID));
						Material = (IdeRenderMaterial*)state->GetRSInterface(IdeRenderState::TYPE_MATERIAL);
						
						ptr = NULL;
						ObjID = pNewWorld->GetNextObjectOfType("deRenderTexture", ptr);
						pObj = pNewWorld->GetWorldObject(ObjID);
						state = (IdeRenderState*)(pObj->GetWOInterface(RenderStateID));
						TextureState = (IdeRenderTexture*)state->GetRSInterface(IdeRenderState::TYPE_TEXTURE);
						
						m_pWorld = pNewWorld;
					}
				}
			}
			m_pDriver->SetRenderState(Light);
			m_pDriver->SetRenderState(Light2);
			m_pDriver->SetRenderState(Material);
		}

		if (0)
		{
			Ide2DObject * Overlay;
			deRect ScreenRect;
			deFloatRect TexCoords;
			ScreenRect.Top = 100;
			ScreenRect.Left = 100;
			ScreenRect.Bottom = 300;
			ScreenRect.Right = 300;
			TexCoords.Top = TexCoords.Left = 0.0f;
			TexCoords.Right = TexCoords.Bottom = 1.0f;
			Overlay = Ide2DObject_Create2DOverlay(	&ScreenRect, &TexCoords, 
										TextureState, 1.0f, 0x80FFFFFF, 0);
			_2D->AddObject(Overlay);
			Overlay->Release();
		}

		if (0)
		{
			Ide2DCollection * _2d2;
			Ide2DCollection * _2d3;
			deRect Rect = {10,30,50,70};
			deFloatRect TexCoords = { 0,0,1,1 };
			Ide2DObject *object = NULL;
			deARGB color = ARGB(255,255,128,128);
			deFloat Depth = 5;

			int i;

			_2d2 = m_pDe3DFactory->CreateIde2DCollection();
			_2d3 = m_pDe3DFactory->CreateIde2DCollection();

			_2d2->SetDepth(10);
			_2d3->SetDepth(20);

			_2D->AddSubCollection(_2d2);
			_2D->AddSubCollection(_2d3);

			_2d2->Release();
			_2d3->Release();

			for (i = 0; i < 3; i++)
			{
				object = Ide2DObject_Create2DOverlay(&Rect, 
													 NULL, 
													 NULL, 
													 Depth, color);
				if (object)
				{
					_2d2->AddObject(object);
					object->Release();
				}

				Rect.Left += 10;
				Rect.Right += 10;
				Rect.Top += 50;
				Rect.Bottom += 50;

				object = Ide2DObject_Create2DOverlay(&Rect, 
													 NULL, 
													 NULL, 
													 Depth, color);

				if (object)
				{
					_2d3->AddObject(object);
					object->Release();
				}

				Rect.Left += 10;
				Rect.Right += 10;
				Rect.Top -= 30;
				Rect.Bottom -= 30;
				Depth += 5;
				color -= (0x40 << 16);
			}
		}
		
		if (0)
		{
			Ide2DObject * Corona;
			deRect SizeRect;
			deFloatRect TexCoords;
			SizeRect.Top = -80;
			SizeRect.Left = -80;
			SizeRect.Bottom = 0;
			SizeRect.Right = 0;
			TexCoords.Top = TexCoords.Left = 0.0f;
			TexCoords.Right = TexCoords.Bottom = 1.0f;
			Corona = Ide2DObject_Create2DCorona(&SizeRect, &TexCoords,
									TextureState, m_Cam, 1.0f, 0xFFFFFFFF);
#pragma todo(interface problem in de2D)
	//		Corona->SetPosition(deMake_Vec3d(-1,2,1));
			_2D->AddObject(Corona);
			Corona->Release();
		}

				
		if (0)
		{
			Ide2DObject * Line;
			deVec3d PList[4];
			PList[0] = deMake_Vec3d(100,10,0);
			PList[1] = deMake_Vec3d(140,10,0);
			PList[2] = deMake_Vec3d(120,30,0);
			PList[3] = deMake_Vec3d(100,10,0);
			Line = Ide2DObject_Create2DLineList(PList, 4, 0xffff0000);
			_2D->AddObject(Line);
			Line->Release();
		}

/*		BRUSH_IDENT.SetTexture(0,TextureState);
		c.SetTexture(0,TextureState);
		c.SetTexture(1,TextureState);
		c.SetTexture(2,TextureState);
*/
	}

	m_pRoom = m_pDe3DFactory->CreateIdeSceneRoom();
	pSG->AddRoom(m_pRoom);
	if (TEST_TERRAIN)
	{
		IdeResourceBase* rsc;
		IdeBitmapProxy* BMP;
		deFloat height;

		// make a terrain
		m_pTerrain = m_pDe3DFactory->CreateIdeSceneTerrain();

		// open a bitmap for doing heightmap
		rsc = m_pDe3DFactory->GetIdeResourceManager()->GetResource("heightmap.bmp", NULL);
		BMP = m_pDe3DFactory->CreateIdeBitmapProxy(rsc);
		if (BMP)
		{
			// assign heightmap
			m_pTerrain->SetTerrainHeightMap(BMP);
			int ChunkSize = BMP->GetWidth()/16;
			ChunkSize = max(32, ChunkSize);
			m_pTerrain->SetGMMChunkSize(ChunkSize);
			BMP->Release();
		}
		else
		{
			MessageBox(WindowHandle, "Failed to load heightmap\nexiting...", "Error", MB_OK);
			goto end_main;
		}

		// open a bitmap for doing colormap
//		rsc = IdeResourceManager_GetManager()->GetResource("texture2k.dds", NULL);
//		if (rsc)
		{
			rsc = 0;
			BMP = m_pDe3DFactory->CreateIdeBitmapProxy(rsc);
			BMP->SetFilename("texture2k.dds");
			// assign colormap
			m_pTerrain->SetTerrainColorMap(BMP);
			BMP->Release();
		}
//		else
		{
//			deConsoleOut("Failed to load TerrainTex.bmp\n");
		}

		// open a bitmap for doing detail map
//		rsc = IdeResourceManager_GetManager()->GetResource("detailmap.bmp", NULL);
//		if (rsc)
		{
			rsc = 0;
			BMP = m_pDe3DFactory->CreateIdeBitmapProxy(rsc);
			BMP->SetFilename("detailmap.bmp");
			// assign detail map
			m_pTerrain->SetTerrainDetailMap(BMP);
			BMP->Release();
		}

		deTransform position;
		//position.FreeRot(DE_PI/2, 0, DE_PI);
		position.Translation.z = 0;
		m_pTerrain->SetWorldTransform(position);

		m_pTerrain->SetTerrainScale(0.25f, 15.0f, 0.25f);
		//m_pTerrain->SetTerrainScale(160/4, 6553.5f, 160/4);
		m_pTerrain->SetDetailRepeat(0.0625f, 0.0625f);

		// test some stuff
		height = m_pTerrain->GetTrueHeightAt(0, 0);
		height = m_pTerrain->GetTrueHeightAt(458, 247);
		height = m_pTerrain->GetTrueHeightAt(210, 328);
		height = m_pTerrain->GetScaledHeightAt(0, 0);
		height = m_pTerrain->GetScaledHeightAt(458, 247);
		height = m_pTerrain->GetScaledHeightAt(210, 328);

		deRect ViewRect = m_Cam->GetRect();
		deDouble Bias = 2.5*(ViewRect.Right - ViewRect.Left)/800.0;
		m_pTerrain->SetLODBias(Bias);
		DEBUGMSG1("LOD Bias Set to %f", Bias);

		//m_pTerrain->BuildRenderable();

		m_pTerrain->SetGMMChunkSize(64);
		m_pTerrain->BuildGeoMipMap(m_pDriver);

		m_pRoom->AddSceneObject(m_pTerrain);

		if (0)
		{
			IdeMesh* pMesh = m_pDe3DFactory->CreateIdeMesh();
			deTransform scaler;
			//scaler.ApplyScaling(0.01);
			deBoolean result = deFALSE;
			result = IdeMesh_LoadStaticFromXFile("bigship1.x", pMesh, &scaler);
			if (result)
			{
				IdeSceneStaticMesh* staticmesh = m_pDe3DFactory->CreateIdeSceneStaticMesh();
				staticmesh->SetMesh(pMesh);
				m_pRoom->AddSceneObject(staticmesh);
				staticmesh->Release();
				pMesh->Release();
			}
		}
		if (TEST_SKY)
		{
			const char * filenames[] = {
				// clouds sky color: 0x00404080
			/**/
				"sky\\clouds\\cloudsRight.bmp",
				"sky\\clouds\\cloudsBottom.bmp",
				"sky\\clouds\\cloudsBack.bmp",
				"sky\\clouds\\cloudsLeft.bmp",
				"sky\\clouds\\cloudsTop.bmp",
				"sky\\clouds\\cloudsFront.bmp",
			/*/
				// space sky color: 0x0
				"sky\\jf-nebula_sky\\Nebular_rt.bmp",
				"sky\\jf-nebula_sky\\Nebular_dn.bmp",
				"sky\\jf-nebula_sky\\Nebular_bk.bmp",
				"sky\\jf-nebula_sky\\Nebular_lf.bmp",
				"sky\\jf-nebula_sky\\Nebular_up.bmp",
				"sky\\jf-nebula_sky\\Nebular_ft.bmp",
			/**/
			};
			deVec3d vecs[4] = {{-5,2,0},{-5,0,0},{-5,2,2},{-5,0,2}};
			deVec3d Normal = {1,0,0};
			int i;
			IdeResourceBase * rsc;
			IdeBitmapProxy * BMP;
			IdeSceneSky::SkyInfo info;
			IdeSceneRoom * skyRoom;
			IdeSceneSky * sky;
			IdePortal * portal;

			skyRoom = m_pDe3DFactory->CreateIdeSceneRoom();
			sky = m_pDe3DFactory->CreateIdeSceneSky();

			info.type = IdeSceneSky::SKY_BOX;
			for (i = 0; i < 6; ++i)
			{
				rsc = NULL;
				rsc = m_pDe3DFactory->GetIdeResourceManager()->GetResource(filenames[i], NULL);
				BMP = m_pDe3DFactory->CreateIdeBitmapProxy(rsc);
				//BMP->SetFilename(filenames[i]);
				if (rsc)
					rsc->Release();
				rsc = NULL;
				m_pDriver->AddBitmapProxy(BMP);
				info.Box.Faces[i] = BMP;
			}
			sky->SetInfo(&info);
			skyRoom->SetWorldID(m_WorldID);
			sky->SetWorldID(m_WorldID);
			skyRoom->AddSceneObject(sky);
			pSG->AddRoom(skyRoom);
			for (i = 0; i < 6; ++i)
			{
				BMP = info.Box.Faces[i];
				if (BMP)
					BMP->Release();
			}
			
			portal = IdePortal_CreatePortalWithVerts(vecs,4);
			portal->LinkTo(skyRoom);
			portal->SetNormal(Normal);
			m_pRoom->AddPortal(portal);
			
			if (0)
			{
				// this makes the "sky portal" use t-portal logic
				deTransform M;
				portal->SetTransform(M);
			}

			IdeSceneGraph_GetSceneGraphPtr();
			
			skyRoom->Release();
			sky->Release();
		}
	}

	if (TEST_ABT)
	{
		//IdeScene_TestABT();
		IdeSceneABT* abtset = m_pDe3DFactory->CreateIdeSceneABT();
		//abtRoom->AddGeometry(NULL);

		if (TEST_Q3LOADER)
		{
			IdeLargeStaticBrush* pLargeBrush = NULL;
			deTransform scaler;
			scaler.ApplyScaling(0.0625);
			{
				IdeBrush* pBrush;
				pBrush = IdeBrush_CreateBrush(IdeBrush::Brush_LargeStatic);
				if (pBrush)
					pLargeBrush = (IdeLargeStaticBrush*)pBrush->GetBrushInterface(IdeBrush::Brush_LargeStatic);
			}
			//			char* filename = "q3dm3\\maps\\ame7q3dm3.bsp";
			//			char* filename = "q3dm3\\maps\\aqua.bsp";
			//			char* filename = "q3dm3\\maps\\Level.bsp";
			char* filename = "q3dm3\\maps\\chiropteradm.bsp";
			if (IdeBrush_LoadFromQ3BSP(filename, pLargeBrush, 0.0625))
			{
				//abtRoom->AddGeometry(pLargeBrush);
#pragma todo(fix Q3 loader to use a deMesh instead of a brush)
			}
			if (pLargeBrush)
				pLargeBrush->Release();
		}
		else if (1)
		{
			IdeMesh* pMesh = m_pDe3DFactory->CreateIdeMesh();
			deTransform scaler;
			//scaler.ApplyScaling(0.01);
			deBoolean result = deFALSE;
			if (1)
				result = IdeMesh_LoadStaticFromXFile("bigship1.x", pMesh, &scaler);
			else if (1)
			{
				int c, numfaces = 1;
				deVertex** pos;
				deTexCoord2** uv;
				deARGB** color;
				pMesh->SetNumSubMeshes(1);
				pMesh->SetNumFaces(0, numfaces);
				result = pMesh->Lock(pos, uv, color);
				if (result)
				{
					pos[0][0].x = 0;
					pos[0][0].y = 0;
					pos[0][0].z = 10;
					uv[0][0].u = 0;
					uv[0][0].v = 0;
					color[0][0] = 0xffffffff;
					for (c = 1; c < numfaces*3; ++c)
					{
						pos[0][c] = pos[0][c-1];
						uv[0][c] = uv[0][c-1];
						color[0][c] = color[0][c-1];
					}
					pos[0][1].x = 10;
					pos[0][2].y = 10;
				}
				result = pMesh->Unlock(pos, uv, color);
			}
			if (result)
			{
				if (0)
				{
					deTransform ident;
					abtset->AddGeometry(pMesh, ident);
				}
				else
				{
					IdeSceneStaticMesh* staticmesh = m_pDe3DFactory->CreateIdeSceneStaticMesh();
					staticmesh->SetMesh(pMesh);
					m_pRoom->AddSceneObject(staticmesh);
					staticmesh->Release();
					pMesh->Release();
				}
			}
		}

		m_pRoom->AddSceneObject(abtset);
	}

	if (0)
	{
		m_pRoom = m_pDe3DFactory->CreateIdeSceneRoom();
		m_pRoom->SetWorldID(m_WorldID);

		IdeSceneRoom* sceneRoom = NULL;
		if (TEST_WORLD)
		{
			sceneRoom = m_pDe3DFactory->CreateIdeSceneRoom();
		}
		
#if 0
		// T-Portal testing
		if (TEST_TPORTAL)
		{
			// put up a big backdrop
			if (1)
			{
				deVertex		verts[] = {{-35,0,0},{0,-35,0},{0,35,0},{35,0,0}};
				deTexCoord		cords[] = {{0,0}, {0,1}, {1,0}, {1,1}};
				unsigned short  indices[] = {0,1,2, 1,3,2};
				BIndexList blah;
				IdeBrush * b = IdeBrush_CreateBrush(IdeBrush::Brush_Static);
				IdeStaticBrush * s = (IdeStaticBrush*)(b->GetBrushInterface(IdeBrush::Brush_Static));
				blah.positions = verts;
				blah.normals = verts;
				blah.uvcoords = cords;
				blah.numpoints = 4;
				blah.numtexstages = 1;
				blah.indices = indices;
				blah.numindices = 6;
				s->SetTextureState(TextureState);
				s->AddIndexedBuffer(blah);
				s->BuildIndexedBuffers();
				s->SetDiffuseColor(0x00808080);
				
				IdeSceneBrush * Sceneb = IdeSceneObject_CreateSceneBrush();
				Sceneb->SetBrush(s);
				s->Release();
				bRoom->AddSceneObject(Sceneb);
				Sceneb->Release();
			}

			// let's make a neat-o box!
			{
				deVertex		verts[] = {{-1,2,-10},{-1,0,-10},{1,2,-10},{1,0,-10},{-1,2,-8},{-1,0,-8},{1,2,-8},{1,0,-8}};
				deTexCoord		cords[] = {{0,0}, {0,1}, {1,0}, {1,1},  {1,1}, {1,0}, {0,1}, {0,0}};
				unsigned short  indices[] = {2,3,6, 6,3,7, 6,7,4, 4,7,5, 4,5,0, 0,5,1, 4,0,6, 6,0,2, 1,5,3, 3,5,7};
				BIndexList blah;
				IdeBrush * b = IdeBrush_CreateBrush(IdeBrush::Brush_Static);
				IdeStaticBrush * s = (IdeStaticBrush*)(b->GetBrushInterface(IdeBrush::Brush_Static));
				blah.positions = verts;
				blah.normals = verts;
				blah.uvcoords = cords;
				blah.numpoints = 8;
				blah.numtexstages = 1;
				blah.indices = indices;
				blah.numindices = 30;
				s->SetTextureState(TextureState);
				s->AddIndexedBuffer(blah);
				s->BuildIndexedBuffers();
				s->SetDiffuseColor(0x00808080);
				
				IdeSceneBrush * Sceneb = IdeSceneObject_CreateSceneBrush();
				Sceneb->SetBrush(s);
				s->Release();
				bRoom->AddSceneObject(Sceneb);
				Sceneb->Release();
			}

			{
				IdeBrushRoom * bRoom2 = IdeSceneRoom_CreateBrushRoom();
				bRoom2->SetWorldID(m_WorldID);
				
				deTransform M;
				M.Translation = deMake_Vec3d(1, -3, -6);
				deVec3d vecs[4] = {{-1,2,-10},{-1,0,-10},{1,0,-10},{1,2,-10}};
				deVec3d Normal = {0,0,-1};
				IdePortal *p = IdePortal_CreatePortalWithVerts(vecs,4);
				p->SetTransform(M);
				p->LinkTo(bRoom2);
				p->SetNormal(Normal);
				bRoom->AddPortal(p);
				if (!TEST_WORLD)
					pSG->AddRoom(bRoom);

				bRoom = bRoom2;
			}
			
			
			// put up a big backdrop
			if (0)
			{
				deVertex		verts[] = {{-40,40,20},{-40,0,20},{40,40,20},{40,0,20}};
				deTexCoord		cords[] = {{0,0}, {0,1}, {2,0}, {2,1}};
				unsigned short  indices[] = {0,1,2, 1,3,2};
				BIndexList blah;
				IdeBrush * b = IdeBrush_CreateBrush(IdeBrush::Brush_Static);
				IdeStaticBrush * s = (IdeStaticBrush*)(b->GetBrushInterface(IdeBrush::Brush_Static));
				blah.positions = verts;
				blah.normals = verts;
				blah.uvcoords = cords;
				blah.numpoints = 4;
				blah.numtexstages = 1;
				blah.indices = indices;
				blah.numindices = 6;
				s->SetTextureState(TextureState);
				s->AddIndexedBuffer(blah);
				s->BuildIndexedBuffers();
				s->SetDiffuseColor(0x00808080);
				
				IdeSceneBrush * Sceneb = IdeSceneObject_CreateSceneBrush();
				Sceneb->SetBrush(s);
				s->Release();
				bRoom->AddSceneObject(Sceneb);
				Sceneb->Release();
			}
			
		}
		else if (0)
		{
			// used for "portal-testing"
			deVec3d verts[] = {{-1,2,1}, {1,2,1}, {1,0,1}, {-1,0,1}, {-1,2,1}};
			IdeSceneBrush * Sceneb = IdeSceneObject_CreateSceneBrush();
			// both should return valid
			IdeSceneObject * so = (IdeSceneObject*)Sceneb->GetSOInterface(Sceneb->iface_IdeSceneObject);
			IdeSceneBrush * sb = (IdeSceneBrush*)Sceneb->GetSOInterface(Sceneb->iface_IdeSceneBrush);
			// should return NULL
			IdeSceneAnimatedMesh * sam = (IdeSceneAnimatedMesh*)Sceneb->GetSOInterface(Sceneb->iface_IdeSceneAnimatedMesh);
			LineB->SetCVList(5, verts);
			sb->SetBrush(LineB);
			bRoom->AddSceneObject(Sceneb);
			Sceneb->Release();
		}
		
		if (!TEST_WORLD)
		{
			pSG->AddRoom(bRoom);

		}
		
		if (1)
		{
			deVertex		verts[] = {{-40,20,20},{-40,-20,20},{40,20,20},{40,-20,20}};
			deVertex		norms[] = {{0,0,-1},{0,0,-1},{0,0,-1},{0,0,-1}};
			deTexCoord		cords[] = {{0,0}, {0,1}, {2,0}, {2,1},    {0,0}, {0,8}, {16,0}, {16,8}};
			unsigned short  indices1[] = {0,1,2};
			unsigned short  indices2[] = {1,3,2};
			BIndexList blah;
			IdeBrush * b = IdeBrush_CreateBrush(IdeBrush::Brush_Static);
			IdeStaticBrush * s = (IdeStaticBrush*)(b->GetBrushInterface(IdeBrush::Brush_Static));
			blah.positions = verts;
			blah.normals = norms;
			blah.uvcoords = cords;
			blah.numpoints = 4;
			blah.numtexstages = 2;
			blah.indices = indices1;
			blah.numindices = 3;
			s->SetTextureState(TextureState);
			s->AddIndexedBuffer(blah);
			blah.positions = verts;
			blah.normals = norms;
			blah.uvcoords = cords;
			blah.numpoints = 4;
			blah.numtexstages = 2;
			blah.indices = indices2;
			blah.numindices = 3;
			s->SetTextureState(TextureState);
			s->AddIndexedBuffer(blah);
			s->BuildIndexedBuffers();
			s->SetDiffuseColor(0xc0808080);
			
			IdeSceneBrush * Sceneb = IdeSceneObject_CreateSceneBrush();
			Sceneb->SetBrush(s);
			s->Release();

//			Sceneb->MakeTransparent();

			if (TEST_WORLD)
			{
				s->SetWorldID(m_WorldID);
				Sceneb->SetWorldID(m_WorldID);
				sceneRoom->AddSceneObject(Sceneb);
			}
			else
			{
				bRoom->AddSceneObject(Sceneb);
			}
			Sceneb->Release();
		}
#endif

		if (0)
		{
			IdeResourceBase * rsc = IdeResourceManager_GetManager()->GetResource("players\\alita\\tris.md2", NULL);
			m_pMD2 = (IdeAnimatedMesh*)rsc->GetRscInterface(IdeAnimatedMesh_GetRscInterfaceID());
			IdeSceneAnimatedMesh * sam = IdeSceneObject_CreateSceneAnimatedMesh();
			sam->SetMesh(m_pMD2);
			m_pRoom->AddSceneObject(sam);
			if (1)
			{
				// do a little mesh optimization, using a triangle-stripping utility
				IdeVertexBuffer * VB;
				VB = m_pMD2->GetVBuffer();
//				IdeMeshOptimizer_GetMeshOptPtr()->OptimizeIndices(VB, m_pDriver, 0, deTRUE);
			}
			sam->Release();
		}

		if (TEST_XLOADER)
		{
			if (0)
			{
				IdeMesh* pMesh = m_pDe3DFactory->CreateIdeMesh();
				deTransform scaler;
				//scaler.ApplyScaling(0.01);
				deBoolean result = deFALSE;
				result = IdeMesh_LoadStaticFromXFile("tiger.x", pMesh, &scaler);
				if (result)
				{
					IdeSceneStaticMesh* staticmesh = m_pDe3DFactory->CreateIdeSceneStaticMesh();
					staticmesh->SetMesh(pMesh);
					m_pRoom->AddSceneObject(staticmesh);
					staticmesh->Release();
					pMesh->Release();
				}
			}
			if (1)
			{
				IdeMesh* pMesh = m_pDe3DFactory->CreateIdeMesh();
				deTransform scaler;
				//scaler.ApplyScaling(0.01);
				deBoolean result = deFALSE;
				result = IdeMesh_LoadStaticFromXFile("indoors.x", pMesh, &scaler);
				if (result)
				{
					IdeSceneStaticMesh* staticmesh = m_pDe3DFactory->CreateIdeSceneStaticMesh();
					staticmesh->SetMesh(pMesh);
					m_pRoom->AddSceneObject(staticmesh);
					staticmesh->Release();
					pMesh->Release();
				}
			}
		}

		// brush tests
		if (1)
		{
			deVec3d p;
			IdeLine * al = IdeLine_CreateArcLine();
			IdeLine * bl = IdeLine_CreateBezierLine();
			IdeLine * sl = IdeLine_CreateStraightLine();
			IdeLine * g = IdeLine_CreateGroupLine();

			{
				deVec3d list[] = {{0,-4,0},{0,0,0}};
				sl->SetCVList(2, list);
			}
			
			{
				deVec3d hull[] = {{0,0,0},{0,2,0},{2,2,0},{2,4,0}};
				bl->SetCVList(4, hull);
			}

			{
				deVec3d hull[] = {{1,4,0},{2,4,0},{1,4,-0.25}};
				al->SetCVList(3, hull);
			}

			IdeLine_GroupLineAdd(g, sl);
			IdeLine_GroupLineAdd(g, bl);
			//IdeLine_GroupLineAdd(g, al);
			al->GetTangentAtPoint(1, p);

			testBrush = NULL;

			if (0)
			{
				IdeBrush * b = IdeBrush_CreateBrush(IdeBrush::Brush_Cylinder);
				IdeCylinderBrush * CB = (IdeCylinderBrush*)(b->GetBrushInterface(IdeBrush::Brush_Cylinder));
				
				//deVec3d hull[] = {{0,1,0},{0,0,5},{0,0,0}};
				deVec3d hull[] = {{0,1,0},{0,0,5},{0,0,0}};
				CB->SetCVList(3, hull);
				CB->SetTexCoord(0,0, 0,0);
				CB->SetTexCoord(0,1, 1,0);
				CB->SetTexCoord(0,2, 0,1);
				CB->SetTexCoord(0,3, 1,1);

				CB->SetTexCoord(1,0, 0.5,0.5);
				CB->SetTexCoord(1,1, 1.0,0.5);
				CB->SetTexCoord(1,2, 0.5,0.0);

				CB->SetTexCoord(2,0, 0.5,0.5);
				CB->SetTexCoord(2,1, 1.0,0.5);
				CB->SetTexCoord(2,2, 0.5,1.0);
				CB->SetLOD(16);

				CB->SetTexture(0,TextureState);
				CB->SetTexture(1,TextureState);
				CB->SetTexture(2,TextureState);

				testBrush = CB;
			}
			else if (0)
			{
				// lathedbrush is currently slow, leaks like a sieve, 
				// and it doesn't produce the correct geometry
				IdeBrush * b = IdeBrush_CreateBrush(IdeBrush::Brush_Lathed);
				IdeLathedBrush * LB = (IdeLathedBrush*)(b->GetBrushInterface(IdeBrush::Brush_Lathed));

				{
					deVec3d hull[] = {{0,1,0},{0,2,0},{0.5,1,0}};
					al->SetCVList(3, hull);
				}

				LB->SetLine(al);
				LB->SetDegree(-360);

				deVec3d hull[] = {{0,0,0},{0,2,0}};
				LB->SetCVList(2, hull);

				LB->SetLOD(16);
				LB->SetLOD2(12);

				deFloat f0 = 1/255.0f;
				deFloat f1 = 1 - f0;
				LB->SetTexCoord(0,0, f0,f0);
				LB->SetTexCoord(0,1, f1,f0);
				LB->SetTexCoord(0,2, f0,f1);
				LB->SetTexCoord(0,3, f1,f1);

				LB->SetTexCoord(1,0, 0.5,0.5);
				LB->SetTexCoord(1,1, 1.0,0.5);
				LB->SetTexCoord(1,2, 0.5,0.0);

				LB->SetTexCoord(2,0, 0.5,0.5);
				LB->SetTexCoord(2,1, 1.0,0.5);
				LB->SetTexCoord(2,2, 0.5,1.0);

				LB->SetTexture(0,TextureState);
				LB->SetTexture(1,TextureState);
				LB->SetTexture(2,TextureState);
				LB->SetTexture(3,TextureState);
				
				LB->Update();
				
				testBrush = LB;
			}
			else if (0)
			{
				// also working (with a slight fix) - Assassin
				IdeBrush * b = IdeBrush_CreateBrush(IdeBrush::Brush_Extruded);
				IdeExtrudedBrush * EB = (IdeExtrudedBrush*)(b->GetBrushInterface(IdeBrush::Brush_Extruded));
				EB->SetSourceLine(al);
				EB->SetExtrudeLine(bl);

				EB->SetLOD(8);
				EB->SetLOD2(8);

				EB->SetTexCoord(0,0, 0,0);
				EB->SetTexCoord(0,1, 1,0);
				EB->SetTexCoord(0,2, 0,1);
				EB->SetTexCoord(0,3, 1,1);
				
				EB->SetTexCoord(1,0, 0.5,0.5);
				EB->SetTexCoord(1,1, 1.0,0.5);
				EB->SetTexCoord(1,2, 0.5,0.0);
				
				EB->SetTexCoord(2,0, 0.5,0.5);
				EB->SetTexCoord(2,1, 1.0,0.5);
				EB->SetTexCoord(2,2, 0.5,1.0);

				EB->SetTexture(0,TextureState);
				EB->SetTexture(1,TextureState);
				EB->SetTexture(2,TextureState);
				
				testBrush = EB;
			}
			else if (0)
			{
				IdeBrush * b = IdeBrush_CreateBrush(IdeBrush::Brush_Prism);
				IdePrismBrush * PB = (IdePrismBrush*)(b->GetBrushInterface(IdeBrush::Brush_Prism));

				// pairs of vectors - 14 vectors makes 7 planes
				// first in pair is normal, 2nd is a point on plane
				deVec3d hull[] = {{6,0,4},{-1,0,0},{-1,0,0},{1,0,0},{0,1,0},{0,-1,0},{0,-1,0.5},{0,1,0},
								{0,0,1},{0,0,-1},{0,0,-1},{0,0,1},{0,-1,-0.5},{0,1,0},};
				PB->SetCVList(14, hull);

				PB->SetTexCoord(0,0, 0,0);
				PB->SetTexCoord(0,1, 1,0);
				PB->SetTexCoord(0,2, 0,1);
				PB->SetTexCoord(0,3, 1,1);
				PB->SetTexCoord(0,4, 0,0);

				PB->SetTexCoord(1,0, 0,0);
				PB->SetTexCoord(1,1, 1,0);
				PB->SetTexCoord(1,2, 0,1);
				PB->SetTexCoord(1,3, 1,1);
				PB->SetTexCoord(1,4, 0,0);

				PB->SetTexCoord(2,0, 1,0);
				PB->SetTexCoord(2,1, 0,0);
				PB->SetTexCoord(2,2, 0,1);
				PB->SetTexCoord(2,3, 1,1);
				PB->SetTexCoord(2,4, 0,0);

				PB->SetTexCoord(3,0, 1,0);
				PB->SetTexCoord(3,1, 0,0);
				PB->SetTexCoord(3,2, 0,1);
				PB->SetTexCoord(3,3, 1,1);
				PB->SetTexCoord(3,4, 0,0);

				PB->SetTexCoord(4,0, 0,1);
				PB->SetTexCoord(4,1, 1,0);
				PB->SetTexCoord(4,2, 0,0);
				PB->SetTexCoord(4,3, 1,1);
				PB->SetTexCoord(4,4, 0,0);

				PB->SetTexCoord(5,0, 0,1);
				PB->SetTexCoord(5,1, 1,0);
				PB->SetTexCoord(5,2, 0,0);
				PB->SetTexCoord(5,3, 1,1);
				PB->SetTexCoord(5,4, 0,0);

				PB->SetTexture(0,TextureState);
				PB->SetTexture(1,TextureState);
				PB->SetTexture(2,TextureState);
				PB->SetTexture(3,TextureState);
				PB->SetTexture(4,TextureState);
				PB->SetTexture(5,TextureState);

				testBrush = PB;
			}
			else if (0)
			{
				IdeSplinePatch * sp = IdeLine_CreateSplinePatch();
				deVec3d * dblverts;
				deVertex* fltverts;
				deTexCoord * coords;
				unsigned short * indices;
				int i, len;

				deVec3d UNormal = {0,0,1};
				deVec3d VNormal = {1,1,0};
				deTexCoord Scale= {1,1};
				deTexCoord Offset={0,0};
				Vec3d_Normalize(UNormal);
				Vec3d_Normalize(VNormal);

				deVec3d hull1[] = {{0,0,0},{0,1,0},{1,0,0},{1,1,0}};
				deVec3d hull2[] = {{0,0,1},{1,0,1},{1,2,1}};
				deVec3d hull3[] = {{0,0,2},{1,0,2},{1,1,2}};
				deVec3d arcdef[] = {{0,1,2},{0,0,2},{0,1,2 - 0.25}};
				IdeLine * lines[3];
				lines[0] = IdeLine_CreateBezierLine();
				lines[0]->SetCVList(4, hull1);
				lines[1] = IdeLine_CreateBezierLine();
				lines[1]->SetCVList(3, hull2);
				lines[2] = IdeLine_CreateArcLine();
				lines[2]->SetCVList(3, arcdef);
				sp->SetAllControls(3, lines);
				sp->SetNumControlSamples(15);
				sp->SetNumInterSamples(15);

				dblverts = sp->GetVertices();
				indices = sp->GetIndices();
				len = sp->GetNumVertices();
				fltverts = new deVertex[len];
				coords = new deTexCoord[len];
				for (i = 0; i < len; ++i)
				{
#pragma todo(integrate this code into BezierBrush)
					fltverts[i] = deMake_Vertex(dblverts[i]);

					if (0)
					{
						// planar texturing
						coords[i].u = (deFloat)Vec3d_Dot(dblverts[i], UNormal);
						coords[i].v = (deFloat)Vec3d_Dot(dblverts[i], VNormal);

						// divide by scale
						coords[i].u /= Scale.u;
						coords[i].v /= Scale.v;
						// add offset
						coords[i].u += Offset.u;
						coords[i].v += Offset.v;
					}
					else if (1)
					{
						// parametric texturing
						coords[i].u = (deFloat)(i / sp->GetNumControlSamples()) / sp->GetNumControlSamples();
						coords[i].v = (deFloat)(i % sp->GetNumControlSamples()) / sp->GetNumInterSamples();
					}
				}

				BIndexList blah;
				IdeBrush * b = IdeBrush_CreateBrush(IdeBrush::Brush_Static);
				IdeStaticBrush * s = (IdeStaticBrush*)(b->GetBrushInterface(IdeBrush::Brush_Static));
				blah.positions = fltverts;
				blah.normals = fltverts;
				blah.uvcoords = coords;
				blah.numpoints = len;
				blah.numtexstages = 1;
				blah.indices = indices;
				blah.numindices = sp->GetNumIndices();
				s->SetTextureState(TextureState);
				s->AddIndexedBuffer(blah);
				s->BuildIndexedBuffers();
				s->SetDiffuseColor(0x00808080);
			}

			if (testBrush)
			{
				IdeMesh* mesh = m_pDe3DFactory->CreateIdeMesh();
				IdeSceneStaticMesh* SceneMesh = m_pDe3DFactory->CreateIdeSceneStaticMesh();
				mesh->BuildFromBrushGeometry(testBrush);
				SceneMesh->SetMesh(mesh);
				if (TEST_WORLD)
				{
					sceneRoom->AddSceneObject(SceneMesh);
					mesh->SetWorldID(m_WorldID);
					SceneMesh->SetWorldID(m_WorldID);
					sceneRoom->SetWorldID(m_WorldID);
				}
				else
				{
					m_pRoom->AddSceneObject(SceneMesh);
				}
				mesh->Release();
				SceneMesh->Release();
			}

			al->Release();
			bl->Release();
			sl->Release();
			g->Release();
		}
		if (TEST_SKY)
		{
			const char * filenames[] = {
				"snow\\negx.bmp",
				"snow\\negy.bmp",
				"snow\\negz.bmp",
				"snow\\posx.bmp",
				"snow\\posy.bmp",
				"snow\\posz.bmp",
			};
			deVec3d vecs[4] = {{-5,2,0},{-5,0,0},{-5,2,2},{-5,0,2}};
			deVec3d Normal = {1,0,0};
			int i;
			IdeResourceBase * rsc;
			IdeBitmapProxy * BMP;
			IdeSceneSky::SkyInfo skyInfo;
			IdeSceneRoom * skyRoom;
			IdeSceneSky * sky;
			IdePortal * portal;
			
			skyRoom = m_pDe3DFactory->CreateIdeSceneRoom();
			sky = m_pDe3DFactory->CreateIdeSceneSky();
			
			skyInfo.type = IdeSceneSky::SKY_BOX;
			for (i = 0; i < 6; ++i)
			{
				rsc = m_pDe3DFactory->GetIdeResourceManager()->GetResource(filenames[i], NULL);
				BMP = m_pDe3DFactory->CreateIdeBitmapProxy(rsc);
				if (rsc)
					rsc->Release();
				rsc = NULL;
				m_pDriver->AddBitmapProxy(BMP);
				skyInfo.Box.Faces[i] = BMP;
			}
			pSG->AddRoom(skyRoom);
			skyRoom->AddSceneObject(sky);
			sky->SetInfo(&skyInfo);
			sky->SetWorldID(m_WorldID);
			skyRoom->SetWorldID(m_WorldID);
			for (i = 0; i < 6; ++i)
			{
				BMP = skyInfo.Box.Faces[i];
				if (BMP)
					BMP->Release();
			}
			
			portal = IdePortal_CreatePortalWithVerts(vecs,4);
			portal->LinkTo(skyRoom);
			portal->SetNormal(Normal);
			m_pRoom->AddPortal(portal);
			
			if (0)
			{
				// this makes the "sky portal" use t-portal logic
				deTransform M;
				portal->SetTransform(M);
			}
			
		}
	}

	if (TEST_WORLD)
	{
		IdeFSReal * WorldFS = NULL;
		IdeFile * WorldFile = NULL;
		deBoolean Success = deFALSE;
		if (1)
		{
			WorldFS = m_pDe3DFactory->CreateIdeFSReal();
			if (WorldFS)
			{
				WorldFile = WorldFS->Open("testworld.dworld", deFile_Open_CreateAlways | deFile_Open_Write);
				if (WorldFile)
				{
					Success = m_pWorld->Serialize(WorldFile);
					WorldFile->Close();
					WorldFile->Release();
					WorldFile = NULL;
				}
				WorldFS->Release();
			}
		}
		if (1 && Success)
		{
			if (testBrush)
				testBrush->Release();
			testBrush = NULL;
			/*
			WorldFile = IdeFileSystem_CreateFSReal();
			if (WorldFile)
			{
				deWorldID NewID = m_pWorldManager->CreateWorld();
				IdeWorld* pNewWorld = m_pWorldManager->GetWorld(NewID);
				if (WorldFile->Open("testworld.dworld", deFile_Open_Existing | deFile_Open_Read))
				{
					IdeFileSystem* FS = (IdeFileSystem*)(WorldFile->GetInterface(IdeFileSystem::iface_IdeFileSystem));
					Success = pNewWorld->DeSerialize(FS);
					WorldFile->Close();
				}
				if (Success && pNewWorld)
				{
					m_pWorld->Release();
					
					m_pWorld = pNewWorld;
				}
				WorldFile->Release();
				WorldFile = NULL;
			}
			*/
			IdeResourceBase * rsc = IdeResourceManager_GetManager()->GetResource("testworld.dworld", NULL);
			IdeWorld * pWorld = (IdeWorld*)rsc->GetRscInterface(IdeWorld_GetManager()->GetRscInterfaceID());
			deWorldID ID = pWorld->GetWorldID();
		}
	}
	if (TEST_WORLD_LOAD)
	{
		IdeResourceBase * rsc = IdeResourceManager_GetManager()->GetResource("testworld.dworld", NULL);
		IdeWorld * pWorld = (IdeWorld*)rsc->GetRscInterface(IdeWorld_GetManager()->GetRscInterfaceID());
		deWorldID ID = pWorld->GetWorldID();

		pWorld->Release();
	}

#if (0)
	{
		//SCENEGRAPH TESTING GOES HERE
		deBrushRoom n;
		deFrustum f;
		deSceneObject *so;
		deTList <deSceneObject*> olist1, olist2;
		so = new deSceneObject;
		so->SetOccludeCenter(deMake_Vec3d(0,0,1));
		so->SetOccludeRadius(1);
		so->SetBoundCenter(deMake_Vec3d(0,0,1));
		so->SetBoundRadius(1);
		olist1.AddElement(so);

		m_Cam->BuildRootFrustum(f);
		//n.ViewCullObjectList(m_Cam, f, olist1, olist2);
	}
#endif

	// FPS counter
	{
		Font = m_pDe3DFactory->CreateIdeFont();

		Font->SetFont("Arial", 12, IdeFont::STYLE_BOLD);
		Font->SetScale(1.0f);
		Font->SetColor(0xff000000);
	}

	// now try wreaking havoc by RESETTING the device!
	// after all that work to get things on it, we are gonna go and screw things up
	// if you don't set a light after this call, lighting will look wrong
	if (0 && !m_pDriver->Reset(NULL))
	{
		MessageBox(NULL, "Reset", "Error", MB_OK);
		goto end_main;
	}

	if (0)
	{
		// test using the offset
		deRect Clipper;
		Clipper.Top = 100;
		Clipper.Left = 100;
		Clipper.Right = 300;
		Clipper.Bottom = 300;
		_2D->SetRect(Clipper);

		if (1)
		{
			_2D->SetBGColor(0x80ff0000);
		}

		if (1)
		{
			deVec3d scroll = {0,0,0};
			_2D->SetScrollValue(scroll);
		}

		if (1)
		{
			Ide2DCollection * NewCollection;

			NewCollection = m_pDe3DFactory->CreateIde2DCollection();
			Clipper.Top = 50;
			Clipper.Left = 50;
			Clipper.Right = 250;
			Clipper.Bottom = 150;
			NewCollection->SetRect(Clipper);
			NewCollection->SetBGColor(0xff00ff00);
			NewCollection->SetDepth(3);

			Ide2DObject * obj;
			obj = Font->Print2D(m_pDriver, NULL, 10,10, 10, NULL, NULL, 0, "Blah");
			NewCollection->AddObject(obj);
			obj->Release();

			_2D->AddSubCollection(NewCollection);
			NewCollection->Release();
		}
	}

	//SetCapture(m_cWorld.GetWindowHandle());
	//SetCursorPos(SCREEN_WIDTH/2, SCREEN_HEIGHT/2);
	{
	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 (FAST_KEYS)
			{
				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();

			/**/
			Ide2DObject * object;
//			object = Font->Print2D(m_pDriver, NULL, 3, 0, deFONT_POSITION_DEFAULT, "%0.2f", TotalFrames/TotalTime);
			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();
			}

			// this will cause a brush that uses an index buffer to crash
			if (m_SetLOD && testBrush)
			{
				m_SetLOD = false;
				testBrush->SetLOD(m_LOD1);
				testBrush->SetLOD2(m_LOD2);
			}

			if (TEST_DOT3)
			{
				deVec3d v;
				deARGB color;

				((deTransform)m_Cam->Position()).GetIn(v);
				Vec3d_Normalize(v);
				v.y *= -1;
				color = Vec3d_ConvertToDot3(v, 0);
				//color = 0x007fd9d9;

				m_pDriver->SetRenderState(IdeDriver::RENDER_TEXTUREFACTOR, color);
			}

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

				if (0)
				{
					deRect rect;
					rect = m_Cam2->GetRect();
					if (PosX)
					{
						rect.Left++;
						rect.Right++;
						if (rect.Right >= VIEW_WIDTH)
							PosX = 0;
					}
					else
					{
						rect.Left--;
						rect.Right--;
						if (rect.Left <= 0)
							PosX = 1;
					}
					if (PosY)
					{
						rect.Top++;
						rect.Bottom++;
						if (rect.Bottom >= VIEW_HEIGHT)
							PosY = 0;
					}
					else
					{
						rect.Top--;
						rect.Bottom--;
						if (rect.Top <= 0)
							PosY = 1;
					}
					m_Cam2->SetRect(rect);
				}
			}

			// screen<-->world
			// and portal test
			if (1)
			{
				int x,y;
				deVec3d tempvec;
				x = 100;
				y = 200;
				deVec3d vec = m_Cam->ScreenPointToWorldVec(x, y, &tempvec);
				vec = vec + tempvec;
				m_Cam->WorldPosToScreenPos(vec, x, y);
				x = x;
				y = y;


				if(1)
				{
					IdePlaneFrustum* f;
					f = m_pDe3DFactory->CreateIdePlaneFrustum();
					m_Cam->BuildRootFrustum(f);

					{
						deAABB BBox = {{-1,-1,8},{1,1,10}};
						deBoolean Inside;
						deBoolean test = f->TestAABBInside(BBox, m_Cam->Position().Translation, Inside);
					}
					{
						deAABB BBox = {{-100,-1,0},{-50,1,1}};
						deBoolean Inside;
						deBoolean test = f->TestAABBInside(BBox, m_Cam->Position().Translation, Inside);
					}

					if (0)
					{
						deTransform M(m_Cam->Position());
						deVec3d vecs[4] = {{-1,2,1},{1,2,1},{1,0,1},{-1,0,1}};
						IdePortal *p = IdePortal_CreatePortalWithVerts(vecs,4);
						deBoolean blahbool = p->IntersectsFrustum(M, f);
						if (blahbool == DE_TRUE)
						{
							m_pRender->SetBGColor(0x00008080);
							p->ClipFrustum(M,f,f);
						}
						else
						{
							// insert breakpoint to see when portal goes invisible
							m_pRender->SetBGColor(0x008080ff);
							//int x = 1;
						}
						p->Release();
					}

					deRect r;
					m_Cam->FrustumRect(f, r);
					
					/*
					deVec3d * CVList = new deVec3d[8];
					deTransform position = m_Cam.Position;
					CVList[6] = CVList[4] = CVList[2] = CVList[0] = ZeroVec;
					CVList[1].y = f.TopTan;
					CVList[1].x = f.LeftTan;
					CVList[1].z = 1;
					CVList[3].y = f.TopTan;
					CVList[3].x = f.RightTan;
					CVList[3].z = 1;
					CVList[5].y = f.BottomTan;
					CVList[5].x = f.RightTan;
					CVList[5].z = 1;
					CVList[7].y = f.BottomTan;
					CVList[7].x = f.LeftTan;
					CVList[7].z = 1;
					position.TransformArray(CVList, CVList, 8);
					LB->SetCVList(8, CVList);

					delete[] CVList;
					*/

					f->Release();
				}
			}

			if (TEST_COLLISION)
			{
				IdeCollision * Collision = m_pDe3DFactory->CreateIdeCollision();
				IdeCollision::deCollideParams Params;
				IdeCollision::deCollideInfo Result;
				deTransform tform;

				static deVec3d MotionVec = {0.005, 0, -0.01};

				m_pCylinder->GetWorldTransform(tform);
				m_pCylinder->GetWorldAABB(Params.AABB);

				{
					static deBoolean donethis = deFALSE;
					static deVec3d OriginalPos = {-3, 0.5, 10};
					if (!donethis)
					{
						donethis = deTRUE;
						if (TEST_XLOADER)
						{
							tform.Translation = OriginalPos;
						}
						else
						{
							MotionVec.z *= -1;
						}
					}
				}

				Params.Start = tform.Translation;
				Params.Delta = MotionVec;
				Params.ThisDetail = IdeCollision::deCollideAABB;
				Params.WorldDetail = IdeCollision::deCollideAABB;

				IdeSceneGraph_GetSceneGraphPtr()->TestCollision(Params, Collision);
				if (Collision->GetNumCollisions() > 0)
				{
					Collision->GetCollision(0, Result);
					tform.Translation = Result.Position;

					deDouble Projection;
					deVec3d Adder;
					Projection = Vec3d_Dot(MotionVec, Result.Normal);
					if (TEST_XLOADER)
						Projection *= 2;
					Adder = Result.Normal;
					Adder *= Projection;
					MotionVec -= Adder;
				}
				else
				{
					tform.Translation += MotionVec;
				}
				m_pCylinder->SetWorldTransform(tform);
			}

			//m_pWorld->ClearBackground(m_Cam, 0x00808080);

			m_pRender->SetStatStruct(&RenderStats);

			if (!m_pRender->BeginFrame(WindowHandle, deTRUE))
			{
				MessageBox(NULL, "BeginFrame() Failed", "Error", MB_OK);
				goto end_main;
			}
#if RENDER_TEXTURE
			if (TotalFrames % 5 == 0)
				m_pRender->RenderTexture(RenderBitmap, m_Cam2, 0);
#endif
			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
			//m_pWorld->SetBGColor(0x00ff8080);
			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;
			}
			if (m_pOGGBuff)
				m_pOGGBuff->Update();
			int k;
			for (k = 0; k < sizeof(m_pWAVBuff)/sizeof(m_pWAVBuff[0]); ++k)
			{
				if (m_pWAVBuff[k])
				{
					m_pWAVBuff[k]->Update();
					//if (!m_pWAVBuff[k]->IsPlaying())
					//	m_pWAVBuff[k]->Play(deFALSE);
				}
			}
			{
				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;
        }
//		if (TotalFrames > 0)
//			break;
//		Sleep(1);
	} 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;
	}
	//delete LB;
	DE3D_SAFE_RELEASE(LineB);
	DE3D_SAFE_RELEASE(Light);
	DE3D_SAFE_RELEASE(Light2);
	DE3D_SAFE_RELEASE(Material);
	DE3D_SAFE_RELEASE(TextureState);
	DE3D_SAFE_RELEASE(Font);
	DE3D_SAFE_RELEASE(testBrush);
	DE3D_SAFE_RELEASE(m_pTerrain);
	DE3D_SAFE_RELEASE(m_pRoom);
	m_Cam->Release();
	m_Cam2->Release();
	m_pWorld->Release();
	delete m_ResPicker;

	if (m_pDe3DFactory)
		m_pDe3DFactory->ShutDown();
	
	if (m_pSoundSys)
		m_pSoundSys->Release();	// YOU CANNOT DELETE THIS BEFORE DELETING SOUNDS!
	if (FSR)
		FSR->Release();

	return (int)(TotalFrames/TotalTime);
}

bool InitEngine()
{
	m_pDe3DFactory = Destiny3D_GetFactory();
	if (!m_pDe3DFactory)
		return false;
	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;
	}
	IdeDriver::deDisplay display;
#ifdef __GNUC__
	display.Adapter = 0;
    display.Windowed = deTRUE;
    display.Width = VIEW_WIDTH;
    display.Height = VIEW_HEIGHT;
	display.MonitorHandle = 0;
    display.RefreshRate = 0;
	display.BackBpp = IdeDriver::BPP_UNKNOWN;
	display.FrontBpp = IdeDriver::BPP_UNKNOWN;
	display.Zpp = IdeDriver::ZPP_UNKNOWN;
	display.ZDepth = 24;
	display.StencilDepth = 0;
	display.RefreshRate = 0;
	display.FSAASamples = 1;
	display.TripleBuffer = deFALSE;
	display.IgnoreVSync = deFALSE;
#else
	m_ResPicker = new deResPicker;
	if (m_ResPicker->PickResolution(hInstance, WindowHandle, m_pDriver, &display))
	{
		if (display.Windowed)
		{
			display.Width = VIEW_WIDTH;
			display.Height = VIEW_HEIGHT;
			display.RefreshRate = 0;
		}
		else
		{
			deRect r;
			r = m_Cam->GetRect();
			r.Left = 0;
			r.Top = 0;
			r.Right = display.Width;
			r.Bottom = display.Height;
			m_Cam->SetRect(r);
		}
	}
	else
	{
		return false;
	}
#endif
	if (0)
	{
		memset(&display, 0, sizeof(IdeDriver::deDisplay));
		display.Adapter = VIEW_ADAPTER;
		if (VIEW_FULLSCREEN)
		{
			int i=0;
			deBoolean RetVal;
			do
			{
				RetVal = m_pRender->GetResolution(m_pDriver, display.Adapter, i, &display.Width, &display.Height, &display.RefreshRate);
				i++;
			} while (RetVal && (display.Width != VIEW_WIDTH || display.Height != VIEW_HEIGHT || display.RefreshRate < 60));
		}
		else
		{
			display.Width = VIEW_WIDTH;
			display.Height = VIEW_HEIGHT;
			display.RefreshRate = 0;
		}
		display.BackBpp = IdeDriver::BPP_A8R8G8B8;
		display.FrontBpp = IdeDriver::BPP_X8R8G8B8;
		display.ZDepth = 24;
		display.StencilDepth = 0;
		display.FSAASamples = 0;
		display.TripleBuffer = deFALSE;
		display.Windowed = !VIEW_FULLSCREEN;
	}
	if (!m_pRender->QueryFormat(m_pDriver, &display, deTRUE))
	{
		MessageBox(WindowHandle, "QueryFormat returned false, using recommended format", "Warning", MB_OK);
	}
//	display.IgnoreVSync = deTRUE;
	if (!m_pDriver || !m_pRender->LoadDriver(WindowHandle, &display, DRIVER_NAME))
	{
		MessageBox(WindowHandle, "No driver available", "ERROR!", MB_OK);
		return false;
	}
	const IdeDriver::deDriverCaps * caps = m_pDriver->GetCaps(0);
	_2D = m_pRender->Get2DCollection(WindowHandle);

#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;
}

bool InitData()
{
	m_LOD1 = 8;
	m_LOD2 = 8;
	m_SetLOD = false;
	
	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 = m_pDe3DFactory->GetIdeWorldManager();
	m_WorldID = m_pWorldManager->CreateWorld();
	m_pWorld = m_pWorldManager->GetWorld(m_WorldID);
	m_pRender = m_pDe3DFactory->GetIdeRender();
	pSG = m_pDe3DFactory->GetIdeSceneGraph();

	{
		deDouble aspect;
		m_Cam = m_pDe3DFactory->CreateIdeCamera();
		m_Cam2 = m_pDe3DFactory->CreateIdeCamera();
		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 = 25000;
			m_Cam->SetFog(10, Dist, FOGCOLOR, deTRUE);
			m_Cam->SetClip(0.5, Dist);
		}
		//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;
	}

	return true;
}

bool TestStuff_1()
{
	{
		// fancy absolute value using only bitwise values
		int i = -1234;
		int x = ((i  >> 31) ^ i) + (1 & (i >> 31));
	}
	
	if (0)
	{
		// test of memory allocation speed
		long idnum;
		{
			int i;
			void * ptr;
			deProfile memspeed(&idnum);
			for (i = 0; i < 1000000; ++i)
			{
				ptr = new char[5000];
				delete[] ptr;
			}
		}
		
		IdeProfileManager* manager = IdeProfile_GetTheManager();
		manager->TimeSpentIn(NULL, idnum);
		// windows memory: 21136688181, on Athlon 1400 = 15 seconds
	}
	
	{
		IdeIDServer * server = IdeIDServer_CreateServer(deTRUE, 13);
		deID_t id1 = server->AddData(server); // ID = 1
		deID_t id2 = server->AddData(server); // ID = 2
		server->RemoveData(id1, server);
		deID_t id3 = server->AddData(server); // should re-use ID = 1
		server->RemoveData(id2, server);
		server->RemoveData(id3, server);
		server->Release();
	}

	if (0)
	{
		HINSTANCE machinelib = 0;
#ifdef _DEBUG
		machinelib = LoadLibrary("deMachined.dll");
#else
		machinelib = LoadLibrary("deMachine.dll");
#endif
#ifndef __GNUC__
		if (machinelib)
		{
			fGetIdeMachineInterface pGetIdeMachineInterface;
			pGetIdeMachineInterface = (fGetIdeMachineInterface)GetProcAddress(machinelib, "GetIdeMachineInterface");

			if (pGetIdeMachineInterface)
			{
				IdeMachine * machine = pGetIdeMachineInterface();
				if (machine)
				{
					const deSystemInfo * sysinfo;
					sysinfo = machine->GetSystemInfo();
					deSystemInfo sysinfo2(*sysinfo);
				}
				else
				{
					MessageBox(NULL, "Could not get deMachine object", "Error", MB_OK);
				}
			}
			else
			{
				MessageBox(NULL, "Could not get deMachine interface", "Error", MB_OK);
			}

			FreeLibrary(machinelib);
		}
		else
		{
			MessageBox(NULL, "Could not load deMachine.dll", "Error", MB_OK);
		}
#endif
	}

	long IDNum = 0;
	if (1)
	{
		PROFILE("test");
		{
			PROFILE(&IDNum);
			int i = 2;
			i += 3;
		}
		{
			PROFILE(&IDNum);
			int i = 2;
			i -= 3;
		}
		{
			PROFILE(&IDNum);
			int i = 2;
			i *= 3;
		}
		{
			PROFILE(&IDNum);
		}
	}
	{
		__int64 time1, time2;
		time1 = IdeProfile_GetTheManager()->TimeSpentIn("test");
		time2 = IdeProfile_GetTheManager()->TimeSpentIn(NULL, IDNum);
		time1 -= time2;
	}
#if 0
	if (0)
	{
		// string operation testing
		char * string = "hello";
		deString SS1(string);
		deString SS2("world");
		SS1 = "hello ";
		SS1 += SS2;
		SS1 = SS2 = SS1;
		deTArray <deString> strings;
		SS1.Split(' ', strings);
		SS1.SetCaseSensitivity(deFALSE);
		SS1 == "Hello World";
		SS1.SetCaseSensitivity(deTRUE);
		SS1 = SS2;
		SS1 == SS2;

		string = SS1.Reserve(100);
		strcpy(string, "123456789012345678901234567890");
		SS1.Trim();

		SS1 = "Hello World!";
		SS2 = "AEIOUaeiou";
		SS1.Strip(SS2, SS2);

		SS1 = "testing123\n";
		char c = SS1[SS1.Length()-1];

		// "streaming" operators
		SS1 = "";
		SS1 << (char)'h';
		SS1 << (unsigned char)'i';
		SS1 << " you. ";
		SS1 << SS2;
		SS1 << ' ';
		SS1 << (int)-13;
		SS1 << ' ';
		SS1 << (unsigned int)254;
		SS1 << ' ';
		SS1 << 3.14159f;
		SS1 << ' ';
		SS1 << DE_PI;

		// printf
		SS1.Format("%-6.3hd", (short)64);
		SS1.Format("%+I64d", (__int64)1234567890123456789);
		SS1.Format("%#6.3lx", (long)0x10abcd10);
		SS1.Format("%-10.3X", 0x10abcd10);
		SS1.Format("%#.3o", 64);
		SS1.Format("%6u", (unsigned)64);
		SS1.Format("1234 %p", &SS1);
		SS1.Format("%s", "hello world!");
		SS1.Format("%35.22s", "123456789012345678901234567890");
		SS1.Format("%-35.22s", "123456789012345678901234567890");
		SS1.Format("%s", 0);
		SS1.Format("%e", .00105);
		SS1.Format("%.e", 10.5);
		SS1.Format("%.3e", -10.5);
		SS1.Format("%f", .00105);
		SS1.Format("%.f", 10.5);
		SS1.Format("%.3f", 10.5);
		SS1.Format("%.2g", 10000.5);
		SS1.Format("%g", 0.00105);
		SS1.Format("%g", 0.000001052675);
		SS1.Format("%.2g", 10.5);
		SS1.Format("%.3g", 10.5);

		char buffer[256];
		sprintf(buffer, "%35.22s", "123456789012345678901234567890");
		sprintf(buffer, "%-35.22s", "123456789012345678901234567890");
		sprintf(buffer, "%e", .00105);
		sprintf(buffer, "%.3f", 10.5);
		sprintf(buffer, "%.2g", 10000.5);
		sprintf(buffer, "%g", 0.00105);
		sprintf(buffer, "%g", 0.00000105);
		sprintf(buffer, "%.2g", 10.5);
		sprintf(buffer, "%.3g", 10.5);
	}
#endif
	if (0)
	{
		// array operation testing
		deTArray <int> array(5);
		array.Resize(2);
		array.Resize(4);
		array.Resize(7);
		array.Resize(2);
		array.Resize(4);
		array[0] = 0;
		array[1] = 1;
		array[2] = 2;
		array[3] = 3;
		array.RemoveElementAt(0);
		array.RemoveElementAt(2);
	}

#if 0
	if (0)
	{
		deTRedBlack <DWORD> m_RedBlack;
		DWORD data, *pData;
		void * ptr;
		// the pathological case of 1,2,3,...,n
		data = 1;
		m_RedBlack.AddElement(data);
		data = 2;
		m_RedBlack.AddElement(data);
		data = 3;
		m_RedBlack.AddElement(data);
		data = 4;
		m_RedBlack.AddElement(data);
		data = 5;
		m_RedBlack.AddElement(data);
		data = 6;
		m_RedBlack.AddElement(data);
		data = 7;
		m_RedBlack.AddElement(data);
		data = 8;
		m_RedBlack.AddElement(data);
		data = 9;
		m_RedBlack.AddElement(data);
		data = 10;
		ptr = m_RedBlack.AddElement(data);
		m_RedBlack.RemoveElement(ptr);
		// the pathological case of 1,2,3,...,n
		m_RedBlack.EmptyTree();
		data = 11;
		m_RedBlack.AddElement(data);
		data = 2;
		m_RedBlack.AddElement(data);
		data = 14;
		m_RedBlack.AddElement(data);
		data = 1;
		m_RedBlack.AddElement(data);
		data = 7;
		m_RedBlack.AddElement(data);
		data = 15;
		m_RedBlack.AddElement(data);
		data = 5;
		m_RedBlack.AddElement(data);
		data = 8;
		m_RedBlack.AddElement(data);

		ptr = m_RedBlack.GetRoot(pData);
		m_RedBlack.RemoveElement(ptr);
		ptr = m_RedBlack.GetLeftMost(pData);
		m_RedBlack.RemoveElement(ptr);
		ptr = m_RedBlack.GetLeftMost(pData);
		m_RedBlack.RemoveElement(ptr);
		ptr = m_RedBlack.GetLeftMost(pData);
		m_RedBlack.RemoveElement(ptr);
		ptr = m_RedBlack.GetLeftMost(pData);
		m_RedBlack.RemoveElement(ptr);
		ptr = m_RedBlack.GetLeftMost(pData);
		m_RedBlack.RemoveElement(ptr);
	}
#endif

	if (1)
	{
		// math testing
		deTransform tform;
		tform.RotateY(2);
		tform.Translation.x += 12;
		tform.IsOrthoNormal();
		deVec3d pt = {1,2,3};
		tform.Transform(pt, pt);
		tform.TransposeTransform(pt, pt);
	}

	if (0)
	{
		// sub-VB testing
		IdeVertexBuffer *composite, *sub1, *sub2;
		composite = m_pDe3DFactory->CreateIdeVertexBuffer();
		composite->Lock();
		composite->CreateBuffer(IdeVertexBuffer::BUFFER_POSITION, deFALSE);
		composite->CreateBuffer(IdeVertexBuffer::BUFFER_INDICES16, deFALSE);
		composite->Unlock();
		sub1 = IdeVertexBuffer_CreateSubVBuffer(composite);
		sub2 = IdeVertexBuffer_CreateSubVBuffer(composite);
		sub1->Lock();
		sub2->Lock();
		sub1->SetBufferSize(10);
		sub2->SetBufferSize(10);
		sub2->SetBufferSize(10, deTRUE);
		sub1->SetBufferSize(10, deTRUE);
		sub1->Unlock();
		sub2->Unlock();
		sub1->Release();
		sub2->Release();
		composite->Release();
	}

	{
		// test some geometry routines
		deVec3d Start = {4,0,0};
		deVec3d End = {-4,0,0};
		deVec3d Pos = {0,1,1};
		deAABB Box1 = {{-1,-1,-1},{1,1,1}};
		deAABB Box2 = {{-1,-1,-1},{1,1,1}};
		deVec3d TempVec, Norm;
		deDouble Percent;

		// put a breakpoint on this and play with the input values
		if (deGeometry::AABBCollision(Box1, Start, End, Box2, Pos, TempVec, Norm, Percent))
		{
			int i = 1;
			Percent += Vec3d_Compare(TempVec, Norm); // does nothing, just an easy way to get the values into the watch window
		}
	}

	deConsole_MakeConsole();
	if (0)
	{	// testing involving console-out
		if (1)
		{
			// fractions
			deFraction f1 = 1, f2(8), f3(1,8);
			deConsoleOut("f1 = %d/%d\n", f1.Num(), f1.Den());
			deConsoleOut("f2 = %d/%d\n", f2.Num(), f2.Den());
			deConsoleOut("f3 = %d/%d\n", f3.Num(), f3.Den());
			
			if (f1 == f2 * f3)
			{
				int x = 5;
			}
			float f = f3 / f2;
		}
		if (0)
		{
			deConsoleOut("Some Structure Sizes:\n");
			deConsoleOut("deVec3d:       %d\n", sizeof(deVec3d));
			deConsoleOut("deVertex:      %d\n", sizeof(deVertex));
			deConsoleOut("deTexCoord:    %d\n", sizeof(deTexCoord));
			deConsoleOut("deColor:       %d\n", sizeof(deColor));
			deConsoleOut("deLVert:       %d\n", sizeof(deLVert));
			deConsoleOut("deRect:        %d\n", sizeof(deRect));
			deConsoleOut("deFloatRect:   %d\n", sizeof(deFloatRect));
			deConsoleOut("deTransformInfo:  %d\n", sizeof(deTransformInfo));
			deConsoleOut("deFractionInfo:%d\n", sizeof(deFractionInfo));
		}
	}

	if (1)
	{
		IdeResourceBase * rsc;
		IdeResourceManager * Manager = IdeResourceManager_GetManager();
		Manager->RegisterResourceType("test", MakeTest);
		long IDNum = Manager->GetUniqueInterfaceID();
		
		CTestResource *ptr1, *ptr2;
		
		rsc = Manager->GetResource("hello.test", NULL);
		ptr1 = (CTestResource*)rsc->GetRscInterface(IDNum);
		rsc = Manager->GetResource("hello.test", NULL);
		ptr2 = (CTestResource*)rsc->GetRscInterface(IDNum);
		// ??? ptr1 == ptr2 ???
		
		int i = CTestResource::count;
		
		DE3D_SAFE_RELEASE(ptr1);
		DE3D_SAFE_RELEASE(ptr2);

		rsc = Manager->GetResourceThreaded("hello.test", NULL);
		if (rsc)
			ptr1 = (CTestResource*)rsc->GetRscInterface(IDNum);
		rsc = Manager->GetResource("hello.test", NULL);
		if (rsc)
			ptr2 = (CTestResource*)rsc->GetRscInterface(IDNum);
		// ??? ptr1 == ptr2 ???

		DE3D_SAFE_RELEASE(ptr1);
		DE3D_SAFE_RELEASE(ptr2);
	}

	return true;
}

struct ThreadTest_t
{
	IdeThreadLock* pLock;
	u32 arrayLen;
	char* pArray;
	u32 index;
};
u32 ThreadFunc(void* param)
{
	ThreadTest_t* tester = (ThreadTest_t*)param;
	while (1)
	{
#if 1 // set to 0 to disable the lock
		deThreadScopeLock scopelock(tester->pLock);
#endif
		u32 idx;
		for (u32 n = 0; n < 26; ++n)
		{
			// By repeatedly getting the index, we're hoping to get
			// interrupted in the middle of this loop and then
			// enter an inconsistent state.
			// The lock should prevent this.
			idx = tester->index;
			if (idx + 27 >= tester->arrayLen)
				break;
			tester->pArray[idx + n] = (char)('A' + n);
		}
		tester->index += 26;
		idx = tester->index;
		if (idx >= tester->arrayLen)
			break;
		tester->pArray[idx] = '\0';
	}
	return 0;
}
bool TestStuff_2()
{
	// test our endian-conversion routines
	u16 test_u16 = 0xabcd;
	u32 test_u32 = 0x1234abcd;
	u64 test_u64 = 0x0123456789abcdef;
	s16 test_s16 = 0x1234;
	s32 test_s32 = 0x1234abcd;
	s64 test_s64 = 0x0123456789abcdef;
	float test_f32 = 12345678.0f;
	double test_f64 = 1234567890.0;
	if (0xcdab != deSwap16(test_u16)) return false;
	if (0xcdab3412 != deSwap32(test_u32)) return false;
	if (0xefcdab8967452301 != deSwap64(test_u64)) return false;
	if (0x3412 != deSwap16(test_s16)) return false;
	if (0xcdab3412 != deSwap32(test_s32)) return false;
	if (0xefcdab8967452301 != deSwap64(test_s64)) return false;
	if (test_u16 != deSwap16(deSwap16(test_u16))) return false;
	if (test_u32 != deSwap32(deSwap32(test_u32))) return false;
	if (test_u64 != deSwap64(deSwap64(test_u64))) return false;
	if (test_s16 != deSwap16(deSwap16(test_s16))) return false;
	if (test_s32 != deSwap32(deSwap32(test_s32))) return false;
	if (test_s64 != deSwap64(deSwap64(test_s64))) return false;
	if (test_f32 != deSwap32(deSwap32(test_f32))) return false;
	if (test_f64 != deSwap64(deSwap64(test_f64))) return false;
	return true;
	// big threading test
	u32 x, numThreads = 10;
	u32 arrayLen = 100000001; // 100MB of data
	char* array = new char[arrayLen];
	array[0] = '\0';
	IdeThreadLock* lock = m_pDe3DFactory->CreateIdeThreadLock(0);
	ThreadTest_t tester;
	tester.pLock = lock;
	tester.arrayLen = arrayLen;
	tester.pArray = array;
	tester.index = 0;
	IdeThread** pThreads = new IdeThread*[numThreads];
	for (x = 0; x < numThreads; ++x)
	{
		pThreads[x] = m_pDe3DFactory->CreateIdeThread(ThreadFunc);
		pThreads[x]->Start(&tester);
	}
	for (x = 0; x < numThreads; ++x)
	{
		pThreads[x]->Join(0);
		pThreads[x]->Release();
	}
	delete pThreads;
	lock->Release();
	bool retVal = true;
	for (x = 1; x < arrayLen; ++x)
	{
		if (array[x] != array[x-1] + 1)
		{
			if (array[x] == '\0')
			{
				if (x < (arrayLen - 30))
					retVal = false;
				break;
			}
			if (array[x] != 'A' || array[x-1] != 'Z')
			{
				retVal = false;
				break;
			}
		}
	}
	delete array;
	return retVal;
}

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
	*****************************/

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

	static BOOL 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);

#if FPS_CAMERA
	{
		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;
	}
#else
	if (m_ptDelta.x != 0)
	{
		// mouse moved left or right
		((deTransform*)&m_Cam->Position())->FreeRotInPlace(0, (m_ptDelta.x) * 0.002, 0);
	}
	if (m_ptDelta.y != 0)
	{
		// mouse moved up or down
		((deTransform*)&m_Cam->Position())->FreeRotInPlace((m_ptDelta.y) * 0.002, 0, 0);
	}
#endif // FPS_CAMERA
#else
	if (!m_bMouseMove)
		return;
	
	GetCursorPos(&m_ptMouse);
	x Motion = 
	m_ptMouse.x -= m_ptOffset.x;
	m_ptMouse.y -= m_ptOffset.y;
	
	// define null zone for mouse
	RECT ptNullZone;
	ptNullZone.left = (WINDOW_WIDTH / 2) - 5;
	ptNullZone.right = (WINDOW_WIDTH / 2) + 5;
	ptNullZone.top = (WINDOW_HEIGHT / 2) - 5;
	ptNullZone.bottom = (WINDOW_HEIGHT / 2) + 5;

	// trap cursor
	if (m_ptMouse.x < 0)
		m_ptMouse.x = 0;
	if (m_ptMouse.y < 0)
		m_ptMouse.y = 0;
	if (m_ptMouse.x > WINDOW_WIDTH)
		m_ptMouse.x = WINDOW_WIDTH;
	if (m_ptMouse.y > WINDOW_HEIGHT)
		m_ptMouse.y = WINDOW_HEIGHT;
	if (m_ptMouse.x < ptNullZone.left)
	{
		// mouse moved left
		/*
		deTransform M, Rotater;
		deVec3d v;
		M = m_Cam.Position;
		v = M.Translation;
		Rotater.RotateY((ptNullZone.left - m_ptMouse.x) * -0.0001);
		M = M.Multiply(Rotater);
		M.Translation = v;
		m_Cam.Position = M;
		*/
		((deTransform*)&m_Cam->Position())->FreeRotInPlace(0, (ptNullZone.left - m_ptMouse.x) * -0.00005, 0);
		//m_fRotation += ((ptNullZone.left - m_ptMouse.x) * 0.001f);
		//m_cWorld.CameraSetRotationY(m_fRotation);
	}
	else if (m_ptMouse.x > ptNullZone.right)
	{
		// mouse moved right
		/*
		deTransform M, Rotater;
		deVec3d v;
		M = m_Cam.Position;
		v = M.Translation;
		Rotater.RotateY((m_ptMouse.x - ptNullZone.right) * 0.0001);
		M = M.Multiply(Rotater);
		M.Translation = v;
		m_Cam.Position = M;
		*/
		((deTransform*)&m_Cam->Position())->FreeRotInPlace(0, (m_ptMouse.x - ptNullZone.right) * 0.00005, 0);
		//m_fRotation -= ((m_ptMouse.x - ptNullZone.right) * 0.001f);
		//m_cWorld.CameraSetRotationY(m_fRotation);
	}
	if (m_ptMouse.y < ptNullZone.top)
	{
		// mouse moved up
		/*
		deTransform M, Rotater;
		deVec3d v;
		M = m_Cam.Position;
		v = M.Translation;
		Rotater.RotateX((ptNullZone.top - m_ptMouse.y) * -0.0001);
		M = M.Multiply(Rotater);
		M.Translation = v;
		m_Cam.Position = M;
		*/
		((deTransform*)&m_Cam->Position())->FreeRotInPlace((ptNullZone.top - m_ptMouse.y) * -0.00005, 0, 0);
		//m_fRotation += ((ptNullZone.left - m_ptMouse.x) * 0.001f);
		//m_cWorld.CameraSetRotationY(m_fRotation);
	}
	else if (m_ptMouse.y > ptNullZone.bottom)
	{
		// mouse moved down
		/*
		deTransform M, Rotater;
		deVec3d v;
		M = m_Cam.Position;
		v = M.Translation;
		Rotater.RotateX((m_ptMouse.y - ptNullZone.bottom) * 0.0001);
		M = M.Multiply(Rotater);
		M.Translation = v;
		m_Cam.Position = M;
		*/
		((deTransform*)&m_Cam->Position())->FreeRotInPlace(FOV * (m_ptMouse.y - ptNullZone.bottom) * 0.00005, 0, 0);
		//m_fRotation -= ((m_ptMouse.x - ptNullZone.right) * 0.001f);
		//m_cWorld.CameraSetRotationY(m_fRotation);
	}
#endif
#pragma message ("The Source is strong with this one.")
}

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_DISPLAYCHANGE:
		m_pRender->UpdateDisplay();
		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 < 1.0/131072)
				m_SpeedMultiplier = 1.0/131072;
			break;
		case VK_OEM_PLUS:
			m_SpeedMultiplier *= 2;
			if (m_SpeedMultiplier > 131072)
				m_SpeedMultiplier = 131072;
			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_UP:
				if (!FAST_KEYS)
				{
					// move camera forward
					deTransform M1,M2;
					M1.SetTranslation(deMake_Vec3d(0,0,1));
					M2 = m_Cam->Position();
					M1 = M2.Multiply(M1);
					m_Cam->Position() = M1;
				}
				break;
			case VK_DOWN:
				if (!FAST_KEYS)
				{
					// move camera backward
					deTransform M1,M2;
					M1.SetTranslation(deMake_Vec3d(0,0,-1));
					M2 = m_Cam->Position();
					M1 = M2.Multiply(M1);
					m_Cam->Position() = M1;
				}
				break;
			case VK_LEFT:
				if (!FAST_KEYS)
				{
					deTransform M1,M2;
					if (m_bMouseMove)
					{
						// in mouse move, we STRAFE
						M1.SetTranslation(deMake_Vec3d(-1,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(-0.1);
						M2.Translation = v;
						m_Cam->Position() = M2;
					}
				}
				break;
			case VK_RIGHT:
				if (!FAST_KEYS)
				{
					deTransform M1,M2;
					if (m_bMouseMove)
					{
						// in mouse move, we STRAFE
						M1.SetTranslation(deMake_Vec3d(1,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(0.1);
						M2.Translation = v;
						m_Cam->Position() = M2;
					}
				}
				break;
			case VK_F1:
				m_LOD1-=2;
				if (m_LOD1 > 30)
					m_LOD1 -= 4;
				if (m_LOD1 < 4)
					m_LOD1 = 4;
				m_SetLOD = true;
				break;
			case VK_F2:
				m_LOD1+=2;
				if (m_LOD1 > 30)
					m_LOD1 += 4;
				if (m_LOD1 > 100)
					m_LOD1 = 100;
				m_SetLOD = true;
				break;
			case VK_F3:
				m_LOD2-=2;
				if (m_LOD2 > 30)
					m_LOD2 -= 4;
				if (m_LOD2 < 4)
					m_LOD2 = 4;
				m_SetLOD = true;
				break;
			case VK_F4:
				m_LOD2+=2;
				if (m_LOD2 > 30)
					m_LOD2 += 4;
				if (m_LOD2 > 100)
					m_LOD2 = 100;
				m_SetLOD = true;
				break;
			case VK_F5:
				m_bReset = true;
				break;
			case VK_F6:
				{
					static BOOL 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, height;
#if (WINVER >= 0x0501)
						HMONITOR hmon;
						hmon = MonitorFromWindow(WindowHandle, MONITOR_DEFAULTTOPRIMARY);
						MONITORINFO moninfo;
						moninfo.cbSize = sizeof(moninfo);
						GetMonitorInfo(hmon, &moninfo);
						width = moninfo.rcMonitor.right - moninfo.rcMonitor.left;
						height= moninfo.rcMonitor.bottom - moninfo.rcMonitor.top;
#else
						width = VIEW_WIDTH;
						height = VIEW_HEIGHT;
#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_F9:
				{
					if (m_pMD2)
					{
						int i = m_pMD2->GetCurrentAnim();
						if (!m_pMD2->SetCurrentAnim(i+1))
							m_pMD2->SetCurrentAnim(0);
					}
				}
				break;
			case VK_F11:
				{
					static bool WideScreen = false;
					int width, height;
#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;
#else
					width = VIEW_WIDTH;
					height = VIEW_HEIGHT;
#endif
					WideScreen = !WideScreen;
					deDouble Aspect = (WideScreen) ? 16.0/9.0 : 4.0/3.0;
					m_Cam->SetScreenAspect(width, height, Aspect);
				}
				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;										
}


