//
// Asura_Direct3D_UserOptions.cpp
//
// Created by KJL - 03/09/2003 13:44:42
//
// Copyright (C) 2003 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"

// This file's header.
#include "Rendering/Asura_Direct3D_UserOptions.h"
#include "Core/Asura_TextureManagement.h"
#include "Core/Asura_Windows.h"
#include "FSFX/Asura_FSFX_System.h"
#include "Interface/Asura_CommandConsole.h"
#include "Registry/Asura_PC_WindowsRegistry.h"
#include "Rendering/Asura_Direct3D.h"
#include "Rendering/Asura_Direct3D_Caps.h"
#include "Rendering/Asura_Viewport.h"
#include "Shadows/Asura_Shadow_System.h"

Asura_Direct3D_UserOptions::Options	Asura_Direct3D_UserOptions::s_xCurrentOptions;
Asura_List<Asura_Direct3D_UserOptions::ResolutionInfoList>	Asura_Direct3D_UserOptions::s_xEnumDisplayModes;

u_int Asura_Direct3D_UserOptions::s_uTextureDetailBasic = BASIC_SETTING_HIGH;
u_int Asura_Direct3D_UserOptions::s_uShaderQualityBasic = BASIC_SETTING_HIGH;
u_int Asura_Direct3D_UserOptions::s_uShadowQualityBasic = BASIC_SETTING_HIGH;
u_int Asura_Direct3D_UserOptions::s_uVisualDetailBasic = BASIC_SETTING_HIGH;

Asura_Direct3D_UserOptions::TextureDetailSetting Asura_Direct3D_UserOptions::s_xTextureDetail( BASIC_SETTING_HIGH );
Asura_Direct3D_UserOptions::ShaderQualitySetting Asura_Direct3D_UserOptions::s_xShaderQuality( BASIC_SETTING_HIGH );
Asura_Direct3D_UserOptions::ShadowQualitySetting Asura_Direct3D_UserOptions::s_xShadowQuality( BASIC_SETTING_HIGH );
Asura_Direct3D_UserOptions::VisualDetailSetting Asura_Direct3D_UserOptions::s_xVisualDetail( BASIC_SETTING_HIGH );

Asura_Direct3D_UserOptions::Options::Options()
: m_uDefaultWidth( 1280), 
  m_uDefaultHeight( 720),
  m_bTrilinearFilteringOn(true),
  m_eTextureDetail(TEXTURE_DETAIL_HIGH),
  m_fGammaSetting(0.5f),
  m_uAnisotropySetting(0),
  m_eSmoothSkinShadowSetting(SHADOW_PLANAR),
  m_eObjectHierarchyShadowSetting(SHADOW_PLANAR),
  m_eObjectShadowSetting(SHADOW_PLANAR),
#ifdef ASURA_TARGET_SM3
  m_bFilterShadows(true),
#endif
#ifdef ASURA_SUPPORT_MULTIPLE_MONITORS
  m_bMultiheadEnabled(false),
#endif
  m_uAdapterIndex(D3DADAPTER_DEFAULT),
  m_eFrontBufferFormat(D3DFMT_X8R8G8B8),
  m_eBackBufferFormat(D3DFMT_X8R8G8B8),
  m_eDepthStencilFormat(D3DFMT_D24S8),
  m_uBackBufferCount(1),
  m_eMultiSampleType(D3DMULTISAMPLE_NONE),
  m_uMultiSampleQuality(0),
  m_eSwapEffect(D3DSWAPEFFECT_DISCARD),
  m_uRefreshRate(60),
  m_uPresentationInterval(D3DPRESENT_INTERVAL_IMMEDIATE),
  m_eDevType(D3DDEVTYPE_HAL),
  m_eRenderTargetBufferFormat(D3DFMT_A8R8G8B8),
  m_eRenderTargetDepthFormat(D3DFMT_D24S8),
  m_bMultiThreadingEnabled( false)
{
}

Asura_Direct3D_UserOptions::Options::Options(const Options& xOther)
{
	*this = xOther;
}

Asura_Direct3D_UserOptions::Options& Asura_Direct3D_UserOptions::Options::operator =(const Options& xOther)
{
#if 0 && defined( _DEBUG)
	memset( this, 0xCC, sizeof(Asura_Direct3D_UserOptions::Options));
#endif
	m_uDefaultWidth						= xOther.m_uDefaultWidth;
	m_uDefaultHeight					= xOther.m_uDefaultHeight;
	m_bTrilinearFilteringOn				= xOther.m_bTrilinearFilteringOn;
	m_eTextureDetail					= xOther.m_eTextureDetail;
	m_fGammaSetting						= xOther.m_fGammaSetting;
	m_uAnisotropySetting				= xOther.m_uAnisotropySetting;
	m_eSmoothSkinShadowSetting			= xOther.m_eSmoothSkinShadowSetting;
	m_eObjectHierarchyShadowSetting		= xOther.m_eObjectHierarchyShadowSetting;
	m_eObjectShadowSetting				= xOther.m_eObjectShadowSetting;
#ifdef ASURA_TARGET_SM3
	m_bFilterShadows					= xOther.m_bFilterShadows;
#endif
#ifdef ASURA_SUPPORT_MULTIPLE_MONITORS
	m_bMultiheadEnabled					= xOther.m_bMultiheadEnabled;
#endif
	m_uAdapterIndex						= xOther.m_uAdapterIndex;
	m_eFrontBufferFormat				= xOther.m_eFrontBufferFormat;
	m_eBackBufferFormat					= xOther.m_eBackBufferFormat;
	m_eDepthStencilFormat				= xOther.m_eDepthStencilFormat;
	m_uBackBufferCount					= xOther.m_uBackBufferCount;
	m_eMultiSampleType					= xOther.m_eMultiSampleType;
	m_uMultiSampleQuality				= xOther.m_uMultiSampleQuality;
	m_eSwapEffect						= xOther.m_eSwapEffect;
	m_uRefreshRate						= xOther.m_uRefreshRate;
	m_uPresentationInterval				= xOther.m_uPresentationInterval;
	m_eDevType							= xOther.m_eDevType;
	m_eRenderTargetBufferFormat			= xOther.m_eRenderTargetBufferFormat;
	m_eRenderTargetDepthFormat			= xOther.m_eRenderTargetDepthFormat;
	m_bMultiThreadingEnabled			= xOther.m_bMultiThreadingEnabled;

	return *this;
}

Asura_Direct3D_UserOptions::Options::~Options()
{
	DeleteAllBackBufferDimensions();
}

