#include "Core/Asura.h"

#include "Misc/Tools_Render_Options.h"

#include "Animation/Asura_TextureAnimation.h"
#include "Rendering/Asura_Module.h"
#ifdef ASURA_TARGET_SM3
#include "Entity/DynamicLight/Asura_ClientEntity_DynamicLight.h"
#endif
#include "Mesh/Asura_Mesh.h"
#include "Mesh/Asura_Mesh_System.h"
#include "Camera/Asura_Camera.h"
#include "Core/Asura_Windows.h"
#include "Cutscene/Asura_Cutscene.h"
#if defined(ASURA_USE_SCREENSHOT_SYSTEM)
#include "Debugging/Asura_ScreenShot_System.h"
#endif	//defined(ASURA_USE_SCREENSHOT_SYSTEM)
#include "Interface/Asura_Overlay_System.h"
#include "Interface/Asura_Overlay.h"
#include "Interface/Asura_Dialog.h"
#include "Interface/Asura_Cursor.h"
#include "Interface/Asura_Menubar_System.h"
#include "Debugging/Asura_Assert.h"
#include "Physics/Asura_Physics.h"
#include "Rendering/Asura_Direct3d.h"
#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM
#include "Rendering/Asura_Direct3D_EnvironmentRenderer.h"
#endif
#include "Rendering/Asura_PatchSubdivision.h"
#include "Rendering/Asura_PlatformRenderMesh.h"
#include "Rendering/Asura_Render.h"
#include "Rendering/Asura_Viewport.h"

#include "Tools_Overlays.h"
#include "Tools_System.h"
#include "Cutscene/Tools_Mode_Cutscene.h"
#include "Entity/Tools_Entity_PFX_Effect.h"
#ifdef ASURA_USE_FSFX
#include "FSFX/Tools_FSFX_DropDownList_Dialog.h"
#endif
#include "Interface/Tools_ColourPicker.h"
#include "Lighting/Tools_LightSets.h"
#include "Mesh/Tools_PlatformMesh_System.h"
#include "Misc/Tools_Render.h"
#include "Misc/Tools_GeneralOptions.h"
#include "Regions/Tools_Mode_Regions.h"
#include "Rendering/Tools_RenderModules.h"
#include "Rendering/Tools_RenderCollisionMesh.h"
#include "Skybox/Tools_Mode_Skybox.h"
#include "SpecialFX/Asura_FullScreenSFX_System.h"
#ifdef ASURA_SUPPORT_WEATHER_SYSTEM
#include "SpecialFX/Asura_Weather_System.h"
#endif
#ifdef ASURA_USE_STREAMING
#include "Streaming/Tools_Streaming_System.h"
#endif
#ifdef ASURA_SUPPORT_MULTIPLE_MONITORS
#include "Misc/Tools_Timed_Messages.h"
#endif

#include "Rendering/Asura_Direct3D_HDR.h"
#include "Rendering/Asura_Direct3D_UserOptions.h"


#ifdef ASURA_USE_CONTAINER_SYSTEM
#include "Entity/Container/Tools_Container_System.h"
#endif //ASURA_USE_CONTAINER_SYSTEM

//////////////////////////////////////////////////////////////////////////////////////////////////
/*-----------**
** Constants **
**-----------*/
const float fKEY_VALUE_MIN = 0.0f;
const float fKEY_VALUE_MAX = 1.0f;

const float fADAPTATION_RATE_MIN = 0.0f;
const float fADAPTATION_RATE_MAX = 100.0f;

const float fMIN_LUMINANCE_MIN = 0.0f;
const float fMIN_LUMINANCE_MAX = 10.0f;

const float fMAX_LUMINANCE_MIN = 0.0f;
const float fMAX_LUMINANCE_MAX = 10.0f;

const float fWHITE_POINT_MIN = 0.0f;
const float fWHITE_POINT_MAX = 1000.0f;

const float fBLACK_POINT_MIN = 0.0f;
const float fBLACK_POINT_MAX = 1000.0f;

#if defined ASURA_TOOLS
	static bool g_bCaptureFixedLuminance = false;
#endif

//////////////////////////////////////////////////////////////////////////////////////////////////
/*----------------------**
** Tools_Render_Options **
**----------------------*/
int Tools_Render_Options::NumberOfModules = 0;
Tools_Module_Render_Options** Tools_Render_Options::ModuleData = 0;
int* Tools_Render_Options::s_piMeshToModuleIndex = 0;
bool Tools_Render_Options::ShowDestroyedPolygons = false;
bool Tools_Render_Options::HideEnvironment = false;

bool Tools_Render_Options::DefaultFieldOfViewIsVertical = false;
Asura_Angle Tools_Render_Options::DefaultFieldOfView = 75.0f;
bool Tools_Render_Options::FieldOfViewIsVertical;
float Tools_Render_Options::HorizontalFieldOfViewInDegress;
float Tools_Render_Options::VerticalFieldOfViewInDegress;
bool Tools_Render_Options::FieldOfViewChanged = false;
bool Tools_Render_Options::UseViewDistance = false;
float Tools_Render_Options::ViewDistance = 20.0f;
bool Tools_Render_Options::s_bUseRenderAsIconDistance = true;
float Tools_Render_Options::s_fRenderAsIconDistance = 25.0f;
float Tools_Render_Options::s_fDistantIconSize = 0.5f;
bool Tools_Render_Options::NoBackFaceCull = false;
bool Tools_Render_Options::s_bNoBackFaceCullChanged = false;

float Tools_Render_Options::s_fGamma = 0.5f;
bool Tools_Render_Options::s_bGammaChanged = false;

bool Tools_Render_Options::s_bHighlightDontExportPolygons = false;
int Tools_Render_Options::s_iActiveHideFlags = 0;
int Tools_Render_Options::s_iAlwaysVisiblePolygonFlags = 0;
int Tools_Render_Options::s_iPolygonFlagsToHide = 0;

bool Tools_Render_Options::s_bUsePlayerHeight = false;
float Tools_Render_Options::s_fPlayerHeight = 1.8f;
int Tools_Render_Options::s_iPlayerPosture = Tools_Render_Options::POSTURE_STAND;

bool Tools_Render_Options::s_bDisplayCollisionPolys = false;

enum Tools_SubdivisionMode Tools_Render_Options::s_eSubdivideMode = TOOLS_SUBDIVIDE_NONE;
float Tools_Render_Options::s_fCurvedSubdivideSize = 0.5f;
float Tools_Render_Options::s_fFlatSubdivideSize = 0.5f;
bool Tools_Render_Options::s_bPrelightSubdividedMeshes = false;
//bool Tools_Render_Options::s_bShouldSubdivideForPS2TextureSize = true;

bool Tools_Render_Options::s_bIgnoreDontRenderFlag_Mode = false;
bool Tools_Render_Options::s_bIgnoreDontRenderFlag_User = false;

bool Tools_Render_Options::s_bRenderAllWhenInNoModule = true;

bool Tools_Render_Options::s_bClampFrameRate = false;
float Tools_Render_Options::s_fMaxFrameRate = 50.0f;

int Tools_Render_Options::s_iPSPRenderMode = TOOLS_PSPRENDERMODE_INACTIVE;

#ifdef ASURA_USE_OLD_ENTITY_LIGHTS
bool Tools_Render_Options::s_bUseGlobalIllumination = false;
#else
bool Tools_Render_Options::s_bUseGlobalIllumination = true;
#endif
bool Tools_Render_Options::s_bUseGlobalIlluminationChanged = false;

bool Tools_Render_Options::s_bGlowEffectEnabled = false;
bool Tools_Render_Options::s_bGlowEffectEnabledChanged = false;

bool Tools_Render_Options::s_bHideObjectPolygons = false;
bool Tools_Render_Options::s_bHideObjectPolygonsChanged = false;
bool Tools_Render_Options::s_bDisableHideObjectPolygonFlag = false;

float Tools_Render_Options::s_fCursorSpeed = 1.0f;
bool Tools_Render_Options::s_bCursorSpeedChanged = false;

bool Tools_Render_Options::s_bShowHighPolyModules = false;
int Tools_Render_Options::s_iHighPolyModuleThreshold = 1000;

bool Tools_Render_Options::s_bDiscoLights = false;

Tools_WireframeMode Tools_Render_Options::s_eWireframeMode;
u_int Tools_Render_Options::s_uWireframeColour = 0xffffffff;
bool Tools_Render_Options::s_bUseMaxWireframeColour = false;

Tools_HighlightMode Tools_Render_Options::s_ePolygonHighlightMode = TOOLS_HIGHLIGHT_WIREFRAME;


bool Tools_Render_Options::s_bUseModuleLinks = true;
bool Tools_Render_Options::s_bUseModuleLinksCMesh = false;

bool Tools_Render_Options::s_bEnableTextureAnims = true;
bool Tools_Render_Options::s_bEnableEffectVolume = false;

bool  Tools_Render_Options::s_bLimitBotanicalsRange = true;
float Tools_Render_Options::s_fBotanicalsRange = 75.0f;

bool Tools_Render_Options::s_bHideOtherZones = false;

bool Tools_Render_Options::s_bUseSkinnedUI = true;
bool Tools_Render_Options::s_bUseSkinnedUIChanged = false;

bool Tools_Render_Options::s_bShowPFX = false;
bool Tools_Render_Options::s_bShowPFXChanged = false;
bool Tools_Render_Options::s_bPFXControlledByMode = false;

#ifdef ASURA_SUPPORT_WEATHER_SYSTEM
bool Tools_Render_Options::s_bModeEnableSunGlare = false;
bool Tools_Render_Options::s_bUserEnableSunGlare = false;
#endif

#ifdef ASURA_USE_FSFX
Asura_Hash_ID Tools_Render_Options::s_uFSFXHash = 0;
float Tools_Render_Options::s_fFSFXIntensity = 1.0f;
bool Tools_Render_Options::s_bFSFXChanged = false;
bool Tools_Render_Options::s_bFSFXControlledByMode = false;
#endif

#ifdef ASURA_TARGET_SM3
bool Tools_Render_Options::s_bForceDynamicLightsOn = false;
#endif

#ifdef ASURA_SUPPORT_MULTIPLE_MONITORS
bool Tools_Render_Options::s_bUseMultipleMonitors = false;
bool Tools_Render_Options::s_bUseMultipleMonitorsChanged = false;
bool Tools_Render_Options::s_bUseMultipleMonitorsWarningEmitted = false;
#endif

int* Tools_Render_Options::s_piSelectedResolutions = NULL;
Asura_Char* Tools_Render_Options::s_pszScreenNames = NULL;

