///////////////////////////////////////////////////////////////////////////////
/// @file deRender.cpp
///
/// @brief High-level Rendering interface
///
/// @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 Initial Creation
///
/// @date Oct 2002
/// @author Assassin
/// @remarks Main rendering code moved to RenderCode.cpp
///
///////////////////////////////////////////////////////////////////////////////

#include <windows.h> // for various stuff (device handles, etc)
#include "deRender_priv.hpp"
#include "deCamera.hpp"
#include "de2D.hpp"
#include "deBrush.hpp"
#include "dePortal.hpp"
#include "deMath.hpp"
#include "deDriver.hpp"
#include "deProfile.hpp"

long						RenderProfileID = 0;
deRender *					deRender::s_deRenderSingleton = NULL;
IdeDriverLoad *				deRender::s_DriverLoad = NULL;
IdeRender::deRenderStats	deRender::s_RenderStats;
IdeRenderTexture *			deRender::s_BlankTex = NULL;
IdeRenderMaterial *			deRender::s_BlankMat = NULL;

deTArray <deRender::DriverInfo>	deRender::m_DriverList(0);

deBoolean IdeRender_Initialize()
{
	if (!deRender::s_BlankTex)
	{
		deRender::s_BlankTex = IdeRenderState_CreateRenderTexture();
		if (!deRender::s_BlankTex)
			DEBUGRETURN(deFALSE, "IdeRender_Initialize - unable to create s_BlankTex");
		deRender::s_BlankTex->Lock();
		deRender::s_BlankTex->SetColorOperation(0, IdeRenderTexture::TEXTUREOP_DISABLE);
		deRender::s_BlankTex->SetAlphaOperation(0, IdeRenderTexture::TEXTUREOP_DISABLE);
		deRender::s_BlankTex->Unlock();
	}
	if (!deRender::s_BlankMat)
	{
		deRender::s_BlankMat = IdeRenderState_CreateRenderMaterial();
		if (!deRender::s_BlankMat)
			DEBUGRETURN(deFALSE, "IdeRender_Initialize - unable to create s_BlankMat");
		deColor color;
		deRender::s_BlankMat->Lock();
		color = deMake_Color(0xFF000000);
		deRender::s_BlankMat->SetEmissiveColor(&color);
		color = deMake_Color(0xFFFFFFFF);
		deRender::s_BlankMat->SetAmbientColor(&color);
		deRender::s_BlankMat->SetDiffuseColor(&color);
		deRender::s_BlankMat->SetSpecularColor(&color);
		deRender::s_BlankMat->SetDiffuseSource(IdeRenderMaterial::MATSOURCE_MATERIAL);
		deRender::s_BlankMat->SetEmissiveColor(&color);
		deRender::s_BlankMat->SetEmissiveSource(IdeRenderMaterial::MATSOURCE_MATERIAL);
		deRender::s_BlankMat->Unlock();
	}
	return deTRUE;
}

IdeRender* IdeRender_GetPtr()
{
	if (deRender::s_deRenderSingleton == NULL)
		deRender::s_deRenderSingleton = new deRender;

	return deRender::s_deRenderSingleton;
}

void IdeRender_Destroy()
{
	if (deRender::s_deRenderSingleton)
		delete deRender::s_deRenderSingleton;
	deRender::s_deRenderSingleton = NULL;
}

void IdeRender_DestroyDriverLinkages()
{
	deRender::DestroyDriverLinkages();
}

deRender::deRender()
: m_DriverPath("."), m_CurrentPassDriver(m_CurrentPassDriver.LIFO_STACK)
{
#if !defined(DESTINY3D_FREEWARE)
	m_EnableWaterMark = 0; // no watermark by default
#endif
	m_CurrentPassDriver.Clear();
	m_CurrentTimeStep = 0;
	m_TexturesEnabled = deTRUE;
	m_RenderMeshOverFill = deFALSE;
	m_RenderSolidWireframe = deFALSE;
	m_BGColor = 0x00808080;
	m_RenderStats = NULL;
	m_FrameNum = -1;
	m_TPortalDepth = 8;
	m_MaxHWLights = 32;
	m_MaxTexLights = 4;

	m_WaterMarkTex = NULL;
	m_WaterMarkVB = NULL;
	
	m_FillState = IdeDriver::FILL_SOLID;
	m_CullState = IdeDriver::CULL_CW;
	
	int i;
	for (i = 0; i < MAX_LIGHTS_PER_PASS; ++i)
		m_LightsPerPass[i] = IdeRenderState_CreateRenderLight();
	m_PassTexture = IdeRenderState_CreateRenderTexture();
}

deRender::~deRender()
{
	int i;
	for (i = 0; i < MAX_LIGHTS_PER_PASS; ++i)
		m_LightsPerPass[i]->Release();
	m_PassTexture->Release();
	m_RenderBatches.EmptyList();
	if (m_WaterMarkTex)
		m_WaterMarkTex->Release();
	if (m_WaterMarkVB)
		m_WaterMarkVB->Release();
}

void deRender::DestroyDriverLinkages()
{
	size_t i;
	for (i = 0; i < m_DriverList.Length(); i++)
	{
		if (m_DriverList[i]._2D)
		{
			while (m_DriverList[i]._2D->Release() > 0)
			{ /* do nothing */ }
		}
		if (m_DriverList[i].pDriver)
		{
			while (m_DriverList[i].pDriver->Release() > 0)
			{ /* do nothing */ }
		}
	}
	m_DriverList.Resize(0);
	if (s_DriverLoad)
		s_DriverLoad->Release();
	s_DriverLoad = NULL;

	if (s_BlankTex)
		s_BlankTex->Release();
	if (s_BlankMat)
		s_BlankMat->Release();
	s_BlankTex = NULL;
	s_BlankMat = NULL;

}

IdeDriver * deRender::CurrentPassDriver()
{
	IdeDriver ** ppDriver = m_CurrentPassDriver.Peek(0);
	if (ppDriver)
		return *ppDriver;
	DEBUGRETURN(NULL,"CurrentPassDriver: No current driver available");
}

void deRender::SetDriverPath(const char * RelativePath)
{
	m_DriverPath = RelativePath;
}

IdeDriverLoad* deRender::GetDriverLoad()
{
	if (!s_DriverLoad)
	{
		s_DriverLoad = IdeDriverLoad_CreateDriverLoad(".");
	}
	return s_DriverLoad;
}