bool Asura_Direct3D_UserOptions::Options::Validate()
{
	Direct3D_Object* pxD3DObjectRelease = NULL;
	Direct3D_Object* pxD3DObject = Asura_Direct3D::D3DObject;
	bool bValidated = false;

	do
	{
		// DLH - 25 July 2006 16:18:07 - If D3DObject has not been created yet.
		if(NULL == pxD3DObject)
		{
			pxD3DObject = Direct3DCreate9(D3D_SDK_VERSION);
			Asura_Assert( NULL == pxD3DObject,"Unable to create D3D object");

			if( NULL == pxD3DObject)
			{
				break;
			}
			pxD3DObjectRelease = pxD3DObject;
		}

#if 0
		UINT uAdaptorCount = pxD3DObject->GetAdapterCount();
		for( u_int uAdaptorIndex = 0; uAdaptorIndex < uAdaptorCount; uAdaptorIndex += 1)
		{

		}
#endif

		bValidated = true;
	}
	while( false);

	if( NULL != pxD3DObjectRelease)
	{
		pxD3DObjectRelease->Release();
	}

	return( bValidated);
}

void Asura_Direct3D_UserOptions::Options::DeleteAllBackBufferDimensions()
{
	Asura_List_It<ScreenResolution> xIt(&m_xWindowedScreenResolutions);
	while(!xIt.Done())
	{
		delete xIt.GetCurrent();
		xIt.DeleteCurrent();
	}

	Asura_List_It<ScreenResolution> xIt2(&m_xFullscreenScreenResolutions);
	while(!xIt2.Done())
	{
		delete xIt2.GetCurrent();
		xIt2.DeleteCurrent();
	}
}

u_int Asura_Direct3D_UserOptions::Options::GetBackBufferWidth(int iScreenIndex /* = 0 */) const
{
	Asura_List_ConstIt<ScreenResolution> xIt(Asura_Windows::RunningFullScreen() ? &m_xFullscreenScreenResolutions : &m_xWindowedScreenResolutions);
	while(!xIt.Done())
	{
		if(xIt.GetCurrent()->m_iScreen == iScreenIndex)
		{
			if(xIt.GetCurrent()->m_uWidth != -1) 
				return xIt.GetCurrent()->m_uWidth;
			break;
		}
		xIt.Next();
	}
//	return Asura_Direct3D_UserOptions::DEFAULT_BACKBUFFER_WIDTH;
	return Asura_Direct3D_UserOptions::GetCurrentOptions().m_uDefaultWidth;
}

u_int Asura_Direct3D_UserOptions::Options::GetBackBufferHeight(int iScreenIndex /* = 0 */) const
{
	Asura_List_ConstIt<ScreenResolution> xIt(Asura_Windows::RunningFullScreen() ? &m_xFullscreenScreenResolutions : &m_xWindowedScreenResolutions);
	while(!xIt.Done())
	{
		if(xIt.GetCurrent()->m_iScreen == iScreenIndex)
		{ 
			if(xIt.GetCurrent()->m_uHeight != -1) 
				return xIt.GetCurrent()->m_uHeight;
			break;
		}
		xIt.Next();
	}
//	return Asura_Direct3D_UserOptions::DEFAULT_BACKBUFFER_HEIGHT;
	return Asura_Direct3D_UserOptions::GetCurrentOptions().m_uDefaultHeight;
}

void Asura_Direct3D_UserOptions::Options::SetBackBufferWidth(u_int dwWidth, int iScreenIndex /* = 0  */, bool bForceWriteToWindowedSettings /* = false */, bool bForceWriteToFullscreenSettings /* = false */)
{
	Asura_Assert(!(bForceWriteToWindowedSettings && bForceWriteToFullscreenSettings), "Both of these flags cannot be set!");
	Asura_List<ScreenResolution>& xScreenResolutions = ((Asura_Windows::RunningFullScreen() || bForceWriteToFullscreenSettings) && !bForceWriteToWindowedSettings) ? m_xFullscreenScreenResolutions : m_xWindowedScreenResolutions;

	Asura_List_It<ScreenResolution> xIt(xScreenResolutions);
	while(!xIt.Done())
	{
		if(xIt.GetCurrent()->m_iScreen == iScreenIndex)
		{
			xIt.GetCurrent()->m_uWidth = dwWidth;
			return;
		}
		xIt.Next();
	}
	// Not found - create a new record
	xScreenResolutions.AddToList(new ScreenResolution(iScreenIndex, dwWidth, (u_int)-1));
}

void Asura_Direct3D_UserOptions::Options::SetBackBufferHeight(u_int dwHeight, int iScreenIndex /* = 0  */, bool bForceWriteToWindowedSettings /* = false */, bool bForceWriteToFullscreenSettings /* = false */)
{
	Asura_Assert(!(bForceWriteToWindowedSettings && bForceWriteToFullscreenSettings), "Both of these flags cannot be set!");
	Asura_List<ScreenResolution>& xScreenResolutions = ((Asura_Windows::RunningFullScreen() || bForceWriteToFullscreenSettings) && !bForceWriteToWindowedSettings) ? m_xFullscreenScreenResolutions : m_xWindowedScreenResolutions;


	Asura_List_It<ScreenResolution> xIt(xScreenResolutions);
	while(!xIt.Done())
	{
		if(xIt.GetCurrent()->m_iScreen == iScreenIndex)
		{
			xIt.GetCurrent()->m_uHeight = dwHeight;
			return;
		}
		xIt.Next();
	}
	xScreenResolutions.AddToList(new ScreenResolution(iScreenIndex, (u_int)-1, dwHeight));
}

void Asura_Direct3D_UserOptions::Options::SetBackBufferDimensions(u_int dwWidth, u_int dwHeight, int iScreenIndex /* = 0  */)
{
	Asura_List<ScreenResolution>& xScreenResolutions = Asura_Windows::RunningFullScreen() ? m_xFullscreenScreenResolutions : m_xWindowedScreenResolutions;

	Asura_List_It<ScreenResolution> xIt(xScreenResolutions);
	while(!xIt.Done())
	{
		if(xIt.GetCurrent()->m_iScreen == iScreenIndex)
		{
			xIt.GetCurrent()->m_uWidth = dwWidth;
			xIt.GetCurrent()->m_uHeight = dwHeight;
			return;
		}
		xIt.Next();
	}
	xScreenResolutions.AddToList(new ScreenResolution(iScreenIndex, dwWidth, dwHeight));
}