bool  Tools_Render_Options::s_bEnableOverlayScaling = false;

#ifdef ASURA_USE_HDR
Asura_CameraData::HDRSettings Tools_Render_Options::s_xHDRSettings;
#endif

#if defined(ASURA_USE_SCREENSHOT_SYSTEM)
bool	Tools_Render_Options::s_bEnableHiResScreenshotMode = false;
bool	Tools_Render_Options::s_bDisableMipMaps = false;

int		Tools_Render_Options::s_iHiResScreenshotMagnification			= 2;
bool	Tools_Render_Options::s_bHiResScreenshotMagnificationChanged	= false;
#endif	//defined(ASURA_USE_SCREENSHOT_SYSTEM)

static const char* s_apszPSPRenderMode[] =
{
	"Off",
	"Actual Res (480x272)",
	"Stretch To Screen",
};

static const char* s_apszPSPRenderModeHelp[] =
{
	"PSP mode off",
	"Renders at the same pixel resolution as the PSP for the most accurate representation.",
	"Renders at the same aspect ratio as the PSP, but fills the PC screen (so higher res than the PSP).",
};

//dialog control for selecting a display resolution. RJF 30/08/06
class Tools_Resolution_DropDownList_Dialog : public Asura_DropDown_List_Dialog
{
public :
	Tools_Resolution_DropDownList_Dialog(int iAdapterIndex, Asura_Vector_2& xOffset, int iNumberOfLines,int& iSelectionIndex, bool* pbChangedFlag = 0 ,const char* szName = NULL)
		:Asura_DropDown_List_Dialog(xOffset), m_pszResolutionStrings(NULL)
	{
		const Asura_List<Asura_Direct3D_UserOptions::ResolutionInfo>* pxList = Asura_Direct3D_UserOptions::GetSupportedResolutions(iAdapterIndex);
		int iNumEntries = 0; 
		Asura_List_ConstIt<Asura_Direct3D_UserOptions::ResolutionInfo> xIt(pxList);
		while(!xIt.Done()) { ++iNumEntries; xIt.Next();}

		m_pszResolutionStrings = new const char*[iNumEntries];
		u_int uIndex = 0;
		xIt.Restart();
		iSelectionIndex = iNumEntries - 1;//Initialse in case resolution doesn't match any in list. This may happen in subwindow mode. RAR 06/09/2006
		while(!xIt.Done())
		{
			if((xIt.GetCurrent()->m_xModeData.Width == Asura_Direct3D::GetPresentParameters(iAdapterIndex).BackBufferWidth)
				&&(xIt.GetCurrent()->m_xModeData.Height == Asura_Direct3D::GetPresentParameters(iAdapterIndex).BackBufferHeight))
			{
				iSelectionIndex = uIndex;
			}
			m_pszResolutionStrings[uIndex++] = xIt.GetCurrent()->m_szDisplayName;
			xIt.Next();
		}

		Asura_DropDown_List_Dialog::Initialise(xOffset, m_pszResolutionStrings, &iSelectionIndex, iNumberOfLines, iNumEntries, NULL, pbChangedFlag, szName );
	}
	~Tools_Resolution_DropDownList_Dialog()
	{
		delete[] m_pszResolutionStrings;
	}
	const char** m_pszResolutionStrings;
};

void Tools_Render_Options::Initialise()
{

	Asura_Camera::SetToDefaults();
	FieldOfViewIsVertical = false;
	HorizontalFieldOfViewInDegress = Asura_Maths::RadToDeg(Asura_Camera::GetHorizontalFieldOfView());
	VerticalFieldOfViewInDegress = Asura_Maths::RadToDeg(Asura_Camera::GetVerticalFieldOfView());

	s_iActiveHideFlags = ToolsRenderFlag_ModeHide|ToolsRenderFlag_ToBeDestroyed|ToolsRenderFlag_AsrFileManagerHide;
	s_iPolygonFlagsToHide = AsuraPolygonFlag_DontRender;
	s_iAlwaysVisiblePolygonFlags = 0;

	s_bRenderAllWhenInNoModule = Asura_Module_System::GetRenderAllWhenInNoModule();

		
	if(NumberOfModules == Asura_Module_System::GetNumberOfModules())
	{
		Asura_Assert(ModuleData, "");

		//make sure the tools module data is up to date
		for(int i=0;i<NumberOfModules;i++)
		{
			Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(i);
			Asura_Assert(pxMesh,"Failed to get the mesh for the module");
			
			ModuleData[i]->HandleMeshChange(pxMesh);
		}
	}
	else
	{
		Asura_Assert(NumberOfModules == 0, "Number of modules has changed?");
		
		NumberOfModules = Asura_Module_System::GetNumberOfModules();
		ModuleData = new Tools_Module_Render_Options*[NumberOfModules];
		
		//initialise render option data for each module
		for(int i=0;i<NumberOfModules;i++)
		{
			Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(i);
			Asura_Assert(pxMesh,"Failed to get the mesh for the module");

			ModuleData[i] = new Tools_Module_Render_Options(i,pxMesh);
		}

		UpdateAllPolygonVisibilities();
	}

	//initialise conversion array from mesh to module indeces
	s_piMeshToModuleIndex = new int[ASURA_MAX_NO_OF_MESHES];
	for(int i=0;i<ASURA_MAX_NO_OF_MESHES;i++)
	{
		s_piMeshToModuleIndex[i] = -1;
	}
	for(int i=0;i<NumberOfModules;i++)
	{
		Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(i);
		s_piMeshToModuleIndex[pxMesh->Index] = i;
	}

	//wirefame mode
	s_eWireframeMode = TOOLS_WIREFRAME_OFF;
	Asura_Render::SetWireframe(false);


	s_bShowPFXChanged = true;//will force initial state of PFX to be set correctly
	#ifdef ASURA_USE_FSFX
	UpdateFSFXSettings();
	#endif

	s_bUseSkinnedUI = Asura_Overlay_System::UseSkinnedUI();

	#ifdef ASURA_USE_HDR
	s_xHDRSettings.SetToDefaults();
	#endif

#if defined(ASURA_USE_SCREENSHOT_SYSTEM)
	s_iHiResScreenshotMagnification	= Asura_ScreenShot_System::GetMagnification();
#endif	//defined(ASURA_USE_SCREENSHOT_SYSTEM)
}
	

void Tools_Render_Options::Shutdown()
{
	//If quitting to game , make sure the hidden state of polygons is no longer being
	//modified by various tools options / modes
	//RAR 29/10/2007
	if(!Tools_System::ShouldQuitToDesktop())
	{
		s_iActiveHideFlags = 0;
		s_iPolygonFlagsToHide = AsuraPolygonFlag_DontRender;
		s_iAlwaysVisiblePolygonFlags = 0;

		UpdateAllPolygonVisibilities();
	}

	delete [] s_piMeshToModuleIndex;
	s_piMeshToModuleIndex=NULL;

	delete[] s_piSelectedResolutions; s_piSelectedResolutions = NULL;
	delete[] s_pszScreenNames; s_pszScreenNames = NULL;

	Asura_TextureAnimation_System::DisableAnimations(false);

	//close overlays
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_RENDEROPTIONS);

	SetRecalculatePrelightingForSubdividedMeshes(false);

	if(!Tools_System::ShouldQuitToDesktop())
	{
		Tools_Entity_PFX_Effect::ActivateStartsActivePFX(true);
	}
	#ifdef ASURA_SUPPORT_WEATHER_SYSTEM
	Asura_Weather_System::SetToolsDisableSunGlare(false);
	#endif
	#ifdef ASURA_USE_FSFX
	Tools_FSFX_System::SetOverrideFSFX(0,1.0f);
	#endif

	#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM
	Asura_MaterialResponse_System::SetUseUVOrientMaterial(false);
	#endif

}

void Tools_Render_Options::FinalShutdown()
{
	//Only delete this lot when quitting to desktop , to speed up returning from game
	for(int i=0;i<NumberOfModules;i++)
	{
		delete ModuleData[i];
	}
	delete [] ModuleData;
	ModuleData = 0;
	NumberOfModules = 0;
}