deBoolean deRender::DetachFromWindow(HWND hWnd)
{
	IdeDriver * pDriver = NULL;
	size_t i;
	
	for (i = 0; i < m_DriverList.Length(); i++)
	{
		if (hWnd == m_DriverList[i].DriverWindow)
		{
			pDriver = m_DriverList[i].pDriver;
			break;
		}
	}

	if (!pDriver)
	{
		DEBUGRETURN(deFALSE,"DetachFromWindow: driver not attached to window");
	}

	pDriver->Release();
	
	if (!m_DriverList.RemoveElementAt(i))
	{
		DEBUGRETURN(deFALSE,"DetachFromWindow: could not remove window entry");
	}
	
	return deTRUE;
}

IdeDriver * deRender::AttachToWindow(HWND hWnd, char * DriverName)
{
	HDC				DeviceHandle;
	IdeDriver * pDriver = NULL;
	size_t i;

	for (i = 0; i < m_DriverList.Length(); i++)
	{
		if (hWnd == m_DriverList[i].DriverWindow)
		{
			pDriver = m_DriverList[i].pDriver;
			break;
		}
	}

	if (pDriver)
	{
		return pDriver;
	}
	// now pDriver == NULL
	if (!DriverName)
	{
		DEBUGMSG0("AttachToWindow: window not found, no driver specified, returning NULL");
		return NULL;
	}

	if (!GetDriverLoad())
	{
		DEBUGRETURN(NULL,"AttachToWindow: could not obtain DriverLoad");
	}

	pDriver = s_DriverLoad->GetDriver(DriverName);
	//init the driver
	if(!pDriver)
	{
		DEBUGMSG1("AttachToWindow: error on load of the requested driver: '%s'", DriverName);
		DEBUGMSG0("Check your Working Directory and make sure that the corresponding ddriver file exists there");
		return NULL;
	}
	if(!pDriver->Init(hWnd))
	{
		DEBUGMSG1("AttachToWindow: error on init of the requested driver: '%s'", DriverName);
		return NULL;
	}
	
	DEBUGMSG1("loaded driver: %s", DriverName);
	
	// resize our lists of drivers an hwnds and stick this new one in
	i =  m_DriverList.Length();
	m_DriverList.Resize(i+1);
	m_DriverList[i].pDriver = pDriver;
	m_DriverList[i].Name = DriverName;
	m_DriverList[i].DriverWindow = hWnd;
	m_DriverList[i]._2D = Ide2DObject_Create2DCollection();
	m_DriverList[i].InFrame = deFALSE;
	m_DriverList[i].DisplaySet = deFALSE;
	DeviceHandle = GetDC(hWnd);
	m_DriverList[i].FullWidth = GetDeviceCaps(DeviceHandle, HORZRES);
	m_DriverList[i].FullHeight = GetDeviceCaps(DeviceHandle, VERTRES);
	ReleaseDC(hWnd, DeviceHandle);
	m_DriverList[i].SettingMode = deFALSE;
/*
#pragma todo (rip this all out and push it into the shader system)
	{
		deRenderFuncs & funcs = m_DriverList[i].RenderFuncs;

		funcs.pZPass		= &deRender::RenderPassZOnly;
		funcs.pDiffusePass	= &deRender::RenderPassDiffuseVertexOnly8Light;
		funcs.pTexturePass	= &deRender::RenderPassTexturesTNT;
		funcs.pSpecularPass = &deRender::RenderPassSpecularVertexOnly8Light;
	}
*/
	return pDriver;
}

deBoolean deRender::LoadDriver(HWND hWnd, IdeDriver::deDisplay * Display, char * DriverName)
{
	// this might be better as an assert
	if (!DriverName)
		DEBUGRETURN(deFALSE,"LoadDriver: supplied parameter was NULL: 'DriverName'");
	if (!Display)
		DEBUGRETURN(deFALSE,"LoadDriver: supplied parameter was NULL: 'Display'");
	
	IdeDriver * pDriver = NULL;
	size_t i;

	pDriver = AttachToWindow(hWnd, DriverName);
	
	for (i = 0; i < m_DriverList.Length(); i++)
	{
		if (hWnd == m_DriverList[i].DriverWindow)
		{
			break;
		}
	}

	if (i == m_DriverList.Length())
	{
		DEBUGRETURN(deFALSE,"LoadDriver: specified window not found");
	}

	if (m_DriverList[i].DisplaySet)
	{
		const IdeDriver::deDisplay * display2 = pDriver->GetDisplay();
		if (display2 && display2->Adapter == Display->Adapter
			&& m_DriverList[i].Name == DriverName)
		{
			// prevent UpdateDisplay from changing the display on us
			m_DriverList[i].SettingMode = deTRUE;
			DEBUGMSG2("LoadDriver: resetting driver: %s, windowed: %d", DriverName, Display->Windowed);
			if (InitDriver(pDriver, hWnd, Display, deTRUE))
			{
				m_DriverList[i].SettingMode = deFALSE;
				DEBUGMSG0("LoadDriver: driver successfully reset");
				return deTRUE;
			}
			DEBUGMSG0("LoadDriver: failed to reset driver");
			m_DriverList[i].SettingMode = deFALSE;
		}
		m_DriverList[i].DisplaySet = deFALSE;
	}
	
	if (!InitDriver(pDriver, hWnd, Display, deFALSE))
	{
		DEBUGRETURN(deFALSE,"LoadDriver: failed to initialize driver");
	}

	m_DriverList[i].DisplaySet = deTRUE;
	
	return deTRUE;
}

deBoolean deRender::GetResolution(IdeDriver * pDriver, long Adapter, long EntryNum, long * Width, long * Height, long * RefreshRate)
{
	if (!pDriver)
		DEBUGRETURN(deFALSE,"LoadDriver: supplied parameter was NULL: 'pDriver'");
	if (!Width)
		DEBUGRETURN(deFALSE,"LoadDriver: supplied parameter was NULL: 'Width'");
	if (!Height)
		DEBUGRETURN(deFALSE,"LoadDriver: supplied parameter was NULL: 'Height'");
	if (!RefreshRate)
		DEBUGRETURN(deFALSE,"LoadDriver: supplied parameter was NULL: 'RefreshRate'");

	if (Adapter < 0 || Adapter >= pDriver->GetAdapterCount())
	{
		DEBUGRETURN(deFALSE,"GetResolution: invalid adapter number");
	}

	if (EntryNum < 0 || EntryNum >= pDriver->GetModeCount(Adapter))
	{
		DEBUGRETURN(deFALSE,"GetResolution: invalid mode number");
	}

	IdeDriver::deDisplay Display;
	//memset(&Display, 0, sizeof(IdeDriver::deDisplay));
	
	if (!pDriver->GetDisplayMode(Adapter, EntryNum, &Display))
	{
		DEBUGRETURN(deFALSE,"GetResolution: invalid mode number");
	}

	*Width = Display.Width;
	*Height = Display.Height;
	*RefreshRate = Display.RefreshRate;

	return deTRUE;
}