Asura_Direct3D_UserOptions::TextureDetailSetting::TextureDetailSetting( BASIC_SETTING xSetting /*= High*/ )
{
	switch ( xSetting )
	{
	case BASIC_SETTING_LOW:
		{
			m_eTexDetail = TEXTURE_DETAIL_VERY_LOW;
			m_bTrilinearFiltering = false;
			m_uAnisotropicFiltering = 0;
			break;
		}
	case BASIC_SETTING_MEDIUM:
		{
			m_eTexDetail = TEXTURE_DETAIL_MEDIUM;
			m_bTrilinearFiltering = true;
			m_uAnisotropicFiltering = 2;
			break;
		}
	case BASIC_SETTING_HIGH:
		{
			m_eTexDetail = TEXTURE_DETAIL_HIGH;
			m_bTrilinearFiltering = true;
			m_uAnisotropicFiltering = 4;
			break;
		}
	case BASIC_SETTING_CUSTOM:	// Leave this group of settings alone
	default:
		{
			break;
		}
	}
}

Asura_Direct3D_UserOptions::BASIC_SETTING Asura_Direct3D_UserOptions::TextureDetailSetting::GetBasicSetting( void )
{
	if ( *this == TextureDetailSetting( BASIC_SETTING_LOW ) )
	{
		return BASIC_SETTING_LOW;
	}
	else if ( *this == TextureDetailSetting( BASIC_SETTING_MEDIUM ) )
	{
		return BASIC_SETTING_MEDIUM;
	}
	else if ( *this == TextureDetailSetting( BASIC_SETTING_HIGH ) )
	{
		return BASIC_SETTING_HIGH;
	}
	else
	{
		return BASIC_SETTING_CUSTOM;
	}
}

void Asura_Direct3D_UserOptions::TextureDetailSetting::ApplySettings( void )
{
	// Project_ApplySettings can return false to prevent default 'Apply Settings' from being called
	if ( Project_ApplySettings() )
	{
		Asura_Direct3D_UserOptions::SetTextureDetail( static_cast<TEXTURE_DETAIL>( m_eTexDetail ) );
		Asura_Direct3D_UserOptions::ApplyTextureDetailSettings();

		Asura_Direct3D_UserOptions::SetTrilinearFiltering( m_bTrilinearFiltering );
		if ( m_uAnisotropicFiltering > Asura_Direct3D_UserOptions::GetMaxAnisotropySetting() )
		{
			m_uAnisotropicFiltering = Asura_Direct3D_UserOptions::GetMaxAnisotropySetting();
		}
		Asura_Direct3D_UserOptions::SetAnisotropicFilteringSetting( m_uAnisotropicFiltering );
	}
}

bool Asura_Direct3D_UserOptions::TextureDetailSetting::operator==( const TextureDetailSetting& xOther )
{
	if ( m_eTexDetail != xOther.m_eTexDetail )
	{
		return false;
	}
	if ( m_bTrilinearFiltering != xOther.m_bTrilinearFiltering )
	{
		return false;
	}
	if ( m_uAnisotropicFiltering != xOther.m_uAnisotropicFiltering )
	{
		return false;
	}

	return true;
}

#ifdef ASURA_PC_SUPPORT_WINDOWS_REGISTRY

void Asura_Direct3D_UserOptions::TextureDetailSetting::WriteSettingsToRegistry(  const char* const pszSubKey)
{
	Asura_PC_WindowsRegistry xRegistry;

	xRegistry.WriteNumber( pszSubKey, "Tex_Detail", m_eTexDetail);
	xRegistry.WriteNumber( pszSubKey, "Tex_TrilinearFiltering", m_bTrilinearFiltering);
	xRegistry.WriteNumber( pszSubKey, "Tex_AnisotropicFiltering", m_uAnisotropicFiltering);
}

void Asura_Direct3D_UserOptions::TextureDetailSetting::ReadSettingsFromRegistry(  const char* const pszSubKey)
{
	u_int uReadVal;
	Asura_PC_WindowsRegistry xRegistry;

	xRegistry.ReadNumber( pszSubKey, "Tex_Detail", &m_eTexDetail);

	if( xRegistry.ReadNumber( pszSubKey, "Tex_TrilinearFiltering", &uReadVal))
	{
		m_bTrilinearFiltering = (uReadVal != 0);
	}

	xRegistry.ReadNumber( pszSubKey, "Tex_AnisotropicFiltering", &m_uAnisotropicFiltering);
}

#endif


Asura_Direct3D_UserOptions::ShaderQualitySetting::ShaderQualitySetting( BASIC_SETTING xSetting )
{
	// No settings yet
}

Asura_Direct3D_UserOptions::BASIC_SETTING Asura_Direct3D_UserOptions::ShaderQualitySetting::GetBasicSetting( void )
{
	// No settings yet
	return BASIC_SETTING_HIGH;
}

void Asura_Direct3D_UserOptions::ShaderQualitySetting::ApplySettings( void )
{
	// Project_ApplySettings can return false to prevent default 'Apply Settings' from being called
	if ( Project_ApplySettings() )
	{
		// No settings yet
	}
}

#ifdef ASURA_PC_SUPPORT_WINDOWS_REGISTRY
void Asura_Direct3D_UserOptions::ShaderQualitySetting::WriteSettingsToRegistry(  const char* const pszSubKey)
{
}

void Asura_Direct3D_UserOptions::ShaderQualitySetting::ReadSettingsFromRegistry(  const char* const pszSubKey)
{
}
#endif


bool Asura_Direct3D_UserOptions::ShaderQualitySetting::operator==( const ShaderQualitySetting& xOther )
{
	// No settings yet
	return true;
}

Asura_Direct3D_UserOptions::ShadowQualitySetting::ShadowQualitySetting( BASIC_SETTING xSetting )
{
	switch ( xSetting )
	{
	case BASIC_SETTING_OFF:
		{
			// No shadowing at all
			m_bShadowsEnabled = false;
			m_bFilterShadows = false;
			m_bBlobShadowsEnabled = true;
			break;
		}
	case BASIC_SETTING_MEDIUM:
		{
			// Just blob shadows
			m_bShadowsEnabled = true;
			m_bFilterShadows = false;
			m_bBlobShadowsEnabled = false;
			break;
		}
	case BASIC_SETTING_HIGH:
		{
			// 'Real' shadows
			m_bShadowsEnabled = true;
			m_bFilterShadows = true;
			m_bBlobShadowsEnabled = false;
			break;
		}
	case BASIC_SETTING_CUSTOM:	// Leave this group of settings alone
	default:
		{
			break;
		}
	}
}