void Tools_Render_Options::Update()
{
	//update field of view if needed
	if(FieldOfViewChanged)
	{
		FieldOfViewChanged = false;
		UpdateFieldOfView();
	}

	if(s_bGammaChanged)
	{
		s_bGammaChanged = false;
		SetGamma(s_fGamma);
	}

#if defined(ASURA_USE_SCREENSHOT_SYSTEM)
	if(s_bHiResScreenshotMagnificationChanged)
	{
		Asura_ScreenShot_System::SetMagnification(s_iHiResScreenshotMagnification);
	}

	if(s_bEnableHiResScreenshotMode)
	{
		Asura_Render::EnableHiResScreenshotMode();
	}
	else
	{
		Asura_Render::DisableHiResScreenshotMode();
	}

	if(s_bDisableMipMaps)
	{
		Asura_Render::DisableMipMapping();
	}
	else
	{
		Asura_Render::EnableMipMapping();
	}

#endif	//defined(ASURA_USE_SCREENSHOT_SYSTEM)
	
	//determine polygon flags to hide
	if(!Tools_RenderCollisionMesh_System::IsRenderingCollMeshes())
	{
		SetPolygonFlagToHide(AsuraPolygonFlag_DontRender,!(s_bIgnoreDontRenderFlag_User || s_bIgnoreDontRenderFlag_Mode));
		// AJG - 20/09/2005 - I believe ensuring these flags are unset each frame when we're not rendering collision mesh is a safe thing to
		//					do. However,I'm not 100% sure so if bits of mesh aren't rendering when they should be, look to alternatives here.
		//					The reason this is done is so that the flags are unset after turning off collision mesh rendering (previously
		//					this wasn't done leading to, for instance, only the collidable parts of the visible mesh appearing after turning
		//					off collision mesh rendering).
		SetMaskedPolygonFlagsToHide(0, AsuraPolygonFlag_NoCollisions | AsuraPolygonFlag_IgnoreLOS);
	}

	if(ShowDestroyedPolygons)
	{
		DeactivateHideFlag(ToolsRenderFlag_ToBeDestroyed);
	}
	else
	{
		ActivateHideFlag(ToolsRenderFlag_ToBeDestroyed);
	}

	if(s_bNoBackFaceCullChanged)
	{
		s_bNoBackFaceCullChanged = false;

		//Need to update the tools render meshes for any that contain double sided polygons
		for(int i=0;i<NumberOfModules;i++)
		{
			Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(i);
			if(!pxMesh->PolygonFlagDataPtr) continue;

			for(int j=0;j<pxMesh->NumberOfPolygons;j++)
			{
				if(pxMesh->PolygonFlagDataPtr[j].Flags & AsuraPolygonFlag_DoubleSided)
				{
					Tools_RenderModule_System::UpdateModuleMesh(pxMesh->Index);
					break;
				}
			}
		}
	}


	if(UseViewDistance)
	{
		//work out which modules are in range
		for(int i=0;i<NumberOfModules;i++)
		{
			const Asura_Vector_3& centre = Asura_Module_System::GetCentreOfModule( i );
			float radius = Asura_Module_System::GetRadiusOfModule(i);

			float distance = (*Asura_Camera::GetPosition()-centre).Magnitude();
			
			ModuleData[i]->WithinViewDistance = (distance-radius)<ViewDistance;
		}
	}

	// KJFL - 2004-06-18 10:55:41 - currently subdivision when using GI will just use interpolated colours
	SetRecalculatePrelightingForSubdividedMeshes(s_bPrelightSubdividedMeshes && !s_bUseGlobalIllumination);
	
	Asura_Module_System::SetRenderAllWhenInNoModule(s_bRenderAllWhenInNoModule);

#ifndef ASURA_USE_VISIBILITY_SYSTEM
	//update use of module links
	if(Tools_RenderCollisionMesh_System::IsRenderingCollMeshes())
	{
		Asura_Module_System::UseModLinks = s_bUseModuleLinksCMesh;
	}
	else
	{
		Asura_Module_System::UseModLinks = s_bUseModuleLinks;
	}
#endif


	if (s_bUseGlobalIlluminationChanged)
	{
		s_bUseGlobalIlluminationChanged = false;
	
		for (int i=0; i<Asura_Module_System::GetNumberOfModules(); ++i)
		{
			Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(i);
			pxMesh->PrelightingDataValid = false;
		}
	}

	if (s_bGlowEffectEnabledChanged)
	{
		s_bGlowEffectEnabledChanged = false;
#ifndef ASURA_USE_FSFX
		Asura_FullScreenSFX_System::EnableGlow(s_bGlowEffectEnabled);
#endif
	}

	if(s_bHideObjectPolygonsChanged)
	{
		//need to check to see if any polygon has been hidden/made visible as a result of this changed
		s_bHideObjectPolygonsChanged = true;
		UpdateAllPolygonVisibilities();
	}

	if(s_bCursorSpeedChanged)
	{
		s_bCursorSpeedChanged = false;
		Asura_Cursor::SetCursorSpeed(s_fCursorSpeed);
	}
	else
	{
		s_fCursorSpeed = Asura_Cursor::GetCursorSpeed();
	}

	if(s_bShowPFXChanged)
	{
		//Activate/deactivate the PFX only when the flag changes. This should prevent it from interfering
		//with other modes controlling the PFX. RAR 28/06/2006
		Tools_Entity_PFX_Effect::ActivateStartsActivePFX(s_bShowPFX);

		#ifdef ASURA_USE_CONTAINER_SYSTEM
		Tools_Container_System::SetShowPFX(s_bShowPFX);
		#endif //ASURA_USE_CONTAINER_SYSTEM

		s_bShowPFXChanged = false;
	}

	#ifdef ASURA_SUPPORT_WEATHER_SYSTEM
	Asura_Weather_System::SetToolsDisableSunGlare(!s_bModeEnableSunGlare && !s_bUserEnableSunGlare);
	#endif

	#ifdef ASURA_USE_FSFX
	if(s_bFSFXChanged)
	{
		UpdateFSFXSettings();
		s_bFSFXChanged = false;
	}
	#endif

	if(s_bUseSkinnedUIChanged)
	{		
		Asura_Overlay_System::SetUseSkinnedUI(s_bUseSkinnedUI);		
		if( s_bUseSkinnedUI )
		{
			Asura_Overlay_System::LoadSkinnedUITexture();
		}

		s_bUseSkinnedUIChanged = false;

		// update menu bar widths
		Asura_Menubar_System::ForceRecalculateWidths();
	}

	Asura_TextureAnimation_System::DisableAnimations(!s_bEnableTextureAnims);

#ifdef ASURA_SUPPORT_MULTIPLE_MONITORS
	if(s_bUseMultipleMonitorsChanged && !s_bUseMultipleMonitorsWarningEmitted)
	{
		// Warn users that changing the multimon setting will require a restart
		Tools_Timed_Message_System::AddMessage(0xffffff00, "Changes to the \"Use multiple monitors\" setting will not take effect until you next launch Tools.");
		s_bUseMultipleMonitorsWarningEmitted = true;
	}
	if(!s_bUseMultipleMonitorsChanged) s_bUseMultipleMonitorsWarningEmitted = false;
#endif

#ifdef ASURA_USE_HDR
	// No 'changed' flag around this. Projects might fiddle with the settings in their own Tools
	// code to simulate different characters/vision modes etc, so we need to put it back when they
	// stop doing that
	
	// Disable dynamic exposure while rendering collision mesh or in wireframe.
	// RAR 09/11/2007
	if(!Asura_Render::GetCutsceneHasCameraControl())
	{
		Asura_CameraData::HDRSettings xHDRSettingsToUse;
		if(s_eWireframeMode == TOOLS_WIREFRAME_ON || Tools_RenderCollisionMesh_System::IsRenderingCollMeshes())
		{
			xHDRSettingsToUse.SetToDefaults();
			xHDRSettingsToUse.m_bDynamicExposure = false;
			xHDRSettingsToUse.m_fFixedLuminance = 0.1f;
		}
		else
		{
			xHDRSettingsToUse = s_xHDRSettings;
		}

		Asura_Camera::SetHDRSettings(xHDRSettingsToUse);
	}

#endif
}

void Tools_Render_Options::Render()
{
	if(s_bHighlightDontExportPolygons)
	{
		for(int i=0;i<Asura_Module_System::GetNumberOfModules();i++)
		{
			Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(i);
			Asura_Assert(pxMesh,"Failed to get the mesh for the module");
			if(!pxMesh->PolygonFlagDataValid) continue;

			for(int j=0;j<pxMesh->NumberOfPolygons;j++)
			{
				if(pxMesh->PolygonFlagDataPtr[j].Flags & AsuraPolygonFlag_DontExport)
				{
					Tools_Render::RenderPolygonOutline(j,i,0xff00ff00);//green
				}
			}
		}
	}

	if(s_bShowHighPolyModules)
	{
		for(int i=0;i<Asura_Module_System::GetNumberOfModules();i++)
		{
			Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(i);
			Asura_Assert(pxMesh,"Failed to get the mesh for the module");
			if(pxMesh->NumberOfPolygons > s_iHighPolyModuleThreshold)
			{
				Tools_Render::RenderMeshOutline(i,0xff00ff00);
			}
		}
	}
}

void Tools_Render_Options::UpdateFieldOfView()
{
	if(Tools_Mode_Cutscene::IsControllingCamera())
	{
		//Leave FoV alone if a cutscene is being played
		return;
	}
	
	if(FieldOfViewIsVertical)
	{
		Asura_Camera::SetVerticalFieldOfView(Asura_Maths::DegToRad(VerticalFieldOfViewInDegress));
		HorizontalFieldOfViewInDegress = Asura_Maths::RadToDeg(Asura_Camera::GetHorizontalFieldOfView());
	}
	else
	{
		Asura_Camera::SetHorizontalFieldOfView(Asura_Maths::DegToRad(HorizontalFieldOfViewInDegress));
		VerticalFieldOfViewInDegress = Asura_Maths::RadToDeg(Asura_Camera::GetVerticalFieldOfView());
	}
}

void Tools_Render_Options::UseDefaultFieldOfView()
{
	FieldOfViewIsVertical = DefaultFieldOfViewIsVertical;
	if(DefaultFieldOfViewIsVertical)
	{
		VerticalFieldOfViewInDegress = DefaultFieldOfView;
	}
	else
	{
		HorizontalFieldOfViewInDegress = DefaultFieldOfView;
	}
	UpdateFieldOfView();
}

void Tools_Render_Options::AddRenderFlagPolygon(int iModule,int iPolygon,int iFlags)
{
	Asura_Assert(iModule>=0 && iModule<NumberOfModules,"");
	ModuleData[iModule]->AddRenderFlagPolygon(iPolygon,iFlags);
}

void Tools_Render_Options::RemoveRenderFlagPolygon(int iModule,int iPolygon,int iFlags)
{
	Asura_Assert(iModule>=0 && iModule<NumberOfModules,"");
	ModuleData[iModule]->RemoveRenderFlagPolygon(iPolygon,iFlags);
}

void Tools_Render_Options::RemoveRenderFlagFromAllPolygonsInModule(int iModule,int iFlags)
{
	Asura_Assert(iModule>=0 && iModule<NumberOfModules,"");
	for(int i=0;i<ModuleData[iModule]->NumberOfPolygons;i++)
	{
		ModuleData[iModule]->RemoveRenderFlagPolygon(i,iFlags);
	}
}


void Tools_Render_Options::AddRenderFlagModule(int iModule,int iFlags)
{
	Asura_Assert(iModule>=0 && iModule<NumberOfModules,"");

	//add the flag to each polygon in the module
	ModuleData[iModule]->AddRenderFlagModule(iFlags);
	
}

void Tools_Render_Options::RemoveRenderFlagModule(int iModule,int iFlags)
{
	Asura_Assert(iModule>=0 && iModule<NumberOfModules,"");

	ModuleData[iModule]->RemoveRenderFlagModule(iFlags);
}

int Tools_Render_Options::GetRenderFlags(int iModule)
{
	Asura_Assert(iModule>=0 && iModule<NumberOfModules,"");
	return ModuleData[iModule]->m_iRenderFlags;
}

int Tools_Render_Options::GetRenderFlags(int iModule,int iPolygon)
{
	Asura_Assert(iModule>=0 && iModule<NumberOfModules,"");
	Asura_Assert(iPolygon>=0 && iPolygon<ModuleData[iModule]->NumberOfPolygons,"");
	return ModuleData[iModule]->PolygonData[iPolygon].m_iRenderFlags | ModuleData[iModule]->m_iRenderFlags;
}



void Tools_Render_Options::HandlePolygonConversion(int module,int* PolyConv1,int* PolyConv2 /*=0*/)
{
	Asura_Mesh* mesh = Asura_Module_System::GetMeshForModule(module);
	ModuleData[module]->HandlePolygonConversion(mesh,PolyConv1,PolyConv2);
}