static IdeDriver::BPP MatchBackToFront(IdeDriver::BPP Back, IdeDriver::BPP Front)
{
	IdeDriver::BPP RetFormat = IdeDriver::BPP_UNKNOWN;
	
	switch (IdeDriver_BPPBitDepth(Front)/8)
	{
	default:
		DEBUGRETURN(IdeDriver::BPP_UNKNOWN, "MatchBackToFront: unknown formats are not valid");
		// 8-bit formats
	case 1:
		DEBUGRETURN(IdeDriver::BPP_UNKNOWN, "MatchBackToFront: 8-bit formats are not valid");

		// 16-bit formats
	case 2:
		switch (Back)
		{
		case IdeDriver::BPP_R5G6B5:
		case IdeDriver::BPP_X1R5G5B5:
		case IdeDriver::BPP_A1R5G5B5:
		case IdeDriver::BPP_X4R4G4B4:
		case IdeDriver::BPP_A4R4G4B4:
		default:
			RetFormat = Back;
			break;
		case IdeDriver::BPP_A2B10G10R10:
			DEBUGMSG0("MatchBackToFront: attempt to use BPP_A2B10G10R10 in 16-bit, trying BPP_A1R5G5B5");
			RetFormat = IdeDriver::BPP_A1R5G5B5;
			break;
		case IdeDriver::BPP_A8R8G8B8:
			DEBUGMSG0("MatchBackToFront: attempt to use BPP_A8R8G8B8 in 16-bit, trying BPP_X4R4G4B4");
			RetFormat = IdeDriver::BPP_X4R4G4B4;
			break;
		case IdeDriver::BPP_R8G8B8:
		case IdeDriver::BPP_X8R8G8B8:
			DEBUGMSG0("MatchBackToFront: attempt to use BPP_X8R8G8B8 in 16-bit, trying BPP_R5G6B5");
			RetFormat = IdeDriver::BPP_R5G6B5;
			break;
		}
		break;

	case 3:
		switch (Back)
		{
		case IdeDriver::BPP_R8G8B8:
			RetFormat = Back;
		default:
			DEBUGMSG0("MatchBackToFront: attempt to use non-24-bit format in 32-bit, trying BPP_R8G8B8");
			RetFormat = IdeDriver::BPP_R8G8B8;
		}
		break;
		
	// 32-bit formats
	case 4:
		switch (Back)
		{
		case IdeDriver::BPP_R5G6B5:
			DEBUGMSG0("MatchBackToFront: attempt to use BPP_R5G6B5 in 32-bit, trying BPP_X8R8G8B8");
			RetFormat = IdeDriver::BPP_X8R8G8B8;
			break;
		case IdeDriver::BPP_X1R5G5B5:
			DEBUGMSG0("MatchBackToFront: attempt to use BPP_X1R5G5B5 in 32-bit, trying BPP_X8R8G8B8");
			RetFormat = IdeDriver::BPP_X8R8G8B8;
			break;
		case IdeDriver::BPP_A1R5G5B5:
			DEBUGMSG0("MatchBackToFront: attempt to use BPP_A1R5G5B5 in 32-bit, trying BPP_A2B10G10R10");
			RetFormat = IdeDriver::BPP_A2B10G10R10;
			break;
		case IdeDriver::BPP_X4R4G4B4:
			DEBUGMSG0("MatchBackToFront: attempt to use BPP_X4R4G4B4 in 32-bit, trying BPP_X8R8G8B8");
			RetFormat = IdeDriver::BPP_X8R8G8B8;
			break;
		case IdeDriver::BPP_A4R4G4B4:
			DEBUGMSG0("MatchBackToFront: attempt to use BPP_A4R4G4B4 in 32-bit, trying BPP_A8R8G8B8");
			RetFormat = IdeDriver::BPP_A8R8G8B8;
			break;
		case IdeDriver::BPP_R8G8B8:
			DEBUGMSG0("MatchBackToFront: attempt to use BPP_R8G8B8 in 32-bit, trying BPP_X8R8G8B8");
			RetFormat = IdeDriver::BPP_X8R8G8B8;
			break;
		case IdeDriver::BPP_A2B10G10R10:
			RetFormat = Back;
			break;
		case IdeDriver::BPP_A8R8G8B8:
		case IdeDriver::BPP_X8R8G8B8:
		default:
			RetFormat = IdeDriver::BPP_A8R8G8B8;
			break;
		}
		break;
	}
	
	DEBUG_EXP_RETURNMSG(RetFormat != IdeDriver::BPP_UNKNOWN, IdeDriver::BPP_UNKNOWN, "MatchBackToFront: failed to find a matching format");
	return RetFormat;
}

static IdeDriver::BPP CycleBPP(IdeDriver::BPP Input)
{
	IdeDriver::BPP RetFormat = IdeDriver::BPP_UNKNOWN;

	switch (Input)
	{
		// 8-bit formats
	case IdeDriver::BPP_R3G3B2:
		DEBUGRETURN(IdeDriver::BPP_UNKNOWN, "CycleBPP: 8-bit formats are not valid");
	default:
		DEBUGRETURN(IdeDriver::BPP_UNKNOWN, "CycleBPP: unknown formats are not valid");
		
	case IdeDriver::BPP_R8G8B8:
		RetFormat = IdeDriver::BPP_R8G8B8;
		break;

		// 16-bit formats
	case IdeDriver::BPP_R5G6B5:
		DEBUGMSG0("CycleBPP: failed to use BPP_R5G6B5, attempting BPP_X1R5G5B5");
		RetFormat = IdeDriver::BPP_X1R5G5B5;
		break;
	case IdeDriver::BPP_X1R5G5B5:
		DEBUGMSG0("CycleBPP: failed to use BPP_X1R5G5B5, attempting BPP_A1R5G5B5");
		RetFormat = IdeDriver::BPP_A1R5G5B5;
		break;
	case IdeDriver::BPP_A1R5G5B5:
		DEBUGMSG0("CycleBPP: failed to use BPP_A1R5G5B5, attempting BPP_X4R4G4B4");
		RetFormat = IdeDriver::BPP_X4R4G4B4;
		break;
	case IdeDriver::BPP_X4R4G4B4:
		DEBUGMSG0("CycleBPP: failed to use BPP_X4R4G4B4, attempting BPP_A4R4G4B4");
		RetFormat = IdeDriver::BPP_A4R4G4B4;
		break;
	case IdeDriver::BPP_A4R4G4B4:
		DEBUGMSG0("CycleBPP: failed to use BPP_A4R4G4B4, attempting BPP_R5G6B5");
		RetFormat = IdeDriver::BPP_R5G6B5;
		break;
		
		// 32-bit formats
	case IdeDriver::BPP_A2B10G10R10:
		DEBUGMSG0("CycleBPP: failed to use BPP_A2B10G10R10, attempting BPP_A8R8G8B8");
		RetFormat = IdeDriver::BPP_A8R8G8B8;
		break;
	case IdeDriver::BPP_A8R8G8B8:
		DEBUGMSG0("CycleBPP: failed to use BPP_A8R8G8B8, attempting BPP_X8R8G8B8");
		RetFormat = IdeDriver::BPP_X8R8G8B8;
		break;
	case IdeDriver::BPP_X8R8G8B8:
		DEBUGMSG0("CycleBPP: failed to use BPP_X8R8G8B8, attempting BPP_A2B10G10R10");
		RetFormat = IdeDriver::BPP_A2B10G10R10;
		break;
	}

	return RetFormat;
}