Asura_Direct3D_UserOptions::BASIC_SETTING Asura_Direct3D_UserOptions::ShadowQualitySetting::GetBasicSetting( void )
{
	// Find matching setting or return custom
	if ( *this == ShadowQualitySetting( BASIC_SETTING_OFF ) )
	{
		return BASIC_SETTING_OFF;
	}
	else if ( *this == ShadowQualitySetting( BASIC_SETTING_MEDIUM ) )
	{
		return BASIC_SETTING_MEDIUM;
	}
	else if ( *this == ShadowQualitySetting( BASIC_SETTING_HIGH ) )
	{
		return BASIC_SETTING_HIGH;
	}
	else
	{
		return BASIC_SETTING_CUSTOM;
	}
}

void Asura_Direct3D_UserOptions::ShadowQualitySetting::ApplySettings( void )
{
	// Project_ApplySettings can return false to prevent default 'Apply Settings' from being called
	// Is it worth putting in a check to stop both blob and normal shadows being used at once?
	if ( Project_ApplySettings() )
	{
		Asura_Shadow_System::EnableShadows( m_bShadowsEnabled );
		#ifdef ASURA_TARGET_SM3
		Asura_Direct3D_UserOptions::SetFilterShadows( m_bFilterShadows );
		#endif
		// ToDo: Blob shadow setting will take effect when a system exists for blob shadows
	}
}

#ifdef ASURA_PC_SUPPORT_WINDOWS_REGISTRY
void Asura_Direct3D_UserOptions::ShadowQualitySetting::WriteSettingsToRegistry(  const char* const pszSubKey)
{
	Asura_PC_WindowsRegistry xRegistry;

	xRegistry.WriteNumber( pszSubKey, "Shadows_Enabled", m_bShadowsEnabled);
	xRegistry.WriteNumber( pszSubKey, "Shadows_Filtered", m_bFilterShadows);
	xRegistry.WriteNumber( pszSubKey, "Shadows_BlobsEnabled", m_bBlobShadowsEnabled);
}

void Asura_Direct3D_UserOptions::ShadowQualitySetting::ReadSettingsFromRegistry(  const char* const pszSubKey)
{
	u_int uRegVal;
	Asura_PC_WindowsRegistry xRegistry;

	if( xRegistry.ReadNumber( pszSubKey, "Shadows_Enabled", &uRegVal))
	{
		m_bShadowsEnabled = (uRegVal != 0);
	}

	if( xRegistry.ReadNumber( pszSubKey, "Shadows_Filtered", &uRegVal))
	{
		m_bFilterShadows = (uRegVal != 0);
	}

	if( xRegistry.ReadNumber( pszSubKey, "Shadows_BlobsEnabled", &uRegVal))
	{
		m_bBlobShadowsEnabled = (uRegVal != 0);
	}
}
#endif

bool Asura_Direct3D_UserOptions::ShadowQualitySetting::operator==( const ShadowQualitySetting& xOther )
{
	if ( m_bShadowsEnabled != xOther.m_bShadowsEnabled )
	{
		return false;
	}
	if ( m_bBlobShadowsEnabled != xOther.m_bBlobShadowsEnabled )
	{
		return false;
	}
	if ( m_bFilterShadows != xOther.m_bFilterShadows )
	{
		return false;
	}

	return true;
}

Asura_Direct3D_UserOptions::VisualDetailSetting::VisualDetailSetting( BASIC_SETTING xSetting )
{
	switch ( xSetting )
	{
	case BASIC_SETTING_LOW:
		{
			m_bSimplifyFSFX = true;
			break;
		}
	case BASIC_SETTING_MEDIUM:
		{
			m_bSimplifyFSFX = false; 
			break;
		}
	case BASIC_SETTING_HIGH:
		{
			m_bSimplifyFSFX = false; 
			break;
		}
	case BASIC_SETTING_CUSTOM:	// Leave this group of settings alone
	default:
		{
			break;
		}
	}
}

Asura_Direct3D_UserOptions::BASIC_SETTING Asura_Direct3D_UserOptions::VisualDetailSetting::GetBasicSetting( void )
{
	// At the moment Low and Medium are actually identical - this will change when there are more settings
	if ( *this == VisualDetailSetting( BASIC_SETTING_LOW ) )
	{
		return BASIC_SETTING_LOW;
	}
	else if ( *this == VisualDetailSetting( BASIC_SETTING_MEDIUM ) )
	{
		return BASIC_SETTING_MEDIUM;
	}
	else if ( *this == VisualDetailSetting( BASIC_SETTING_HIGH ) )
	{
		return BASIC_SETTING_HIGH;
	}
	else
	{
		return BASIC_SETTING_CUSTOM;
	}
}

void Asura_Direct3D_UserOptions::VisualDetailSetting::ApplySettings( void )
{
	// Project_ApplySettings can return false to prevent default 'Apply Settings' from being called
	if ( Project_ApplySettings() )
	{
		//TODO: TY 14.07.08 - Force FSFX system to only render essential effects
		//Asura_FSFX_System::SetRenderOnlyEssentialEffects( m_bSimplifyFSFX );
	}
}

#ifdef ASURA_PC_SUPPORT_WINDOWS_REGISTRY

void Asura_Direct3D_UserOptions::VisualDetailSetting::WriteSettingsToRegistry(  const char* const pszSubKey)
{
	Asura_PC_WindowsRegistry xRegistry;

	xRegistry.WriteNumber( pszSubKey, "Visual_SimplifyFSFX", m_bSimplifyFSFX);
}

void Asura_Direct3D_UserOptions::VisualDetailSetting::ReadSettingsFromRegistry(  const char* const pszSubKey)
{
	u_int uRegVal;
	Asura_PC_WindowsRegistry xRegistry;

	if( xRegistry.ReadNumber( pszSubKey, "Visual_SimplifyFSFX", &uRegVal))
	{
		m_bSimplifyFSFX = (uRegVal != 0);
	}
}
#endif

bool Asura_Direct3D_UserOptions::VisualDetailSetting::operator==( const VisualDetailSetting& xOther )
{
	if ( m_bSimplifyFSFX != xOther.m_bSimplifyFSFX )
	{
		return false;
	}

	return true;
}