void Tools_Render_Options::HandleMeshChange(int iModuleIndex)
{
	Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(iModuleIndex);
	ModuleData[iModuleIndex]->HandleMeshChange(pxMesh);
}

void Tools_Render_Options::DeleteModule(int iModuleIndex)
{
	Asura_Assert(iModuleIndex>=0 && iModuleIndex<NumberOfModules,"");

	for(int i=0;i<ASURA_MAX_NO_OF_MESHES;i++)
	{
		if(s_piMeshToModuleIndex[i] == iModuleIndex)
		{
			s_piMeshToModuleIndex[i] = -1;
		}
		else if(s_piMeshToModuleIndex[i] == NumberOfModules-1)
		{
			s_piMeshToModuleIndex[i] = iModuleIndex;
		}
	}

	delete ModuleData[iModuleIndex];
	ModuleData[iModuleIndex] = ModuleData[NumberOfModules-1];
	NumberOfModules--;
}

bool Tools_Render_Options::IsHidden(int iModule)
{
   	#ifdef ASURA_USE_STREAMING
	if(!Tools_Streaming_System::IsSetToMainZone()) return false;
	#endif

	if( Tools_Mode_Regions::IsModuleInHiddenRegion(iModule) ) { return true; }
	if( Tools_LightSets::ShouldHideModulesInOtherSets())
	{
		if(!Tools_LightSets::IsModuleInCurrentLightSet(iModule))
		{
			return true;
		}
	}

	int flags = GetRenderFlags(iModule);
	if(flags & GetHideFlags()) return true;
	return false;
}

bool Tools_Render_Options::IsHidden(int iModule,int iPolygon)
{
	#ifdef ASURA_USE_STREAMING
	if(!Tools_Streaming_System::IsSetToMainZone())
	{
		//System only setup for the main level. So check the dont render flag directly
		Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(iModule);
		return (pxMesh->GetPolygonFlags(iPolygon) & AsuraPolygonFlag_DontRender)!=0;
	}
	#endif

	if(IsHidden(iModule)) return true;

	return ModuleData[iModule]->IsPolygonHidden(iPolygon);
}

bool Tools_Render_Options::IsHidden(const Asura_Mesh* pxMesh,int iPolygon)
{
	Asura_Assert(pxMesh->Index < ASURA_MAX_NO_OF_MESHES,"");
	
	// DaveR (12/01/06). Something odd is going on with the BotanicalShape rendering - when
	// the SpecialFX rendering is done for the first time, the tools system seems to be shut down.
	// Not sure about the reason for this - but to fix it, to allow shape rendering at that point,
	// I need to make sure this function doesn't crash if it's called when the tools system is shut down...
	// Asura_Assert(s_piMeshToModuleIndex,"");
	if (s_piMeshToModuleIndex==NULL)
	{
		return false;
	}

	int iModuleIndex = s_piMeshToModuleIndex[pxMesh->Index];
	if(iModuleIndex==-1) return false;//mesh doesn't belong to a module

	return IsHidden(iModuleIndex,iPolygon);
}

bool Tools_Render_Options::AreAllPolygonsInModuleHidden(int iModule)
{
   	#ifdef ASURA_USE_STREAMING
	if(!Tools_Streaming_System::IsSetToMainZone()) return false;
	#endif

	Asura_Assert(iModule>=0 && iModule<NumberOfModules,"");
	Tools_Module_Render_Options* pxModule = ModuleData[iModule];

	return !pxModule->m_iNumVisiblePolygons;

}