deBoolean deRender::QueryFormat(IdeDriver * pDriver, IdeDriver::deDisplay * Display, deBoolean PreferStencil)
{
	if (!pDriver)
		DEBUGRETURN(deFALSE,"LoadDriver: supplied parameter was NULL: 'pDriver'");
	if (!Display)
		DEBUGRETURN(deFALSE,"LoadDriver: supplied parameter was NULL: 'Display'");

	IdeDriver::Resource rsc, fsaa;
	if (Display->Windowed)
	{
		IdeDriver::deDisplay	DisplayMode;

		fsaa = IdeDriver::RESOURCE_FSAAWINDOWED;
		rsc = IdeDriver::RESOURCE_DISPLAYWINDOWED;
		pDriver->GetCurrentDisplay(Display->Adapter, &DisplayMode);
		Display->FrontBpp = DisplayMode.FrontBpp;
		Display->BackBpp = DisplayMode.BackBpp;
	}
	else
	{
		fsaa = IdeDriver::RESOURCE_FSAA;
		rsc = IdeDriver::RESOURCE_DISPLAY;
		//Display->FrontBpp = Display->BackBpp;
	}

	IdeDriver::BPP TempBPP;
	deBoolean ParamsValid = deTRUE;
	TempBPP = MatchBackToFront(Display->BackBpp, Display->FrontBpp);
	if (TempBPP != Display->BackBpp)
	{
		Display->BackBpp = TempBPP;
		//ParamsValid = deFALSE; // the params changed
	}

	IdeDriver::BPP StartBPP = Display->BackBpp;
	IdeDriver::BPP StartFront = Display->FrontBpp;
	// find a good color-buffer format of the same bit-depth
	while (!pDriver->ValidFormat(Display->Adapter, rsc, Display->BackBpp, IdeDriver::ZPP_UNKNOWN, Display->FrontBpp))
	{
		Display->BackBpp = CycleBPP(Display->BackBpp);
		ParamsValid = deFALSE; // the params changed
		
		if (Display->BackBpp == StartBPP)
		{
			if (!Display->Windowed)
			{
				ParamsValid = deFALSE; // the params changed
				DEBUGMSG0("QueryFormat: requested color-buffer format not valid, trying another with the same bitdepth");
				Display->FrontBpp = CycleBPP(Display->FrontBpp);
				TempBPP = MatchBackToFront(Display->BackBpp, Display->FrontBpp);
				if (TempBPP != Display->BackBpp)
				{
					Display->BackBpp = TempBPP;
				}
			}
			if (Display->Windowed || StartFront == Display->FrontBpp)
			{
				if (!Display->Windowed)
				{
					if (IdeDriver_BPPBitDepth(Display->FrontBpp) > 24)
					{
						// try 24-bit front buffer
						ParamsValid = deFALSE; // the params changed
						StartBPP = IdeDriver::BPP_R8G8B8;
						StartFront = StartBPP;
						Display->BackBpp = StartBPP;
						Display->FrontBpp = StartBPP;
						TempBPP = MatchBackToFront(Display->BackBpp, Display->FrontBpp);
					}
					else if (IdeDriver_BPPBitDepth(Display->FrontBpp) > 16)
					{
						// try 16-bit front buffer
						ParamsValid = deFALSE; // the params changed
						StartBPP = IdeDriver::BPP_R5G6B5;
						StartFront = StartBPP;
						Display->BackBpp = StartBPP;
						Display->FrontBpp = StartBPP;
						TempBPP = MatchBackToFront(Display->BackBpp, Display->FrontBpp);
					}
					continue;
				}
				DEBUGMSG0("QueryFormat: could not find a color-buffer bitdepth matching requested format");
				return deFALSE;
			}
		}
	}

	if (Display->FSAASamples > 1)
	{
		deBoolean	ValidFound = deFALSE;
		int			counter;
		for (counter = Display->FSAASamples; counter <= 16; ++counter)
		{
			if (pDriver->ValidFormat(Display->Adapter, fsaa, Display->BackBpp, 
							IdeDriver::ZPP_UNKNOWN, IdeDriver::BPP_UNKNOWN, counter))
			{
				ValidFound = deTRUE;
				break;
			}
		}
		if (!ValidFound)
		{
			ParamsValid = deFALSE;
			for (counter = Display->FSAASamples; counter > 1; --counter)
			{
				if (pDriver->ValidFormat(Display->Adapter, fsaa, Display->BackBpp, 
								IdeDriver::ZPP_UNKNOWN, IdeDriver::BPP_UNKNOWN, counter))
				{
					ValidFound = deTRUE;
					break;
				}
			}
			if (!ValidFound)
			{
				DEBUGMSG1("Unsupported number of FSAA samples: %i", Display->FSAASamples);
				counter = 0;
			}
		}
		Display->FSAASamples = counter;
	}
	else
	{
		if (Display->FSAASamples < 0 || Display->FSAASamples > 16)
			DEBUGMSG1("Unsupported number of FSAA samples: %i", Display->FSAASamples);
		Display->FSAASamples = 0;
	}

	// check for an un-stenciled format
	if (Display->StencilDepth <= 0)
	{
		if (Display->ZDepth <= 16)
		{
			if (pDriver->ValidFormat(Display->Adapter, rsc, Display->BackBpp, IdeDriver::ZPP_D16, Display->FrontBpp))
			{
				Display->ZDepth = 16;
				Display->StencilDepth = 0;
				Display->Zpp = IdeDriver::ZPP_D16;
				return ParamsValid; // true only if nothing was changed
			}
		}
		
		if (Display->ZDepth <= 24)
		{
			if (pDriver->ValidFormat(Display->Adapter, rsc, Display->BackBpp, IdeDriver::ZPP_D24, Display->FrontBpp))
			{
				Display->ZDepth = 24;
				Display->StencilDepth = 0;
				Display->Zpp = IdeDriver::ZPP_D24;
				return ParamsValid; // true only if nothing was changed
			}
		}
		
		if (Display->ZDepth <= 32)
		{
			if (pDriver->ValidFormat(Display->Adapter, rsc, Display->BackBpp, IdeDriver::ZPP_D32, Display->FrontBpp))
			{
				Display->ZDepth = 32;
				Display->StencilDepth = 0;
				Display->Zpp = IdeDriver::ZPP_D32;
				return ParamsValid; // true only if nothing was changed
			}
		}
	}
	
	if (Display->ZDepth <= 15 && Display->StencilDepth <= 1)
	{
		if (pDriver->ValidFormat(Display->Adapter, rsc, Display->BackBpp, IdeDriver::ZPP_D15S1, Display->FrontBpp))
		{
			Display->ZDepth = 15;
			Display->StencilDepth = 1;
			Display->Zpp = IdeDriver::ZPP_D15S1;
				return ParamsValid; // true only if nothing was changed
		}
	}
	
	if (Display->ZDepth <= 24 && Display->StencilDepth <= 4)
	{
		if (pDriver->ValidFormat(Display->Adapter, rsc, Display->BackBpp, IdeDriver::ZPP_D24S4, Display->FrontBpp))
		{
			Display->ZDepth = 24;
			Display->StencilDepth = 4;
			Display->Zpp = IdeDriver::ZPP_D24S4;
				return ParamsValid; // true only if nothing was changed
		}
	}
	
	if (Display->ZDepth <= 24 && Display->StencilDepth <= 8)
	{
		if (pDriver->ValidFormat(Display->Adapter, rsc, Display->BackBpp, IdeDriver::ZPP_D24S8, Display->FrontBpp))
		{
			Display->ZDepth = 24;
			Display->StencilDepth = 8;
			Display->Zpp = IdeDriver::ZPP_D24S8;
				return ParamsValid; // true only if nothing was changed
		}
	}

	// at this point, we have no options left
	// let's find the highest possible that comes close to criteria

	IdeDriver::ZPP HighestStencil = IdeDriver::ZPP_UNKNOWN;

	// try to at least give a stenciled format if they asked for one
	if (Display->StencilDepth > 0)
	{
		if(pDriver->ValidFormat(Display->Adapter, rsc, Display->BackBpp, IdeDriver::ZPP_D15S1, Display->FrontBpp))
		{
			if ((PreferStencil && Display->StencilDepth <= 1) || (!PreferStencil && Display->ZDepth <= 15))
			{
				Display->ZDepth = 15;
				Display->StencilDepth = 1;
				Display->Zpp = IdeDriver::ZPP_D15S1;
				DEBUGMSG0("QueryFormat: Could not match requested depth format, using D15S1");
				return deFALSE;
			}
			HighestStencil = IdeDriver::ZPP_D15S1;
		}
		if(pDriver->ValidFormat(Display->Adapter, rsc, Display->BackBpp, IdeDriver::ZPP_D24S4, Display->FrontBpp))
		{
			if ((PreferStencil && Display->StencilDepth <= 4) || (!PreferStencil && Display->ZDepth <= 24))
			{
				Display->ZDepth = 24;
				Display->StencilDepth = 4;
				Display->Zpp = IdeDriver::ZPP_D24S4;
				DEBUGMSG0("QueryFormat: Could not match requested depth format, using D24S4");
				return deFALSE;
			}
			HighestStencil = IdeDriver::ZPP_D24S4;
		}
		if (pDriver->ValidFormat(Display->Adapter, rsc, Display->BackBpp, IdeDriver::ZPP_D24S8, Display->FrontBpp))
		{
			if ((PreferStencil && Display->StencilDepth <= 8) || (!PreferStencil && Display->ZDepth <= 24))
			{
				Display->ZDepth = 24;
				Display->StencilDepth = 8;
				Display->Zpp = IdeDriver::ZPP_D24S8;
				DEBUGMSG0("QueryFormat: Could not match requested depth format, using D24S8");
				return deFALSE;
			}
			HighestStencil = IdeDriver::ZPP_D24S8;
		}

		// we couldn't meet the depth buffer criteria, so let's just return the highest we can
		switch (HighestStencil)
		{
		case IdeDriver::ZPP_D15S1:
			Display->ZDepth = 15;
			Display->StencilDepth = 1;
			Display->Zpp = IdeDriver::ZPP_D15S1;
			DEBUGMSG0("QueryFormat: Could not match requested depth format, forcing stencil - using D15S1");
			return deFALSE;
		case IdeDriver::ZPP_D24S4:
			Display->ZDepth = 24;
			Display->StencilDepth = 4;
			Display->Zpp = IdeDriver::ZPP_D24S4;
			DEBUGMSG0("QueryFormat: Could not match requested depth format, forcing stencil - using D24S4");
			return deFALSE;
		case IdeDriver::ZPP_D24S8:
			Display->ZDepth = 24;
			Display->StencilDepth = 8;
			Display->Zpp = IdeDriver::ZPP_D24S8;
			DEBUGMSG0("QueryFormat: Could not match requested depth format, forcing stencil - using D24S8");
			return deFALSE;
		case IdeDriver::ZPP_UNKNOWN:
			// no stenciled formats supported
			DEBUGMSG0("QueryFormat: Could not match requested depth format, no stencil available");
			// continue on with more non-stencil formats
			break;
		default:
			break;
		}
	}
	
	Display->StencilDepth = 0;
	IdeDriver::ZPP HighestZ = IdeDriver::ZPP_UNKNOWN;

	if(pDriver->ValidFormat(Display->Adapter, rsc, Display->BackBpp, IdeDriver::ZPP_D16, Display->FrontBpp))
	{
		if (Display->ZDepth <= 16)
		{
			Display->ZDepth = 16;
			Display->Zpp = IdeDriver::ZPP_D16;
			DEBUGMSG0("QueryFormat: Could not match requested depth format, using D16");
			return deFALSE;
		}
		HighestZ = IdeDriver::ZPP_D16;
	}
	if(pDriver->ValidFormat(Display->Adapter, rsc, Display->BackBpp, IdeDriver::ZPP_D24, Display->FrontBpp))
	{
		if (Display->ZDepth <= 24)
		{
			Display->ZDepth = 24;
			Display->Zpp = IdeDriver::ZPP_D24;
			DEBUGMSG0("QueryFormat: Could not match requested depth format, using D24");
			return deFALSE;
		}
		HighestZ = IdeDriver::ZPP_D24;
	}
	if (pDriver->ValidFormat(Display->Adapter, rsc, Display->BackBpp, IdeDriver::ZPP_D32, Display->FrontBpp))
	{
		if (Display->ZDepth <= 32)
		{
			Display->ZDepth = 32;
			Display->Zpp = IdeDriver::ZPP_D32;
			DEBUGMSG0("QueryFormat: Could not match requested depth format, using D32");
			return deFALSE;
		}
		HighestZ = IdeDriver::ZPP_D32;
	}
	
	// last ditch
	DEBUGMSG1("QueryFormat: Could not match requested z-depth precision (%d-bit)", Display->ZDepth);
	Display->Zpp = HighestZ;
	switch(Display->Zpp)
	{
	default:
		Display->ZDepth = 0;
		break;
	case IdeDriver::ZPP_D16:
		Display->ZDepth = 16;
		break;
	case IdeDriver::ZPP_D24:
		Display->ZDepth = 24;
		break;
	case IdeDriver::ZPP_D32:
		Display->ZDepth = 32;
		break;
	}
	DEBUGMSG1("QueryFormat: Modifying z-depth precision to %d-bit", Display->ZDepth);
	
	return deFALSE;
}