void Asura_Direct3D_UserOptions::SetupDVSInterface( void )
{

	// Add basic settings
	Asura_CommandConsole::AddCmd( L"Render.UserOptions.Basic.Apply", ConsoleCmd_ApplyBasicSettings, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );

	Asura_CommandConsole::AddVar( L"Render.UserOptions.Basic.TextureDetail", &s_uTextureDetailBasic, 0, 3, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"Render.UserOptions.Basic.ShaderQuality", &s_uShaderQualityBasic, 0, 3, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"Render.UserOptions.Basic.ShadowQuality", &s_uShadowQualityBasic, 0, 3, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"Render.UserOptions.Basic.VisualDetail", &s_uVisualDetailBasic, 0, 3, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );

	// Add advanced settings
	Asura_CommandConsole::AddCmd( L"Render.UserOptions.Advanced.Apply", ConsoleCmd_ApplyAdvancedSettings, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );

	// Texture detail
	Asura_CommandConsole::AddVar( L"Render.UserOptions.Advanced.TextureDetail", &s_xTextureDetail.m_eTexDetail, 0, 3, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"Render.UserOptions.Advanced.TrilinearFiltering", &s_xTextureDetail.m_bTrilinearFiltering, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"Render.UserOptions.Advanced.AnisotropicFiltering", &s_xTextureDetail.m_uAnisotropicFiltering, 0, GetMaxAnisotropySetting(), Asura_CommandConsole::REMOVE_AT_SHUTDOWN );

	// Shadow Quality
	Asura_CommandConsole::AddVar( L"Render.UserOptions.Advanced.EnableShadows", &s_xShadowQuality.m_bShadowsEnabled, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"Render.UserOptions.Advanced.EnableShadowFiltering", &s_xShadowQuality.m_bFilterShadows, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );
	Asura_CommandConsole::AddVar( L"Render.UserOptions.Advanced.EnableBlobShadows", &s_xShadowQuality.m_bBlobShadowsEnabled, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );

	// Visual detail
	Asura_CommandConsole::AddVar( L"Render.UserOptions.Advanced.SimplifyFSFX", &s_xVisualDetail.m_bSimplifyFSFX, Asura_CommandConsole::REMOVE_AT_SHUTDOWN );

}

bool Asura_Direct3D_UserOptions::ConsoleCmd_ApplyBasicSettings( bool bHelp )
{
	if ( bHelp )
	{
		Asura_CommandConsole::Printf( L"Render.UserOptions.Basic.Apply\n" );
		Asura_CommandConsole::Printf( L"Apply basic graphics settings and update advanced settings as appropriate.\n" );
	}
	else
	{

		// Overwrite and apply the advanced settings if not set to custom

		if ( s_uTextureDetailBasic != BASIC_SETTING_CUSTOM )
		{
			s_xTextureDetail = TextureDetailSetting( static_cast<BASIC_SETTING>( s_uTextureDetailBasic ) );
			s_xTextureDetail.ApplySettings();
		}

		if ( s_uShaderQualityBasic != BASIC_SETTING_CUSTOM )
		{
			s_xShaderQuality = ShaderQualitySetting( static_cast<BASIC_SETTING>( s_uShaderQualityBasic ) );
			s_xShaderQuality.ApplySettings();
		}

		if ( s_uShadowQualityBasic != BASIC_SETTING_CUSTOM )
		{
			s_xShadowQuality = ShadowQualitySetting( static_cast<BASIC_SETTING>( s_uShadowQualityBasic ) );
			s_xShadowQuality.ApplySettings();
		}

		if ( s_uVisualDetailBasic != BASIC_SETTING_CUSTOM )
		{
			s_xVisualDetail = VisualDetailSetting( static_cast<BASIC_SETTING>( s_uVisualDetailBasic ) );
			s_xVisualDetail.ApplySettings();
		}

	}
	return true;
}

bool Asura_Direct3D_UserOptions::ConsoleCmd_ApplyAdvancedSettings( bool bHelp )
{
	if ( bHelp )
	{
		Asura_CommandConsole::Printf( L"Render.UserOptions.Advanced.Apply\n" );
		Asura_CommandConsole::Printf( L"Apply advanced graphics settings and update basic settings to custom as appropriate.\n" );
	}
	else
	{

		// Apply the advanced settings and refresh the basic setting knobs

		s_xTextureDetail.ApplySettings();
		s_uTextureDetailBasic = s_xTextureDetail.GetBasicSetting();

		s_xShaderQuality.ApplySettings();
		s_uShaderQualityBasic = s_xShaderQuality.GetBasicSetting();

		s_xShadowQuality.ApplySettings();
		s_uShadowQualityBasic = s_xShadowQuality.GetBasicSetting();

		s_xVisualDetail.ApplySettings();
		s_uVisualDetailBasic = s_xVisualDetail.GetBasicSetting();

	}
	return true;
}

bool Asura_Direct3D_UserOptions::ValidateOptions( Options& xOptions)
{
	return xOptions.Validate();
}

bool Asura_Direct3D_UserOptions::GetAllOptions( Options& xOptions)
{
	xOptions = s_xCurrentOptions;
	return( true);
}

bool Asura_Direct3D_UserOptions::SetAllOptions( Options& xOptions)
{
	s_xCurrentOptions = xOptions; 
	return( true);
}