void Tools_Render_Options::AddOverlayControls(Asura_Overlay* pxOverlay, Asura_Vector_2& xOffset, int iTab)
{
	Asura_Dialog* pxDialog;

	switch(iTab)
	{
		case TOOLS_GENERALOPTIONS_VISIBILITY :
		{

			pxDialog = new Asura_Numerical_Dialog("View Distance",xOffset,&ViewDistance,0,10000,1.0f,"%.1f");
			pxDialog->SetHelpText("Maximum distance (in metres) at which objects/modules should be rendered. Ignored if checkbox isn't set.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Tickbox_Dialog("Use View Distance",xOffset,&UseViewDistance);
			pxDialog->SetHelpText("Activates the 'View Distance' setting above.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=1.5f*Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Numerical_Dialog("Icon Distance",xOffset,&s_fRenderAsIconDistance,0,10000,1.0f,"%.1f");
			pxDialog->SetHelpText("Distance at which tools objects get rendered as icons (for ones that have an icon texture defined).");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Numerical_Dialog("Icon Size",xOffset,&s_fDistantIconSize,0.01f,10.0f,0.01f,"%.2f");
			((Asura_Numerical_Dialog*) pxDialog)->SetBoxLength(8);
			pxDialog->SetHelpText("How large the distant icons should be.\nThis works out as the radius when within 20 metres of the camera , and is scaled when further away.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Tickbox_Dialog("Use Icon Distance",xOffset,&s_bUseRenderAsIconDistance);
			pxDialog->SetHelpText("Activates the 'Icon Distance' setting above.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=1.5f*Asura_Dialog::DefaultSpacing();


			pxDialog = new Asura_Numerical_Dialog("Botanicals view Distance",xOffset,&s_fBotanicalsRange,0,2500,20.0f,"%.1f");
			pxDialog->SetHelpText("Maximum distance (in metres) at which botanicals should be rendered. Ignored if checkbox isn't set.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Tickbox_Dialog("Use botanicals view Distance",xOffset,&s_bLimitBotanicalsRange);
			pxDialog->SetHelpText("Activates the 'Botanicals view Distance' setting above.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=1.5f*Asura_Dialog::DefaultSpacing();

			#ifndef ASURA_USE_VISIBILITY_SYSTEM
			pxDialog = new Asura_Tickbox_Dialog("Use Module Links",xOffset,&s_bUseModuleLinks);
			pxDialog->SetHelpText("Causes only the linked in modules to be drawn.\nIf unticked then all modules will be shown.\nF4 will toggle this setting when using standard rendering.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Tickbox_Dialog("Use Module Links (Coll Mesh)",xOffset,&s_bUseModuleLinksCMesh);
			pxDialog->SetHelpText("As above , but this is used when rendering collision meshes.\nF4 will toggle this setting when rendering collision meshes.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();
			#endif

			pxDialog = new Asura_Tickbox_Dialog("No Back-Face Cull",xOffset,&NoBackFaceCull,&s_bNoBackFaceCullChanged);
			pxDialog->SetHelpText("All polygons are rendered as double sided.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

		 	pxDialog = new Asura_Tickbox_Dialog("Ignore 'Don't Render' Flag",xOffset,&s_bIgnoreDontRenderFlag_User);
			pxDialog->SetHelpText("Forces polygons marked as 'Don't Render' to be drawn anyway.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

		 	pxDialog = new Asura_Tickbox_Dialog("Hide Object Polygons",xOffset,&s_bHideObjectPolygons,&s_bHideObjectPolygonsChanged);
			pxDialog->SetHelpText("Hides any static object polygons that have been merged into the environment as a result of the 'Merge With Env' flag.");
			pxDialog->SetIsEnabledFunction(IsHideObjectPolygonFlagEnabled);
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			#ifdef ASURA_USE_STREAMING
		 	pxDialog = new Asura_Tickbox_Dialog("Hide Other zones",xOffset,&s_bHideOtherZones);
			pxDialog->SetHelpText("Prevents the environmental polygons belonging to any connected zones from being rendered.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();
			#endif 

			xOffset.y+=Asura_Dialog::LargeSpacing() - Asura_Dialog::DefaultSpacing();
			

		 	pxDialog = new Asura_Tickbox_Dialog("Render All When In No Module",xOffset,&s_bRenderAllWhenInNoModule);
			pxDialog->SetHelpText("By default no modules are drawn if not in any module. This will force everything to be drawn instead.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::LargeSpacing();

			pxDialog = new Asura_FunctionTickbox_Dialog("Show phys objs in other modes", xOffset, Tools_Object_System::ShouldShowPhysicalObjectsInOtherModes, Tools_Object_System::SetShowPhysicalObjectsInOtherModes);
			pxDialog->SetHelpText("Causes tools objects for physical entities to be created (and be visible depending on other flags) in modes where they wouldn't normally be edited.\nThis won't do anything if a mode has already created the objects and is hiding them for its own diabolical schemes.");
			pxOverlay->AddDialog( pxDialog );
			xOffset.y += Asura_Dialog::LargeSpacing();

		}
		break;

		case TOOLS_GENERALOPTIONS_RENDERMODES :
		{

			//Platform specific rendering.
			Tools_PlatformMesh_System::AddOverlayControls(pxOverlay,xOffset);

			// PSP rendering mode
			pxDialog = new Asura_Dialog("PSP Mode Rendering :",xOffset);
			pxOverlay->AddDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();

			Asura_DropDown_List_Dialog* pxListDialog;
			pxListDialog = new Asura_DropDown_List_Dialog(xOffset,s_apszPSPRenderMode,&s_iPSPRenderMode,3,3,NULL,NULL);
			pxListDialog->SetListHelpStrings(s_apszPSPRenderModeHelp);
			pxOverlay->AddDialog(pxListDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();

			Tools_RenderCollisionMesh_System::AddRenderModeOverlayControls(pxOverlay,xOffset);


			pxDialog = new Asura_FunctionTickbox_Dialog("Physics Render",xOffset,0,IsShowPhysicsDebugInfo,SetShowPhysicsDebugInfo);
			pxDialog->SetHelpText("Shows the bounding boxes of physics objects.\nEquivalent to using the Physics.Render console variable in game.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Tickbox_Dialog("Show High Poly Modules",xOffset,&s_bShowHighPolyModules);
			pxDialog->SetHelpText("Highlights in green all modules with more polygons than the threshold value specified below.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();
			
			pxDialog = new Asura_Numerical_Dialog("Threshold",xOffset,&s_iHighPolyModuleThreshold,0,99999,100,"%d");
			pxDialog->SetHelpText("Any modules with more polygons than this will be highlighted if the above option is ticked.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y += Asura_Dialog::LargeSpacing();

		 	pxDialog = new Asura_Tickbox_Dialog("Highlight 'Don't Export' Polys",xOffset,&s_bHighlightDontExportPolygons);
			pxDialog->SetHelpText("Adds a green outline to any polygon marked as 'Don't Export'.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM
			pxDialog = new Asura_FunctionTickbox_Dialog("Disable Dual Pass", xOffset, Asura_Direct3D_EnvironmentRenderer::GetDisableDualPass, Asura_Direct3D_EnvironmentRenderer::SetDisableDualPass);
			pxDialog->SetHelpText("Disables rendering of the second material on each polygon for the environment");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_FunctionTickbox_Dialog("Show UV Orient", xOffset, Asura_MaterialResponse_System::GetUseUVOrientMaterial, Asura_MaterialResponse_System::SetUseUVOrientMaterial);
			pxDialog->SetHelpText("Forces everything to be rendered using a special material for showing the orientation of the texturing.\nMaterial used : Materials\\Tools\\UVOrientation.AsuraMaterial.\nHotkey : Alt+F3");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			#endif
		}
		break;
	
		case TOOLS_GENERALOPTIONS_SUBDIVISION :
		{
			pxDialog = new Asura_Dialog("Subdivide Near Waypoint Settings :",xOffset);
			pxDialog->SetHelpText("Subdivision options for rendering with subdivide near waypoint (F8).");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::SmallSpacing();
			
			pxDialog = new Asura_Numerical_Dialog("Subdivide Size (Flat)",xOffset,&s_fFlatSubdivideSize,0,100,0.01f,"%.2f");
			pxDialog->SetHelpText("Size on screen (in not very meaningful units) at which a flat polygon should be subdivided.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Numerical_Dialog("Subdivide Size (Curved)",xOffset,&s_fCurvedSubdivideSize,0,100,0.01f,"%.2f");
			pxDialog->SetHelpText("Size on screen (in not very meaningful units) at which a curved polygon should be subdivided.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();
		}
		break;

		case TOOLS_GENERALOPTIONS_COLOURS :
		{

			pxDialog = new Asura_Dialog("Wireframe Colour",xOffset);
			pxDialog->SetHelpText("Set the colour for the mixed wireframe/solid mode");
			pxOverlay->AddDialog(pxDialog);

			xOffset.x = pxDialog->m_xMaxCoord.x + 1.0f;
			pxDialog = new Tools_ARGBColourPicker_Dialog("Wireframe Colour",xOffset,Asura_Vector_2(1.5f,1.0f),&s_uWireframeColour,NULL);
			((Tools_ARGBColourPicker_Dialog*)pxDialog)->EnableAlphaEditing(true);
			pxDialog->SetHelpText("Set the colour for the mixed wireframe/solid mode");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();
			xOffset.x = 1.0f;

			pxDialog = new Asura_Tickbox_Dialog("3dsMax Colours",xOffset,&s_bUseMaxWireframeColour);
			pxDialog->SetHelpText("Makes use of the 3dsMax module wireframe colours if available. The alpha value will be taken from the wireframe colour above.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();


			pxDialog = new Asura_Dialog("Overlay Colour",xOffset);
			pxDialog->SetHelpText("Set the colour to be used for overlays");
			pxOverlay->AddDialog(pxDialog);

			xOffset.x = pxDialog->m_xMaxCoord.x + 1.0f;
			pxDialog = new Tools_ARGBColourPicker_Dialog("Overlay Colour",xOffset,Asura_Vector_2(1.5f,1.0f),&Asura_Overlay_System::s_uOverlayColour,NULL);
			pxDialog->SetHelpText("Set the colour to be used for overlays");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();
			xOffset.x = 1.0f;

		
			pxDialog = new Asura_Numerical_Dialog("Faded Overlay Alpha", xOffset, &Asura_Overlay_System::s_uFadedOverlayAlpha, 0, 255, 1, "%d");
			pxDialog->SetHelpText("Determines how visible overlays in the background should be.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y += Asura_Dialog::LargeSpacing();
		}
		break;

		case TOOLS_GENERALOPTIONS_SFX :
		{
			#ifdef ASURA_TARGET_SM3
			pxDialog = new Asura_FunctionTickbox_Dialog("Force Dynamic Lights On", xOffset, ShouldForceDynamicLightsOn, SetForceDynamicLightsOn);
			pxDialog->SetHelpText("Forces dynamic lights to be turned on.\nDynamic lights within templates will only be switched on if they are only off as a result of the template being off");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();
			#endif

			pxDialog = new Asura_Tickbox_Dialog("Enable Glow", xOffset, &s_bGlowEffectEnabled, &s_bGlowEffectEnabledChanged);
			pxDialog->SetHelpText("Apply the bloom filter when rendering the environment");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();

			#ifdef ASURA_SUPPORT_WEATHER_SYSTEM
				pxDialog = new Asura_Tickbox_Dialog("Enable Sun Glare",xOffset, &s_bUserEnableSunGlare);
				pxDialog->SetIsEnabledFunction(IsEnableSunGlareTickboxEnabled);
				pxDialog->SetHelpText("Enables/disables sun glare if it has been switched on for the level.\nIt will always be enabled in weather mode.");
				pxOverlay->AddDialog(pxDialog);
				xOffset.y += Asura_Dialog::DefaultSpacing();
			#endif

				pxDialog = new Asura_Tickbox_Dialog("Enable PFX",xOffset, &s_bShowPFX, &s_bShowPFXChanged);
				pxDialog->SetIsEnabledFunction(IsShowPFXTickboxEnabled);
				pxDialog->SetHelpText("Enables/disables all 'Starts Active' PFX effects.\n");
				pxOverlay->AddDialog(pxDialog);
				xOffset.y += Asura_Dialog::DefaultSpacing();

			AddDisableTextureAnimControl(pxOverlay,xOffset);

			Asura_Dialog* pxDialog = new Asura_Tickbox_Dialog("Enable Effect Volume",xOffset,&s_bEnableEffectVolume);
			pxDialog->SetHelpText("Enables/disables all 'Effect Volumes' in level.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();


			#ifdef ASURA_USE_FSFX
				xOffset.y += Asura_Dialog::LargeSpacing() - Asura_Dialog::DefaultSpacing();
				pxDialog = new Tools_FSFX_DropDownList_Dialog(xOffset,8,&s_uFSFXHash,&s_bFSFXChanged,"FSFX");
				pxDialog->SetIsEnabledFunction(IsFSFXControlEnabled);
				pxDialog->SetHelpText("Sets the current FSFX template to be used");
				pxOverlay->AddDialog(pxDialog);

				xOffset.x = pxDialog->m_xMaxCoord.x + 1.0f;
				pxDialog = new Asura_Numerical_Dialog("Intensity",xOffset, &s_fFSFXIntensity, 0.0f, 1.0f, 0.05f, "%.2f",&s_bFSFXChanged);
				pxDialog->SetIsEnabledFunction(IsFSFXControlEnabled);
				pxDialog->SetHelpText("Sets the intensity of the FSFX effect");
				pxOverlay->AddDialog(pxDialog);
				xOffset.x = 1.0f;
				xOffset.y += Asura_Dialog::LargeSpacing();
			#endif //ASURA_USE_FSFX

			#ifdef ASURA_USE_HDR

				xOffset.y += Asura_Dialog::LargeSpacing();

				// Show region
				pxDialog = new Asura_Tickbox_Dialog( "HDR: Show measurement region", xOffset,
					Asura_Direct3D_HDR::GetShowRegionVar() );
				pxDialog->SetHelpText( "Show the region where scene luminance will be measured for tone mapping." );
				pxOverlay->AddDialog( pxDialog );
				xOffset.y += Asura_Numerical_Dialog::DefaultSpacing();

				// Measurement region

				pxDialog = new Asura_Numerical_Dialog( "HDR: Measurement region bottom-left x",
					xOffset, &s_xHDRSettings.m_xRegion.MinX, -1.2f, 1.2f, 0.01f, "%.2f" );
				pxOverlay->AddDialog( pxDialog );
				xOffset.y += Asura_Numerical_Dialog::DefaultSpacing();

				pxDialog = new Asura_Numerical_Dialog( "HDR: Measurement region bottom-left y",
					xOffset, &s_xHDRSettings.m_xRegion.MinY, -1.0f, 1.0f, 0.01f, "%.2f" );
				pxOverlay->AddDialog( pxDialog );
				xOffset.y += Asura_Numerical_Dialog::DefaultSpacing();

				pxDialog = new Asura_Numerical_Dialog( "HDR: Measurement region top-right x",
					xOffset, &s_xHDRSettings.m_xRegion.MaxX, -1.2f, 1.2f, 0.01f, "%.2f" );
				pxOverlay->AddDialog( pxDialog );
				xOffset.y += Asura_Numerical_Dialog::DefaultSpacing();

				pxDialog = new Asura_Numerical_Dialog( "HDR: Measurement region top-right y",
					xOffset, &s_xHDRSettings.m_xRegion.MaxY, -1.0f, 1.0f, 0.01f, "%.2f" );
				pxOverlay->AddDialog( pxDialog );
				xOffset.y += Asura_Numerical_Dialog::LargeSpacing();

				// Scene exposure
				pxDialog = new Asura_Numerical_Dialog( "HDR: Scene Exposure", xOffset,
					&s_xHDRSettings.m_fKeyValue, fKEY_VALUE_MIN, fKEY_VALUE_MAX, 0.01f, "%.02f" );
				pxDialog->SetHelpText( "Sets the overall exposure of the scene." );
				pxOverlay->AddDialog( pxDialog );
				xOffset.y += Asura_Numerical_Dialog::DefaultSpacing();

				// White point
				pxDialog = new Asura_Numerical_Dialog( "HDR: White Point", xOffset,
					&s_xHDRSettings.m_fWhitePoint, fWHITE_POINT_MIN, fWHITE_POINT_MAX, 0.1f, "%.01f" );
				pxDialog->SetHelpText( "Sets the white point, above which values will white out. Set to a large number to remove the effect." );
				pxOverlay->AddDialog( pxDialog );
				xOffset.y += Asura_Numerical_Dialog::DefaultSpacing();

				// Black point
				pxDialog = new Asura_Numerical_Dialog( "HDR: Black Point", xOffset,
					&s_xHDRSettings.m_fBlackPoint, fBLACK_POINT_MIN, fBLACK_POINT_MAX, 0.001f, "%.03f" );
				pxDialog->SetHelpText( "Sets the black point, below which values will come out pure black. Set to 0 to remove the effect." );
				pxOverlay->AddDialog( pxDialog );
				xOffset.y += Asura_Numerical_Dialog::LargeSpacing();

				// Use dynamic exposure
				pxDialog = new Asura_Tickbox_Dialog( "HDR: Use Dynamic Exposure", xOffset,
					&s_xHDRSettings.m_bDynamicExposure );
				pxDialog->SetHelpText( "Toggles dynamic exposure adjustments." );
				pxOverlay->AddDialog( pxDialog );
				xOffset.y += Asura_Tickbox_Dialog::LargeSpacing();

				// Light adaptation rate
				pxDialog = new Asura_Numerical_Dialog( "HDR: Light Adaptation Rate", xOffset,
					&s_xHDRSettings.m_fAdaptationRate, fADAPTATION_RATE_MIN, fADAPTATION_RATE_MAX,
					0.1f, "%.01f" );
				pxDialog->SetHelpText( "Sets the rate at which the camera adapts to light levels. The higher the number, the faster the eye will adjust." );
				pxDialog->SetIsEnabledFunction( IsUsingDynamicExposure );
				pxOverlay->AddDialog( pxDialog );
				xOffset.y += Asura_Numerical_Dialog::DefaultSpacing();

				// Min light adaptation
				pxDialog = new Asura_Numerical_Dialog( "HDR: Min Light Adaptation", xOffset,
					&s_xHDRSettings.m_fMinLuminance, fMIN_LUMINANCE_MIN, fMIN_LUMINANCE_MAX, 0.1f,
					"%.01f" );
				pxDialog->SetHelpText( "Sets the minimum luminance the camera is capable of adapting to. If light levels drop below this, the scene will get dark." );
				pxDialog->SetIsEnabledFunction( IsUsingDynamicExposure );
				pxOverlay->AddDialog( pxDialog );
				xOffset.y += Asura_Numerical_Dialog::DefaultSpacing();

				// Max light adaptation
				pxDialog = new Asura_Numerical_Dialog( "HDR: Max Light Adaptation", xOffset,
					&s_xHDRSettings.m_fMaxLuminance, fMAX_LUMINANCE_MIN, fMAX_LUMINANCE_MAX, 0.1f,
					"%.01f" );
				pxDialog->SetHelpText( "Sets the maximum luminance the camera is capable of adapting to. If light levels rise above this, the scene will white out." );
				pxDialog->SetIsEnabledFunction( IsUsingDynamicExposure );
				pxOverlay->AddDialog( pxDialog );
				xOffset.y += Asura_Numerical_Dialog::LargeSpacing();

				// Fixed scene luminance
				pxDialog = new Asura_Numerical_Dialog( "HDR: Fixed Scene Luminance", xOffset,
					&s_xHDRSettings.m_fFixedLuminance, 0.0f, 32.0f, 0.01f, "%.02f" );
				pxDialog->SetHelpText( "Fixes the scene luminance at the given value." );
				pxDialog->SetIsEnabledFunction( IsUsingFixedExposure );
				pxOverlay->AddDialog( pxDialog );
				xOffset.y += Asura_Numerical_Dialog::DefaultSpacing();

				// Capture current luminance
				pxDialog = new Asura_Function_Dialog( "HDR: Capture Current Luminance", xOffset,
					OnCaptureLuminance, NULL, IsUsingFixedExposure, true );
				pxDialog->SetHelpText( "Fills in the value of the above control with the current scene luminance." );
				pxOverlay->AddDialog( pxDialog );
				xOffset.y += Asura_Dialog::LargeSpacing();

			#endif // ASURA_USE_HDR
		}
		break;

		case TOOLS_GENERALOPTIONS_MOVEMENT :
		{


			pxDialog = new Asura_Tickbox_Dialog("",xOffset,&s_bUsePlayerHeight);
			pxDialog->SetHelpText("Activates the 'Player Height' setting.");
			pxOverlay->AddDialog(pxDialog);

			xOffset.x = pxDialog->m_xMaxCoord.x;
			pxDialog = new Asura_Numerical_Dialog("Player Height",xOffset,&s_fPlayerHeight,0,10.0f,0.1f,"%.2f");
			pxDialog->SetHelpText("Overrides the height of the character to use when collisions (F9) are active.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.x = 1.0f;
			xOffset.y+=Asura_Dialog::DefaultSpacing();


		}
		break;

		case TOOLS_GENERALOPTIONS_STATUSTEXT :
		{
			pxDialog = new Asura_Tickbox_Dialog("Display Collision Polys",xOffset,&s_bDisplayCollisionPolys);
			pxDialog->SetHelpText("If ticked then the number of collision polys will be displayed");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+= Asura_Dialog::LargeSpacing();
		}
		break;

		case TOOLS_GENERALOPTIONS_PERFORMANCE :
		{
			pxDialog = new Asura_Tickbox_Dialog("Clamp Frame Rate",xOffset,&s_bClampFrameRate);
			pxDialog->SetHelpText("If ticked then the frame rate will be clamped to the value below");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+= Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Numerical_Dialog("Max Frame Rate",xOffset,&s_fMaxFrameRate,5.0f,999.0f,1.0f,"%.0f");
			pxDialog->SetHelpText("Sets the maximum frame rate.\nOnly used if Clamp Frame Rate is ticked.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+= Asura_Dialog::DefaultSpacing();
		}
		break;


		case TOOLS_GENERALOPTIONS_MOUSE :
		{
			pxDialog = new Asura_Numerical_Dialog("Cursor Speed",xOffset,&s_fCursorSpeed,0.1f,10.0f,1.0f,"%.1f",&s_bCursorSpeedChanged);
			pxDialog->SetHelpText("Sets a multiplier for the rate at which the mouse cursor moves.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();
		}
		break;

	
		case TOOLS_GENERALOPTIONS_DISPLAY :
		{


		#ifdef ASURA_SUPPORT_MULTIPLE_MONITORS
			pxDialog = new Asura_Tickbox_Dialog("Use Multiple Monitors",xOffset, &s_bUseMultipleMonitors, &s_bUseMultipleMonitorsChanged);
			pxDialog->SetHelpText("Sets whether Tools will expand to cover all available monitors.\nChanges to this option will not take effect until restarting tools.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+= Asura_Dialog::DefaultSpacing();
		#endif

			delete[] s_piSelectedResolutions; delete[] s_pszScreenNames;
			s_piSelectedResolutions = new int[Asura_Direct3D::GetNumPresentParameters()];
			s_pszScreenNames = new Asura_Char[20*Asura_Direct3D::GetNumPresentParameters()];
			for(u_int uAdapter = 0; uAdapter < Asura_Direct3D::GetNumPresentParameters(); ++uAdapter)
			{
				Asura_PrintfToBfr(s_pszScreenNames + uAdapter * 20, "Screen %i", 20, true, uAdapter);
				pxDialog = new Tools_Resolution_DropDownList_Dialog(uAdapter + Asura_Direct3D_UserOptions::GetCurrentOptions().m_uAdapterIndex, xOffset, 8, s_piSelectedResolutions[uAdapter], NULL, s_pszScreenNames + (uAdapter*20));
				pxOverlay->AddDialog(pxDialog);
				xOffset.y+= Asura_Dialog::DefaultSpacing();
			}

			pxDialog = new Asura_Function_Dialog("Apply", xOffset, UpdateDisplaySettings);
			pxDialog->SetHelpText("Applies the changes to the screen resolution.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y += Asura_Dialog::LargeSpacing();


			pxDialog = new Asura_Numerical_Dialog("Gamma",xOffset,&s_fGamma,0,1.0f,0.01f,"%.2f",&s_bGammaChanged);
			pxDialog->SetHelpText("Sets gamma (brightness) for rendering. Default is 0.5.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::LargeSpacing();
			

			pxDialog = new Asura_Tickbox_Dialog("Use Vertical Field of View",xOffset,&FieldOfViewIsVertical,&FieldOfViewChanged);
			pxDialog->SetHelpText("Toggles the specified field-of-view between horizontal and vertical.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Numerical_Dialog("Horizontal field of View",xOffset,&HorizontalFieldOfViewInDegress,5,175,1.0f,"%.1f",&FieldOfViewChanged);
			pxDialog->SetIsEnabledFunction(IsHorizontalFOVEnabled);
			pxDialog->SetHelpText("Horizontal field-of-view in degrees. Default is 75 (may be changed by project).");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Numerical_Dialog("Vertical field of View",xOffset,&VerticalFieldOfViewInDegress,5,175,1.0f,"%.1f",&FieldOfViewChanged);
			pxDialog->SetIsEnabledFunction(IsVerticalFOVEnabled);
			pxDialog->SetHelpText("Vertical field-of-view in degrees.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::LargeSpacing();


			pxDialog = new Asura_Tickbox_Dialog("Use Skinned UI",xOffset, &s_bUseSkinnedUI, &s_bUseSkinnedUIChanged);
			pxDialog->SetHelpText("Sets whether tools uses the skinned UI or the old-style overlay rendering.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+= Asura_Dialog::LargeSpacing();


#if defined(ASURA_USE_SCREENSHOT_SYSTEM)
			pxDialog = new Asura_Tickbox_Dialog("Enable Hi-Res screenshot mode", xOffset, &s_bEnableHiResScreenshotMode);
			pxDialog->SetHelpText("Toggles whether we have the renderers set for hi-resolution screenshots.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Numerical_Dialog("Hi-Res screenshot magnification", xOffset, &s_iHiResScreenshotMagnification, 2, Asura_ScreenShot_System::uMAX_MAGNIFICATION, 1, "%d", &s_bHiResScreenshotMagnificationChanged);
			pxDialog->SetIsEnabledFunction(IsHiResScreenshotModeEnabled);
			pxDialog->SetHelpText("Horizontal field-of-view in degrees. Default is 75 (may be changed by project).");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::LargeSpacing();

			pxDialog = new Asura_Tickbox_Dialog("Disable mip-mapping", xOffset, &s_bDisableMipMaps);
			pxDialog->SetHelpText("Disables mip-mapping.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();


#endif	//defined(ASURA_USE_SCREENSHOT_SYSTEM)
		}
		break;
	}
}


void Tools_Render_Options::UpdateDisplaySettings()
{
	for(u_int uDisplay = 0; uDisplay < Asura_Direct3D::GetNumPresentParameters(); ++uDisplay)
	{
		Asura_List_ConstIt<Asura_Direct3D_UserOptions::ResolutionInfo> xIt(Asura_Direct3D_UserOptions::GetSupportedResolutions(uDisplay));
		int iIndex = 0;
		while(iIndex != s_piSelectedResolutions[uDisplay]) { ++iIndex; xIt.Next(); }
		if(xIt.Done()) continue;

		UINT uWidth = xIt.GetCurrent()->m_xModeData.Width;
		UINT uHeight = xIt.GetCurrent()->m_xModeData.Height;
		Tools_Render::SetVideoMode(uWidth, uHeight);
		Asura_Direct3D_UserOptions::GetCurrentOptions().SetBackBufferDimensions(uWidth, uHeight, uDisplay);
	}
	UpdateFieldOfView();
	Asura_Direct3D::RecalcPresentParameters();
	Asura_Direct3D::RestoreAll(true);
}

void Tools_Render_Options::AddDisableTextureAnimControl(Asura_Overlay* pxOverlay,Asura_Vector_2& xOffset)
{
	Asura_Dialog* pxDialog = new Asura_Tickbox_Dialog("Enable Texture Anim",xOffset,&s_bEnableTextureAnims);
	pxDialog->SetHelpText("Enables/disables all texture animations.");
	pxOverlay->AddDialog(pxDialog);
	xOffset.y += Asura_Dialog::DefaultSpacing();
}


bool Tools_Render_Options::IsModuleWithinViewDistance(int iModule)
{
	if(!UseViewDistance) return true;
	
	#ifdef ASURA_USE_STREAMING
	if(!Tools_Streaming_System::IsSetToMainZone())
	{
		//Don't have cached version of within view distance for other zones yet.
		//RAR 11/04/2006
		Asura_Assert(iModule>=0 && iModule<Asura_Module_System::GetNumberOfModules(),"");	
			
		const Asura_Vector_3& xCentre = Asura_Module_System::GetCentreOfModule( iModule );
		float fRadius = Asura_Module_System::GetRadiusOfModule(iModule);
		float fDistance = (*Asura_Camera::GetPosition()-xCentre).Magnitude();

		return (fDistance-fRadius)<ViewDistance;
	}
	#endif

	Asura_Assert(iModule>=0 && iModule<NumberOfModules,"");
	return ModuleData[iModule]->WithinViewDistance;
}

bool Tools_Render_Options::IsPointWithinViewDistance(const Asura_Vector_3& point)
{
	if(!UseViewDistance) return true;

	float distance = (*Asura_Camera::GetPosition()-point).Magnitude();
	return distance<ViewDistance;
}

void Tools_Render_Options::SetGamma(float fGamma)
{
	Asura_Assert(fGamma>=0 && fGamma<=1.0f,"");
	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);
	}

//	if(Asura_Windows::RunningFullScreen())
	{
		Asura_Direct3D::D3DDevice->SetGammaRamp(0,D3DSGR_CALIBRATE,&xRamp);
	}
//	else
//	{
//		SetDeviceGammaRamp(GetDC(Asura_Windows::GetWindowHandle()),&xRamp);
//	}
}

void Tools_Render_Options::ActivateHideFlag(int iFlags)
{
	int iOldFlags = s_iActiveHideFlags;
	s_iActiveHideFlags |= iFlags;
	int iChangedFlags = iOldFlags^s_iActiveHideFlags;

	//may need to update some render meshes from polygons becoming hidden
	if(iChangedFlags)
	{
		UpdateAllPolygonVisibilities();
	}
}

void Tools_Render_Options::DeactivateHideFlag(int iFlags)
{
	int iOldFlags = s_iActiveHideFlags;
	s_iActiveHideFlags &=~ iFlags;
	int iChangedFlags = iOldFlags^s_iActiveHideFlags;

	//may need to update some render meshes from polygons becoming revealed
	if(iChangedFlags)
	{
		UpdateAllPolygonVisibilities();
	}
}

void Tools_Render_Options::SetPolygonFlagToHide(int iFlags,bool bAdd)
{
	int iOldFlags = s_iPolygonFlagsToHide;
	if(bAdd)
		s_iPolygonFlagsToHide |= iFlags;
	else
		s_iPolygonFlagsToHide &=~ iFlags;

	int iChangedFlags = iOldFlags^s_iPolygonFlagsToHide;

	//may need to update some render meshes from polygons becoming hidden
	if(iChangedFlags)
	{
		UpdateAllPolygonVisibilities();
	}
}

void Tools_Render_Options::SetMaskedPolygonFlagsToHide(int iFlags,int iMask)
{
	int iOldFlags = s_iPolygonFlagsToHide;
	s_iPolygonFlagsToHide &=~ iMask;
	s_iPolygonFlagsToHide |= iFlags;

	int iChangedFlags = iOldFlags^s_iPolygonFlagsToHide;

	//may need to update some render meshes from polygons becoming hidden
	if(iChangedFlags)
	{
		UpdateAllPolygonVisibilities();
	}
}



void Tools_Render_Options::UpdateAllPolygonVisibilities()
{
	for(int i=0;i<NumberOfModules;i++)
	{
		for(int j=0;j<ModuleData[i]->NumberOfPolygons;j++)
		{
			ModuleData[i]->UpdatePolygonVisibility(j);
		}
	}
}

void Tools_Render_Options::SetSubdivisionMode(enum Tools_SubdivisionMode eMode)
{
	s_eSubdivideMode = eMode;
	ApplySubdivisionMode();
}

void Tools_Render_Options::ApplySubdivisionMode()
{
	Asura_PatchSubdivision::SetSubdivideFlat(false);
	Asura_PatchSubdivision::SetFlatSubdivideSize(ASURA_PATCH_DEFAULT_SUBDIVIDE_SIZE);
	Asura_PatchSubdivision::SetCurveSubdivideSize(ASURA_PATCH_DEFAULT_SUBDIVIDE_SIZE);

	switch(s_eSubdivideMode)
	{
		case TOOLS_SUBDIVIDE_NONE :
			Asura_Render::SetPatchesSubdivLevel(0);
			Asura_PatchSubdivision::SubdivideEvenly();
			break;

		case TOOLS_SUBDIVIDE_EVENLY :
			Asura_Render::SetPatchesSubdivLevel(3);
			Asura_PatchSubdivision::SubdivideEvenly();
			Asura_Mesh_System::PlatformResetRenderMeshesOnly();
			break;

		case TOOLS_SUBDIVIDE_NEARWAYPOINTS :
			Asura_Render::SetPatchesSubdivLevel(4);
			Asura_PatchSubdivision::SubdivideNearWaypoints();
			Asura_PatchSubdivision::SetSubdivideFlat(true);
			Asura_PatchSubdivision::SetFlatSubdivideSize(s_fFlatSubdivideSize);
			Asura_PatchSubdivision::SetCurveSubdivideSize(s_fCurvedSubdivideSize);
			Asura_Mesh_System::PlatformResetRenderMeshesOnly();
			break;
	};
}


float Tools_Render_Options::GetPlayerHeight()
{
	if(!s_bUsePlayerHeight)
	{
		switch(s_iPlayerPosture)
		{
		case POSTURE_PRONE :
			return Tools_System::This->GetDefaultProneHeight();
		
		case POSTURE_CROUCH :
			return Tools_System::This->GetDefaultCrouchHeight();
		
		case POSTURE_STAND :
		default :
			return Tools_System::This->GetDefaultPlayerHeight();
		}
	}
	return s_fPlayerHeight;
}

void Tools_Render_Options::SetAlwaysVisiblePolygonFlags(int iFlags)
{
	int iChangedFlags = iFlags ^ s_iAlwaysVisiblePolygonFlags;
	s_iAlwaysVisiblePolygonFlags = iFlags;

	if(iChangedFlags)
	{
		//update visibility for any polygons that were using this flag
		for(int i=0;i<NumberOfModules;i++)
		{
			if(!ModuleData[i]->Mesh->PolygonFlagDataPtr) continue;
			
			for(int j=0;j<ModuleData[i]->NumberOfPolygons;j++)
			{
				ModuleData[i]->UpdatePolygonVisibility(j);
			}
		}
	}
}

void Tools_Render_Options::UpdatePolygonVisibility(int iModule,int iPolygon)
{
	Asura_Assert(iModule>=0 && iModule<NumberOfModules,"");

	ModuleData[iModule]->UpdatePolygonVisibility(iPolygon);
	
}

void Tools_Render_Options::SetDisableHideObjectPolygonFlag(bool bDisable)
{
	s_bDisableHideObjectPolygonFlag = bDisable;
	UpdateAllPolygonVisibilities();
}

bool Tools_Render_Options::MoveTowardsStandPosture()
{
	if(s_bUsePlayerHeight) return false;
	
	if(s_iPlayerPosture == POSTURE_STAND) return false;
	s_iPlayerPosture--;
	return true;
}

bool Tools_Render_Options::MoveTowardsPronePosture()
{
	if(s_bUsePlayerHeight) return false;
	
	if(s_iPlayerPosture == POSTURE_PRONE) return false;
	s_iPlayerPosture++;
	return true;
}


void Tools_Render_Options::SetUseDiscoLights(bool bUse)
{
	if(bUse != s_bDiscoLights)
	{
		s_bDiscoLights = bUse;
		//invalidate lighting
		Tools_RenderModule_System::UpdateAllModuleLighting();
	}
}

void Tools_Render_Options::NextWireframeMode()
{
	s_eWireframeMode = (Tools_WireframeMode)((s_eWireframeMode+1)%3);
	Asura_Render::SetWireframe(s_eWireframeMode==TOOLS_WIREFRAME_ON);
}

u_int Tools_Render_Options::GetWireframeColour(bool bMixedWireframe /*= true*/,int iModule /*= -1*/)
{
	if(s_bUseMaxWireframeColour && iModule>=0)
	{
		//get the colour that has been set for the module
		Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(iModule);
		if(pxMesh->m_uMaxWireframeColour)
		{
			u_int uColour = pxMesh->m_uMaxWireframeColour & 0xffffff;
			//take the alpha from the default wireframe colour however
			if(bMixedWireframe)
				uColour |= (s_uWireframeColour & 0xff000000);
			else
				uColour |= 0xff000000;

			return uColour;
		}
	}

	return bMixedWireframe ? s_uWireframeColour : 0xffffffff;
}

void Tools_Render_Options::NextPolygonHighlightMode()
{
	s_ePolygonHighlightMode = (Tools_HighlightMode)((s_ePolygonHighlightMode+1)%3);
}


#ifndef ASURA_USE_VISIBILITY_SYSTEM
void Tools_Render_Options::ToggleUseModLinks()
{
	if(Tools_RenderCollisionMesh_System::IsRenderingCollMeshes())
	{
		s_bUseModuleLinksCMesh = !s_bUseModuleLinksCMesh;
		Asura_Module_System::UseModLinks = s_bUseModuleLinksCMesh;
	}
	else
	{
		s_bUseModuleLinks = !s_bUseModuleLinks;
		Asura_Module_System::UseModLinks = s_bUseModuleLinks;
	}
}
#endif

void Tools_Render_Options::SetPFXControlledByMode(bool bSet)
{
	s_bPFXControlledByMode = bSet;
	if(!s_bPFXControlledByMode) s_bShowPFXChanged = true;
}

#ifdef ASURA_USE_FSFX
void Tools_Render_Options::SetFSFXControlledByMode(bool bSet)
{
	if(bSet != s_bFSFXControlledByMode)
	{
		s_bFSFXControlledByMode = bSet;
		UpdateFSFXSettings();
	}
}

void Tools_Render_Options::UpdateFSFXSettings()
{
	//Update settings in Tools_FSFX_System unless the template is being controlled by the FSFX mode
	if(!s_bFSFXControlledByMode)
	{
		Asura_FSFX_Template* pxTemplate = Asura_FSFX_System::FindTemplate(s_uFSFXHash);
		Tools_FSFX_System::SetOverrideFSFX(pxTemplate,s_fFSFXIntensity);
	}
}
#endif //ASURA_USE_FSFX


bool Tools_Render_Options::IsShowPhysicsDebugInfo(void* pJunk)
{
	return Asura_Physics_System::GetDisplayDebugInfo();
}

void Tools_Render_Options::SetShowPhysicsDebugInfo(bool bSet,void* pJunk)
{
	Asura_Physics_System::SetDisplayDebugInfo(bSet);
}

bool  Tools_Render_Options::IsOverlayScalingEnabled()
{
	return !Tools_System::IsActive() && s_bEnableOverlayScaling;
}

float Tools_Render_Options::GetOverlayScale()
{
	if( IsOverlayScalingEnabled() )
	{
		if( Tools_Render_Options::IsInPSPMode() && !Tools_Render_Options::IsPSPModeActualSize() )
		{
			return Asura_Viewport::GetWidth() / 480.0f;
		}	
	}	

	return 1.0f;
}

void Tools_Render_Options::TogglePSPMode()
{
	s_iPSPRenderMode	= (s_iPSPRenderMode + 1) % TOOLS_PSPRENDERMODE_MAX_MODES;
	PSPModeChanged();
}

void Tools_Render_Options::SetPSPMode(const Tools_PSPRenderMode eMode)	
{
	s_iPSPRenderMode = eMode;
	PSPModeChanged();
};

void Tools_Render_Options::PSPModeChanged()
{
	if(Tools_Render_Options::IsInPSPMode())
	{
		if(Tools_Render_Options::IsPSPModeActualSize())
		{
			Asura_Render::ActivateScreenBorder(Asura_Render::SCREEN_BORDER_ACTUAL_SIZE, 480, 272);
		}
		else
		{
			Asura_Render::ActivateScreenBorder(Asura_Render::SCREEN_BORDER_STRETCH_TO_FIT, 480, 272);
		}
	}	
	else
	{
		Asura_Render::ActivateScreenBorder(Asura_Render::SCREEN_BORDER_DISABLED, 480, 272);
	}
};

#ifdef ASURA_USE_HDR

void Tools_Render_Options::OnCaptureLuminance()
{
	Asura_Direct3D_HDR::CaptureFixedLuminance( s_xHDRSettings.m_fFixedLuminance );
}

#endif // ASURA_USE_HDR

#ifdef ASURA_TARGET_SM3
void Tools_Render_Options::SetForceDynamicLightsOn(bool bSet)
{
	s_bForceDynamicLightsOn = bSet;
	Asura_ClientEntity_DynamicLight::HandleForceActiveChange();
}
#endif

//////////////////////////////////////////////////////////////////////////////////////////////////
/*-----------------------------**
** Tools_Module_Render_Options **
**-----------------------------*/


Tools_Module_Render_Options::Tools_Module_Render_Options(int moduleIndex,Asura_Mesh* mesh)
{
	Mesh = mesh;
	ModuleIndex = moduleIndex;
	NumberOfPolygons = mesh->NumberOfPolygons;
	m_iNumVisiblePolygons = mesh->NumberOfPolygons;
	PolygonData = new Tools_Polygon_Render_Options[NumberOfPolygons];
	WithinViewDistance = true;
	m_iRenderFlags = 0;

}

Tools_Module_Render_Options::~Tools_Module_Render_Options()
{
	delete [] PolygonData;
}

void Tools_Module_Render_Options::AddRenderFlagModule(int iFlags)
{
	int iOldRenderFlags = m_iRenderFlags;
	m_iRenderFlags |= iFlags;

	if(m_iRenderFlags != iOldRenderFlags)
	{
		if(iFlags & (Tools_Render_Options::GetHideFlags()|ToolsRenderFlag_ToBeDestroyed))
		{
			Tools_RenderModule_System::UpdateModuleMesh(Mesh->Index);//to update visibility	
		}
	}
}

void Tools_Module_Render_Options::RemoveRenderFlagModule(int iFlags)
{
	int iOldRenderFlags = m_iRenderFlags;
	m_iRenderFlags &=~ iFlags;

	if(m_iRenderFlags != iOldRenderFlags)
	{
		if(iFlags & (Tools_Render_Options::GetHideFlags()|ToolsRenderFlag_ToBeDestroyed))
		{
			Tools_RenderModule_System::UpdateModuleMesh(Mesh->Index);//to update visibility	
		}
	}
}

void Tools_Module_Render_Options::AddRenderFlagPolygon(int iPolygon,int iFlags)
{
	Asura_Assert(iPolygon>=0 && iPolygon<NumberOfPolygons,"");
	PolygonData[iPolygon].m_iRenderFlags |= iFlags;

	UpdatePolygonVisibility(iPolygon);
}

void Tools_Module_Render_Options::RemoveRenderFlagPolygon(int iPolygon,int iFlags)
{
	Asura_Assert(iPolygon>=0 && iPolygon<NumberOfPolygons,"");
	PolygonData[iPolygon].m_iRenderFlags &=~ iFlags;

	UpdatePolygonVisibility(iPolygon);
}

void Tools_Module_Render_Options::HandlePolygonConversion(Asura_Mesh* mesh,int* PolyConv1,int* PolyConv2)
{
	//allocate a new array , and copy across the settings for the polygons , aplying the conversions
	Tools_Polygon_Render_Options* NewPolygonData = new Tools_Polygon_Render_Options[mesh->NumberOfPolygons];
	
	m_iNumVisiblePolygons = mesh->NumberOfPolygons;
	for(int i=0;i<NumberOfPolygons;i++)
	{
		if(PolyConv1 && PolyConv1[i] != -1)
		{
			NewPolygonData[PolyConv1[i]] = PolygonData[i]; 
			if(PolygonData[i].m_bHidden) m_iNumVisiblePolygons--;
		}
		if(PolyConv2 && PolyConv2[i] != -1)
		{
			NewPolygonData[PolyConv2[i]] = PolygonData[i];
			if(PolygonData[i].m_bHidden) m_iNumVisiblePolygons--;
		}
	}
    

	delete [] PolygonData;
	PolygonData = NewPolygonData;
	NumberOfPolygons = mesh->NumberOfPolygons;

	//check polygon visibilities (in case any new ones should be hidden)
	for(int i=0;i<NumberOfPolygons;i++)
	{
		UpdatePolygonVisibility(i);
	}
}

void Tools_Module_Render_Options::HandleMeshChange(Asura_Mesh* pxMesh)
{
	if(pxMesh->NumberOfPolygons != NumberOfPolygons || pxMesh != Mesh)
	{
		Mesh = pxMesh;
		//replace with new array of polygon data
		delete [] PolygonData;
		PolygonData = new Tools_Polygon_Render_Options[pxMesh->NumberOfPolygons];
		NumberOfPolygons = pxMesh->NumberOfPolygons;
		m_iNumVisiblePolygons = NumberOfPolygons;

	}

	//check polygon visibilities (in case any new ones should be hidden)
	for(int i=0;i<NumberOfPolygons;i++)
	{
		UpdatePolygonVisibility(i);
	}
}

void Tools_Module_Render_Options::UpdatePolygonVisibility(int iPolygon)
{
	int iRenderFlags = PolygonData[iPolygon].m_iRenderFlags;
	bool bWasHidden = PolygonData[iPolygon].m_bHidden;

	int iPolygonFlags = Mesh->GetPolygonFlags(iPolygon);

	if(Tools_System::IsShuttingDown())
	{
		//Preparing for quitting to game , so most of the hide options don't apply.
		PolygonData[iPolygon].m_bHidden = (iPolygonFlags & AsuraPolygonFlag_DontRender) ? true : false;
	}
	else
	{
		int iHideFlags = Tools_Render_Options::GetHideFlags();
		int iPolygonFlagsToHide = Tools_Render_Options::GetPolygonFlagsToHide();
		int iAlwaysVisiblePolyFlags = Tools_Render_Options::GetAlwaysVisiblePolygonFlags();
		if( iPolygonFlags & iAlwaysVisiblePolyFlags)
		{
			//polygon has one of the flags that should cause the don't render flag to be disabled
			//In fact , cause it disable all the hide by polygon flagoptions
			iPolygonFlagsToHide = 0;
		}

		//update hidden flag
		PolygonData[iPolygon].m_bHidden = (iHideFlags & iRenderFlags) || (iPolygonFlags & iPolygonFlagsToHide);
	
		//should polygon be hidden as a result of being an object polygon?
		if(Tools_Render_Options::IsHidingObjectPolygons())
		{
			if(Mesh->IsMergedObjectPolygon(iPolygon))
			{
				PolygonData[iPolygon].m_bHidden = true;
			}
		}
	}

	if(PolygonData[iPolygon].m_bHidden != bWasHidden)
	{
		//hidden status has changed
		Tools_RenderModule_System::UpdateModuleMesh(Mesh->Index);
		Asura_Mesh_System::PlatformResetRenderMeshOnly(Mesh);
		Tools_RenderCollisionMesh_System::InvalidateModule(ModuleIndex);

		//update count of visible polygons
		if(PolygonData[iPolygon].m_bHidden)
			m_iNumVisiblePolygons--;
		else
			m_iNumVisiblePolygons++;

		Asura_Assert(m_iNumVisiblePolygons>=0 && m_iNumVisiblePolygons<=NumberOfPolygons,"Tracking of visible polygons gone screwy");
	}

}

bool Tools_Module_Render_Options::IsPolygonHidden(int iPolygon)
{
	return PolygonData[iPolygon].m_bHidden;
}

/////////////////////////////////////////////////////////////////////////////////////////////////
/*------------------------------**
** Tools_Polygon_Render_Options **
**------------------------------*/

Tools_Polygon_Render_Options::Tools_Polygon_Render_Options()
{
	m_iRenderFlags = 0;
	m_bHidden = false;
}