IdeDriver * deRender::GetDriver(HWND hWnd)
{
	IdeDriver * pDriver = NULL;

	// look for an driver that matches this hwnd
	pDriver = AttachToWindow(hWnd, NULL);

	// if it still doesnt have one, return NULL
	return pDriver;
}

deBoolean deRender::InitDriver(IdeDriver * Driver, HWND hWnd, IdeDriver::deDisplay * Display, deBoolean ResetOnly)
{
	long			AdapterCount;
	long			ModeCount;
	IdeDriver::deDisplay	LocalDisplay;
	long			Counter1, Counter2;
	long			Width=0, Height=0;
	int				RefreshRate;
	int				AdapterNum;
	IdeDriver::BPP	Bpp;
	IdeDriver::ZPP	Zpp;
	deBoolean		FullScreen;
	//HDC				DeviceHandle;

	FullScreen = !(Display->Windowed);
	RefreshRate = 0;

	// we want a fullscreen backbuffer no matter what
	// windowed mode gets a full-screen back-buffer so window resizes don't need a reset
	//DeviceHandle = GetDC(hWnd);
	//Width = GetDeviceCaps(DeviceHandle, HORZRES);
	//Height = GetDeviceCaps(DeviceHandle, VERTRES);
	//ReleaseDC(hWnd, DeviceHandle);
	//Width = GetSystemMetrics(SM_CXSCREEN);
	//Height = GetSystemMetrics(SM_CYSCREEN);
	size_t i;
	for (i = 0; i < m_DriverList.Length(); i++)
	{
		if (hWnd == m_DriverList[i].DriverWindow)
		{
			Width = m_DriverList[i].FullWidth;
			Height = m_DriverList[i].FullHeight;
			break;
		}
	}
	if (i >= m_DriverList.Length())
		return deFALSE;
	if (FullScreen)
	{
		if (Display)
		{
			// if the user specified a display for fullscreen, we use it
			Width = Display->Width;
			Height = Display->Height;
			Bpp = Display->BackBpp;
			Zpp = Display->Zpp;
			AdapterNum = Display->Adapter;
			RefreshRate = Display->RefreshRate;
		}
		else
		{
			// if no display, just use the current screen resolution
			Bpp = IdeDriver::BPP_UNKNOWN;
			Zpp = IdeDriver::ZPP_UNKNOWN;
			AdapterNum = -1;
		}
	}
	else
	{
		if (Display)
		{
			Bpp = Display->BackBpp;
			Zpp = Display->Zpp;
			AdapterNum = Display->Adapter;
		}
		else
		{
			Bpp = IdeDriver::BPP_UNKNOWN;
			Zpp = IdeDriver::ZPP_UNKNOWN;
			AdapterNum = -1;
		}
	}

	//go thru all the modes we have available and find one we like
	AdapterCount = Driver->GetAdapterCount();
	for(Counter1 = 0; Counter1 < AdapterCount; Counter1++)
	{
		ModeCount = Driver->GetModeCount(Counter1);
		for(Counter2 = 0; Counter2 < ModeCount; Counter2++)
		{
			Driver->GetDisplayMode(Counter1, Counter2, &LocalDisplay);
			if (AdapterNum < 0 || (LocalDisplay.Adapter == AdapterNum))
			{
				if (Display->Windowed || RefreshRate == 0 || LocalDisplay.RefreshRate == RefreshRate)
				{
					if(Display->Windowed || LocalDisplay.Width == Width && LocalDisplay.Height == Height)
					{
						//if (Bpp == IdeDriver::BPP_UNKNOWN || (LocalDisplay.Bpp == Bpp))
						{
							goto FoundDriver;
						}
					}
				}
			}
			else
				break;
		}
	}

FoundDriver:
	// Bpp is an AND'ed flag, take the one we want
	if (Bpp > IdeDriver::BPP_UNKNOWN && Bpp < IdeDriver::BPP_COUNT)
		LocalDisplay.BackBpp = Bpp;
	else
		LocalDisplay.BackBpp = IdeDriver::BPP_R5G6B5;
	if (Zpp > IdeDriver::ZPP_UNKNOWN && Zpp < IdeDriver::ZPP_COUNT)
		LocalDisplay.Zpp = Zpp;
	else
		LocalDisplay.Zpp = IdeDriver::ZPP_D16;
	LocalDisplay.Windowed = Display->Windowed;
	// test for twinview stuff
	if (Display->Windowed)
	{
		LocalDisplay.Width = Width;
		LocalDisplay.Height = Height;
	}
	LocalDisplay.FrontBpp = Display->FrontBpp;
	LocalDisplay.ZDepth = Display->ZDepth;
	LocalDisplay.StencilDepth = Display->StencilDepth;
	LocalDisplay.IgnoreVSync = Display->IgnoreVSync;
	LocalDisplay.FSAASamples = Display->FSAASamples;
	LocalDisplay.TripleBuffer = Display->TripleBuffer;
	// set the driver's display
	if (ResetOnly)
	{
		if(!Driver->Reset(&LocalDisplay))
		{
			DEBUGRETURN(deFALSE,"InitDriver: Reset() failed");
		}
	}
	else
	{
		if(!Driver->SetDisplay(&LocalDisplay))
		{
			DEBUGRETURN(deFALSE,"InitDriver: SetDisplay() failed");
		}
	}

	// blank the screen while everything gets loaded
	Driver->BeginFrame();
	Driver->ClearFrame(0, deTRUE, deFALSE, deFALSE);
	Driver->EndFrame();

	return deTRUE;
}