bool Asura_Direct3D_UserOptions::BuildPresentParameters( D3DPRESENT_PARAMETERS& xParameters, int iScreenIndex /* = 0 */ )
{
	HRESULT xResult;
	u_int uRequiredRefreshRate = 0;
	D3DFORMAT xFormat = D3DFMT_UNKNOWN;

	xParameters.BackBufferWidth		= s_xCurrentOptions.GetBackBufferWidth(iScreenIndex);
	xParameters.BackBufferHeight	= s_xCurrentOptions.GetBackBufferHeight(iScreenIndex);

	if(Asura_Windows::RunningFullScreen())
	{
		// check that this resolution is actually supported on the current adapter, and drop it down to the closest smaller resolution if not
		if(!Asura_Direct3D::D3DObject) Asura_Direct3D::CreateD3DObject();
		const Asura_List<ResolutionInfo>& xSupportedResolutions = *GetSupportedResolutions(GetAdapterIndex() + iScreenIndex);
		Asura_List_ConstIt<ResolutionInfo> xIt(&xSupportedResolutions);
		bool bFound = false;
		D3DDISPLAYMODE xBestMode = { 0, 0, 0, D3DFMT_UNKNOWN };
		D3DDISPLAYMODE xFoundMode = { 0, 0, 0, D3DFMT_UNKNOWN };
		while(!xIt.Done())
		{
			// JEB 19/05/2008 - Don't check for refresh rate compatibility (allows Dell widescreen monitors & Vista to work in full screen).
			const D3DDISPLAYMODE& xThisMode = xIt.GetCurrent()->m_xModeData;
			if( xThisMode.Width == xParameters.BackBufferWidth
			 && xThisMode.Height == xParameters.BackBufferHeight)
//			 && xThisMode.RefreshRate == GetRefreshRate() )
			{
				// The originally requested resolution is supported
				xFoundMode = xThisMode;
				bFound = true;
				break;
			}
			if((xThisMode.Width <= xParameters.BackBufferWidth) && (xThisMode.Height <= xParameters.BackBufferHeight)
			 && (xThisMode.Width >= xBestMode.Width) && (xThisMode.Height >= xBestMode.Height))
//			 && (xThisMode.RefreshRate == GetRefreshRate()))
			{
				xBestMode = xThisMode;
			}
			xIt.Next();
		}

		if(!bFound)
		{
			if(!xBestMode.Width && !xBestMode.Height)
			{
				xBestMode.Width = 800;
				xBestMode.Height = 600;
			}
			xParameters.BackBufferWidth = xBestMode.Width;
			xParameters.BackBufferHeight = xBestMode.Height;
			uRequiredRefreshRate = xBestMode.RefreshRate;
			xFormat = xBestMode.Format;
		}
		else
		{
			uRequiredRefreshRate = xFoundMode.RefreshRate;
			xFormat = xFoundMode.Format;
		}
	}

	if (Asura_Windows::RunningFullScreen())
	{
		xParameters.Windowed = FALSE;
		xParameters.FullScreen_RefreshRateInHz = uRequiredRefreshRate;/*Asura_Direct3D_UserOptions::GetRefreshRate()*/;
		xParameters.PresentationInterval = Asura_Direct3D_UserOptions::GetPresentationInterval();
		xParameters.BackBufferFormat = xFormat/*Asura_Direct3D_UserOptions::GetBackBufferFormat()*/;
	}
	else
	{
		xParameters.Windowed = TRUE;
		xParameters.FullScreen_RefreshRateInHz = 0;
		xParameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
		xParameters.BackBufferFormat = Asura_Direct3D_UserOptions::GetBackBufferFormat();
		if( D3DFMT_UNKNOWN == xParameters.BackBufferFormat)
		{
			D3DDISPLAYMODE d3ddm = {0};

			xResult = Asura_Direct3D::D3DObject->GetAdapterDisplayMode( GetAdapterIndex(), &d3ddm);
			if( ASURA_D3D_FAILED( xResult))
			{
				Asura_Assert( false,"Can't find adapter's present screen format");
				return( false);
			}

			xParameters.BackBufferFormat = d3ddm.Format;
		}
	}
    xParameters.SwapEffect = Asura_Direct3D_UserOptions::GetSwapEffect();
   	xParameters.BackBufferCount = Asura_Direct3D_UserOptions::GetBackBufferCount();	

	xParameters.MultiSampleType = Asura_Direct3D_UserOptions::GetMultiSampleType();
	xParameters.MultiSampleQuality = Asura_Direct3D_UserOptions::GetMultiSampleQuality();

	xParameters.EnableAutoDepthStencil = FALSE;
	xParameters.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
	xParameters.hDeviceWindow = Asura_Windows::GetWindowHandle();

	xParameters.Flags = 0;
	// RJF 05-09-06: This flag needs to be set for SetDialogBoxMode() to work, required by
	// assertions and some bits of tools. 
#if defined ASURA_TOOLS || defined ASURA_ASSERT
#if defined ASURA_SUPPORT_MULTIPLE_MONITORS
	if(!GetCurrentOptions().m_bMultiheadEnabled)	// can't do SetDialogBoxMode in multihead anyway
#endif
	{
		if(D3DMULTISAMPLE_NONE == xParameters.MultiSampleType)
		{
			xParameters.Flags |= D3DPRESENTFLAG_LOCKABLE_BACKBUFFER;
		}
	}
#endif
	
	return( true);
}

DWORD Asura_Direct3D_UserOptions::GetMultiSampleQuality()
{
	if( D3DSWAPEFFECT_DISCARD != GetSwapEffect())
	{
		return( 0);
	}
	
	return( s_xCurrentOptions.m_uMultiSampleQuality);
}
	
D3DMULTISAMPLE_TYPE Asura_Direct3D_UserOptions::GetMultiSampleType()
{
	if( D3DSWAPEFFECT_DISCARD != GetSwapEffect())
	{
		return( D3DMULTISAMPLE_NONE);
	}
	
	return( s_xCurrentOptions.m_eMultiSampleType);
}

void Asura_Direct3D_UserOptions::ApplyTextureDetailSettings( void )
{
	for (u_int u=0; u<ASURA_MAX_NO_OF_TEXTURES; u++)
	{
		if (Asura_Texture_Management::IsTextureLoaded(u))
		{
			// Prepare texture information and get scaling info
			const TexInfo xTexInfo( Asura_Texture_Management::GetTextureName( u ), Asura_Texture_Management::GetTextureFlags( u ) );
			const TexScalingInfo xScalingInfo = GetTextureScalingInfo( xTexInfo );

			// Scale if necessary
			if ( xScalingInfo.m_bScale == true )
			{
				const u_int uMaxNumberOfLevels = xScalingInfo.m_uMaxLevel;
				int iLevelsToDrop = Asura_Direct3D::GetDirect3DTextureByIndex(u)->GetLevelCount() - uMaxNumberOfLevels;
	
				if (iLevelsToDrop < 0) iLevelsToDrop = 0;
			
				Asura_Direct3D::GetDirect3DTextureByIndex(u)->SetLOD(iLevelsToDrop);
			}
		}
	}
}

void Asura_Direct3D_UserOptions::SetTrilinearFiltering( const bool bOn )
{
	s_xCurrentOptions.m_bTrilinearFilteringOn = bOn;
}

void Asura_Direct3D_UserOptions::SetTextureDetail( const enum TEXTURE_DETAIL eSetting )
{
//	if (s_eTextureDetail == eSetting) return;

	s_xCurrentOptions.m_eTextureDetail = eSetting;
}