void deRender::SetInFrame(HWND hWnd, deBoolean InFrame)
{
	size_t i;
	for (i = 0; i < m_DriverList.Length(); i++)
	{
		if (hWnd == m_DriverList[i].DriverWindow)
		{
			m_DriverList[i].InFrame = InFrame;
		}
	}
}

deBoolean deRender::IsInFrame(HWND hWnd, deBoolean ErrorVal)
{
	size_t i;
	for (i = 0; i < m_DriverList.Length(); i++)
	{
		if (hWnd == m_DriverList[i].DriverWindow)
		{
			return m_DriverList[i].InFrame;
		}
	}
	return ErrorVal;
}

void deRender::RenderPrepBuffer(deRenderObject & obj)
{
	deRenderBatch *CurrentBatch;
	if (!m_RenderBatches.GetNext(NULL, CurrentBatch))
	{
		// you don't have a valid batch
		BREAK_EXECUTION();
		return;
	}
	DWORD dwordarray[3];
#pragma todo (do a more sophisticated sort)
	dwordarray[0] = (DWORD)obj.SurfaceDetail.Texture;
	dwordarray[1] = (DWORD)obj.SurfaceDetail.Material;
	dwordarray[2] = (DWORD)obj.pSurface;
	if (obj.VB)
	{
		CurrentPassDriver()->UpdateVertexBuffer(obj.VB);
		m_RenderStats->VBufferUpdates++;
	}
	if (obj.IndexOverride)
	{
		CurrentPassDriver()->UpdateVertexBuffer(obj.IndexOverride);
		m_RenderStats->VBufferUpdates++;
	}
	int NumLights = 0;
	while (NumLights < DERENDER_MAX_LIGHTS && obj.Lights[NumLights])
	{
		++NumLights;
	}
	m_LightsEncountered = max(m_LightsEncountered, NumLights);

	(CurrentBatch->ObjectTree).AddElement(obj, dwordarray);
}

void deRender::RenderPrepBatch(long Level, IdePortal * Portal, deRect & Viewport, deTransformInfo * PortalPos, deTransformInfo * ConcatM)
{
	deRenderBatch batch;

	batch.PortalLevel = Level;
	batch.Viewport = Viewport;
	// if these are NULL, they will just get set to the identity
	if (PortalPos)
		batch.Position = *PortalPos;
	if (ConcatM)
		batch.Concat = *ConcatM;
	batch.TPortal = Portal;
	if (Portal)
		CurrentPassDriver()->UpdateVertexBuffer(Portal->GetVBuffer());
	m_RenderBatches.AddElementBefore(batch, NULL);
}

deDouble deRender::GetTimeStep()
{
	return m_CurrentTimeStep;
}

deBoolean deRender::SetRenderFlag(RenderFlag_t Flag)
{
	switch (Flag)
	{
	case Render_Dot:
		m_FillState = IdeDriver::FILL_POINT;
		m_RenderMeshOverFill = deFALSE;
		m_RenderSolidWireframe = deFALSE;
		break;

	case Render_Mesh:
		m_FillState = IdeDriver::FILL_WIREFRAME;
		m_RenderMeshOverFill = deFALSE;
		m_RenderSolidWireframe = deFALSE;
		break;

	case Render_Fill:
		m_FillState = IdeDriver::FILL_SOLID;
		m_RenderMeshOverFill = deFALSE;
		m_RenderSolidWireframe = deFALSE;
		break;

	case Render_FillAndMesh:
		m_FillState = IdeDriver::FILL_SOLID;
		m_RenderMeshOverFill = deTRUE;
		m_RenderSolidWireframe = deFALSE;
		break;

	case Render_DepthMesh:
		m_FillState = IdeDriver::FILL_WIREFRAME;
		m_RenderMeshOverFill = deFALSE;
		m_RenderSolidWireframe = deTRUE;
		break;

	case Render_CullCW:
		m_CullState = IdeDriver::CULL_CW;
		break;

	case Render_CullCCW:
		m_CullState = IdeDriver::CULL_CCW;
		break;

	case Render_CullNone:
		m_CullState = IdeDriver::CULL_NONE;
		break;

#if !defined(DESTINY3D_WATERMARK)
	case Render_NoWaterMark:
		m_EnableWaterMark = 0;
		break;

	case Render_WaterMark:
		m_EnableWaterMark = 1;
		break;
		
	case Render_WaterMarkFade:
		m_EnableWaterMark = 2;
		break;
#endif
		
	default:
		DEBUGRETURN(deFALSE,"SetRenderFlag: unknown flag");
		break;
	}
	return deTRUE;
}