Asura_Direct3D_UserOptions::ANTIALIASING_SETTING Asura_Direct3D_UserOptions::GetAntiAliasingSetting( void)
{
	u_int uMultiSampleType = static_cast< u_int>( s_xCurrentOptions.m_eMultiSampleType);
	
	static const Asura_Direct3D_UserOptions::ANTIALIASING_SETTING aeAntiAliasingSetting[] =
	{
		ANTIALIASING_OFF,
		ANTIALIASING_NUM_SETTINGS,
		ANTIALIASING_2X,
		ANTIALIASING_NUM_SETTINGS,
		ANTIALIASING_4X,
		ANTIALIASING_NUM_SETTINGS,
		ANTIALIASING_6X,
		ANTIALIASING_NUM_SETTINGS,
		ANTIALIASING_8X
	};
	Asura_Assertf( uMultiSampleType < sizeof( aeAntiAliasingSetting), ("MultiSample Value %d not supported", uMultiSampleType));
	const Asura_Direct3D_UserOptions::ANTIALIASING_SETTING eAntiAliasingSetting = aeAntiAliasingSetting[ uMultiSampleType];
	Asura_Assertf( ANTIALIASING_NUM_SETTINGS != eAntiAliasingSetting, ("Unsupported AntiAliasValue %d. Change code to use MultiSample values.", uMultiSampleType))	;
	
	return( eAntiAliasingSetting);
}

void Asura_Direct3D_UserOptions::SetAntiAliasingSetting( const enum ANTIALIASING_SETTING eSetting )
{
	u_int uAntiAliasSetting = static_cast< u_int>( eSetting);
	static const D3DMULTISAMPLE_TYPE aeMultiSampleTypes[] = 
	{
		D3DMULTISAMPLE_NONE,
		D3DMULTISAMPLE_2_SAMPLES,
		D3DMULTISAMPLE_4_SAMPLES,
		D3DMULTISAMPLE_6_SAMPLES,
		D3DMULTISAMPLE_8_SAMPLES
	};
	Asura_Assertf( uAntiAliasSetting < sizeof( aeMultiSampleTypes), ("AntiAlias Value %d not supported", uAntiAliasSetting));
	const D3DMULTISAMPLE_TYPE eMultiSampleType = aeMultiSampleTypes[ uAntiAliasSetting];

	s_xCurrentOptions.m_eMultiSampleType = eMultiSampleType;
}

void Asura_Direct3D_UserOptions::SetGammaSetting( const float fGamma )
{
	D3DGAMMARAMP xRamp;
	for (int i=0; i<=255; i++)
	{
		float u = i/255.0f;
		float m = u*u;
		float l = 2*u*(1-u);

		float a = m + fGamma*l;
		
		if (a<0) a=0;
		if (a>1.0f) a=1.0f;

		xRamp.red[i]=(WORD)(a*65535);
		xRamp.green[i]=(WORD)(a*65535);
		xRamp.blue[i]=(WORD)(a*65535);
	}

	Asura_Direct3D::D3DDevice->SetGammaRamp(0,D3DSGR_CALIBRATE,&xRamp);

	s_xCurrentOptions.m_fGammaSetting = fGamma;
}

void Asura_Direct3D_UserOptions::SetAnisotropicFilteringSetting( const u_int uSetting )
{
	if (uSetting > GetMaxAnisotropySetting())
	{
		Asura_Assert( false, "Trying to set Anisotropic filtering to an unsupported level" );
		return;
	}

	s_xCurrentOptions.m_uAnisotropySetting = uSetting;
	Asura_Direct3D::ResetStates();
}

void Asura_Direct3D_UserOptions::SetSmoothSkinShadows( const enum SHADOW_SETTING eSetting )
{
	switch (eSetting)
	{
		default:
		{
			Asura_Assertf( false, ( "Invalid shadow setting (%d) for smooth skins", eSetting ) );
			break;
		}
		case SHADOW_OFF:
		case SHADOW_PLANAR:
		{
			s_xCurrentOptions.m_eSmoothSkinShadowSetting = eSetting;
			break;
		}
	}
}

void Asura_Direct3D_UserOptions::SetObjectHierarchyShadows( const enum SHADOW_SETTING eSetting )
{
	switch (eSetting)
	{
		default:
		{
			Asura_Assertf( false, ( "Invalid shadow setting (%d) for object hierarchies", eSetting ) );
			break;
		}
		case SHADOW_OFF:
		case SHADOW_PLANAR:
		{
			s_xCurrentOptions.m_eObjectHierarchyShadowSetting = eSetting;
			break;
		}
	}
}

void Asura_Direct3D_UserOptions::SetObjectShadows( const enum SHADOW_SETTING eSetting )
{
	switch (eSetting)
	{
		default:
		{
			Asura_Assertf( false, ( "Invalid shadow setting (%d) for objects", eSetting ) );
			break;
		}
		case SHADOW_OFF:
		case SHADOW_PLANAR:
		{
			s_xCurrentOptions.m_eObjectShadowSetting = eSetting;
			break;
		}
	}
}

#ifdef ASURA_TARGET_SM3
void Asura_Direct3D_UserOptions::SetFilterShadows(const bool bOn )
{
	s_xCurrentOptions.m_bFilterShadows = bOn;
}
#endif

#ifdef ASURA_SUPPORT_MULTIPLE_MONITORS
void Asura_Direct3D_UserOptions::SetMultiheadEnabled(const bool bEnabled)
{
	s_xCurrentOptions.m_bMultiheadEnabled = bEnabled;
}
#endif

bool Asura_Direct3D_UserOptions::IsAntiAliasingSettingAvailable( const enum ANTIALIASING_SETTING eSetting )
{
	// KJL - 10/09/2003 10:17:32 - these formats are what we're currently using - need to change this to be variable
	D3DFORMAT eBackBufferFormat = D3DFMT_X8R8G8B8;
	D3DFORMAT eDepthBufferFormat = D3DFMT_D24S8;

	D3DMULTISAMPLE_TYPE eMultiSampleType;

	switch (eSetting)
	{
		default:
		{
			return false;
		}

		case (ANTIALIASING_OFF):
		{
			return true;
		}

		case (ANTIALIASING_2X):
		{
			eMultiSampleType = D3DMULTISAMPLE_2_SAMPLES;
			break;
		}
		
		case (ANTIALIASING_4X):
		{
			eMultiSampleType = D3DMULTISAMPLE_4_SAMPLES;
			break;
		}
		
		case (ANTIALIASING_6X):
		{
			eMultiSampleType = D3DMULTISAMPLE_6_SAMPLES;
			break;
		}
		
		case (ANTIALIASING_8X):
		{
			eMultiSampleType = D3DMULTISAMPLE_8_SAMPLES;
			break;
		}
	}

	DWORD uQualityLevels;

	if( 
		SUCCEEDED
		(
			Asura_Direct3D::D3DObject->CheckDeviceMultiSampleType
			(
				D3DADAPTER_DEFAULT,
				D3DDEVTYPE_HAL ,
				eBackBufferFormat,
				FALSE,
				eMultiSampleType,
				&uQualityLevels
			)
		)
		
		&& 

		SUCCEEDED
		(
			Asura_Direct3D::D3DObject->CheckDeviceMultiSampleType
			(
				D3DADAPTER_DEFAULT,
				D3DDEVTYPE_HAL ,
				eDepthBufferFormat,
				FALSE,
				eMultiSampleType,
				&uQualityLevels
			)
		)
	)
	{
		return true;
	}



	return false;
}