deBoolean deRender::SetStencilState(IdeDriver * pDriver, StencilType_t Stencil, DWORD Ref, DWORD X,
									IdeDriver::RenderCmpFunc Comparison,
									IdeDriver::RenderState StencilTest,
									DWORD StencilMask, DWORD WriteMask)
{
	IdeDriver::RenderStencilOp op = IdeDriver::STENCIL_KEEP;

	switch (Stencil)
	{
	case Stencil_UseColor:
		if (Ref)
		{
			pDriver->SetRenderState(IdeDriver::RENDER_COLORMASK, 0xffffffff);
			if (!pDriver->SetRenderState(IdeDriver::RENDER_ALPHABLENDENABLE, deFALSE))
				DEBUGRETURN(deFALSE,"SetStencilState: RENDER_ALPHABLENDENABLE : deFALSE failed");
			pDriver->SetRenderState(IdeDriver::RENDER_SHADEMODE, IdeDriver::SHADE_GOURAUD);
		}
		else
		{
			if (!pDriver->SetRenderState(IdeDriver::RENDER_COLORMASK, 0x00000000))
			{
				if (!pDriver->SetRenderState(IdeDriver::RENDER_ALPHABLENDENABLE, deTRUE))
					DEBUGRETURN(deFALSE,"SetStencilState: RENDER_ALPHABLENDENABLE : deTRUE failed");
				if (!pDriver->SetRenderState(IdeDriver::RENDER_SOURCEBLEND, IdeDriver::BLEND_ZERO))
					DEBUGRETURN(deFALSE,"SetStencilState: RENDER_SOURCEBLEND : BLEND_ZERO failed");
				if (!pDriver->SetRenderState(IdeDriver::RENDER_DESTBLEND, IdeDriver::BLEND_ONE))
					DEBUGRETURN(deFALSE,"SetStencilState: RENDER_DESTBLEND : BLEND_ONE failed");
			}
			pDriver->SetRenderState(IdeDriver::RENDER_SHADEMODE, IdeDriver::SHADE_FLAT);
		}
		return deTRUE;
	case Stencil_Disable:
		break;
	case Stencil_DrawOn:
		if (Comparison == IdeDriver::COMPARE_ALWAYS)
			Comparison = IdeDriver::COMPARE_EQUAL;
		op = IdeDriver::STENCIL_KEEP;
		break;
	case Stencil_SetTo:
		if (Ref == 0)
			op = IdeDriver::STENCIL_ZERO;
		else
			op = IdeDriver::STENCIL_REPLACE;
		break;
	case Stencil_Invert:
		op = IdeDriver::STENCIL_INVERT;
		break;
	case Stencil_Increment:
		if (X)
			op = IdeDriver::STENCIL_INCRWRAP;
		else
			op = IdeDriver::STENCIL_INCR;
		break;
	case Stencil_Decrement:
		if (X)
			op = IdeDriver::STENCIL_DECRWRAP;
		else
			op = IdeDriver::STENCIL_DECR;
		break;
	default:
		return deFALSE;
		break;
	}

	if (Stencil == Stencil_Disable)
	{
		if (!pDriver->SetRenderState(IdeDriver::RENDER_STENCILENABLE, deFALSE))
			DEBUGRETURN(deFALSE,"SetStencilState: RENDER_STENCILENABLE : deFALSE failed");
		return deTRUE;
	}
	else
	{
		if (!pDriver->SetRenderState(IdeDriver::RENDER_STENCILENABLE, deTRUE))
			DEBUGRETURN(deFALSE,"SetStencilState: RENDER_STENCILENABLE : deTRUE failed");
	}
	
	if (!pDriver->SetRenderState(IdeDriver::RENDER_STENCILMASK, StencilMask))
		DEBUGRETURN(deFALSE,"SetStencilState: RENDER_STENCILMASK failed");
	if (!pDriver->SetRenderState(IdeDriver::RENDER_STENCILWRITEMASK, WriteMask))
		DEBUGRETURN(deFALSE,"SetStencilState: RENDER_STENCILWRITEMASK failed");
	if (!pDriver->SetRenderState(IdeDriver::RENDER_STENCILREF, Ref))
		DEBUGRETURN(deFALSE,"SetStencilState: RENDER_STENCILREF failed");
	if (!pDriver->SetRenderState(IdeDriver::RENDER_STENCILFUNCTION, Comparison))
		DEBUGRETURN(deFALSE,"SetStencilState: RENDER_STENCILFUNCTION failed");
	
	pDriver->SetRenderState(StencilTest, op);
	if (StencilTest != IdeDriver::RENDER_STENCILFAIL)
	{
		if (!pDriver->SetRenderState(IdeDriver::RENDER_STENCILFAIL, IdeDriver::STENCIL_KEEP))
			DEBUGRETURN(deFALSE,"SetStencilState: RENDER_STENCILFAIL : STENCIL_KEEP failed");
	}
	if (StencilTest != IdeDriver::RENDER_STENCILFAIL)
	{
		if (!pDriver->SetRenderState(IdeDriver::RENDER_STENCILZFAIL, IdeDriver::STENCIL_KEEP))
			DEBUGRETURN(deFALSE,"SetStencilState: RENDER_STENCILZFAIL : STENCIL_KEEP failed");
	}
	if (StencilTest != IdeDriver::RENDER_STENCILFAIL)
	{
		if (!pDriver->SetRenderState(IdeDriver::RENDER_STENCILPASS, IdeDriver::STENCIL_KEEP))
			DEBUGRETURN(deFALSE,"SetStencilState: RENDER_STENCILPASS : STENCIL_KEEP failed");
	}

	return deTRUE;
}

void deRender::UpdateWindow(HWND hWnd)
{
	IdeDriver *pDriver = GetDriver(hWnd);
	pDriver->UpdateWindowRect();
}

void deRender::UpdateDisplay()
{
	DEBUGMSG0("UpdateDisplay");
	size_t i;
	for (i = 0; i < m_DriverList.size(); ++i)
	{
		// don't want to grab the resolution change when we're changing it
		if (!m_DriverList[i].SettingMode)
		{
			HDC				DeviceHandle;
			DeviceHandle = GetDC(m_DriverList[i].DriverWindow);
			m_DriverList[i].FullWidth = GetDeviceCaps(DeviceHandle, HORZRES);
			m_DriverList[i].FullHeight = GetDeviceCaps(DeviceHandle, VERTRES);
			ReleaseDC(m_DriverList[i].DriverWindow, DeviceHandle);
		}
	}
}

void deRender::SetBGColor(deARGB color)
{
	m_BGColor = color;
}

void deRender::SetMaxTPortalDepth(long Depth)
{
	m_TPortalDepth = min (0,Depth);
}

void deRender::SetMaxLights(long MaxHWLights, long MaxTexLights)
{
	m_MaxHWLights =  min(0, MaxHWLights);
	m_MaxTexLights = min(0, MaxTexLights);
}

void deRender::EnableTexturing(deBoolean Enabled)
{
	m_TexturesEnabled = Enabled;
}

deBoolean deRender::Use2DCollection(HWND hWnd, Ide2DCollection * Collection)
{
	size_t i;
	for (i = 0; i < m_DriverList.Length(); i++)
	{
		if (hWnd == m_DriverList[i].DriverWindow)
		{
			Collection->Claim();
			if (m_DriverList[i]._2D)
				m_DriverList[i]._2D->Release();
			m_DriverList[i]._2D = Collection;
			return deTRUE;
		}
	}
	return deFALSE;
}

Ide2DCollection * deRender::Get2DCollection(HWND hWnd)
{
	size_t i;
	for (i = 0; i < m_DriverList.Length(); i++)
	{
		if (hWnd == m_DriverList[i].DriverWindow)
		{
			return m_DriverList[i]._2D;
		}
	}
	return NULL;
}

void deRender::SetStatStruct(deRenderStats * StatStruct)
{
	#ifdef _DEBUG
	// if a bad value is passed in, this should cause an access violation
	StatStruct->VertexRenders = 0;
	#endif
	m_RenderStats = StatStruct;
}

long deRender::GetFrameNum()
{
	return m_FrameNum;
}