u_int Asura_Direct3D_UserOptions::GetMaxAnisotropySetting( void )
{
	// KJL - 10/09/2003 11:17:50 - pass it on to Asura_Direct3D_Caps
	// a value of zero means no Anisotropio filtering is available at all
	return Asura_Direct3D_Caps::GetMaxLevelOfAnisotropicFiltering();
}

const Asura_List<Asura_Direct3D_UserOptions::ResolutionInfo>* Asura_Direct3D_UserOptions::GetSupportedResolutions(int iAdapterIndex /* = -1 */, bool bForceRebuild /* = false */)
{
	if(iAdapterIndex == -1)
	{
		iAdapterIndex = s_xCurrentOptions.m_uAdapterIndex;
	}

	if(bForceRebuild)
	{
		ClearResolutionCache(iAdapterIndex);
	}

	// See if we already have this resolution list cached
	Asura_List_It<Asura_Direct3D_UserOptions::ResolutionInfoList> xIt(&s_xEnumDisplayModes);
	while(!xIt.Done())
	{
		if(xIt.GetCurrent()->m_iAdapterIndex == iAdapterIndex) break;
		xIt.Next();
	}

	if(!xIt.Done())
	{
		// We've got it cached
		return &(xIt.GetCurrent()->m_xModes);
	}

	Asura_Assert(Asura_Direct3D::D3DObject, "D3D Object does not exist yet");
	if(!Asura_Direct3D::D3DObject) return NULL;

	// We need to build it
	Asura_Direct3D_UserOptions::ResolutionInfoList* pxResolutionInfoList = new Asura_Direct3D_UserOptions::ResolutionInfoList();
	pxResolutionInfoList->m_iAdapterIndex = iAdapterIndex;

	u_int uAdapterModeCount = Asura_Direct3D::D3DObject->GetAdapterModeCount(iAdapterIndex, s_xCurrentOptions.m_eBackBufferFormat);
	for(u_int uMode = 0; uMode < uAdapterModeCount; ++uMode)
	{
		D3DDISPLAYMODE xDM;
		if(SUCCEEDED(Asura_Direct3D::D3DObject->EnumAdapterModes(iAdapterIndex, s_xCurrentOptions.m_eBackBufferFormat, uMode, &xDM)))
		{
			// Drop any mode that is less than 640x480
			if( (xDM.Width < 640) || (xDM.Height < 480) ) continue;
			// Drop any mode that is less than 32bpp
			if( (xDM.Format != D3DFMT_A2R10G10B10) && (xDM.Format != D3DFMT_A8R8G8B8) && (xDM.Format != D3DFMT_X8R8G8B8)) continue;

			// Do we already have it?
			Asura_List_It<Asura_Direct3D_UserOptions::ResolutionInfo> xIt(&pxResolutionInfoList->m_xModes);
			while(!xIt.Done())
			{
				D3DDISPLAYMODE xDM2 = xIt.GetCurrent()->m_xModeData;
				if((xDM.Width == xDM2.Width) && (xDM.Height == xDM2.Height)) break;
				xIt.Next();
			}
			if(!xIt.Done()) continue;

			Asura_Direct3D_UserOptions::ResolutionInfo* pxRI = new Asura_Direct3D_UserOptions::ResolutionInfo(xDM);
			Asura_PrintfToBfr(pxRI->m_szDisplayName, "%ix%i", 30, true, xDM.Width, xDM.Height);
			pxResolutionInfoList->m_xModes.AddToList(pxRI);
		}
	}

	// Cache it for next time
	s_xEnumDisplayModes.AddToList(pxResolutionInfoList);

	// Done
	return &(pxResolutionInfoList->m_xModes);
}

void Asura_Direct3D_UserOptions::ClearResolutionCache(int iAdapterIndex /* = -1 */)
{
	// Delete the resolution cache
	Asura_List_It<Asura_Direct3D_UserOptions::ResolutionInfoList> xIt(&s_xEnumDisplayModes);
	while(!xIt.Done())
	{
		if((iAdapterIndex == -1) || iAdapterIndex == xIt.GetCurrent()->m_iAdapterIndex)
		{
			Asura_List_It<Asura_Direct3D_UserOptions::ResolutionInfo> xItInner(&xIt.GetCurrent()->m_xModes);
			while(!xItInner.Done())
			{
				delete xItInner.GetCurrent();
				xItInner.DeleteCurrent();
			}
			delete xIt.GetCurrent();
			xIt.DeleteCurrent();
		}
		else
		{
			xIt.Next();
		}
	}
}

#ifdef ASURA_PC_SUPPORT_WINDOWS_REGISTRY

// -------------------------------------------------------------------------------------

void Asura_Direct3D_UserOptions::WriteSettingsToRegistry( const char* const pszSubKey)
{
	s_xTextureDetail.WriteSettingsToRegistry( pszSubKey);
	s_xShaderQuality.WriteSettingsToRegistry( pszSubKey);
	s_xShadowQuality.WriteSettingsToRegistry( pszSubKey);
	s_xVisualDetail.WriteSettingsToRegistry( pszSubKey);
}

// -------------------------------------------------------------------------------------

void Asura_Direct3D_UserOptions::ReadSettingsFromRegistry( const char* const pszSubKey)
{
	s_xTextureDetail.ReadSettingsFromRegistry( pszSubKey);
	s_xShaderQuality.ReadSettingsFromRegistry( pszSubKey);
	s_xShadowQuality.ReadSettingsFromRegistry( pszSubKey);
	s_xVisualDetail.ReadSettingsFromRegistry( pszSubKey);

	ConsoleCmd_ApplyAdvancedSettings( false);
}

// -------------------------------------------------------------------------------------

#endif

//eof
