//									   
// Tools_System.cpp
//
// Created by Kevin Lea - 25/06/2001 14:51:11
// 
// Copyright (C) 2001 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"
#include "Core/Asura_MaterialResponse_System.h"

// This file's header
#include "Tools_System.h"

// Asura includes
#include "Animation/Asura_Hierarchy.h"

#ifdef ASURA_USE_BOTANICALS
#include "Botanicals/Asura_Botanical_Game_Render_Manager.h"
#include "Botanicals/Asura_Botanicals_TemplateManager.h"
#include "Botanicals/Asura_Botanicals_InstanceManager.h"
#endif // #ifdef ASURA_USE_BOTANICALS
#if defined( ASURA_BOTANICAL_SUPPORT_INTERACTIVE)
#include "BotanicalCreation/Tools_BotanicalCreation_BasicInteractive.h"
#endif

#include "Camera/Asura_Camera.h"

#ifdef ASURA_USE_CARPET
#include "Carpet/Asura_Carpet_StyleManager.h"
#include "Carpet/Asura_Carpet_MeshManager.h"
#endif // #ifdef ASURA_USE_CARPET

#include "ChunkSystem/Asura_Chunk_Cutscene.h"
#include "ChunkSystem/Asura_Chunk_ModuleLinking.h"
#ifdef ASURA_DISABLE_DYNAMICS_WITH_PARTICLE_GENERATORS
#include "ChunkSystem/Asura_Chunk_ParticleTemplates.h"
#endif
#include "Core/Asura_PlatformBasics.h" // for sprintf
#include "Core/Asura_Timers.h"
#include "Core/Asura_UserInput.h"
#include "Core/Asura_Windows.h"
#include "Core/Asura_Material_System.h"
#include "Cutscene/Asura_Cutscene_System.h"
#include "Debugging/Asura_Assert.h"
#include "Debugging/Asura_CPUProfile.h"
#include "Debugging/Asura_Debug_Timers.h"
#include "Debugging/Asura_Version.h"
#ifdef ASURA_DISABLE_DYNAMICS_WITH_PARTICLE_GENERATORS
#include "Entity/Asura_Entity.h"
#include "Entity/ParticleGenerator/Asura_ServerEntity_ParticleGenerator.h"
#endif
#include "Entity/Asura_Entity_Classification.h"
#ifndef ASURA_TARGET_SM3
#include "Entity/PhysicalObject/Asura_ServerEntity_AdvancedLight.h"
#include "Entity/PhysicalObject/Asura_ServerEntity_DestructibleLight.h"
#endif // #ifndef ASURA_TARGET_SM3
#ifdef ASURA_TOOLS_USE_NEW_MESSAGE_EDITOR
#include "Entity/Tools_MessageEditor.h"
#endif
#if defined(ASURA_USE_FACIAL_ANIMATION_SYSTEM)
#include "FacialAnimation/Asura_FacialAnimation_System.h"
#endif	//defined(ASURA_USE_FACIAL_ANIMATION_SYSTEM)
#ifdef ASURA_USE_GUI_MENU_SYSTEM
#include "GUIMenu/Asura_GUIMenu_System.h"
#endif
#include "Interface/Asura_Overlay_System.h"
#include "Interface/Asura_Interface.h"
#include "Interface/Asura_Menubar_System.h"
#include "Interface/Asura_Menubar.h"
#include "Interface/Asura_Dialog.h"
#include "Interface/Asura_Key_Combination.h"
#include "Interface/Asura_Cursor.h"
#include "Interface/Asura_Overlay.h"
#include "Input/Asura_Mouse.h"
#include "Light/Asura_Photon.h" // for photon test
#include "Mesh/Asura_Mesh.h" // for Drew's body stuff
#include "Mesh/Asura_Mesh_System.h"
#include "Mesh/Asura_Env.h"
#include "Mesh/Asura_Env_System.h"
#include "Network/Asura_Network.h"
#if defined(ASURA_TARGET_SM3)
#include "PC/Rendering/Asura_Direct3D_EnvironmentRenderer.h"
#endif
#include "Physics/Asura_Physics.h"
#include "SpecialFX/Asura_Corona_System.h"
#include "Ragdoll/Tools_Mode_RagdollEditor.h"
#include "Rendering/Asura_Render.h"
#include "Rendering/Asura_SortedRender.h"
#include "Rendering/Asura_Module.h"
#ifdef ASURA_SUPPORT_FMV_TEXTURES
#include "Rendering/Asura_MovieToTexture_System.h"
#endif
#ifdef ASURA_TARGET_SM3
#include "Rendering/Asura_DeferredShading.h"
#endif
#ifdef ASURA_TARGET_SM3
#include "Projectors/Asura_Projector_System.h"
#endif

#include "Rendering/Asura_Text_Output.h"
#include "Rendering/Asura_Viewport.h"
#include "Rendering/Asura_PatchSubdivision.h"
#include "Rendering/Asura_Direct3D.h"
#include "Rendering/Asura_Viewport.h"
#include "Shadows/Asura_CSM.h"
#include "Sound/Asura_Audio_Systems_Manager.h"
#ifdef ASURA_USE_DIALOGUE_SYSTEM
#include "Sound/Asura_Dialogue.h"
#endif
#ifdef ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM
#include "Sound/Asura_Dynamic_Music_System.h"
#endif
#include "Sound/Asura_MetaMusic_System.h"

#include "SpecialFX/Asura_SpecialFX.h"
#include "SpecialFX/Asura_Skybox.h"
#ifdef ASURA_SUPPORT_WEATHER_SYSTEM
#include "SpecialFX/Asura_Weather_System.h"
#endif
#ifdef ASURA_USE_DECAL_MANAGER

#endif

// Tools includes
#ifdef ASURA_USE_ANIMATION_IK_SOLVER
#include "Animation/IK/Tools_Animation_IK_Template_System.h"
#endif

#ifdef ASURA_USE_ATTRACTORS
#include "Attractors/Tools_Mode_Attractors.h"
#endif

#ifdef ASURA_USE_BILLBOARD_PLANTS
#include "BillboardPlants/Tools_Mode_BillboardPlants.h"
#endif //ASURA_USE_BILLBOARD_PLANTS

#include "Blueprint/Tools_Mode_Blueprint.h"

#ifdef ASURA_USE_BOTANICALS
#include "Botanicals/Tools_Botanicals_Object.h"
#include "Botanicals/Tools_Mode_Botanicals.h"
#include "BotanicalCreation/Tools_Mode_BotanicalCreation.h"
#include "Botanicals/Tools_Botanicals_Statistics.h"
#endif // #ifdef ASURA_USE_BOTANICALS

#ifdef ASURA_USE_CARPET
#include "Carpet/Tools_Mode_Carpet.h"
#include "Carpet/Tools_Carpet_Statistics.h"
#endif // #ifdef ASURA_USE_CARPET

#ifdef ASURA_USE_STATIC_DECAL_SYSTEM
#include "Decals/Tools_Mode_Decals.h"
#endif

#include "Cutscene/Tools_Mode_Cutscene.h"
#include "Cutscene/Tools_CutsceneModeAVI.h"

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

#ifdef ASURA_DISABLE_DYNAMICS_WITH_PARTICLE_GENERATORS
#include "Entity/Tools_Entity_Data.h"
#endif

#include "Entity/Tools_Message_Editing.h"
#include "Entity/Tools_SecondaryEntityFile_System.h"
#include "Entity/Tools_Entity_PhysicalObject.h"
#include "EntityTemplate/Tools_Entity_Template_Object.h"
#include "EntityTemplate/Tools_EntityTemplate_System.h"

#include "Entity/Tools_Entity_PFX_Effect.h"
#include "Particles/Tools_PFX_Overrides.h"
#include "FSFX/Tools_FSFX_Overrides.h"

#ifdef ASURA_TARGET_SM3
#include "Entity/Tools_Entity_DynamicLight.h"
#endif

#ifdef ASURA_USE_FASTPATH_PFX
#include "SpecialFX/Pfx/Asura_PFX_System.h"
#include "SpecialFX/Asura_Platform_PFX_System_FastPath.h"
#endif

#if defined(ASURA_USE_FACIAL_ANIMATION_SYSTEM)
#include "FacialAnimation/Tools_FacialAnimation_System.h"
#include "FacialAnimation/Overlays/Tools_Overlay_FacialAnimation.h"
#endif	//defined(ASURA_USE_FACIAL_ANIMATION_SYSTEM)

#include "Flags/Tools_Mode_Flags.h"

#ifdef ASURA_USE_FSFX
#include "FSFX/Tools_Mode_FSFX.h"
#endif

#ifdef ASURA_USE_GUI_MENU_SYSTEM
#include "GUIMenu/Tools_Mode_GUIMenu.h"
#endif

#include "HelperObject/Tools_HelperObject_System.h"
#include "Hierarchy/Tools_Mode_Hierarchy.h"
#include "Hierarchy/Tools_Animation_Files.h"

#if defined(ASURA_SUPPORT_BODYPART_SYSTEM)
#include "Hierarchy/Tools_Hierarchy_BodyPart_System.h"
#endif	// defined(ASURA_SUPPORT_BODYPART_SYSTEM)

#include "Interface/Tools_ContextMenu_System.h"
#include "Interface/Tools_WindowsCursor.h"
#include "LevelOfDetail/Tools_Mode_LOD.h"
#include "Lighting/Tools_Mode_PhotonMapping.h"
#include "Lighting/Tools_Photon_Object.h"
#include "Lighting/Tools_PhotonMapping_System.h"
#include "Lighting/Tools_LightSets.h"
#if defined(ASURA_USE_ARTICULATION_SYSTEM)
#include "LipSync/Tools_Lipsync.h"
#endif	//defined(ASURA_USE_ARTICULATION_SYSTEM)
#include "Load&Save/Tools_AsrFileManager.h"
#include "Load&Save/Tools_SaveAsura.h"
#include "Load&Save/Tools_OptionsFile.h"
#include "Load&Save/LevelExport/Tools_Level_Export.h"
#include "Load&Save/Tools_BatchProcessing.h"
#include "Load&Save/Tools_LoadedFileList.h"
#include "MeshEdit/Tools_Mode_MeshEdit.h"
#include "Misc/Tools_CyclicBuffer.h"
#include "Misc/Tools_Timed_Messages.h"
#include "Misc/Tools_Help.h"
#include "Misc/Tools_Render.h"
#include "Misc/Tools_Render_Options.h"
#include "Misc/Tools_LOS.h"
#include "Misc/Tools_AVI_Writer.h"
#include "Misc/Tools_Modal_Overlay.h"
#include "Misc/Tools_Flag_IniFile.h"
#include "Misc/Tools_Polygon_Selection.h"
#include "Misc/Tools_Vertex_Selection.h"
#include "Misc/Tools_Edge_Selection.h"
#include "Misc/Tools_VertexPerPoly_Selection.h"
#include "Misc/Tools_Module_Selection.h"
#include "Misc/Tools_Prompted_Selection.h"
#include "Misc/Tools_GeneralOptions.h"
#include "Module/Tools_Mode_Module.h"
#include "ModuleLinking/Tools_Mode_ModuleLinking.h"
#include "Movement/Tools_Movement.h"
#include "Objects/Tools_Mode_Object.h"
#include "AssetManager/Tools_Mode_AssetManager.h"
#include "Objects/Tools_Object_System.h"
#include "Particles/Tools_Mode_PFX.h"
#include "PC/OS/Tools_OS.h"
#include "Regions/Tools_Mode_Regions.h"
#include "Rendering/Tools_RenderCollisionMesh.h"
#include "Rendering/Tools_RenderModules.h"
#include "Shapes/Tools_Mode_ShapeData.h"
#include "Shapes/Tools_Shapes.h"
#include "Skybox/Tools_Mode_Skybox.h"
#include "Smoothing/Tools_Mode_Smoothing.h"
#include "Smoothing/Tools_ModuleSmoothing.h"
#include "Sound/Tools_Audio_DSP.h"
#include "Sound/Tools_Audio_Monitor.h"
#include "Sound/Tools_Overlay_DynamicMusic.h"
#include "Sound/Tools_Mode_Sound.h"
#include "Sound/Tools_Mode_MetaMusic.h"
#include "Sound/Tools_Sound_PS2Settings.h"
#include "Sound/Tools_Sound_System.h"
#include "Sound/Tools_SoundConversionPreview.h"
#include "Sound/Tools_SoundEvent_System.h"
#include "Sound/Tools_SoundEvent_Overlay.h"
#include "Sound/Tools_SoundMixer_Overlay.h"
#ifdef ASURA_USE_DIALOGUE_SYSTEM
#include "Sound/Tools_Dialogue_System.h"
#endif
#ifdef ASURA_USE_STREAMING
#include "Streaming/Tools_Mode_Streaming.h"
#include "Streaming/Tools_Streaming_System.h"
#endif
#include "Texturing/Tools_Texturing_MaterialResponse.h"
#include "Texturing/Tools_Mode_Texturing.h"
#include "Texturing/Tools_PickTexture.h"
#include "Texturing/Tools_TextureReport.h"
#include "Texturing/Tools_Cubemap_Generator.h"
#include "TextureTiler/Tools_Mode_TextureTiler.h"
#include "TextureTiler/Tools_PickTiledTexture.h"
#include "Waypointing/Tools_Batch_Waypointing.h"
#include "Waypointing/Tools_Mode_Waypointing.h"
#ifdef ASURA_SUPPORT_WEATHER_SYSTEM
#include "Weather/Tools_Mode_Weather.h"
#endif
#ifdef ASURA_USE_WATER
#include "Weather/Tools_WaterTemplate.h"
#include "Rendering/Asura_Water.h"
#endif

#include "VertexPainting/Tools_Mode_VertexPainting.h"

#include "Rendering/Asura_Fog.h"

#ifdef ASURA_USE_DECAL_MANAGER
#include "Decals/Tools_Overlay_Decals.h"
#endif

#ifdef ASURA_DEBUG_VARIABLE_SYSTEM
#include "DVS/Tools_Overlay_DVS.h"
#endif

#ifdef ASURA_USE_GUI_MENU_SYSTEM
#include "GUIMenu/Tools_GUIMenu_Audio_Overlay.h"
#endif // ASURA_USE_GUI_MENU_SYSTEM

#if defined(ASURA_USE_MATERIAL_RESPONSE_SYSTEM)
#include "Materials/Tools_Overlay_MaterialResponseOverrides.h"
#include "Texturing/Tools_Texturing_MaterialResponse.h"
#endif	// defined(ASURA_USE_MATERIAL_RESPONSE_SYSTEM)
#include "Texturing/Tools_Overlay_ViewTextures.h"

#ifdef ASURA_USE_NEW_VISIBILITY_SYSTEM
#include "Visibility/Asura_Visibility_System.h"
#include "Visibility/Tools_Visibility_System.h"
#endif

#if defined ASURA_USE_HDR
#include "HDR/Tools_HDR_Overlay.h"
#endif

#ifdef ASURA_USE_STATIC_DECAL_SYSTEM
#include "Decals/Tools_StaticDecal_System.h"
#endif

Tools_System*	Tools_System::This = NULL;
 
Tools_Mode*		Tools_System::CurrentModeClass;
int				Tools_System::CurrentMode;
int				Tools_System::NextMode = TOOLS_MODE_NULL;
void			(*Tools_System::UpdateCurrentMode)(void);
bool			Tools_System::ReadyToQuitOut;
bool			Tools_System::QuitToDesktop = false;
Asura_Handle	Tools_System::BaseMenuHandle;
bool			Tools_System::ShowAllModuleOutlines;
bool			Tools_System::ShowCursorModuleOutline;
bool			Tools_System::RequestHardwareMouse = false;
float			Tools_System::UserSetGameTimeScale = 1.0f;
bool			Tools_System::ShowCursorInformation = false;
bool			Tools_System::s_bHideToolsStatusText = false;
Tools_Flag_IniFile* Tools_System::CommonFlagIni = 0;
bool			Tools_System::s_bDontCompressTexturesOnLoad = false;
bool            Tools_System::s_bShowPS2PerfMetrics = false;
bool            Tools_System::s_bIsCurrentDirectorySet = false;
bool			Tools_System::s_bHasBeenMinimised = false;
u_int			Tools_System::s_uReactivationCount = 0;

bool			Tools_System::s_bSwapMouseButtons = false;
bool			Tools_System::s_bInitialSwapMouseButtons = false;

bool			Tools_System::s_bRestrictMouseToWindowInSubwindowTools = false;
bool			Tools_System::s_bRestrictMouseToWindowInSubwindowGame = true;
bool			Tools_System::s_bRestrictMouseToWindowInFullScreenTools = true;
bool			Tools_System::s_bRestrictMouseToWindowInFullScreenGame = true;
bool			Tools_System::s_bUseWindowsCursor = true;
bool			Tools_System::s_bIdlePriorityWhileMinimised = true;


bool			Tools_System::s_bRecordScreenshots = false;
bool            Tools_System::s_bHideBotanicals = false;
bool			Tools_System::s_bBotanicalsStatistics = false;
bool            Tools_System::s_bHideCarpet = false;
bool			Tools_System::s_bCarpetStatistics = false;
bool			Tools_System::s_bAutoQuitToGame = false;

bool			Tools_System::s_bToolsActive = false;
bool			Tools_System::s_bShuttingDown = false;

int				Tools_System::s_iDefaultMode = TOOLS_MODE_NULL;

//#include "Asura_Demomode.h"
//Asura_Demo_Mode DemoMode;

#if( defined( ASURA_USE_MATERIAL_RESPONSE_SYSTEM ) )

static Tools_Overlay_MaterialResponseOverrides s_xMaterialResponseOverrides;

static void MaterialResponseOverridesToggleOverlay( void )
{
	s_xMaterialResponseOverrides.ToggleOverlay();
}
static bool MaterialResponseOverridesIsOpen( void )
{
	return( s_xMaterialResponseOverrides.IsOpen() );
}

#endif // ( defined( ASURA_USE_MATERIAL_RESPONSE_SYSTEM ) )

static Tools_PFX_Overrides s_xPFXOverrides;

static void PFXOverridesToggleOverlay( void )
{
	s_xPFXOverrides.ToggleOverlay();
}
static bool PFXOverridesIsOpen( void )
{
	return( s_xPFXOverrides.IsOpen() );
}

static Tools_FSFX_Overrides s_xFSFXOverrides;

static void FSFXOverridesToggleOverlay( void )
{
	s_xFSFXOverrides.ToggleOverlay();
}
static bool FSFXOverridesIsOpen( void )
{
	return( s_xFSFXOverrides.IsOpen() );
}



#include "Light/Asura_Light.h"


#include "Sound/Asura_Sound.h"


#include "Core/Asura_TextureManagement.h"


////////////////////////////////////////////////////////////////////////////////////////////
/*-----------**
** Help Text **
**-----------*/

static const char* MovementHelpStrings[] =
{
	"W :                Forwards",
	"S :                Backwards",
	"A :                Left",
	"D :                Right",
	"Q :                Forward quickly",
	"E :                Up (while using dynamics)",
	"Left Arrow :       Left",
	"Right Arrow :      Right",
	"Up Arrow :         Up",
	"Down Arrow :       Down",
	"",
	"Hold MMB :         Rotate using mouse",
	"Hold Shift :       Restrict mouse rotation to one axis",
	"Hold Control :     (While using mouse rotation). Orbit around selection or cursor",
	"",
	"Number pad controls (Num Lock must be on) :",
	"4 :                Yaw Left",
	"6 :                Yaw Right",
	"8 :                Pitch Up",
	"2 :                Pitch Down",
	"7 :                Roll Left",
	"9 :                Roll Right",
	"1 :                Left",
	"3 :                Right",
	"- (Num Pad):       Up",
	"+ (Num Pad):       Down",
	"Shift - (Num Pad): 'Stand up' (while using dynamics , if not overriding player height)",
	"Shift + (Num Pad): 'Crouch/Go Prone' (while using dynamics , if not overriding player height)",
	"* :                Level out",
	"Alt+* :            Remove roll component of orientation.",
	"Shift+* :          Snap to nearest axes",
	"Ctrl+* :           Snap to 45 degrees from nearest axes",
	"                   Repeated presses will rotate by 90 degrees",
	"/+Rotation Keys:   Orbit around selection or screen centre. Rotation is relative to world axes.",
	"                   If Numberpad '/' is used then rotation is relative to the camera.",
	"                   If the standard rotation style is set to world-relative then the.",
	"                   distinction between the slash keys is ignored..",
	"",
	"[,] :              Change movement speed",
    "Alt+[,] :          Change movement speed quickly",
	"Shift+[,] :        Change rotation speed",
    "Shift+Alt+[,] :    Change rotation speed quickly",
	"Mouse wheel can be used instad of [,] if cursor isn't over an overlay."
	"",
	"Shift+F1,...,F10 : Save camera position",
	"Ctrl+F1,...,F10 :  Restore camera position",
	"F12 :              Teleport to specified absolute/relative position",
	"Ctrl+F12 :         Teleport to origin",
    "",
    "Ctrl+F :           Find Module",
	NULL
};

static const char* GeneralHelpStrings[] =
{
	"F1 :          Toggle wireframe",
	"Alt+F1 :      Cycle through collision mesh rendering modes.",
	"F2 :          Cycle through highlight mode for selected polygons. (Wireframe->Solid->Translucent)",
	"Alt+F2 :      Toggle highlight of polygon/module selection.",
	"F3 :          Toggle highlight poly/object under cursor",
	#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM
	"Alt+F3 :      Forces all polygons to be rendered using the 'UV Orientation' material.",
	#endif
	"F4 :          Toggle use module links",
	"F6 :          Curved surfaces off",
	"F7 :          Curved surfaces on (dynamic subdivide)",
	"F8 :          Subdivide near waypoints (PS2 preview)",
	"F9 :          Toggle dynamics for camera",
	"F10 :         Toggle rotation style (player relative/world relative)",
	"Alt+F10 :     Toggle movement style (object relative/world relative)",
	"F11 :         Quit to game",
	"Pause :       Screenshot",
	"Shift+Pause : Screenshot (Before tools rendering)",
	"Alt+C :       Copies the position to the windows clipboard."
//	"Ctrl+Pause : Start/Stop AVI recording",
	"",
	"Ctrl+1 :      Set resolution to 640x480",
	"Ctrl+2 :      Set resolution to 800x600",
	"Ctrl+3 :      Set resolution to 1024x768",
	"Ctrl+4 :      Set resolution to 1280x960",
	"Ctrl+5 :      Set resolution to 1600x1200",
	"Ctrl+6 :      Set resolution to 1280x720",
	"Ctrl+7 :      Set resolution to 1920x1080",
	"Ctrl+7 :      Set resolution to 1920x1200",
	"Ctrl+9 :      Set resolution to Maximised",
	"Ctrl+0 :      Set resolution to 1920x1080 Anti-aliased",
	"",
	"Ctrl+O :      Hide all overlays",
	"Ctrl+M :      Minimise all overlays",
	"Tab :         Cycle forwards through edit boxes on current overlay",         
	"Shift + Tab : Cycle backwards through edit boxes on current overlay",         
    "Ctrl + Tab :  Cycle through open overlays",
	"",
	"-,+ :         Change game speed",
	"Shift - :     Set game speed to 0",
	"Shift + :     Set game speed to 1",
	"",
	"Ctrl+S :      Quicksave",
	"Ctrl+H :      Help",
	"",
	"Ctrl+` :      Switch to standy mode",
	NULL
};



static const char* g_apszOverlayHelpStrings[] =
{
	"Ctrl+O or `:    Hide all overlays",
	"Ctrl+M :        Minimise all overlays",
	"Shift + ` :     Repeat most recent (overlay) button",
	"",

	"**Graphs**",
	"",
	"Ctrl + LMB :    Create node",
	"Shift + LMB :   Delete node",
	"LMB :           Select node",
	"N :             Select nearest node",
	"Shift + RMB :   Move all graph nodes",
	"Alt + RMB   :   Scale all graph nodes (from zero)",
	"                If a colour component/dimension is selected , then scaling",
	"                or shifting is limited to that component",
	"",
	"While Selected",
	"LMB drag :      Move node",
	"Shift+Arrows :  Move node",
	"Ctrl+Arrows :   Move node fast",
	"Alt+Arrows :    Change node",
	"< :             Cancel move",
	"",

	"**Edit Boxes**",
	"",
	"LMB :           Start keyboard input",
	"Arrows :        Move cursor",
	"Home :          Move cursor to start",
	"End :           Move cursor to end",
	"Del :           Delete character at cursor",
	"Backspace :     Delete character before cursor",
	"Enter :         End input , accepting changes",
	"Escape :        End Input , discarding changes",
	"",

	"*Incrementor / Decrementor*",
	"",
	"LMB :           Increase/decrease value",
	"RMB :           Increase/decrease value at 10 times the speed",
	"Hold shift :    As above , but value is only changed once per mouse click",
	"",

	"**Lists**",
	"",
	"LMB :           Select item",
	"RMB :           Test sound etc (depends on list)",
	"MW up :         Scroll up 3 lines",
	"Shift MW up :   Scroll up 1 page",
	"MW down :       Scroll down 3 lines",
	"Shift MW down : Scroll down 1 page",
	"Up/Down :       Up/down 1 line",
	"Shift Up/Down : Up/down 5 lines",
	"Pg Up :         Up one page",
	"Pg Down :       Down one page",
	"Home :          Start of list",
	"End :           End of list",
	"",
	"Multple selection lists :-",
	"Ctrl+LMB :      Add/remove from the current selection",
	"Shift+LMB :     Select entries between the previous and the current item clicked on",
	"LMB drag :      Select the list items dragged over.",
	"",

	"**Surround Pan**",
	"",
	"LMB :           Set fade/pan.",
	"Shift+LMB :     Snaps fade/pan when near to middle or edges.",

	NULL

};

////////////////////////////////////////////////////////////////////////////////////////////


// KJL - 15-Mar-01 17:13:04 - useful file list functions: probably need there own class (file access grouping?)

#define MAX_NO_OF_FILES 100
static char* Namelist[MAX_NO_OF_FILES];
static char* Shortnamelist[MAX_NO_OF_FILES];


void ClearFileLists(void)
{
	for (int i=0; i<MAX_NO_OF_FILES; i++)
	{
		if(Namelist[i]) delete [] Namelist[i];
		if(Shortnamelist[i]) delete [] Shortnamelist[i];

		Namelist[i] = 0;
		Shortnamelist[i] = 0;
	}
}

Tools_System::Tools_System()
{
	This = this;

	m_iColourSample_RequestedSize = 0;
	m_fColourSample_Red = 0;
	m_fColourSample_Green = 0;
	m_fColourSample_Blue = 0;
}

int Tools_System::MakeListOfFiles(const char* load_name, char**& filenames, char**& shortnames)
{
	ClearFileLists();
#if 01 // KJL - 02-May-01 12:20:32 - turned off for PS2
	filenames = Namelist;
	shortnames = Shortnamelist;
	unsigned int maxNoOfFiles = MAX_NO_OF_FILES;

	// allow a wildcard search
	WIN32_FIND_DATA wfd;

	HANDLE hFindFile = ::FindFirstFile(load_name,&wfd);

	unsigned int numberFound = 0;

	if (INVALID_HANDLE_VALUE == hFindFile)
	{
//		printf("File Not Found: <%s>\n",load_name);
		return 0;
	}

	// get any path in the load_name
	size_t nPathLen = 0;
	const char * pColon = strrchr(load_name,':');
	if (pColon) 
	{
		nPathLen = pColon - load_name + 1;
	}
	const char * pBackSlash = strrchr(load_name,'\\');
	if (pBackSlash)
	{
		size_t nLen = pBackSlash - load_name + 1;
		if (nLen > nPathLen) 
		{
			nPathLen = nLen;
		}
	}
	const char * pSlash = strrchr(load_name,'/');
	if (pSlash)
	{
		size_t nLen = pSlash - load_name + 1;
		if (nLen > nPathLen) 
		{
			nPathLen = nLen;
		}
	}

	do
	{
		if
		(
			!(wfd.dwFileAttributes &
				(FILE_ATTRIBUTE_DIRECTORY
				|FILE_ATTRIBUTE_SYSTEM
				|FILE_ATTRIBUTE_HIDDEN))
//				|FILE_ATTRIBUTE_READONLY))
				// not a directory, hidden or system file
		)
		{
			char * pszFullPath = new char [nPathLen+strlen(wfd.cFileName)+1];
			strncpy(pszFullPath,load_name,nPathLen);
			strcpy(pszFullPath+nPathLen,wfd.cFileName);
			
			
			//make sure the file is a rif file
			HANDLE rif_file;
			rif_file = CreateFile (pszFullPath, GENERIC_READ, 0, 0, OPEN_EXISTING, 
					FILE_FLAG_RANDOM_ACCESS, 0);
			if(rif_file==INVALID_HANDLE_VALUE)
			{
//				printf("couldn't open %s\n",pszFullPath);
				delete[] pszFullPath;
				continue;
			}

		
			CloseHandle (rif_file);
		//	delete[] pszFullPath;

			shortnames[numberFound] = new char [strlen(wfd.cFileName)+1];
			strcpy(shortnames[numberFound],wfd.cFileName);

			filenames[numberFound++] = pszFullPath;		

		}

		if (numberFound == maxNoOfFiles) return numberFound;

	}
	while (::FindNextFile(hFindFile,&wfd));


	if (ERROR_NO_MORE_FILES != GetLastError())
	{
	   //	printf("Error finding next file\n");
	}

	::FindClose(hFindFile);

	return numberFound;
#endif
//	return 0;
}

static bool ShouldPS2PerfMetricsBeAvailable( void )
{
//  return( TOOLS_SUBDIVIDE_NEARWAYPOINTS == Tools_Render_Options::GetSubdivisionMode() );
    return true;
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////

/*---------------------**
** SaveQuestionOverlay **
**---------------------*/

Tools_SaveConfirmationOverlay::Tools_SaveConfirmationOverlay()
:Tools_Modal_Overlay("Save changes now?")
{
}

void Tools_SaveConfirmationOverlay::InitialiseOverlay(class Asura_Overlay* pxOverlay)
{
	Asura_Dialog* pxDialog;

	Asura_Vector_2 xOffset = Asura_Vector_2(1.0f,3.0f);

	pxDialog = new Asura_FunctionWithKeybinding_Dialog("Save (A)ll",xOffset,&Tools_System::SaveAllAndChangeToNextMode,'a',&pxOverlay->m_bShouldClose);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::LargeSpacing();

	pxDialog = new Asura_FunctionWithKeybinding_Dialog("Save (M)odified",xOffset,&Tools_System::SaveModifiedAndChangeToNextMode,'m',&pxOverlay->m_bShouldClose);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::LargeSpacing();

//	pxDialog = new Asura_FunctionWithKeybinding_Dialog("Save M(o)de",xOffset,&Tools_System::SaveAndChangeToNextMode,'o',&pxOverlay->m_bShouldClose);
//	pxOverlay->AddDialog(pxDialog);
//	xOffset.y+=Asura_Dialog::LargeSpacing();

	pxDialog = new Asura_FunctionWithKeybinding_Dialog("(N)o",xOffset,&Tools_System::ChangeToNextMode,'n',&pxOverlay->m_bShouldClose);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::LargeSpacing();

	pxDialog = new Asura_FunctionWithKeybinding_Dialog("(C)ancel",xOffset,&Tools_System::CancelModeChange,'c',&pxOverlay->m_bShouldClose);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::LargeSpacing();
}

void Tools_SaveConfirmationOverlay::Update()
{
	//allow escape to be used for cancel
	if(Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_ESCAPE))
	{
		GetOverlay()->m_bShouldClose = true;			
		Tools_System::CancelModeChange();
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////
/*-------------------------------**
** Tools_ExitConfirmationOverlay **
**-------------------------------*/
Tools_ExitConfirmationOverlay::Tools_ExitConfirmationOverlay(TOOLS_MODE eNextMode)
:Tools_Modal_Overlay(eNextMode == TOOLS_MODE_QUITTOGAME ? "Quit to Game?" : "Quit to Desktop?")
{
}


void Tools_ExitConfirmationOverlay::InitialiseOverlay(class Asura_Overlay* pxOverlay)
{
	Asura_Dialog* pxDialog;

	Asura_Vector_2 xOffset = Asura_Vector_2(1.0f,3.0f);



	pxDialog = new Asura_FunctionWithKeybinding_Dialog("(O)k",xOffset,&Tools_System::ChangeToNextMode,'o',&pxOverlay->m_bShouldClose);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::LargeSpacing();

	pxDialog = new Asura_FunctionWithKeybinding_Dialog("(C)ancel",xOffset,&Tools_System::CancelModeChange,'c',&pxOverlay->m_bShouldClose);
	pxOverlay->AddDialog(pxDialog);
	xOffset.y+=Asura_Dialog::LargeSpacing();
}

void Tools_ExitConfirmationOverlay::Update()
{
	//allow escape to be used for cancel
	if(Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_ESCAPE))
	{
		GetOverlay()->m_bShouldClose = true;			
		Tools_System::CancelModeChange();
	}
	//allow enter/space for okay
	if(Asura_UserInput::DebouncedKeyPressed(' ') || Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_ENTER))
	{
		GetOverlay()->m_bShouldClose = true;			
		Tools_System::ChangeToNextMode();
	}

}


///////////////////////////////////////////////////////////////////////////////////////////////////////////
/*--------------**
** Tools_System **
**--------------*/

void Tools_System::Allocate()
{
	Project_Allocate_Tools_System();
	Asura_Assert(This,"Could not create tools system!");
}

void Tools_System::Deallocate()
{
	delete This;
}

void Tools_System::Initialise(bool loadEnvironment /*= false*/)
{

#ifdef ASURA_USE_PROFILING_SYSTEM
	Asura_CPUProfile_Renderer::Reset();
#endif

	ASURA_CPU_PROFILE_SCOPED_TIMER( "Tools_System::Initialise");
	
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_OS::Initalise() );

	// initialise the lighting systems
	//Tools_PhotonMapping_System::Initialise();

	ASURA_CPU_PROFILE_CALL_TIMER( Asura_Text_Output::LoadFonts() );
    
    if ( !This )
    {
        return;
    }

	s_bToolsActive = true;

	ASURA_CPU_PROFILE_CALL_TIMER( This->AllocateAllToolsClasses() );

	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Timed_Message_System::Initialise() );

	if(loadEnvironment)
	{
		ASURA_CPU_PROFILE_CALL_TIMER( Tools_SaveAsura::LoadEnvironment() );
	}
	extern Asura_String EnvironmentFilename;
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_SaveAsura::UpdateFilename(EnvironmentFilename) );



	//check that the loaded file is okay for editing in tools
	bool bOkayToEnterTools = true;
	if(!Asura_Module_System::GetNumberOfModules())
	{
		Asura_Assert(0,"Failed to find any modules (or shapes if a shape file).\nAborting tools.");
		QuitToDesktop = true;
		bOkayToEnterTools = false;
	}
	for(int i=0;i<Asura_Module_System::GetNumberOfModules() && bOkayToEnterTools;i++)
	{
		if(!Asura_Module_System::GetMeshForModule(i))
		{
			Asura_Assert(0,"The file loaded appears to be an exported level file (which cannot be used in the tools).\nAborting tools.");
			bOkayToEnterTools = false;
		}
	}

#if !defined( _WIN64)
	// RJF 27-06-06: Check for the nvdxt DLL. Without it we can't do any texture conversions.
	// RAR 27-06-06: Changed this to a fatal error instead of a warning.
	HMODULE hNVDXT = LoadLibrary("nvdxtlib.dll");
	if(!hNVDXT)
	{
		AsuraAssert_SetIgnoreAll(false);//Best make sure that this assert is always visible.
		Tools_BatchProcessing::Abort();//Not much point in continuing with a batch process after this.
		Asura_Assert(0,"Failed to find nvdxtlib.dll.\n If this is a new project , you may need to copy it from the Asura_Files directory of another project.\nAborting tools.");
		QuitToDesktop = true;
		bOkayToEnterTools = false;
	}
	else
	{
		FreeLibrary(hNVDXT);
	}
#endif

	if(!bOkayToEnterTools)
	{
		Tools_OptionsFile::Load();
		//No good , shutdown the small amount that has been initialised so far , and quit
		This->DeallocateAllToolsClasses();
		s_bToolsActive = false;
		Tools_OS::Shutdown();
		//Tools_PhotonMapping_System::Shutdown();
		return;
	}

	//Cancel various SFX etc that might still be active after being in game
	//RAR 15/02/2008
	ASURA_CPU_PROFILE_CALL_TIMER( ResetSystemsAfterReturningFromGame() );


	#ifdef ASURA_USE_STREAMING
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Streaming_System::Initialise() );
	#endif

	//set files that should be checked for modification outside of tools
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_SaveAsura::SetFilesToCheckForExternalModification() );
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_SecondaryEntityFile_System::SetFilesToCheckForExternalModification() );


	ASURA_CPU_PROFILE_CALL_TIMER( Tools_PickTexture::GetThis()->Initialise() );
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_PickTiledTexture::GetThis()->Initialise() );

	#ifdef ASURA_USE_ANIMATION_IK_SOLVER
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Animation_IK_Template_System::Initialise() );
	#endif



	ASURA_CPU_PROFILE_CALL_TIMER( OpenIniFiles() );
	
	
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Render::Initialise() );
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Render_Options::Initialise() );
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_RenderCollisionMesh_System::Initialise() );

	ASURA_CPU_PROFILE_CALL_TIMER( Tools_AsrFileManager::UpdateModuleVisibility() );

	AsuraFileType eFileType = Tools_SaveAsura::GetFileType();

	// Kevin Lea - 25/06/2001 15:06:45 - setup basic tools menu
	BaseMenuHandle = Asura_Menubar_System::CreateMenuSection();
	Asura_Menubar_Title* title;
	title = Asura_Menubar_System::AddTitle(BaseMenuHandle,"File");
//	title->AddItem("Load");
	title->AddItem("Unlock Externally Modified",Tools_LoadedFileList::UnlockFiles);
//	title->AddItem("Save Current Mode [Ctrl-S]",Tools_System::QuickSave);
	title->AddItem("Save Modified [Ctrl-S]",Tools_SaveAsura::SaveModified);
	title->AddItem("Save All",Tools_SaveAsura::SaveAll);
	if(eFileType != AsuraFile_Template)
	{
		This->AddExportOptions( title );
	}
	title->AddItem("Write AVI",Tools_System::StartAVI);
	title->AddItem("");
	title->AddItem("Reload Anims",Tools_Animation_Files::ReloadAllAnimations);
	title->AddItem("Reload Skins",Tools_Animation_Files::ReloadAllSkins);
	title->AddItem("");
	if(eFileType == AsuraFile_Environment || eFileType == AsuraFile_Template)
	{
		title->AddItem("Quit To Game",Tools_System::RequestQuitToGame);
	}
	title->AddItem("Quit To Desktop",Tools_System::RequestQuitToDesktop);

	title = Asura_Menubar_System::AddTitle(BaseMenuHandle,"Mode");
	//Sort the mode menu alphabetically. RAR 26/01/2006
	title->StartSort();
	title->AddItem("Standby",Tools_System::RequestStandbyMode,Tools_System::IsInStandbyMode);

	title->AddSeparator();

	title->AddItem("Texture Tiler",Tools_System::RequestTextureTilerMode,Tools_System::IsInTextureTilerMode);

	// KJFL - 2004-05-04 - not entirely sure if we'll need this for Templated files, but if any kind of prelighting
	// calculations are needed, this would be the place.
	title->AddItem("Global Illumination", Tools_System::RequestPhotonMappingMode, Tools_System::IsInPhotonMappingMode );

	if(eFileType != AsuraFile_Template)
	{
		title->AddItem("Texturing",Tools_System::RequestTexturingMode,Tools_System::IsInTexturingMode);
		title->AddItem("Smoothing",Tools_System::RequestSmoothingMode,Tools_System::IsInSmoothingMode);
		title->AddItem("Flags",Tools_System::RequestFlagsMode,Tools_System::IsInFlagsMode);
		//Mesh edit mode not allowed when dealing with smooth skins.
		if(!Tools_SaveAsura::GetSkin() || !Tools_SaveAsura::GetSkin()->IsSkinnedModel())
		{
			title->AddItem("Mesh Edit",Tools_System::RequestMeshEditMode,Tools_System::IsInMeshEditMode);
		}
		title->AddItem("Hierarchy",Tools_System::RequestHierarchyMode,Tools_System::IsInHierarchyMode);
		title->AddItem("Ragdoll Editor",Tools_System::RequestRagdollEditorMode,Tools_System::IsInRagdollEditorMode);

	}

	if(eFileType==AsuraFile_Environment || eFileType==AsuraFile_Template)
	{
		title->AddItem("Sound",Tools_System::RequestSoundMode,Tools_System::IsInSoundMode);
#ifndef ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM
		title->AddItem("Meta Music",Tools_System::RequestMetaMusicMode,Tools_System::IsInMetaMusicMode);
#endif
		if(eFileType!=AsuraFile_Template)
		{		
			title->AddItem("Module",Tools_System::RequestModuleMode,Tools_System::IsInModuleMode);
#ifndef ASURA_USE_NEW_VISIBILITY_SYSTEM
			title->AddItem("ModuleLinking",Tools_System::RequestModuleLinkingMode,Tools_System::IsInModuleLinkingMode);
#endif
			title->AddItem("Waypointing",Tools_System::RequestWaypointingMode,Tools_System::IsInWaypointingMode);
			title->AddItem("Cutscene",Tools_System::RequestCutsceneMode,Tools_System::IsInCutsceneMode);
		}
		title->AddItem("Objects",Tools_System::RequestObjectMode,Tools_System::IsInObjectMode);
		title->AddItem("PFX", Tools_System::RequestPFXMode, Tools_System::IsInPFXMode);
		if(eFileType!=AsuraFile_Template)
		{
			title->AddItem("Regions",Tools_System::RequestRegionsMode,Tools_System::IsInRegionsMode);
		}
#ifdef ASURA_USE_BILLBOARD_PLANTS
		title->AddItem("Billboard Plants", Tools_System::RequestBillboardPlantsMode, Tools_System::IsInBillboardPlantsMode);
#endif
#ifdef ASURA_USE_BOTANICALS	
		title->AddItem("Botanical Creation", Tools_System::RequestBotanicalCreationMode, Tools_System::IsInBotanicalCreationMode);
		title->AddItem("Botanical Instances", Tools_System::RequestBotanicalsMode, Tools_System::IsInBotanicalsMode);
#endif

#ifdef ASURA_USE_ASSET_MANAGER
		title->AddItem("Asset Manager", Tools_System::RequestAssetManagerMode, Tools_System::IsInAssetManagerMode);
#endif

#ifdef ASURA_USE_CARPET
		title->AddItem("Carpet", Tools_System::RequestCarpetMode, Tools_System::IsInCarpetMode);				
#endif

#ifdef ASURA_USE_STATIC_DECAL_SYSTEM
		title->AddItem("Decals", Tools_System::RequestDecalsMode, Tools_System::IsInDecalsMode);				
#endif

// JGP 31/1/06
#ifdef ASURA_USE_FSFX
		title->AddItem( "FSFX Templates", Tools_System::RequestFSFXMode, Tools_System::IsInFSFXMode );
#endif

// JGP 2/5/06
#ifdef ASURA_USE_ATTRACTORS
		title->AddItem( "Env Hooks", Tools_System::RequestAttractorsMode, Tools_System::IsInAttractorsMode );
#endif

#ifdef ASURA_SUPPORT_WEATHER_SYSTEM
		if(eFileType!=AsuraFile_Template)
		{
			title->AddItem("Weather",Tools_System::RequestWeatherMode,Tools_System::IsInWeatherMode);
		}
#endif
		
	}

#ifdef ASURA_USE_STREAMING
	if(eFileType==AsuraFile_Environment)
	{
		title->AddItem("Streaming", Tools_System::RequestStreamingMode, Tools_System::IsInStreamingMode);
	}
#endif

#ifdef ASURA_USE_GUI_MENU_SYSTEM
	title->AddItem("Menus", Tools_System::RequestGUIMenuMode, Tools_System::IsInGUIMenuMode);
#endif


	if(eFileType==AsuraFile_Shapes)
	{
		title->AddItem("LOD",Tools_System::RequestLODMode,Tools_System::IsInLODMode);
		title->AddItem("Shape Data", Tools_System::RequestShapeDataMode, Tools_System::IsInShapeDataMode);
	}

	#ifndef ASURA_DISABLE_PAINTED_COLOURS
	if(eFileType!=AsuraFile_Template)
	{
		title->AddItem( "Vertex Painting", Tools_System::RequestVertexPaintingMode, Tools_System::IsInVertexPaintingMode );
	}
	#endif

#ifdef ASURA_USE_CONTAINER_SYSTEM
	title->AddItem("Container", Tools_System::RequestContainerMode, Tools_System::IsInContainerMode);
#endif //#ifdef ASURA_USE_CONTAINER_SYSTEM

	title->AddSeparator();//so there is a gap to project-specific modes (if any)
		
	title = Asura_Menubar_System::AddTitle(BaseMenuHandle,"Render Options");
	title->AddItem("Skybox Overlay",Tools_SkyboxOverlay::ToggleOverlay,Tools_SkyboxOverlay::IsOverlayOn);
	title->AddItem("Lighting",Tools_Render::ToggleLighting,Tools_Render::LightingIsOn);
#if defined( ASURA_TARGET_SM3 )
	title->AddItem( "Texturing", Tools_Render::ToggleTexturing, Tools_Render::TexturingIsOn );
	title->AddItem( "Show Per Pixel Normals", Tools_Render::ToggleShowPerPixelNormals, Tools_Render::ShowPerPixelNormalsIsOn );
#endif // #if defined( ASURA_TARGET_SM3 )
	title->AddItem("Hide Fog",Asura_Fog::ToggleHideFog,Asura_Fog::IsFogHidden);
	title->AddItem("Show All Module Outlines",Tools_System::ToggleShowAllModuleOutlines,Tools_System::IsShowingAllModuleOutlines);
	title->AddItem("Show Cursor Module Outline",Tools_System::ToggleShowCursorModuleOutline,Tools_System::IsShowingCursorModuleOutline);
	title->AddItem("Cursor info",Tools_System::ToggleShowCursorInformation,Tools_System::IsShowingCursorInformation);
	if(Tools_Level_Export::IsPlatformSupported(Tools_Level_Export::Export_PS2))
	{
    	title->AddItem( "Show PS2 performance metrics", Tools_System::ToggleShowPS2PerfMetrics, Tools_System::IsShowingPS2PerfMetrics, ShouldPS2PerfMetricsBeAvailable );
	}
#ifdef ASURA_USE_BOTANICALS	
	title->AddItem("Hide Botanicals", Tools_System::ToggleHideBotanicals, Tools_System::IsHideBotanicalsChecked);	
	title->AddItem("Botanicals Statistics", Tools_System::ToggleBotanicalsStatistics, Tools_System::IsBotanicalsStatisticsChecked);
#endif //ASURA_USE_BOTANICALS	
#ifdef ASURA_USE_CARPET
	title->AddItem("Hide Carpet", Tools_System::ToggleHideCarpet, Tools_System::IsHideCarpetChecked);
	title->AddItem("Carpet Statistics", Tools_System::ToggleCarpetStatistics, Tools_System::IsCarpetStatisticsChecked);
#endif
#if defined( ASURA_USE_PROFILING_SYSTEM)
	title->AddItem("Profile Bar", Tools_System::ToggleShowProfileBars,Tools_System::IsShowingProfileBars);
	title->AddItem("Profile Text", Tools_System::ToggleShowProfileText,Tools_System::IsShowingProfileText);
#endif
#ifdef ASURA_TARGET_SM3
	title->AddItem("Show Deferred Buffers", Tools_System::ToggleShowDeferredBuffers,Asura_DeferredShading::IsShowingDeferredBuffers);
#endif

	// Sound menu
	title = Asura_Menubar_System::AddTitle(BaseMenuHandle,"Audio");
	
	title->AddItem("Switch to Sound Mode", SoundMenuAction_SwitchToSoundMode, SoundMenuTicked_SwitchToSoundMode, SoundMenuEnabled_SwitchToSoundMode);
	title->AddItem("Show Sound Options", SoundMenuAction_SoundOptions, SoundMenuTicked_SoundOptions, SoundMenuEnabled_SoundOptions);
	title->AddItem("Audio Monitor", SoundMenuAction_AudioMonitor, SoundMenuTicked_AudioMonitor, SoundMenuEnabled_AudioMonitor);

	title->AddSeparator();
	
	title->AddItem("Dialogue System", SoundMenuAction_DialogueSystem, SoundMenuTicked_DialogueSystem, SoundMenuEnabled_DialogueSystem);
	title->AddItem("Dynamic Music System", SoundMenuAction_DynamicMusicSystem, SoundMenuTicked_DynamicMusicSystem, SoundMenuEnabled_DynamicMusicSystem);
	
	title->AddSeparator();

	title->AddItem("DSP Effects",SoundMenuAction_DSPEffects, SoundMenuTicked_DSPEffects, SoundMenuEnabled_DSPEffects);
	title->AddItem("Reverb Definitions",SoundMenuAction_ReverbDefintions, SoundMenuTicked_ReverbDefintions, SoundMenuEnabled_ReverbDefintions);
	title->AddItem("Streaming Sound List",SoundMenuAction_StreamingSoundList, SoundMenuTicked_StreamingSoundList, SoundMenuEnabled_StreamingSoundList);
	title->AddItem("Sound Mixers",SoundMenuAction_Mixers, SoundMenuTicked_Mixers, SoundMenuEnabled_Mixers);
		
	
	title = Asura_Menubar_System::AddTitle(BaseMenuHandle,"Options");
	title->AddItem("Overlay",Tools_GeneralOptions::ToggleOptionsOverlay,Tools_GeneralOptions::OptionsOverlayIsOn);

	title = Asura_Menubar_System::AddTitle(BaseMenuHandle,"Utility");
	title->StartSort();
	title->AddItem("Show Poly Counts",ShowPolygonCounts);
	title->AddItem("Write Texture Report",Tools_TextureReport::OutputReport);
	title->AddItem("Message Log",Tools_MessageLog::ShowOverlay);
	title->AddItem("View Textures",ViewTextures);
	title->AddItem("Copy Position (Alt+C)",CopyPositionToClipboard);
	title->AddItem("Generate Cubemap Overlay", Tools_Cubemap_Generator::ToggleOverlay, Tools_Cubemap_Generator::IsOpen);

#if defined( ASURA_SUPPORT_SKIN_ELEMENTS)
	title->AddItem("Skin Elements (Show/Hide)",Tools_Mode_Flags::ToggleElementsOverlay);
#endif

#if defined(ASURA_USE_MATERIAL_RESPONSE_SYSTEM)
	title->AddItem("Material Response Overrides", MaterialResponseOverridesToggleOverlay, MaterialResponseOverridesIsOpen );
	title->AddItem("Show Material Response List",Tools_Texturing_MaterialResponse::ToggleOverlay,Tools_Texturing_MaterialResponse::OverlayIsOn);
#endif
	title->AddItem("PFX System Overrides", PFXOverridesToggleOverlay, PFXOverridesIsOpen );
	title->AddItem("FSFX System Overrides", FSFXOverridesToggleOverlay, FSFXOverridesIsOpen );

	#ifdef ASURA_TOOLS_USE_NEW_MESSAGE_EDITOR
	title->AddItem("Message Editor (Ctrl-r)", Tools_MessageEditor::ToggleOverlay, Tools_MessageEditor::IsOpen);
	#endif

	if(Tools_LightSets::IsUsingLightSets())
	{
		title->AddItem("Light Sets", Tools_LightSets::ToggleOverlay, Tools_LightSets::OverlayIsOn );
	}
	title->AddItem("Tools Lights",Tools_Photon_Object::ToggleGeneralOverlay,Tools_Photon_Object::GeneralOverlayIsOpen);
	title->AddItem("Enable Object Controls", Tools_Object_System::ToggleObjectControls, Tools_Object_System::AreControlsEnabled );

    title->AddItem("Blueprints Overlay", Tools_Mode_Blueprint::ToggleOverlay, Tools_Mode_Blueprint::OverlayIsOpen );

#ifdef ASURA_USE_DECAL_MANAGER
	title->AddItem("Decals Overlay",Tools_Overlay_Decals::ToggleOverlay,Tools_Overlay_Decals::IsOpen);
#endif

#ifdef ASURA_DEBUG_VARIABLE_SYSTEM
	title->AddItem("DVS Overlay",Tools_Overlay_DVS::ToggleOverlay,Tools_Overlay_DVS::IsOpen);
#endif

#ifdef ASURA_USE_NEW_VISIBILITY_SYSTEM
	title->AddItem("Visibility Overlay",Tools_Visibility_System::ToggleOverlay,Tools_Visibility_System::IsOverlayOpen);
#endif
#ifdef ASURA_USE_HDR
	title->AddItem("HDR Overlay",Tools_HDR_Overlay::ToggleOverlay,Tools_HDR_Overlay::IsOverlayOpen);
#endif
#ifdef ASURA_USE_ANIMATION_IK_SOLVER
	title->AddItem("IK Templates",Tools_Animation_IK_Template_System::ToggleOverlay,Tools_Animation_IK_Template_System::IsOverlayOpen);
#endif

#ifdef ASURA_USE_CONTAINER_SYSTEM
	title->AddItem("Container File Overlay", Tools_Container_System::ToggleOverlay, Tools_Container_System::IsOverlayOpen );
#endif // #ifdef ASURA_USE_CONTAINER_SYSTEM

#if defined(ASURA_USE_FACIAL_ANIMATION_SYSTEM)
	title->AddItem("Facial Animation Overlay", Tools_Overlay_FacialAnimation::ToggleOverlay, Tools_Overlay_FacialAnimation::OverlayExists);
#endif	//defined(ASURA_USE_FACIAL_ANIMATION_SYSTEM)

	if(eFileType==AsuraFile_Environment)
	{
		title->AddItem("Env .ASR Files",Tools_AsrFileManager::ToggleOverlay,Tools_AsrFileManager::IsOverlayOpen);
	}

	//initialise selection
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Polygon_Selection::Initialise() );
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Module_Selection::Initialise() );
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Vertex_Selection::Initialise() );
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Edge_Selection::Initialise() );
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_VertexPerPoly_Selection::Initialise() );
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Prompted_Selection::Initialise() );



	// reset mode
	CurrentModeClass = 0;

	ASURA_CPU_PROFILE_CALL_TIMER( Tools_System::RequestStandbyMode() );
	//Tools_System::EnterGameMode();


	// reset cursor
	//DemoMode.Stop();

	ReadyToQuitOut = false;
	QuitToDesktop = false;
	
	ASURA_CPU_PROFILE_CALL_TIMER( Asura_Texture_Management::LoadTextures() );

	Asura_Render::SetPatchesOn(false);
//	Asura_Mesh_System::PlatformResetRenderMeshes();
	Asura_Render::CurrentStates.RequestDynamicLights(false);

	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Help::Initialise() );

	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Object_System::Initialise() );
	//initialise movement system
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Movement::Initialise() );
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_GeneralOptions::Initialise() );

    ASURA_CPU_PROFILE_CALL_TIMER( Tools_Mode_Blueprint::Initialise() );

	#ifdef ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Overlay_DynamicMusic::Initialise() );
	#endif

	//add general help
	Tools_Help::AddHelpTopic("Movement",MovementHelpStrings);
	Tools_Help::AddHelpTopic("General",GeneralHelpStrings);
	Tools_Help::AddHelpTopic("Overlays",g_apszOverlayHelpStrings);
	#if defined(ASURA_TARGET_SM3)
	Tools_Help::AddHelpTopic("Renderer Debug Keys",Asura_Direct3D_EnvironmentRenderer::GetRendererDebugHelpStrings());
	#endif


	{
		
		Asura_Camera::SetNumberOfCameras(1);
		Asura_Camera::SetCameraIndex(0);
		Asura_Camera::SetToDefaults();
		
		Asura_Matrix_3x3 matrix = *Asura_Camera::GetOrientation();
		if(!matrix.e11 && !matrix.e12 && !matrix.e13)
		{
			//camera matrix hasn't been initialised yet , so set it to identity
			matrix.Identity();
			Asura_Camera::SetOrientation(matrix);
		}
		else
		{
			Tools_Movement::TeleportCameraToPosition(Asura_Camera::GetPosition(),Asura_Camera::GetOrientation());
		}
	}
	
	//get pre-tools states for the mouse before they get changed by loading the preferences
	s_bInitialSwapMouseButtons = Asura_Mouse::GetSwapMouseButtons();
   

	//load some preferences
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_OptionsFile::Load() );

	Asura_Mouse::SetUseWindowsCursor(s_bUseWindowsCursor);


	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Sound_PS2Settings::Initialise() );
	
	// Tools_Adjacency now handled by Asura_Core
	//Tools_Adjacency::Initialise();

	ASURA_CPU_PROFILE_CALL_TIMER( Tools_EntityTemplate_System::Initialise() );

#ifdef ASURA_USE_DECAL_MANAGER
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Overlay_Decals::Initialise() );
#endif

#ifdef ASURA_DEBUG_VARIABLE_SYSTEM
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Overlay_DVS::Initialise() );
#endif

#if defined(ASURA_USE_MATERIAL_RESPONSE_SYSTEM)
	ASURA_CPU_PROFILE_CALL_TIMER( s_xMaterialResponseOverrides.Initialise() );
#endif	// defined(ASURA_USE_MATERIAL_RESPONSE_SYSTEM)
	ASURA_CPU_PROFILE_CALL_TIMER( s_xPFXOverrides.Initialise() );

	ASURA_CPU_PROFILE_CALL_TIMER( Project_Initialise() );

	//default to no curving code
	This->InitialPatchesSubdivLevel = Asura_Render::GetPatchesSubdivLevel();
	Asura_Render::SetPatchesSubdivLevel(0);

	This->m_bInitialPauseWhileMinimised = Asura_Windows::GetPauseWhileMinimised();
	Asura_Windows::SetPauseWhileMinimised(false);

#ifdef ASURA_USE_WATER
	Tools_WaterTemplate_System::Initialise();
	Tools_WaterTemplate_System::UpdateFromTemplate();

	// if we were previewing water, quit to game and then quit back to tools, we'll have both base mesh and packets around
	// so drop all packets
	Asura_Water_System::Reset();
#endif

#ifdef ASURA_USE_CONTAINER_SYSTEM
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Container_System::Initialise() );
#endif // #ifdef ASURA_USE_CONTAINER_SYSTEM

	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Animation_Files::LoadMeshesForAllSkins() );
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Animation_Files::LoadSoundsForAllSkinsAndAnims() );

	if(eFileType == AsuraFile_Template)
	{
		//Editing a template file.... make sure the master template exists
		ASURA_CPU_PROFILE_CALL_TIMER( Tools_Entity_TemplateMaster_Object::Create() );
	}
	//Find out which lights/entities/sounds belong to template instances
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Entity_TemplateInstance_Object::FlagAllTemplateInstanceMembers() );

	//get pre-tools sound volumes
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Sound_System::Initialise() );

	
	if(eFileType == AsuraFile_Environment)
	{
		//On first entry into tools , force all tools objects to be created and deleted
		//so that objects that should be merged into the environment are updated
		static bool s_bDoneUpdate = false;
		if(!s_bDoneUpdate)
		{
			s_bDoneUpdate = true;
		    Tools_Entity_Object::CreateAllObjects();
		    ASURA_CPU_PROFILE_CALL_TIMER( Tools_Object_System::DeleteAllModeSpecific() );

			//Also for botanicals. RAR 20/02/2006
			#ifdef ASURA_USE_BOTANICALS
			ASURA_CPU_PROFILE_CALL_TIMER( Tools_Botanicals_Object::CheckAllMerging() );
			#endif

		}

		// SNH: convert environment start points into entities.
		// Should be temporary and only needed until levels have been loaded/saved in tools at least once.
		ASURA_CPU_PROFILE_CALL_TIMER( This->ConvertEnvStartPositionsToEntities() );
	}

#ifndef ASURA_TARGET_SM3
	// (AAM - 29.03.2007) Destructible/advanced lights were having their photons created on first
	// entry into Tools by the code above. Since it's desirable to see these in all modes - and
	// they persist after one visit to Object mode anyway - let's create the clients here if they
	// don't already exist, so the lights reappear immediately after quitting back from game
	for( Asura_Hashed_List_It< Asura_ServerEntity_DestructibleLight > xIter( Asura_ServerEntity_DestructibleLight::GetList() ); !xIter.Done(); xIter.Next() )
	{
		Asura_ServerEntity_DestructibleLight* const pxCurrLight = xIter.GetCurrent();
		if( !pxCurrLight ) continue;

		if( pxCurrLight->GetClassification() == AsuraEntityClass_AdvancedLight )
		{
			// If this is actually an advanced light, it might not have 'starts active' set
			const Asura_ServerEntity_AdvancedLight* const pxAdvancedLight = Asura_ServerEntity_AdvancedLight::FindEntity( pxCurrLight->GetGuid() );
			if( !pxAdvancedLight->GetStartsActive() ) continue;
		}

		Asura_Message* const pxMsg = Asura_Network::CreateMessage( ASURA_MSG_CLIENT_REQUESTCREATEMSG );
		if( !pxMsg ) continue;

		pxCurrLight->HandleMessage( pxMsg );
		Asura_Network::DestroyMessage( pxMsg );
	}
#endif // #ifndef ASURA_TARGET_SM3

	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Message_Editing::LoadSettingsFromIniFile() );
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Movement::LoadSettingsFromIniFile() );
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_GeneralOptions::LoadSettingsFromIniFile() );

	//make sure object skins and anims have been loaded
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Entity_PhysicalObject::LoadSkinsAndAnims() );
	//Force skybox objects to be regenerated , in case skybox and entity files are out of sync
	ASURA_CPU_PROFILE_CALL_TIMER( Asura_Skybox::InvalidateSkyboxObjects() );

	#ifdef ASURA_USE_STREAMING
	//Make sure any connected zones are loaded. This will allow the module linking indices to be sorted out at the same time.
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Streaming_System::LoadConnectedZones() );
	#endif

	#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM
		ASURA_CPU_PROFILE_CALL_TIMER( Tools_Texturing_MaterialResponse::Initialise() );
	#endif

	// handle any automatic quit-to-game requests
	if( s_bAutoQuitToGame )
	{
		Tools_System::RequestQuitToGame();
	}
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Undo_System::Initialise() );

	#ifdef ASURA_USE_NEW_VISIBILITY_SYSTEM
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_Visibility_System::Initialise() );
	#endif

#if defined ASURA_USE_HDR
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_HDR_Overlay::Initialise() );
#endif

	ASURA_CPU_PROFILE_CALL_TIMER( Tools_LightSets::ToolsSystem_Initialise() );

#if defined(ASURA_USE_ARTICULATION_SYSTEM)
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_LipSync::Initialise() );
#endif	//defined(ASURA_USE_ARTICULATION_SYSTEM)

#if defined(ASURA_USE_FACIAL_ANIMATION_SYSTEM)
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_FacialAnimation_System::Initialise() );
#endif	//defined(ASURA_USE_FACIAL_ANIMATION_SYSTEM)

#ifdef ASURA_USE_FSFX
	ASURA_CPU_PROFILE_CALL_TIMER( Tools_FSFX_System::Initialise() );
	s_xFSFXOverrides.Initialise();
#endif //ASURA_USE_FSFX

	ASURA_CPU_PROFILE_CALL_TIMER( Tools_SoundConversionPreview::Initialise() );

	//Apply the idle while minimised setting now.
	//(Doesn't matter too much exactly when this gets down , except that it is being left to
	//sometime after the loading process is finished)
	//RAR 11/09/2007
	Asura_Windows::SetIdlePriorityWhileMinimised(s_bIdlePriorityWhileMinimised);
}

void Tools_System::Shutdown(void)
{
	if(!This || !s_bToolsActive) return;
	s_bShuttingDown = true;

	ASURA_CPU_PROFILE_SCOPED_TIMER( "Tools_System::Shutdown");

	Tools_Undo_System::Shutdown();

	#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM
		Tools_Texturing_MaterialResponse::Shutdown();
	#endif
	#if defined( ASURA_BOTANICAL_SUPPORT_INTERACTIVE)
		Tools_BotanicalCreation_BasicInteractive::CloseOverlay();		
	#endif
	Tools_Overlay_ViewTextures::CloseOverlay();

	Tools_LightSets::ToolsSystem_Shutdown();

	#ifdef ASURA_USE_DIALOGUE_SYSTEM
	//reset state of dialogue system.
	//doing this before the project shutdown , so that it happens before any quicksave and quickload
	if(!QuitToDesktop)
	{
		Asura_Dialogue_Storage::ResetInGameState();
	}
	#endif

	s_xPFXOverrides.Shutdown();
#if defined(ASURA_USE_MATERIAL_RESPONSE_SYSTEM)
	s_xMaterialResponseOverrides.Shutdown();
#endif	// defined(ASURA_USE_MATERIAL_RESPONSE_SYSTEM)

#ifdef ASURA_DEBUG_VARIABLE_SYSTEM
	Tools_Overlay_DVS::Shutdown();
#endif

	//////////////////////////////////////////////////////////////////////////
	// Depending upon the project the shutdown function MAY call the fake
	// level-export code for quitting to game, so make sure we're not shutting
	// down our systems until after this...
	//////////////////////////////////////////////////////////////////////////
	Project_Shutdown();

#ifdef ASURA_USE_DECAL_MANAGER
	Tools_Overlay_Decals::Shutdown();
#endif

#ifdef ASURA_USE_CONTAINER_SYSTEM
	Tools_Container_System::Shutdown();
#endif // #ifdef ASURA_USE_CONTAINER_SYSTEM

#ifdef ASURA_USE_FSFX
	s_xFSFXOverrides.Shutdown();
	Tools_FSFX_System::Shutdown();
#endif

	//Close skybox overlay. (don't ask if changes should be saved ,since that will already have been dealt with)
	Tools_SkyboxOverlay::CloseOverlay(false);

	// Close the skin elements overlay, too
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_SKINELEMENTS);

#ifdef ASURA_USE_AUDIO_SYSTEM
	Tools_Audio_DSP::DestroyOverlay();
#endif

#ifdef ASURA_USE_AUDIO_SYSTEM
	Tools_Audio_Monitor::DestroyOverlay();
#endif

    Tools_Mode_Blueprint::Shutdown();

#ifdef ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM
	Tools_Overlay_DynamicMusic::Shutdown();
#endif

#ifdef ASURA_USE_WATER
	Tools_WaterTemplate_System::Shutdown();
	// the in-game renderer can't currently cope with water-flagged polys/materials, so drop water packets instead
	Asura_Water_System::Reset();
#endif

	Tools_EntityTemplate_System::Shutdown();
	
	// Tools_Adjacency now handled by Asura_Core
	//Tools_Adjacency::Shutdown();
	Tools_Sound_PS2Settings::Shutdown();		

	// (AW - 02.02.2004) - Never save options if batch processing because the user can't possibly 
	// have changed them, but other code has (process while minimised is forced to true)
	if (!Tools_BatchProcessing::IsBatch())
	{
		Tools_OptionsFile::Save();
	}

	if(CurrentModeClass)
	{
		CurrentModeClass->ShutdownMode();
		delete CurrentModeClass;
	}
	CurrentModeClass = 0;

	Tools_Polygon_Selection::Shutdown();
	Tools_Module_Selection::Shutdown();
	Tools_Vertex_Selection::Shutdown();
	Tools_Edge_Selection::Shutdown();
	Tools_VertexPerPoly_Selection::Shutdown();
	Tools_Prompted_Selection::Shutdown();

	
	#if !defined (ASURA_TARGET_SM3)
	Asura_Mesh_System::PlatformResetRenderMeshes();
	#endif

	ClearFileLists();

	Asura_Menubar_System::DestroyMenuSection(BaseMenuHandle);
	

	Tools_Movement::Shutdown();
	Tools_GeneralOptions::Shutdown();
	Tools_Object_System::Shutdown();

	Tools_Timed_Message_System::Shutdown();
	Tools_Help::RemoveHelpTopic("Movement");
	Tools_Help::RemoveHelpTopic("General");
	Tools_Help::RemoveHelpTopic("Overlays");
	#if defined(ASURA_TARGET_SM3)
	Tools_Help::RemoveHelpTopic("Renderer Debug Keys");
	#endif
	Tools_Help::Shutdown();

	Tools_Render_Options::Shutdown();
	Tools_Render::Shutdown();

	#if defined (ASURA_TARGET_SM3)
	//Some render data may have become invalidated as a result of the hidden status of polygons changing
	//in Tools_Render_Options::Shutdown(). So make sure everything is up to date here...
	//RAR 29/10/2007
	if(!QuitToDesktop)
	{
		Tools_RenderModule_System::UpdateRenderData();
	}
	#endif


	Tools_SaveAsura::Shutdown();

	//restore sound volumes
	Tools_Sound_System::Shutdown();
	

	delete CommonFlagIni;
	CommonFlagIni = NULL;

	#if !defined (ASURA_TARGET_SM3)
	//restore settings from before tools were entered
	Asura_Render::SetPatchesSubdivLevel(This->InitialPatchesSubdivLevel);
	Asura_PatchSubdivision::SubdivideEvenly();
	#endif

	Asura_Windows::SetPauseWhileMinimised(This->m_bInitialPauseWhileMinimised);
	

	This->DeallocateAllToolsClasses();
	s_bToolsActive = false;

	//restore mouse button state
	UpdateRestrictMouseToWindow();
	Asura_Mouse::SetSwapMouseButtons(s_bInitialSwapMouseButtons);
	Asura_Mouse::SetUseWindowsCursor(false);


	//For safety , make sure polygon normals etc are valid on all environment meshes before
	//quitting back to the game. RAR 15/08/02
	for(int i=0;i<Asura_Module_System::GetNumberOfModules();i++)
	{
		Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(i);
		if(!pxMesh->AreNormalsValid()) pxMesh->CreateNormals();
		if(!pxMesh->BoundingBoxDataValid) pxMesh->CalculateBoundingBox();
	}


	/// Kevin Lea - 19/08/2002 12:35:19 - popping in a quick reset of user's input
	/// as I've seen left-mouse button 'sticking' as you go back to a project
	Asura_UserInput::Reset();

    Tools_OS::Shutdown();
	//Tools_PhotonMapping_System::Shutdown();

	Tools_Message_Editing::SaveSettingsToIniFile();
	Tools_Movement::SaveSettingsToIniFile();
	Tools_GeneralOptions::SaveSettingsToIniFile();

	Asura_TextureAnimation_System::ResetAnimationControllers();

	#ifdef ASURA_USE_GUI_MENU_SYSTEM
	if(!QuitToDesktop)
	{
		Tools_Mode_GUIMenu::DoStyleUpdateIfRequired();
	}
	#endif

	#ifdef ASURA_USE_NEW_VISIBILITY_SYSTEM
	Tools_Visibility_System::Shutdown();
	#endif
#ifdef ASURA_USE_HDR
	Tools_HDR_Overlay::Shutdown();
#endif

	Tools_AsrFileManager::CloseOverlay();

	#ifdef ASURA_TOOLS_USE_NEW_MESSAGE_EDITOR
	Tools_MessageEditor::Shutdown();
	#endif

	#ifdef ASURA_USE_ANIMATION_IK_SOLVER
	Tools_Animation_IK_Template_System::Shutdown();
	#endif

	Tools_SoundConversionPreview::Shutdown();


	s_bAutoQuitToGame = false;

#ifdef ASURA_USE_PROFILING_SYSTEM
	Asura_CPUProfile_Renderer::Reset();
#endif

	s_bShuttingDown = false;
}

void Tools_System::ResetSystemsAfterReturningFromGame()
{
	//restore phonon positions in case they have been shifted by loading entity files in LoadEnvironment() or
	//by loading from a quicksave when returning from game. RAR 12/11/2007
	Asura_Phonon_System::ResetPositions();

	//Make sure any music from a previous trip into game has been stopped.
	#ifdef ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM
	Asura_Dynamic_Music_System::Stop();
	#else	
	Asura_MetaMusic_System::StopTrack(true);
	#endif

	// Return to the default preset
	Asura_Sound_Mixer_System::Reset();

	#ifdef ASURA_USE_GUI_MENU_SYSTEM
	//reset the menus in case they have been resized while in game
	//RAR 25/02/2008
	Asura_GUIMenu_System::RestoreResizedSettings();
	#endif
}

void Tools_System::AllocateToolsSystemAndToolsClasses()
{
	Asura_Assert(!This,"Tools already initialised");
	Project_Allocate_Tools_System();
	Asura_Assert(This,"Could not create tools system!");

	This->AllocateAllToolsClasses();
	
}

void Tools_System::DeallocateToolsSystemAndToolsClasses()
{
	Asura_Assert(This,"Tools not initialised");

	This->DeallocateAllToolsClasses();
	delete This;
}

void Tools_System::AllocateAllToolsClasses()
{
	Allocate_Tools_SaveAsura();
	Asura_Assert(Tools_SaveAsura::This,"");

	Allocate_Tools_Level_Export();
	Asura_Assert(Tools_Level_Export::This,"");

	Allocate_Tools_Animation_Files();
	Asura_Assert(Tools_Animation_Files::s_xThis,"");

	if(!Tools_Message_Editing::s_pxThis)
	{
		Allocate_Tools_Message_Editing();
		Asura_Assert(Tools_Message_Editing::s_pxThis,"");
	}

#if defined(ASURA_SUPPORT_BODYPART_SYSTEM)
	Allocate_Tools_Hierarchy_BodyPart_System();
	Asura_Assert(Tools_Hierarchy_BodyPart_System::s_pxThis,"");
#endif	// defined(ASURA_SUPPORT_BODYPART_SYSTEM)

	Allocate_Tools_ShapeTable();
	Asura_Assert(Tools_ShapeTable::GetThis(),"");

	Allocate_Tools_PickTexture();
	Asura_Assert(Tools_PickTexture::GetThis(),"");
	
	Allocate_Tools_PickTiledTexture();
	Asura_Assert(Tools_PickTiledTexture::GetThis(),"");

	Allocate_Tools_OptionsFile();
	Asura_Assert(Tools_OptionsFile::GetThis(),"");

	Allocate_Tools_BatchWaypointing();
	Asura_Assert(Tools_Batch_Waypointing::GetThis(), "");

	Allocate_Tools_EntityTemplate_System();
	Asura_Assert(Tools_EntityTemplate_System::GetThis(), "");

	Allocate_Tools_Movement();
	Asura_Assert(Tools_Movement::GetThis(),"");

#if defined(ASURA_USE_MATERIAL_RESPONSE_SYSTEM)
	Allocate_Tools_Texturing_MaterialResponse();
	Asura_Assert(Tools_Texturing_MaterialResponse::GetThis(),"");
#endif

	Allocate_Tools_LightSets();
	Asura_Assert(Tools_LightSets::GetThis(),"");
}

void Tools_System::DeallocateAllToolsClasses()
{
	delete Tools_SaveAsura::This;
	delete Tools_Level_Export::This;
	delete Tools_Animation_Files::s_xThis;
	//delete Tools_Message_Editing::s_pxThis;
#if defined(ASURA_SUPPORT_BODYPART_SYSTEM)
	delete Tools_Hierarchy_BodyPart_System::s_pxThis;
#endif	// defined(ASURA_SUPPORT_BODYPART_SYSTEM)
	delete Tools_ShapeTable::GetThis();
	delete Tools_PickTexture::GetThis();
	delete Tools_PickTiledTexture::GetThis();
	delete Tools_OptionsFile::GetThis();
	delete Tools_Batch_Waypointing::GetThis();
	delete Tools_EntityTemplate_System::GetThis();
	delete Tools_Movement::GetThis();
#if defined(ASURA_USE_MATERIAL_RESPONSE_SYSTEM)
	delete Tools_Texturing_MaterialResponse::GetThis();
#endif
	delete Tools_LightSets::GetThis();

}

void Tools_System::Allocate_Tools_SaveAsura()
{
	new Tools_SaveAsura;
}

void Tools_System::Allocate_Tools_Level_Export()
{
	new Tools_Level_Export;
}

void Tools_System::Allocate_Tools_Animation_Files()
{
	new Tools_Animation_Files;
}

void Tools_System::Allocate_Tools_Message_Editing()
{
	new Tools_Message_Editing;
}

#if defined(ASURA_SUPPORT_BODYPART_SYSTEM)
void Tools_System::Allocate_Tools_Hierarchy_BodyPart_System()
{
	new Tools_Hierarchy_BodyPart_System;
}
#endif	// defined(ASURA_SUPPORT_BODYPART_SYSTEM)

void Tools_System::Allocate_Tools_ShapeTable()
{
	new Tools_ShapeTable;
}

void Tools_System::Allocate_Tools_PickTexture()
{
	new Tools_PickTexture;
}

void Tools_System::Allocate_Tools_PickTiledTexture()
{
	new Tools_PickTiledTexture;
}

void Tools_System::Allocate_Tools_OptionsFile()
{
	new Tools_OptionsFile;
}

void Tools_System::Allocate_Tools_BatchWaypointing()
{
	new Tools_Batch_Waypointing;
}

void Tools_System::Allocate_Tools_EntityTemplate_System()
{
	new Tools_EntityTemplate_System;
}

void Tools_System::Allocate_Tools_Movement()
{
	new Tools_Movement;
}

#ifdef ASURA_USE_DIALOGUE_SYSTEM
void Tools_System::Allocate_Tools_Dialogue_System()
{
	new Tools_Dialogue_System;
}
#endif

#if defined(ASURA_USE_MATERIAL_RESPONSE_SYSTEM)
void Tools_System::Allocate_Tools_Texturing_MaterialResponse()
{
	new Tools_Texturing_MaterialResponse;
}
#endif

void Tools_System::Allocate_Tools_LightSets()
{
	new Tools_LightSets;
}


void Tools_System::OpenIniFiles()
{
	//build the filename
	char iniFileName[MAX_PATH];
	const char* dir = Project_GetIniFileDirectory();
	Asura_Assert(dir,"");
	sprintf(iniFileName,"%s\\CommonFlags.ini",dir);

	//open the flag ini file
	CommonFlagIni = new Tools_Flag_IniFile(iniFileName);
}

bool Tools_System::MainLoop(void)
{
	if(!This) return false;
	
	//ASURA_CPU_PROFILE_SCOPED_TIMER( "Tools_System::MainLoop");

	Tools_Cubemap_Generator::Update ();

	//update state of middle mouse button
	Tools_Movement::UpdateMouseRotationState();
	
	Asura_Cursor::EnableCursorMovement(!Tools_Movement::IsUsingMouseRotation());
	Asura_UserInput::Update();
	Asura_Cursor::EnableCursorMovement(true);//(make sure cursor movement is back on for any other 'main loops' that may occur

	ASURA_CPU_PROFILE__START_LABEL(ASURA_CPU_PROFILE__PROJECT_WHITE, "Tools_Object_System::Update()");
	Tools_Object_System::Update();
	ASURA_CPU_PROFILE__STOP(ASURA_CPU_PROFILE__PROJECT_WHITE);

	//Prune entities in case any were deleted by user in object system update.
	Asura_Entity_System::PruneEntityLists();

	//handle movement
	Tools_Movement::Update();


	// Kevin Lea - 11/09/2001 14:21:56 - Function keys
	// I've gathered all these together into one place to make it a trifle easier
	// to see what's going on...

	#if 1
	if(!Asura_UserInput::KeyPressed(ASURA_KEYID_ALT))
	{
		if(!Asura_UserInput::KeyPressed(ASURA_KEYID_CTRL) && !Asura_UserInput::KeyPressed(ASURA_KEYID_SHIFT))
		{
			// Kevin Lea - 11/09/2001 14:21:44 - wireframe on/off
			if (Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_F1))
			{
				Tools_Render_Options::NextWireframeMode();
			}

			// Kevin Lea - 11/09/2001 14:21:36 - highlighting modes
			if (Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_F2))
			{
				Tools_Render_Options::NextPolygonHighlightMode();
			}
			if (Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_F3))
			{
				Tools_Render::HighlightPolyOrObjectUnderCursor = !Tools_Render::HighlightPolyOrObjectUnderCursor;
			}
			
			// Kevin Lea - 11/09/2001 14:21:28 - mod linking on/off
			if (Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_F4))
			{
				Tools_Render_Options::ToggleUseModLinks();
#ifdef ASURA_USE_NEW_VISIBILITY_SYSTEM
				Asura_Visibility_System::ToggleRenderEverything();
#endif
			}

			// Kevin Lea - 11/09/2001 14:22:48 - I'm actually using F5 for some AI stuff, but that's probably temporary

			// Kevin Lea - 11/09/2001 14:20:55 - patch control
			#if 01
			if (Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_F6))
			{
				Tools_Render_Options::SetSubdivisionMode(TOOLS_SUBDIVIDE_NONE);
			}
			if (Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_F7))
			{
				Tools_Render_Options::SetSubdivisionMode(TOOLS_SUBDIVIDE_EVENLY);
			}
			if (Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_F8))
			{
				Tools_Render_Options::SetSubdivisionMode(TOOLS_SUBDIVIDE_NEARWAYPOINTS);
			}
			#endif
			if (Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_ESCAPE))
			{
				if(TheAviWriter.IsWritingFile())
				{
					EndAVI();
				}
				if (s_bRecordScreenshots)
				{
					s_bRecordScreenshots = false;
				}
			}

			if (Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_F11) && GetCurrentMode() != TOOLS_MODE_GUIMENU)
			{
				RequestQuitToGame();
			}
		}

		if( (Asura_UserInput::KeyPressed(ASURA_KEYID_CTRL)) &&
			(Asura_UserInput::DebouncedKeyPressed('`')))
		{
			RequestStandbyMode();
		}

		#ifndef TOOLS_USE_OLD_ENTITY_MANAGER
		// Handle ctrl+< and ctrl+> to move the primary selection forwards and backwards between all selected

		if(Asura_UserInput::KeyPressed(ASURA_KEYID_CTRL))
		{
			if(Asura_UserInput::DebouncedKeyPressed(','))
			{
				if(Tools_Object_System::SelectedObject)
				{
					u_int uSelectedObjectGuid = Tools_Object_System::SelectedObject->GetGuid();

					u_int uLastObjectGuid = ASURA_GUID_UNREGISTERED;

					for(LIF<Tools_Object*> xObjectLIF(&Tools_Object_System::SelectedObjectList);!xObjectLIF.done();xObjectLIF.next())
					{
						u_int uThisGuid = xObjectLIF()->GetGuid();

						if(uThisGuid == uSelectedObjectGuid)
						{
							if(uLastObjectGuid != ASURA_GUID_UNREGISTERED)
							{
								Tools_Object* pxPrevObject = Tools_Object_System::GetObjectFromGuid(uLastObjectGuid);

								if(pxPrevObject)
								{
									Tools_Object_System::SelectObject(pxPrevObject, true, true);
								}
							}
							else
							{
								Tools_Object_System::SelectObject(Tools_Object_System::SelectedObjectList.last_entry(), true, true);
							}

							break;
						}

						uLastObjectGuid = uThisGuid;
					}
				}
			}

			if (Asura_UserInput::DebouncedKeyPressed('.'))
			{
				if (Tools_Object_System::SelectedObject)
				{
					u_int uSelectedObjectGuid = Tools_Object_System::SelectedObject->GetGuid();

					for(LIF<Tools_Object*> xObjectLIF(&Tools_Object_System::SelectedObjectList);!xObjectLIF.done();xObjectLIF.next())
					{
						u_int uThisGuid = xObjectLIF()->GetGuid();

						if(uThisGuid == uSelectedObjectGuid)
						{
							xObjectLIF.next();

							if(!xObjectLIF.done())
							{
								Tools_Object* pxNextObject = xObjectLIF();

								if(pxNextObject)
								{
									Tools_Object_System::SelectObject(pxNextObject, true, true);
								}
							}
							else
							{
								Tools_Object_System::SelectObject(Tools_Object_System::SelectedObjectList.first_entry(), true, true);
							}

							break;
						}
					}
				}
			}
		}
		#endif

	}
	else
	{
		//(alt is pressed)
		if(!Asura_UserInput::KeyPressed(ASURA_KEYID_CTRL) && !Asura_UserInput::KeyPressed(ASURA_KEYID_SHIFT))
		{
			if (Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_F1))
			{
				Tools_RenderCollisionMesh_System::NextRenderMode();
			}
			#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM
			if (Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_F3))
			{
				Asura_MaterialResponse_System::SetUseUVOrientMaterial(!Asura_MaterialResponse_System::GetUseUVOrientMaterial());
			}
			#endif
		}

	}
	

	Asura_Render::CurrentStates.RequestWireFrameMode(Asura_Render::GetWireframe());

	if(Asura_UserInput::KeyPressed(ASURA_KEYID_ALT))
	{
		if(Asura_UserInput::DebouncedKeyPressed('c'))
		{
			CopyPositionToClipboard();
		}
	}
	else
	{
		// Kevin Lea - 11/09/2001 14:21:20 - saving
		if (Asura_UserInput::DebouncedKeyPressed('s') && Asura_UserInput::KeyPressed(ASURA_KEYID_CTRL))
		{
			Tools_SaveAsura::SaveModified();
		}
	}
	
	#endif

	// (MH - 18.09.2002) does nothing in tools - no network!
    //Asura_Network::Update();

	Asura_Cursor::OncePerFrameUpdate();

	if(!Asura_UserInput::KeyPressed(ASURA_KEYID_ALT))
	{
		if(!Asura_Overlay_System::OverlaysHaveKeyboardFocus() && Asura_UserInput::KeyPressed(ASURA_KEYID_CTRL))
		{
			if (Asura_UserInput::DebouncedKeyPressed('1'))
			{
				Tools_Render::SetVideoMode(640,480);
			}
	
			if (Asura_UserInput::DebouncedKeyPressed('2'))
			{
				Tools_Render::SetVideoMode(800,600);
			}
	
			if (Asura_UserInput::DebouncedKeyPressed('3'))
			{
				Tools_Render::SetVideoMode(1024,768);
			}
			#if 1
			if (Asura_UserInput::DebouncedKeyPressed('4'))
			{
				Tools_Render::SetVideoMode(1280,960);
			}
			if (Asura_UserInput::DebouncedKeyPressed('5'))
			{
				Tools_Render::SetVideoMode(1600,1200);
			}
			if (Asura_UserInput::DebouncedKeyPressed('6'))
			{
				Tools_Render::SetVideoMode(1280,720);
			}
			if (Asura_UserInput::DebouncedKeyPressed('7'))
			{
				Tools_Render::SetVideoMode(1920,1080);
			}
			if (Asura_UserInput::DebouncedKeyPressed('8'))
			{
				Tools_Render::SetVideoMode(1920,1200);
			}
			#endif
			if (Asura_UserInput::DebouncedKeyPressed('9'))
			{
				HWND xWindowHandle = Asura_Windows::GetWindowHandle();
				ShowWindow( xWindowHandle, SW_MAXIMIZE);
				RECT xRectClient;
				GetClientRect( xWindowHandle, &xRectClient);
				
				const u_int uWidth = xRectClient.right - xRectClient.left;
				const u_int uHeight = xRectClient.bottom - xRectClient.top;
				Tools_Render::SetVideoMode( uWidth, uHeight, false);
			}
			#if 01
			if (Asura_UserInput::DebouncedKeyPressed('0'))
			{
				Tools_Render::SetVideoMode(640,480,true);
			}
			#endif
		}
	}

	Asura_Interface::Update();

	Tools_Level_Export::Update();
	Tools_Undo_System::Update();
	ASURA_CPU_PROFILE__START_LABEL(ASURA_CPU_PROFILE__PROJECT_PALE_GREEN, "CurrentModeClass->Update()");
	CurrentModeClass->Update();
	ASURA_CPU_PROFILE__STOP(ASURA_CPU_PROFILE__PROJECT_PALE_GREEN);

	Tools_ContextMenu_System::Update();

	if(Tools_SaveAsura::GetFileType() == AsuraFile_Template)
	{
		//editing template file , keep track of which objects belong to the template
		Tools_Entity_TemplateMaster_Object::UpdateChildListInEntity();
	}	
	Tools_SkyboxOverlay::Update();
	Tools_Prompted_Selection::Update();
	Asura_Module_System::UpdateInvalidCollisionMeshes();
	Asura_Cutscene_System::Update();

#if defined(ASURA_USE_FACIAL_ANIMATION_SYSTEM)
	Asura_FacialAnimation_System::Update();
#endif	//defined(ASURA_USE_FACIAL_ANIMATION_SYSTEM)

#ifdef ASURA_TOOLS_SYSTEM_UPDATE_PHYSICS
	Asura_Physics_System::Update();
#endif

	ASURA_CPU_PROFILE__START_LABEL(ASURA_CPU_PROFILE__PROJECT_PALE_CYAN, "Tools_Entity_PFX_Effect::UpdatePFXEntities()");
	Tools_Entity_PFX_Effect::UpdatePFXEntities();
	ASURA_CPU_PROFILE__STOP(ASURA_CPU_PROFILE__PROJECT_PALE_CYAN);
	#ifdef ASURA_TARGET_SM3
	Tools_Entity_DynamicLight::UpdateEntities();
	#endif
	Asura_SpecialFX_System::Update();
    Tools_Mode_Blueprint::Update();

	#ifdef ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM
	Tools_Overlay_DynamicMusic::Update();
	#endif

#ifdef ASURA_USE_BOTANICALS
	if( !Tools_Render_Options::HideEnvironment &&
		!Tools_RenderCollisionMesh_System::IsRenderingCollMeshes() &&
		!Tools_System::IsHideBotanicalsChecked() )
	{
		Asura_BGR_Manager& xBGRManager = Asura_BGR_Manager::GetBGRManager();
		xBGRManager.Update( Asura_Timers::GetGameTimeSlice());
	}
#endif // #ifdef ASURA_USE_BOTANICALS

#ifdef ASURA_USE_MATERIAL_RESPONSE_SYSTEM
	Tools_Texturing_MaterialResponse::Update();
#endif
#if defined( ASURA_BOTANICAL_SUPPORT_INTERACTIVE)
	Tools_BotanicalCreation_BasicInteractive::Update();
#endif
	
#ifdef ASURA_USE_CONTAINER_SYSTEM
	Tools_Container_System::Update();
#endif //#ifdef ASURA_USE_CONTAINER_SYSTEM
#ifdef ASURA_USE_ANIMATION_IK_SOLVER
	Tools_Animation_IK_Template_System::Update();
#endif

	
	Tools_Help::Update();

	//Deal with one-off warning messages etc
	DoFirstFrameChecksIfRequired();

	if(s_iDefaultMode != TOOLS_MODE_NULL && !ReadyToQuitOut)
	{
		//switch to the default mode requested
		RequestNextMode(s_iDefaultMode,true);
		s_iDefaultMode = TOOLS_MODE_NULL;
	}


	if(s_bHasBeenMinimised)
	{
		//some alt-tabbing has been going on. See if those dastardly artists have checked out
		//a modified file behind our back.
		s_bHasBeenMinimised = false;
		Tools_LoadedFileList::CheckForExternallyModifiedFiles(true);
	}


	//update sound muteness
	Tools_Sound_System::Update();
	Tools_SoundEvent_System::Update();
	Tools_SoundConversionPreview::Update();

	Tools_Render_Options::Update();

	//make sure module normals are up to date
	Tools_ModuleSmoothing::CheckModuleNormals();

	
	if(Tools_BatchProcessing::IsBatch())
	{
		Tools_BatchProcessing::DoBatchProcess();
		RequestNextMode(TOOLS_MODE_QUITTODESKTOP,true);	
	}

#ifdef ASURA_SUPPORT_FMV_TEXTURES
	Asura_MovieToTexture_System::Update();
#endif

#ifdef ASURA_USE_DECAL_MANAGER
	Tools_Overlay_Decals::Update();
#endif

#ifdef ASURA_DEBUG_VARIABLE_SYSTEM
	Tools_Overlay_DVS::Update();
#endif

	This->Project_Update();

	Tools_MessageLog::Update();

	Tools_WindowsCursor::Update();

	Render();
	
	#ifdef ASURA_USE_AUDIO_SYSTEM
	Asura_Audio_Systems_Manager::Update();
	#else
	Asura_Sound_System::Update();
	#endif
	

	if(!Asura_Windows::IsApplicationActive())
	{
		//minimised , so allow other processes to get time
		Sleep(50);
	}
	
	if(Tools_Render_Options::IsFrameRateClamped())
	{
		Asura_Timers::SetMaxFrameRate(Tools_Render_Options::GetMaxFrameRate());
	}
	else
	{
		Asura_Timers::SetMaxFrameRate(0.0f);
	}

	if(This->HandleTimerInMainLoop())
	{
		Asura_Timers::HandlePrimaryTimer();
	}

	if(ReadyToQuitOut)
	{
		Asura_Render::SetWireframe(false);
	}

	return (!ReadyToQuitOut);
}

void Tools_System::Render()
{
	if(NULL != Asura_Direct3D::D3DDevice && !Tools_BatchProcessing::IsConsoleMode() && !Asura_Direct3D::IsReferenceRasterizer())
	{
		//ASURA_CPU_PROFILE_SCOPED_TIMER( "Tools_System::MainLoop Draw");
#ifdef ASURA_USE_CSM
		// Ensure we have updated D3D data for the env before trying to create shadow maps
		Tools_RenderModule_System::UpdateRenderData();
		Asura_CSM::CreateShadowMaps();
#endif

#ifdef ASURA_TARGET_SM3
		Asura_Render::BeginMRT();
#endif

		Asura_Render::ApplyCameraSettings();
		Tools_Render::BeginRenderWorld();
		Tools_CutsceneModeAVI::BeginRenderWorld();
		
		Asura_Skybox::Render();

		Asura_SpecialFX_System::RenderSkyboxEffects();
		
		ASURA_CPU_PROFILE__START_LABEL(ASURA_CPU_PROFILE__WORLD_RENDER, "World Render");
		Tools_Render::RenderEnvironment();
		ASURA_CPU_PROFILE__STOP(ASURA_CPU_PROFILE__WORLD_RENDER);

#ifdef ASURA_USE_STATIC_DECAL_SYSTEM
		if( !Tools_Render_Options::HideEnvironment &&
			!Tools_RenderCollisionMesh_System::IsRenderingCollMeshes() )
		{		
			Asura_Decal_System::RenderStaticDecals();
		}
#endif

#ifdef ASURA_USE_BOTANICALS
		// JAT 31/08/06 - dont draw botanicals or carpet if the level is marked to be hidden
		if( !Tools_Render_Options::HideEnvironment &&
			!Tools_RenderCollisionMesh_System::IsRenderingCollMeshes() &&
			!Tools_System::IsHideBotanicalsChecked() )
		{
			Asura_Botanicals_InstanceManager::Render();
		}
#endif // #ifdef ASURA_USE_BOTANICALS

#ifdef ASURA_USE_CARPET
		// JAT 31/08/06 - dont draw botanicals or carpet if the level is marked to be hidden
		if( !Tools_Render_Options::HideEnvironment &&
			!Tools_RenderCollisionMesh_System::IsRenderingCollMeshes() &&
			!Tools_System::IsHideCarpetChecked() )
		{
			Asura_Carpet_MeshManager::Render();	
		}
#endif // #ifdef ASURA_USE_CARPET

#ifdef ASURA_USE_DECAL_MANAGER
		// DMR - 07/02/2007 - If we're using the decal editor, we need to render decals in tools mode
		//					  Also needed now for static decals
		if( !Tools_Render_Options::HideEnvironment &&
			!Tools_RenderCollisionMesh_System::IsRenderingCollMeshes() )
		{		
			Asura_SpecialFX_System::RenderDecals();
		}
#endif

		// AAM - 05.07.2007 - Profiling categories help with PIX captures
		ASURA_CPU_PROFILE__START_LABEL( ASURA_CPU_PROFILE__ENTITY_RENDER, "Entity Render" );

		// KOR - 04/05/2006 - make sure translucent objects are rendered in correct order.
		// RAR - 27/07/2006 - include the mode render as well so that cutscene rendering is sorted.
		Asura_SortedRender::Start();

		if( CurrentModeClass )
		{
			CurrentModeClass->EarlyRender();//draw mode specific stufff that should appear in screenshots
		}

#ifdef ASURA_USE_MATERIAL_RESPONSE_SYSTEM
		if (Asura_MaterialResponse_System::GetMaterialProjectContextCallback())
		{
			Asura_MaterialResponse_System::GetMaterialProjectContextCallback()(ASURA_MATERIAL_RESPONSE_PROJECT_CONTEXT_INVALID,ASURA_MATERIAL_RESPONSE_PROJECT_CONTEXT_INVALID);
		}
#endif
		Tools_Object_System::RenderPreFSFX();

		// KOR - 04/05/2006 - only Tools_Object_System::EarlyRender needs to be sorted, I think.
		Asura_SortedRender::End();

#ifdef ASURA_USE_MATERIAL_RESPONSE_SYSTEM
		if (Asura_MaterialResponse_System::GetMaterialProjectContextCallback())
		{
			Asura_MaterialResponse_System::GetMaterialProjectContextCallback()(ASURA_MATERIAL_RESPONSE_PROJECT_CONTEXT_INVALID,ASURA_MATERIAL_RESPONSE_PROJECT_CONTEXT_INVALID);
		}
#endif

		ASURA_CPU_PROFILE__STOP( ASURA_CPU_PROFILE__ENTITY_RENDER );

		// DMR - 13/03/2007 - Added a Project_Render (so we can preview explosions in SS2 tools)
		This->Project_Render();

		Asura_Render::CurrentStates.RequestWireFrameMode(false);		

#ifdef ASURA_TARGET_SM3
		Asura_Render::EndMRT();
#endif

		if (Tools_Render::LightingIsOn() && !Tools_RenderCollisionMesh_System::IsRenderingCollMeshes() )
		{		
#ifdef ASURA_TARGET_SM3
			Asura_DeferredShading::Render();
#elif defined ASURA_USE_INDEPENDENT_SHADOW_SYSTEM
			Asura_Shadow_System::Render();
#endif
		}
		else
		{
			// JAT 18/10/07 - clear out any shadows that might have been added in to the list but not rendered
			#if defined(ASURA_USE_INDEPENDENT_SHADOW_SYSTEM)
			Asura_Shadow_System::FinishedRenderingShadows();
			#endif
		}

#ifdef ASURA_TARGET_SM3
		// Check the hideenvironment flag here... don't want to see transparent env strips if the env is hidden
		if( !Tools_Render_Options::HideEnvironment &&
			!Tools_RenderCollisionMesh_System::IsRenderingCollMeshes() )
		{
			Asura_Module_System::RenderLate();
		}

		Asura_SortedRender::RenderTransparentItems();
#ifdef ASURA_USE_MATERIAL_RESPONSE_SYSTEM
		if (Asura_MaterialResponse_System::GetMaterialProjectContextCallback())
		{
			Asura_MaterialResponse_System::GetMaterialProjectContextCallback()(ASURA_MATERIAL_RESPONSE_PROJECT_CONTEXT_INVALID,ASURA_MATERIAL_RESPONSE_PROJECT_CONTEXT_INVALID);
		}
#endif
#endif

		const bool bRenderMode = CurrentModeClass &&
			(!Tools_Modal_Overlay::IsActive() || CurrentModeClass->ShouldRenderDuringModalOverlay());

		if(bRenderMode)
		{
			CurrentModeClass->RenderWorld_PreToneMap();
		}

		Tools_Cubemap_Generator::Render();

		// Check the hideenvironment flag here... don't want to be seeing coronas, lightshafts, etc 
		// in modes like BotanicalCreation
		if( !Tools_Render_Options::HideEnvironment &&
			!Tools_RenderCollisionMesh_System::IsRenderingCollMeshes() )
		{
			Asura_SpecialFX_System::Render();
		}
		else
		{
			//Continue rendering PFX so they can be used in hierarchy mode. RAR 29/05/2008
			Asura_PFX_System::Render(ASURA_PFX_RENDER_NORMAL);
			Asura_PFX_System::RenderHeatHaze();	

			#ifdef ASURA_USE_HDR
			// (AAM - 31.08.2007) We do need tone mapping though!
			Asura_Render::ApplyToneMapping();
			#endif
		}

#ifdef ASURA_USE_HDR
		Asura_Render::CurrentStates.RequestZBufferEnabled(true);

		ASURA_CPU_PROFILE__START_LABEL(ASURA_CPU_PROFILE__WORLD_RENDER, "World Render");
		Tools_Render::RenderEnvironment();
		ASURA_CPU_PROFILE__STOP(ASURA_CPU_PROFILE__WORLD_RENDER);
#endif
		ASURA_CPU_PROFILE__START_LABEL(ASURA_CPU_PROFILE__PROJECT_PALE_BLUE, "Tools_Object_System::Render()");
		Tools_Object_System::Render();
		ASURA_CPU_PROFILE__STOP(ASURA_CPU_PROFILE__PROJECT_PALE_BLUE);

		Asura_Physics_System::DebuggingRender();

#ifdef ASURA_USE_NEW_VISIBILITY_SYSTEM
		Tools_Visibility_System::DebugRender();
#endif

		if(bRenderMode)
		{
			CurrentModeClass->RenderWorld_PostToneMap();
		}

		Asura_SpecialFX_System::RenderHUDEffects();

		Tools_CutsceneModeAVI::EndRenderWorld();

		Tools_Render::EndRenderWorld();

		Asura_SpecialFX_System::Render2DEffects();

		// [18/7/2008 AS] Added a LateRender (for AVP cloak effect in tools)
		This->Project_LateRender();

		if(bRenderMode)
		{
			CurrentModeClass->Render2D();
		}

		if (s_bRecordScreenshots || (Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_PAUSE) && Asura_UserInput::KeyPressed(ASURA_KEYID_SHIFT)))
		{
			ScreenShot(s_bRecordScreenshots);
		}
		if(TheAviWriter.IsWritingFile())
		{
			TheAviWriter.WriteFrame();
		}

		if(This->m_iColourSample_RequestedSize) This->CalculateColourSample();


#ifdef ASURA_USE_BOTANICALS
		if (Tools_System::IsBotanicalsStatisticsChecked())
		{
			Tools_Botanicals_Statistics::Render();
		}
#endif // #ifdef ASURA_USE_BOTANICALS
#ifdef ASURA_USE_CARPET
		if (Tools_System::IsCarpetStatisticsChecked())
		{
			Tools_Carpet_Statistics::Render();
		}
#endif // #ifdef ASURA_USE_CARPET

		ASURA_CPU_PROFILE__START_LABEL(ASURA_CPU_PROFILE__PROJECT_PALE_BLUE, "Tools_Object_System::Render()");
		Tools_Object_System::RenderAsUI();
		ASURA_CPU_PROFILE__STOP(ASURA_CPU_PROFILE__PROJECT_PALE_BLUE);

#ifdef ASURA_TARGET_SM3
	Asura_DeferredShading::RenderDebugOutput();
#endif

		#if 1
		//Disable most of the default status text while in menu mode.
		if(!Asura_Overlay_System::AreOverlaysHidden() && CurrentMode != TOOLS_MODE_GUIMENU)
		{
			Asura_Vector_3 xPosition;
			Asura_Euler_3 xEuler;
			u_int uPosColour = 0;

			//If an object is selected , then show its position and orientation.
			//Otherwise show the camera position/orient
			if(Tools_Object_System::SelectedObject)
			{
				xPosition = Tools_Object_System::SelectedObject->Position;
				xEuler.FromMatrix(Tools_Object_System::SelectedObject->Orientation);
				uPosColour = 0xffffff00;
			}
			else
			{
				xPosition = *Asura_Camera::GetPosition();
				xEuler.FromMatrix(*Asura_Camera::GetOrientation());
				uPosColour = 0xff00ff00;
			}

			static Tools_CyclicBuffer< float> xAverageFrameTime( 256);
			
			const float fFrameRate = Asura_Timers::GetFrameRate();
			xAverageFrameTime.ValueAdd( Asura_Timers::GetFrameTime() );
			const float fAverageFrameTime = xAverageFrameTime.GetAverage();
			const float fAverageFrameRate = fAverageFrameTime ? 1/fAverageFrameTime : 0.0f;
	
			if( !IsHidingToolsStatusText() )
			{
				Asura_Text_Output::Print(3,1,0xff00ff00,0,"%4.1f (%4.1f)", fFrameRate, fAverageFrameRate);
				Asura_Text_Output::Print(3,1,uPosColour,0,"              Pos: %3.1fm,%3.1fm,%3.1fm",xPosition.x,xPosition.y,xPosition.z);
				Asura_Text_Output::Print(3,2,uPosColour,0,"              Orient: %3.3f %3.3f %3.3f",xEuler.x*180.0f/Asura_Maths::Pi,xEuler.y*180.0f/Asura_Maths::Pi,xEuler.z*180.0f/Asura_Maths::Pi);
			
#if 0
				{
					MEMORYSTATUSEX xMemoryStatus = { 0};
					xMemoryStatus.dwLength = sizeof( xMemoryStatus);
					
					GlobalMemoryStatusEx( &xMemoryStatus);
					
					u_int uMemoryLow = uint32( 0xFFFFFFFF & (xMemoryStatus.ullAvailVirtual >> 0));
					if( 32 < sizeof( xMemoryStatus.ullAvailVirtual))
					{
						u_int uMemoryHigh = uint32( 0xFFFFFFFF & (xMemoryStatus.ullAvailVirtual >> 32));
						Asura_Text_Output::Print(3,3,0xff00ff00,0,"Free Mem: 0x%08X%08X", uMemoryHigh, uMemoryLow);
					}
					else
					{
						Asura_Text_Output::Print(3,3,0xff00ff00,0,"Free Mem: 0x%08X", uMemoryLow);
					}
				}
#endif
#if 0
				char buffer[100];

				sprintf( buffer, "TRIS: %d", Asura_Render::GetNumberOfTrianglesRendered() );

				if (Asura_UserInput::DebouncedKeyPressed('z')) Asura_Visibility_System::s_bOverrideModuleLinking = !Asura_Visibility_System::s_bOverrideModuleLinking;

				if ( Asura_Visibility_System::s_bOverrideModuleLinking )
				{
					Asura_Font_System::SetFont( 1 );
					Asura_Font_System::Print( 10, 30, 5, 0xffffffff, 0, "AFTER (new visibility system)" );
					Asura_Font_System::Print( 10, 130, 5, 0xffffffff, 0, buffer );

				}
				else
				{
					Asura_Font_System::SetFont( 1 );
					Asura_Font_System::Print( 10, 30, 5, 0xffffffff, 0, "BEFORE (old 'module-linking' system)" );
					Asura_Font_System::Print( 10, 130, 5, 0xffffffff, 0, buffer );
				}
#endif
				Asura_Text_Output::Print(50,1,0xffffffff,0,"Tris: %d",Asura_Render::GetNumberOfTrianglesRendered());
			}

#ifdef ASURA_TOOLS_SHOW_PFX_COST
#ifdef ASURA_USE_FASTPATH_PFX			
			Asura_Text_Output::Print(70,1,0xffffffff,0,"Approx PFX Cost: %0.02f Screenfills",Asura_Platform_PFX_System_FastPath::GetNumFastPathParticleScreenfullsRenderedThisFrame());
#endif
#endif
			if ( Tools_Render_Options::GetDisplayCollisionPolys() )
			{
				int iCollisionPolyCount = 0;

				for(int i=0;i<Asura_Module_System::GetNumberOfModules();i++)
				{
					const Asura_CollisionMesh	*pxCollisionMesh = Asura_Module_System::GetCollisionMeshForModule(i);

					iCollisionPolyCount += pxCollisionMesh->GetNumberOfPolys();
				}

				Asura_Text_Output::Print(50,2,0xffffffff,0,"Collision Tris: %d",iCollisionPolyCount);
			}

#ifdef ASURA_PC_APPLICATION_TITLE
            const char* szBuildStrFormat = ASURA_PC_APPLICATION_TITLE 
	#if defined( ASURA_TARGET_SM3)
		" SM30"
	#endif
            " - built by %s - %s - Ctrl+H for help";
#else
            const char* szBuildStrFormat = "Asura tools"
	#if defined( ASURA_TARGET_SM3)
		" SM30"
	#endif
            " - built by %s - %s - Ctrl+H for help";
#endif
            
			Asura_Text_Output::Print( 3,
	                                  /*53*/((float)Asura_Viewport::GetHeight()-12.0f)/14.0f-0.5f,
	                                  0xffffff00,
	                                  0,
	                                  szBuildStrFormat,
#ifdef PROGRAMMER_INITIALS
	                                  PROGRAMMER_INITIALS,
#else
	                                  "<unknown - define INITIALS env var>",
#endif
	                                  Asura_BuildTimeAndDate );
		
		}
		#endif
		{
			static float displayingInfo = 0.0f;

			if(!Asura_Overlay_System::OverlaysHaveKeyboardFocus())
			{
				if (Asura_UserInput::DebouncedKeyPressed('-'))
				{
					if(Asura_UserInput::KeyPressed(ASURA_KEYID_SHIFT))
					{
						UserSetGameTimeScale=0.0f;
					}
					else
					{
						UserSetGameTimeScale-=0.1f;
						if (UserSetGameTimeScale<0.0f) UserSetGameTimeScale = 0.0f;
					}
					Asura_Timers::SetGameTimeScale(UserSetGameTimeScale);
					displayingInfo = 1.0f;
				}
				else if (Asura_UserInput::DebouncedKeyPressed('=')||Asura_UserInput::DebouncedKeyPressed('+'))
				{
					if(Asura_UserInput::KeyPressed(ASURA_KEYID_SHIFT))
					{
						UserSetGameTimeScale=1.0f;
					}
					else
					{
						UserSetGameTimeScale+=0.1f;
						if (UserSetGameTimeScale>4.0f) UserSetGameTimeScale = 4.0f;
					}
					Asura_Timers::SetGameTimeScale(UserSetGameTimeScale);
					displayingInfo = 1.0f;
				}
			}
			
			
			
			

			if (displayingInfo>0.0f)
			{
				unsigned int a = (Asura_Maths::FloatToInt(displayingInfo*255.0f)<<24)+0xffffff;
				displayingInfo-=Asura_Timers::GetFrameTime()*0.5f;
				Asura_Text_Output::Print(((float)Asura_Viewport::GetWidth())/20.0f-0.5f,((float)Asura_Viewport::GetHeight()-32.0f)/28.0f-0.5f,a,ASURA_TEXT_FORMAT_CENTREJUSTIFIED,"Time Scale %0.0f%%",UserSetGameTimeScale*100);
			}
		}
				

		// resets flags etc
		Asura_Lighting_System::Update();
			
		//render module outlines if desired
		if(IsShowingAllModuleOutlines())
		{
			RenderAllModuleOutlines();
		}
		if(IsShowingCursorModuleOutline())
		{
			RenderCursorModuleOutline();
		}


		Tools_Render_Options::Render();

		if(!Tools_Modal_Overlay::IsActive() || (CurrentModeClass && CurrentModeClass->ShouldRenderDuringModalOverlay()))
		{
			CurrentModeClass->RenderUI();
		}

		Tools_Prompted_Selection::Render();
		//Some PFX mode rendering stuff needs to be done in other modes. There isn't 
		//any particularly good place to deal with such at the moment , so I'm plonking it here.
		Tools_Mode_PFX::RenderUIExMode();

#ifdef ASURA_USE_DECAL_MANAGER
		Tools_Overlay_Decals::Render();
#endif

        Tools_Mode_Blueprint::Render();

		if(TheAviWriter.IsWritingFile())
		{
			Asura_Text_Output::Print(0,3,0xff00ff00,0,"Recording AVI (Escape to stop)");
		}
		else if (s_bRecordScreenshots)
		{
			Asura_Text_Output::Print(0,3,0xff00ff00,0,"Recording screenshots (Escape to stop)");
		}
		if(ShowCursorInformation) RenderCursorInformation();

	    if( ShouldPS2PerfMetricsBeAvailable() )
	    {
	        if( s_bShowPS2PerfMetrics ) { RenderPS2PerfMetrics(); }
	    }
	    else
	    {
	        s_bShowPS2PerfMetrics = false;
	    }	

#if 1
		{
			static char szOriginalDirectory[ MAX_PATH] = { 0};
			if( 0 == szOriginalDirectory[ 0])
			{
				GetCurrentDirectory( sizeof(szOriginalDirectory) - 1, szOriginalDirectory);
			}
			
			char szCurrentDirectory[ MAX_PATH] = { 0};
			GetCurrentDirectory( sizeof(szCurrentDirectory) - 1, szCurrentDirectory);
			if( 0 != stricmp( szCurrentDirectory, szOriginalDirectory))
			{
				Asura_Text_Output::Print(0,4,0xffFF0000,0,"Working Directory has changed.");
				Asura_Text_Output::Print(2,5,0xffFF0000,0,"Original: '%s'", szOriginalDirectory);
				Asura_Text_Output::Print(2,6,0xffFF0000,0,"Present: '%s'", szCurrentDirectory);
			}
		}
#endif

		Asura_Interface::Render();

		//render current speed
		Tools_Movement::Render();

		Tools_Timed_Message_System::Render();



		Tools_Help::Render();

		Asura_Cursor::Render();

		//take a screenshot
		if(!Asura_UserInput::KeyPressed(ASURA_KEYID_ALT) && !Asura_UserInput::KeyPressed(ASURA_KEYID_CTRL) && !Asura_UserInput::KeyPressed(ASURA_KEYID_SHIFT))
		{
			if (Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_PAUSE))
			{
				Asura_Render::FlushDisplay();
				ScreenShot();
			}
		}

		Asura_Render::EndFrame();
	}
}

void Tools_System::SetSwapMouseButtons(bool bSet)
{
	s_bSwapMouseButtons = bSet;
	if(IsActive())
	{
		Asura_Mouse::SetSwapMouseButtons(s_bSwapMouseButtons);
//		Tools_Timed_Message_System::AddMessage(0xffffff,"Left and Right mouse buttons %s",s_bSwapMouseButtons ? "Swapped" : "Un-Swapped");
	}
}

void Tools_System::SwapMouseButtonsClicked()
{
	Asura_Mouse::SetSwapMouseButtons(s_bSwapMouseButtons);

}


void Tools_System::SetRestrictMouseToWindowInSubwindowTools(bool bSet)
{
	s_bRestrictMouseToWindowInSubwindowTools = bSet;
	UpdateRestrictMouseToWindow();
}

void Tools_System::SetRestrictMouseToWindowInFullScreenTools(bool bSet)
{
	s_bRestrictMouseToWindowInFullScreenTools = bSet;
	UpdateRestrictMouseToWindow();
}

void Tools_System::SetRestrictMouseToWindowInSubwindowGame(bool bSet)
{
	s_bRestrictMouseToWindowInSubwindowGame = bSet;
	UpdateRestrictMouseToWindow();
}

void Tools_System::SetRestrictMouseToWindowInFullScreenGame(bool bSet)
{
	s_bRestrictMouseToWindowInFullScreenGame = bSet;
	UpdateRestrictMouseToWindow();
}


void Tools_System::UpdateRestrictMouseToWindow()
{
	if(IsActive())
	{
		if(Asura_Windows::RunningFullScreen())
		{
			Asura_Mouse::SetRestrictWindowsCursorToWindow(s_bRestrictMouseToWindowInFullScreenTools);
		}
		else
		{
			Asura_Mouse::SetRestrictWindowsCursorToWindow(s_bRestrictMouseToWindowInSubwindowTools);
		}
	}
	else
	{
		if(Asura_Windows::RunningFullScreen())
		{
			Asura_Mouse::SetRestrictWindowsCursorToWindow(s_bRestrictMouseToWindowInFullScreenGame);
		}
		else
		{
			Asura_Mouse::SetRestrictWindowsCursorToWindow(s_bRestrictMouseToWindowInSubwindowGame);
		}
	}
}

void Tools_System::SetUseWindowsCursor(bool bSet)
{
	s_bUseWindowsCursor = bSet;
	if(IsActive())
	{
		Asura_Mouse::SetUseWindowsCursor(s_bUseWindowsCursor);
	}
}

void Tools_System::UseWindowsCursorClicked()
{
	Asura_Mouse::SetUseWindowsCursor(s_bUseWindowsCursor);
}


void Tools_System::IdleWhileMinimisedClicked()
{
	Asura_Windows::SetIdlePriorityWhileMinimised(s_bIdlePriorityWhileMinimised);
}



void Tools_System::RequestStandbyMode()
{
	RequestNextMode(TOOLS_MODE_STANDBY);
}

void Tools_System::RequestStandbyMode(bool bSuppressSavePrompt)
{
	RequestNextMode(TOOLS_MODE_STANDBY,bSuppressSavePrompt);
}


bool Tools_System::IsInStandbyMode(void)
{
	return (CurrentMode == TOOLS_MODE_STANDBY);
}



void Tools_System::RequestTexturingMode(void)
{
	RequestNextMode(TOOLS_MODE_TEXTURING);
}
bool Tools_System::IsInTexturingMode(void)
{
	return (CurrentMode == TOOLS_MODE_TEXTURING);
}

void Tools_System::RequestTextureTilerMode()
{
	RequestNextMode(TOOLS_MODE_TEXTURETILER);
}
bool Tools_System::IsInTextureTilerMode()
{
	return (CurrentMode == TOOLS_MODE_TEXTURETILER);
}

void Tools_System::RequestSoundMode(void)
{
	RequestNextMode(TOOLS_MODE_SOUND);
}
bool Tools_System::IsInSoundMode(void)
{
	return (CurrentMode == TOOLS_MODE_SOUND);
}
#ifndef ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM
void Tools_System::RequestMetaMusicMode(void)
{
	RequestNextMode(TOOLS_MODE_METAMUSIC);
}
bool Tools_System::IsInMetaMusicMode(void)
{
	return (CurrentMode == TOOLS_MODE_METAMUSIC);
}
#endif





void Tools_System::RequestSmoothingMode(void)
{
	RequestNextMode(TOOLS_MODE_SMOOTHING);
}
bool Tools_System::IsInSmoothingMode(void)
{
	return (CurrentMode == TOOLS_MODE_SMOOTHING);
}


void Tools_System::RequestFlagsMode(void)
{
	RequestNextMode(TOOLS_MODE_FLAGS);
}
bool Tools_System::IsInFlagsMode(void)
{
	return (CurrentMode == TOOLS_MODE_FLAGS);
}

void Tools_System::RequestModuleLinkingMode(void)
{
	RequestNextMode(TOOLS_MODE_MODULELINKING);
}
bool Tools_System::IsInModuleLinkingMode(void)
{
	return (CurrentMode == TOOLS_MODE_MODULELINKING);
}


void Tools_System::RequestWaypointingMode(void)
{
	RequestNextMode(TOOLS_MODE_WAYPOINTING);
}
void Tools_System::RequestWaypointingModeSuppressSavePrompt()
{
	RequestNextMode(TOOLS_MODE_WAYPOINTING,true);
}
bool Tools_System::IsInWaypointingMode(void)
{
	return (CurrentMode == TOOLS_MODE_WAYPOINTING);
}

void Tools_System::RequestMeshEditMode(void)
{
	RequestNextMode(TOOLS_MODE_MESHEDIT);
}
bool Tools_System::IsInMeshEditMode(void)
{
	return (CurrentMode == TOOLS_MODE_MESHEDIT);
}

void Tools_System::RequestCutsceneMode(void)
{
	RequestNextMode(TOOLS_MODE_CUTSCENE);
}
bool Tools_System::IsInCutsceneMode(void)
{
	return (CurrentMode == TOOLS_MODE_CUTSCENE);
}

void Tools_System::RequestObjectMode(void)
{
	RequestNextMode(TOOLS_MODE_OBJECT);
}
bool Tools_System::IsInObjectMode(void)
{
	return (CurrentMode == TOOLS_MODE_OBJECT);
}

void Tools_System::RequestHierarchyMode(void)
{
	RequestNextMode(TOOLS_MODE_HIERARCHY);
}
bool Tools_System::IsInHierarchyMode(void)
{
	return (CurrentMode == TOOLS_MODE_HIERARCHY);
}


void Tools_System::RequestRagdollEditorMode(void)
{
	RequestNextMode(TOOLS_MODE_RAGDOLLEDITOR);
}
bool Tools_System::IsInRagdollEditorMode(void)
{
	return (CurrentMode == TOOLS_MODE_RAGDOLLEDITOR);
}

void Tools_System::RequestLODMode(void)
{
	RequestNextMode(TOOLS_MODE_LOD);
}
bool Tools_System::IsInLODMode(void)
{
	return (CurrentMode == TOOLS_MODE_LOD);
}

void Tools_System::RequestRegionsMode(void)
{
	RequestNextMode(TOOLS_MODE_REGIONS);
}
bool Tools_System::IsInRegionsMode(void)
{
	return (CurrentMode == TOOLS_MODE_REGIONS);
}

void Tools_System::RequestBillboardPlantsMode()
{
	RequestNextMode(TOOLS_MODE_BILLBOARDPLANTS);
}
bool Tools_System::IsInBillboardPlantsMode()
{
	return (CurrentMode == TOOLS_MODE_BILLBOARDPLANTS);
}

void Tools_System::RequestWeatherMode()
{
	RequestNextMode(TOOLS_MODE_WEATHER);
}
bool Tools_System::IsInWeatherMode()
{
	return (CurrentMode == TOOLS_MODE_WEATHER);
}

void Tools_System::RequestModuleMode()
{
	RequestNextMode(TOOLS_MODE_MODULE);
}
bool Tools_System::IsInModuleMode()
{
	return (CurrentMode == TOOLS_MODE_MODULE);
}

void Tools_System::RequestShapeDataMode()
{
	RequestNextMode(TOOLS_MODE_SHAPEDATA);
}
bool Tools_System::IsInShapeDataMode()
{
	return (CurrentMode == TOOLS_MODE_SHAPEDATA);
}

void Tools_System::RequestPhotonMappingMode()
{
	RequestNextMode(TOOLS_MODE_PHOTONMAPPING);
}
bool Tools_System::IsInPhotonMappingMode()
{
	return (CurrentMode == TOOLS_MODE_PHOTONMAPPING);
}

void Tools_System::RequestPFXMode(void)
{
	RequestNextMode(TOOLS_MODE_PFX);
}
bool Tools_System::IsInPFXMode(void)
{
	return (CurrentMode == TOOLS_MODE_PFX);
}

#ifdef ASURA_USE_BOTANICALS
void Tools_System::RequestBotanicalsMode()
{
	RequestNextMode(TOOLS_MODE_BOTANICALS);
}
bool Tools_System::IsInBotanicalsMode()
{
	return (CurrentMode == TOOLS_MODE_BOTANICALS);
}

void Tools_System::RequestBotanicalCreationMode()
{
	RequestNextMode(TOOLS_MODE_BOTANICALCREATION);
}

bool Tools_System::IsInBotanicalCreationMode()
{
	return (CurrentMode == TOOLS_MODE_BOTANICALCREATION);
}
#endif // #ifdef ASURA_USE_BOTANICALS

#ifdef ASURA_USE_ASSET_MANAGER
void Tools_System::RequestAssetManagerMode()
{
	RequestNextMode(TOOLS_MODE_ASSETMANAGER);
}

bool Tools_System::IsInAssetManagerMode()
{
	return (CurrentMode == TOOLS_MODE_ASSETMANAGER);
}
#endif

#ifdef ASURA_USE_CARPET
void Tools_System::RequestCarpetMode()
{
	Tools_System::RequestNextMode(TOOLS_MODE_CARPET);
}

bool Tools_System::IsInCarpetMode()
{
	return (Tools_System::GetCurrentMode() == TOOLS_MODE_CARPET);
}
#endif // #ifdef ASURA_USE_CARPET


#ifdef ASURA_USE_STATIC_DECAL_SYSTEM
void Tools_System::RequestDecalsMode()
{
	Tools_System::RequestNextMode(TOOLS_MODE_DECALS);
}

bool Tools_System::IsInDecalsMode()
{
	return (Tools_System::GetCurrentMode() == TOOLS_MODE_DECALS);
}

#endif


#ifdef ASURA_USE_FSFX

void Tools_System::RequestFSFXMode()
{
	Tools_System::RequestNextMode( TOOLS_MODE_FSFX );
}

bool Tools_System::IsInFSFXMode()
{
	return ( Tools_System::GetCurrentMode() == TOOLS_MODE_FSFX );
}

#endif

#ifdef ASURA_USE_ATTRACTORS

void Tools_System::RequestAttractorsMode()
{
	Tools_System::RequestNextMode( TOOLS_MODE_ATTRACTORS );
}

bool Tools_System::IsInAttractorsMode()
{
	return ( Tools_System::GetCurrentMode() == TOOLS_MODE_ATTRACTORS );
}

#endif

#ifdef ASURA_USE_STREAMING
void Tools_System::RequestStreamingMode(void)
{
	RequestNextMode(TOOLS_MODE_STREAMING);
}
bool Tools_System::IsInStreamingMode(void)
{
	return (CurrentMode == TOOLS_MODE_STREAMING);
}
#endif // ASURA_USE_Streaming


void Tools_System::RequestVertexPaintingMode()
{
	Tools_System::RequestNextMode( TOOLS_MODE_VERTEXPAINTING );
}

bool Tools_System::IsInVertexPaintingMode()
{
	return ( Tools_System::GetCurrentMode() == TOOLS_MODE_VERTEXPAINTING );
}

#ifdef ASURA_USE_GUI_MENU_SYSTEM
void Tools_System::RequestGUIMenuMode()
{
	Tools_System::RequestNextMode( TOOLS_MODE_GUIMENU );
}

bool Tools_System::IsInGUIMenuMode()
{
    return ( Tools_System::GetCurrentMode() == TOOLS_MODE_GUIMENU );
}
#endif

#ifdef ASURA_USE_CONTAINER_SYSTEM
void Tools_System::RequestContainerMode()
{
	Tools_System::RequestNextMode(TOOLS_MODE_CONTAINER);
}
bool Tools_System::IsInContainerMode()
{
	return CurrentMode == TOOLS_MODE_CONTAINER;
}
#endif //#ifdef ASURA_USE_CONTAINER_SYSTEM


void Tools_System::QuickSave()
{
	if(Tools_SaveAsura::GetFileType() == AsuraFile_Template)
	{
		//templates store everything in the one file , so ignore the mode specific
		//quick save code
		Tools_SaveAsura::SaveTemplateFile();
		return;
	}

	// Kevin Lea - 28/09/2001 12:16:40 - save the main asura file if in an appropriate mode
	// (AAM - 06.02.2007) Now do this in any mode, if tagged as modified. Material response system
	// might have modified the mesh in any mode, using "import from old system"
	if( Tools_SaveAsura::IsMainFileModified() )
	{
		Tools_SaveAsura::QuickSaveFile();
	}

	if(Tools_HelperObject_System::IsModified()) Tools_HelperObject_System::SaveModified();

	//do any mode-specific saving
	if(CurrentModeClass) CurrentModeClass->QuickSave();

#ifdef ASURA_USE_MATERIAL_RESPONSE_SYSTEM
	Tools_Texturing_MaterialResponse::SaveChangedMaterials();
#endif
}


void Tools_System::RenderAllModuleOutlines()
{
	int Colours[12] = {0xff0000,0x00ff00,0x0000ff,0xffff00,0x00ffff,0xff00ff,0xff7f00,0xff007f,0x7fff00,0x00ff7f,0x7f00ff,0x007fff};
	
	for(int i=0;i<Asura_Module_System::GetNumberOfModules();i++)
	{
		Tools_Render::RenderModuleOutline(i,0xff000000|Colours[i%12],true)	;
	}
}

void Tools_System::RenderCursorModuleOutline()
{
	//first need to find the polygon that the mouse is over
	Asura_Vector_3 zvec;
	Asura_Cursor::GetLOSDirection(zvec);

	const Asura_Vector_3* cameraPosition = Asura_Camera::GetPosition();
	const Asura_Matrix_3x3* cameraOrientation = Asura_Camera::GetOrientation();

 	zvec = zvec * (*cameraOrientation);

	int polyIndex,moduleIndex;
	if(Tools_LOS::FindPolyInLOS(*cameraPosition,zvec,polyIndex,moduleIndex))
	{
		//render the outline
		Tools_Render::RenderModuleOutline(moduleIndex,0x70ffffff,false);
	}
}

void Tools_System::RequestNextMode(int mode,bool bSuppressSavePrompt /*= false*/)
{
	// Check that we are not quitting with the mixer preset overlay open
	if(		( mode == TOOLS_MODE_QUITTOGAME || mode == TOOLS_MODE_QUITTODESKTOP )
		&&	Asura_Overlay_System::DoesOverlayExist( TOOLS_OVERLAY_SOUNDMIXER ) )
	{
		Asura_Overlay_System::CloseOverlays( TOOLS_OVERLAY_SOUNDMIXER );
	}

	if(CurrentModeClass) CurrentModeClass->PreShutdown();
	
	//If changes have been made to the current mode ,or if any changes have made and we are quitting,
	//bring up the save prompt overlay thing
	NextMode = mode;

	if(CurrentModeClass && !bSuppressSavePrompt)
	{
		//if((CurrentModeClass && CurrentModeClass->IsModified()) ||
		//   ((mode == TOOLS_MODE_QUITTOGAME || mode==TOOLS_MODE_QUITTODESKTOP) && Tools_SaveAsura::This->IsModified()))
		if(Tools_SaveAsura::This->IsModified())
		{
			//ask about saving
			Tools_Modal_Overlay* pxOverlay = This->CreateSaveConfirmationOverlay(static_cast<TOOLS_MODE>(mode));
			if( pxOverlay )
			{
				pxOverlay->ShowOverlay();
				delete(pxOverlay);
			}

			return;
		}
		else if (mode == TOOLS_MODE_QUITTOGAME || mode == TOOLS_MODE_QUITTODESKTOP)
		{
			//confirm quitting tools
			if( !s_bAutoQuitToGame )
			{
				Tools_Modal_Overlay* pxOverlay = This->CreateExitConfirmationOverlay(static_cast<TOOLS_MODE>(mode));
				if( pxOverlay )
				{
					pxOverlay->ShowOverlay();
					delete(pxOverlay);
				}

				return;
			}
		}
		
	}
	ChangeToNextMode();
	
}

void Tools_System::SaveAllAndChangeToNextMode()
{
	//Update input one final time in an attempt to debounce any key press that
	//may have been used to close the overlay.
	Asura_Windows::CheckForWindowsMessages();
	Asura_UserInput::Update();

	Tools_SaveAsura::SaveAll();
	if((NextMode == TOOLS_MODE_QUITTOGAME || NextMode == TOOLS_MODE_QUITTODESKTOP) && Tools_SaveAsura::This->IsModified())
	{
		//failed to save changes ,so don't quit
		NextMode = TOOLS_MODE_NULL;
		return;
	}

	ChangeToNextMode();
}

void Tools_System::SaveModifiedAndChangeToNextMode()
{
	//Update input one final time in an attempt to debounce any key press that
	//may have been used to close the overlay.
	Asura_Windows::CheckForWindowsMessages();
	Asura_UserInput::Update();

	Tools_SaveAsura::SaveModified();
	if((NextMode == TOOLS_MODE_QUITTOGAME || NextMode == TOOLS_MODE_QUITTODESKTOP) && Tools_SaveAsura::This->IsModified())
	{
		//failed to save changes ,so don't quit
		NextMode = TOOLS_MODE_NULL;
		return;
	}

	ChangeToNextMode();
}

void Tools_System::SaveAndChangeToNextMode()
{
	//Update input one final time in an attempt to debounce any key press that
	//may have been used to close the overlay.
	Asura_Windows::CheckForWindowsMessages();
	Asura_UserInput::Update();

	QuickSave();

	// (AAM - 23.01.2007) Material responses can be modified in any mode. Don't want to call
	// Tools_SaveAsura::IsModified() here though, because there might be other changes the user
	// doesn't care about. So we'll specifically check the material response system

	#if defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM
		const bool bMaterialsStillModified = Tools_Texturing_MaterialResponse::IsModified();
	#else
		const bool bMaterialsStillModified = false;
	#endif

	if((NextMode == TOOLS_MODE_QUITTOGAME || NextMode == TOOLS_MODE_QUITTODESKTOP)
	 && ((CurrentModeClass && CurrentModeClass->IsModified()) || bMaterialsStillModified) )
	{
		//failed to save changes ,so don't quit
		NextMode = TOOLS_MODE_NULL;
		return;
	}
	ChangeToNextMode();
}

void Tools_System::ChangeToNextMode()
{
	//Update input one final time in an attempt to debounce any key press that
	//may have been used to close the overlay.
	Asura_Windows::CheckForWindowsMessages();
	Asura_UserInput::Update();

	Tools_Prompted_Selection::EndSelection();
	
	if(NextMode == TOOLS_MODE_QUITTOGAME || NextMode == TOOLS_MODE_QUITTODESKTOP)
	{
		//quitting is not a mode change as such , so handled seperately
		ReadyToQuitOut=true;
		QuitToDesktop = (NextMode == TOOLS_MODE_QUITTODESKTOP);
		NextMode = TOOLS_MODE_NULL;
		s_iDefaultMode = CurrentMode;//So the previous mode is reselected when returning to tools. RAR 06/07/2007
		return;
	}

	if(CurrentModeClass)
	{
		CurrentModeClass->ShutdownMode();
		delete CurrentModeClass;
	}
	CurrentModeClass = NULL;

	#ifdef ASURA_USE_GUI_MENU_SYSTEM
	Tools_GUIMenu_Audio_Overlay::CloseOverlay();
	#endif	

	//close sound event editing in between modes. RAR 12/07/2006
	Tools_SoundEvent_Overlay::CloseOverlay();
	#ifdef ASURA_USE_DIALOGUE_SYSTEM
	Tools_Dialogue_System::CloseOverlays();
	#endif

	Project_ChangeToNextMode();
	
	if(!CurrentModeClass)
	{
		switch(NextMode)
		{
			default :
				Asura_Assert(0,"Unknown mode");
				NextMode = TOOLS_MODE_STANDBY;
				//fall through

			case TOOLS_MODE_STANDBY :
				CurrentModeClass = new Tools_Mode;
				break;					

			case TOOLS_MODE_PHOTONMAPPING :
				CurrentModeClass = new Tools_Mode_PhotonMapping;
				break;

			case TOOLS_MODE_SOUND :
				CurrentModeClass = new Tools_Mode_Sound;
				break;
				
			case TOOLS_MODE_TEXTURING :
				CurrentModeClass = new Tools_Mode_Texturing;
				break;
	
			case TOOLS_MODE_TEXTURETILER :
				CurrentModeClass = new Tools_Mode_TextureTiler;
				break;

			case TOOLS_MODE_SMOOTHING :
				CurrentModeClass = new Tools_Mode_Smoothing;
				break;
			
			case TOOLS_MODE_FLAGS :
				CurrentModeClass = new Tools_Mode_Flags;
				break;

			case TOOLS_MODE_MODULELINKING :
				CurrentModeClass = new Tools_Mode_ModuleLinking;
				break;

			case TOOLS_MODE_WAYPOINTING :
                CurrentModeClass = new Tools_Mode_Waypointing;
                break;

			case TOOLS_MODE_MESHEDIT :
				CurrentModeClass = new Tools_Mode_MeshEdit;
				break;

			case TOOLS_MODE_CUTSCENE :
				CurrentModeClass = new Tools_Mode_Cutscene;
				break;

			case TOOLS_MODE_OBJECT :
				CurrentModeClass = new Tools_Mode_Object;
				break;

			#ifdef ASURA_USE_ASSET_MANAGER
			case TOOLS_MODE_ASSETMANAGER :
				CurrentModeClass = new Tools_Mode_AssetManager;
				break;
			#endif

			case TOOLS_MODE_HIERARCHY :
				CurrentModeClass = new Tools_Mode_Hierarchy;
				break;

			case TOOLS_MODE_RAGDOLLEDITOR:
				CurrentModeClass = new Tools_Mode_RagdollEditor;
				break;

			case TOOLS_MODE_LOD :
				CurrentModeClass = new Tools_Mode_LOD;
				break;

			case TOOLS_MODE_REGIONS :
				CurrentModeClass = new Tools_Mode_Regions;
				break;

#ifdef ASURA_USE_BILLBOARD_PLANTS
			case TOOLS_MODE_BILLBOARDPLANTS:
				CurrentModeClass = new Tools_Mode_BillboardPlants;
				break;
#endif

#ifdef ASURA_SUPPORT_WEATHER_SYSTEM 
			case TOOLS_MODE_WEATHER :
				CurrentModeClass = new Tools_Mode_Weather;
				break;
#endif

			case TOOLS_MODE_MODULE :
				CurrentModeClass = new Tools_Mode_Module;
				break;

			case TOOLS_MODE_SHAPEDATA:
				CurrentModeClass = new Tools_Mode_ShapeData;
				break;

#ifndef ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM
			case TOOLS_MODE_METAMUSIC :
				CurrentModeClass = new Tools_Mode_MetaMusic;
				break;
#endif

			case TOOLS_MODE_PFX :
				CurrentModeClass = new Tools_Mode_PFX;
				break;

#ifdef ASURA_USE_BOTANICALS
			case TOOLS_MODE_BOTANICALS :
				CurrentModeClass = new Tools_Mode_Botanicals;
				break;

			case TOOLS_MODE_BOTANICALCREATION :
				CurrentModeClass = new Tools_Mode_BotanicalCreation;
				break;
#endif

#ifdef ASURA_USE_CARPET
			case TOOLS_MODE_CARPET :
				CurrentModeClass = new Tools_Mode_Carpet();
				break;
#endif

#ifdef ASURA_USE_STATIC_DECAL_SYSTEM
			case TOOLS_MODE_DECALS :
				CurrentModeClass = new Tools_Mode_Decals();
				break;
#endif

#ifdef ASURA_USE_FSFX
			case TOOLS_MODE_FSFX:
				CurrentModeClass = new Tools_Mode_FSFX;
				Asura_Assert( CurrentModeClass != NULL, "Error constructing a Tools_Mode_FSFX" );
				break;
#endif

#ifdef ASURA_USE_ATTRACTORS
			case TOOLS_MODE_ATTRACTORS:
				CurrentModeClass = new Tools_Mode_Attractors;
				Asura_Assert( CurrentModeClass != NULL, "Error constructing a Tools_Mode_Attractor" );
				break;
#endif

#ifdef ASURA_USE_STREAMING
			case TOOLS_MODE_STREAMING :
				CurrentModeClass = new Tools_Mode_Streaming;
				break;
#endif 

			case TOOLS_MODE_VERTEXPAINTING :
				CurrentModeClass = new Tools_Mode_VertexPainting;
				break;

#ifdef ASURA_USE_GUI_MENU_SYSTEM
            case TOOLS_MODE_GUIMENU:
                CurrentModeClass = new Tools_Mode_GUIMenu;
				break;
#endif

#ifdef ASURA_USE_CONTAINER_SYSTEM
			case TOOLS_MODE_CONTAINER:
				CurrentModeClass = new Tools_Mode_Container;
				break;
#endif //ASURA_USE_CONTAINER_SYSTEM
		}
	}

	CurrentMode = NextMode;
	CurrentModeClass->InitialiseMode();

	NextMode = TOOLS_MODE_NULL;
}


void Tools_System::CancelModeChange()
{
	NextMode = TOOLS_MODE_NULL;
}

void Tools_System::ScreenShot(bool bSuppressText/* = false*/)
{
	static int index = 0;
	//ensure screenshots directory exists
	CreateDirectory("Screenshots",0);

	//get the filename without path/extension
	extern Asura_String EnvironmentFilename;
	Asura_String environmentName;
	EnvironmentFilename.SplitFilename(0,&environmentName,0);

	//search for an available filename
	char filename[MAX_PATH];
	do
	{
		sprintf(filename,"Screenshots\\%s_%04d.bmp",environmentName.GetString(),index++);
	}while(GetFileAttributes(filename)!=0xffffffff);

	
	//take the screenshot
	extern bool ScreenShot(const char*);
	if(ScreenShot(filename))
	{
		if (!bSuppressText)
		{
			Tools_Timed_Message_System::AddMessage(0x00ff00,"Saved %s",filename);
		}
	}
	else
	{
		Tools_Timed_Message_System::AddMessage(0xff0000,"Error creating %s",filename);
	}

}

void Tools_System::StartAVI()
{

	//ask for the frame rate
	float frameRate = 25.0f;
	GetNumber_Overlay overlay("AVI Frame Rate",frameRate,1,1000);
	if(!overlay.DoModal()) return;
	frameRate = overlay.GetNumber();


	static int index = -1;
	//ensure screenshots directory exists
	CreateDirectory("Screenshots",0);

	//get the filename without path/extension
	extern Asura_String EnvironmentFilename;
	Asura_String environmentName;
	EnvironmentFilename.SplitFilename(0,&environmentName,0);

	//search for an available filename
	char filename[MAX_PATH];
	do
	{
		index++;
		//skip if multipart avi exists at this index
		sprintf(filename,"Screenshots\\%s_%d_Part00.avi",environmentName.GetString(),index);
		if(GetFileAttributes(filename)!=0xffffffff)	continue;
						
		
		sprintf(filename,"Screenshots\\%s_%d.avi",environmentName.GetString(),index);

	}while(GetFileAttributes(filename)!=0xffffffff);


	
	//start the avi
	TheAviWriter.StartAVI(filename,frameRate);
	
}

void Tools_System::EndAVI()
{
	if(TheAviWriter.IsWritingFile())
	{
		Tools_Timed_Message_System::AddMessage(0x00ff00,"Finished recording AVI");
		TheAviWriter.EndAVI();
	}
}

static u_int g_uCursorInfoHeightInChars = 0;

void Tools_System::RenderCursorInformation()
{
	float printx;
	float printy;
	int colour = 0xff50ff90;

	int polyIndex;
	int moduleIndex;
	Asura_Vector_3 position;

	//see if the cursor is over a polygon
	if(!Tools_LOS::FindPolyAndPositionUnderCursor(polyIndex,moduleIndex,position))
    {
        g_uCursorInfoHeightInChars = 0;
        return;
    }

	int iVertexIndex;
	int iModuleIndex2;
	if(!Tools_LOS::FindVertUnderCursor(iVertexIndex,iModuleIndex2)) return;
	if(iModuleIndex2 != moduleIndex) return;

	const Asura_Mesh* mesh = Asura_Module_System::GetMeshForModule(moduleIndex);
	const Asura_Mesh_Polygon* poly = &mesh->PolygonDataPtr[polyIndex];
	const Asura_Mesh_TextureInfo* pxTex = &mesh->TextureDataPtr[polyIndex];
	Asura_Vector_3 modulePosition;
	Asura_Module_System::GetPositionOfModule(moduleIndex,modulePosition);

	const Asura_CollisionMesh* pxCollisionMesh = Asura_Module_System::GetCollisionMeshForModule(moduleIndex);
	
	int iCollisionPolyCount = 0;
	int iCollisionVertexCount = 0;

	for(int i=0;i<Asura_Module_System::GetNumberOfModules();i++)
	{
		const Asura_CollisionMesh	*pxCollisionMesh = Asura_Module_System::GetCollisionMeshForModule(i);

		iCollisionPolyCount += pxCollisionMesh->GetNumberOfPolys();
		iCollisionVertexCount += pxCollisionMesh->GetNumberOfVertices();
	}

	//determine print position
	float width = (float)Asura_Viewport::GetWidth();
	float height = (float)Asura_Viewport::GetHeight();
	Asura_Text_Output::ConvertPixelsToPrintCoords(width,height);
	printx = width-37;
	printy = 2;

	int iTextureID = Asura_Material_System::GetTextureID(pxTex->m_iMaterialID);
	
	g_uCursorInfoHeightInChars = 5 + poly->NumberOfVertices();
	
	if(iTextureID!=ASURA_TEXTURE_NONE)
	{
		g_uCursorInfoHeightInChars += poly->NumberOfVertices() * 2;
	}

    g_uCursorInfoHeightInChars += 3;

	if (pxCollisionMesh)
		g_uCursorInfoHeightInChars += 3;

	//draw a translucent polygon as a background
	Asura_Render::Overlay.SetRectXY((float)(Asura_Viewport::GetWidth()-380),1*14,380, g_uCursorInfoHeightInChars *14.0f);
	Asura_Render::Overlay.SetRectUV(0,0,1,1);
	Asura_Render::Overlay.TranslucencyMode = ASURA_TRANSLUCENCY_NORMAL;
	Asura_Render::Overlay.TextureIndex = ASURA_TEXTURE_NONE;
	Asura_Render::Overlay.Colour=0x4f000000;
	Asura_Render::Overlay.Render();
	Asura_Render::FlushDisplay();

	Asura_Text_Output::Print(printx,printy++,colour,0,"Cursor info:");
	Asura_Text_Output::Print(printx,printy++,colour,0,"Pos:  %8.3f %8.3f %8.3f",position.x,position.y,position.z);
	Asura_Text_Output::Print(printx,printy++,colour,0,"Module: %s (idx %i)", mesh->Name.GetString(), moduleIndex );
	
	printy++;

	if (pxCollisionMesh)
	{
		Asura_Text_Output::Print(printx,printy++,colour,0,"Col Polys: %-4i  Verts: %-4i", iCollisionPolyCount, iCollisionVertexCount);
		Asura_Text_Output::Print(printx,printy++,colour,0,"Module Col Polys: %-4i  Verts: %-4i", pxCollisionMesh->GetNumberOfPolys(), pxCollisionMesh->GetNumberOfVertices());
		printy++;
	}

	Asura_Text_Output::Print(printx,printy++,colour,0,"Tris: %-4i  Polys: %-4i  Verts: %-4i", mesh->NumberOfTriangles, mesh->NumberOfPolygons, mesh->NumberOfVertices);
	Asura_Text_Output::Print(printx,printy++,colour,0,"Poly idx: %d", polyIndex );
	for(int i=0;i<poly->NumberOfVertices();i++)
	{
		int vIndex = poly->VertexID[i];
		Asura_Vector_3 vPos = mesh->VertexDataPtr[vIndex].Position + modulePosition;
		Asura_Text_Output::Print(printx,printy++,colour,0,"V%4d : %8.3f %8.3f %8.3f",vIndex,vPos.x,vPos.y,vPos.z);
	}
	if(iTextureID!=ASURA_TEXTURE_NONE)
	{
		for(int i=0;i<poly->NumberOfVertices();i++)
		{
			Asura_Text_Output::Print(printx,printy++,colour,0,"UV%3d : %8.3f %8.3f",i,pxTex->U[0][i],pxTex->V[0][i]);
		}
	}
    for( int iVtx = 0; iVtx < poly->NumberOfVertices(); ++iVtx )
    {
        // The alpha we care about is stored separately.
        u_int uA = Asura_Maths::FloatToInt_Near( mesh->TextureDataPtr[polyIndex].m_afAlpha[iVtx] * 255.0f );

		if(mesh->PrelightingDataPtr)
		{
			u_int uARGB = mesh->PrelightingDataPtr[polyIndex].Colour[iVtx];

			u_int uR = Asura_Maths::Min( 255u, ((uARGB >> 16) & 0xFF) * 2 );
			u_int uG = Asura_Maths::Min( 255u, ((uARGB >>  8) & 0xFF) * 2 );
			u_int uB = Asura_Maths::Min( 255u, ((uARGB >>  0) & 0xFF) * 2 );
			
			Asura_Text_Output::Print( printx, printy++, colour, 0, "RGBA %i: %3u %3u %3u %3u", iVtx, uR, uG, uB, uA );
		}
		else
		{
			Asura_Text_Output::Print( printx, printy++, colour, 0, "RGBA %i: N/A N/A N/A %3u", iVtx, uA );
		}

    }
	
	Asura_Text_Output::Print( printx, printy++, colour, 0, "Vertex : %d", iVertexIndex );
    for( int iVtx = 0; iVtx < poly->NumberOfVertices(); ++iVtx )
	{
		if(poly->VertexID[iVtx] == iVertexIndex)
		{
			Asura_Vector_3 xNormal = mesh->NormalsDataPtr[polyIndex].VertexNormal[iVtx];
			Asura_Text_Output::Print( printx, printy++, colour, 0, "Norm X : %.4f", xNormal.x );
			Asura_Text_Output::Print( printx, printy++, colour, 0, "Norm Y : %.4f", xNormal.y );
			Asura_Text_Output::Print( printx, printy++, colour, 0, "Norm Z : %.4f", xNormal.z );

		}
	}


}

struct InfoOnPS2VersionOfTexture
{
    bool  bCountedThisFrame;
    u_int uSizeOnPS2;        // In bytes. UINT_MAX => not calculated yet.
};

static InfoOnPS2VersionOfTexture g_axPS2TextureInfo[ASURA_MAX_NO_OF_TEXTURES];

void Tools_System::RenderPS2PerfMetrics( void )
{
    static bool bInitd = false;
    if( !bInitd )
    {
        for( u_int u = 0; u < ASURA_MAX_NO_OF_TEXTURES; ++u )
        {
            if( Asura_Texture_Management::GetTextureLoadState(u) != ASURA_TEXTURE_UNUSED )
            {
                g_axPS2TextureInfo[u].uSizeOnPS2 = Tools_Level_Export::GetTIM2DataSize( u );
            }
        }
        bInitd = true;
    }

    for( u_int u = 0; u < ASURA_MAX_NO_OF_TEXTURES; ++u )
    {
        g_axPS2TextureInfo[u].bCountedThisFrame = false;
    }

    u_int uNumRenderedTris         = 0;
    u_int uRenderedTextureDataSize = 0;
    u_int uTotalTextureDataSize    = 0;

    for( int iModule = 0; iModule < Asura_Module_System::GetNumberOfModules(); ++iModule )
    {
        const bool bIsModuleVisible = Asura_Module_System::IsModuleVisible( iModule );

        const Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule( iModule );
        for( int iPoly = 0; iPoly < pxMesh->NumberOfPolygons; ++iPoly )
        {
            if( bIsModuleVisible )
            {
                if( !pxMesh->PolygonFlagDataValid || !(pxMesh->PolygonFlagDataPtr[iPoly].Flags & (AsuraPolygonFlag_DontExport | AsuraPolygonFlag_DontRender)) )
                {
                    uNumRenderedTris += ( pxMesh->PolygonDataPtr[iPoly].IsQuad() ? 2 : 1 );
                }
            }            

            const int iTexID = Asura_Material_System::GetTextureID( pxMesh->TextureDataPtr[iPoly].m_iMaterialID );
            if( ASURA_TEXTURE_NONE != iTexID && !g_axPS2TextureInfo[iTexID].bCountedThisFrame )
            {
                g_axPS2TextureInfo[iTexID].bCountedThisFrame = true;

                const u_int uTextureSizeOnPS2 = g_axPS2TextureInfo[iTexID].uSizeOnPS2;

                uTotalTextureDataSize += uTextureSizeOnPS2;

                if( bIsModuleVisible )
                {
                    uRenderedTextureDataSize += uTextureSizeOnPS2;
                }
            }
        }
    }

    float fWidth = static_cast<float>( Asura_Viewport::GetWidth() );
    float fDummy = 0.0f;
    Asura_Text_Output::ConvertPixelsToPrintCoords( fWidth, fDummy );

    const float WIDTH_IN_CHARS  = 36.0f;
    const float NUM_TEXT_LINES  = 7.0f;
    const u_int TEXT_COLOUR_NRM = 0xFF50FF90u;
    const u_int TEXT_COLOUR_BAD = 0xFFEE2222u;

    float fX = fWidth - (1.0f + WIDTH_IN_CHARS + 1.0f);
    float fY = (1.0f + static_cast<float>(g_uCursorInfoHeightInChars)) + 1.0f;

    // Background.
	Asura_Render::Overlay.SetRectXY( fX++ * ASURA_TEXT_OUTPUT_FONT_WIDTH,
                                     fY++ * ASURA_TEXT_OUTPUT_FONT_HEIGHT,
                                     (WIDTH_IN_CHARS + 2.0f) * ASURA_TEXT_OUTPUT_FONT_WIDTH,
                                     (NUM_TEXT_LINES + 2.0f) * ASURA_TEXT_OUTPUT_FONT_HEIGHT );
	Asura_Render::Overlay.SetRectUV( 0.0f, 0.0f, 1.0f, 1.0f );
	Asura_Render::Overlay.TranslucencyMode = ASURA_TRANSLUCENCY_NORMAL;
	Asura_Render::Overlay.TextureIndex = ASURA_TEXTURE_NONE;
	Asura_Render::Overlay.Colour = 0x4F000000u;
	Asura_Render::Overlay.Render();
	Asura_Render::FlushDisplay();
    
    u_int uColour;

    uColour = TEXT_COLOUR_NRM;
    Asura_Text_Output::Print( fX, fY++, uColour, 0, "PS2 performance info:" );

    ++fY;

    uColour = ( uNumRenderedTris > This->GetPS2RenderedTriLimit() ? TEXT_COLOUR_BAD : TEXT_COLOUR_NRM );
    Asura_Text_Output::Print( fX, fY++, uColour, 0, "Num rendered tris:           %6u", uNumRenderedTris );

    uColour = TEXT_COLOUR_NRM;
    Asura_Text_Output::Print( fX, fY++, uColour, 0, "Num linked in tris:          %6u", Asura_Module_System::GetNumLinkedInRenderMeshTris() );

    uColour = ( uRenderedTextureDataSize > This->GetPS2TextureUploadLimit() ? TEXT_COLOUR_BAD : TEXT_COLOUR_NRM );
    Asura_Text_Output::Print( fX, fY++, uColour, 0, "Mb of textures this frame:   %6.3f", static_cast<float>(uRenderedTextureDataSize) / (1024.0f * 1024.0f) );

    uColour = TEXT_COLOUR_NRM;
    Asura_Text_Output::Print( fX, fY++, uColour, 0, "Total Mb of textures in env: %6.3f", static_cast<float>(uTotalTextureDataSize) / (1024.0f * 1024.0f) );
    
}


void Tools_System::RequestColourSampleUnderCursor(int iSampleSize)
{
	Asura_Assert(This,"");
	This->m_iColourSample_RequestedSize = iSampleSize;
}

void Tools_System::GetColourSampleUnderCursor(float* pfRed,float* pfGreen,float* pfBlue)
{
	Asura_Assert(This,"");
	*pfRed = This->m_fColourSample_Red;
	*pfGreen = This->m_fColourSample_Green;
	*pfBlue = This->m_fColourSample_Blue;
}

void Tools_System::CalculateColourSample()
{
	//get the cursor position
	int iX,iY;
	Asura_Cursor::GetScreenSpaceCoords(iX,iY);

	//determine the area to average over
	int iMinX = iX - m_iColourSample_RequestedSize/2;
	int iMaxX = iX + m_iColourSample_RequestedSize/2;
	int iMinY = iY - m_iColourSample_RequestedSize/2;
	int iMaxY = iY + m_iColourSample_RequestedSize/2;

	int iScreenWidth = Asura_Viewport::GetWidth();
	int iScreenHeight = Asura_Viewport::GetHeight();

	//clamp coordinates to screen
	iMinX = Asura_Maths::ClampToRange(iMinX,0,iScreenWidth-1);
	iMaxX = Asura_Maths::ClampToRange(iMaxX,0,iScreenWidth-1);
	iMinY = Asura_Maths::ClampToRange(iMinY,0,iScreenHeight-1);
	iMaxY = Asura_Maths::ClampToRange(iMaxY,0,iScreenHeight-1);

	float fRed = 0;
	float fGreen = 0;
	float fBlue = 0;
	int iSamples = 0;


	//access backbuffer
	Direct3D_Surface* pxSurface = 0;
	HRESULT hres;
	hres = Asura_Direct3D::D3DDevice->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&pxSurface);
	if(FAILED(hres))
	{
		Asura_Assert(0,"Failed to get backbiffer for sample");
		goto Cleanup;
	}
	
	D3DLOCKED_RECT rect;
	hres = pxSurface->LockRect(&rect,NULL,D3DLOCK_READONLY);
	if(FAILED(hres))
	{
		Asura_Assert(0,"Failed to lock backbuffer for sample");
		goto Cleanup;
	}

	D3DSURFACE_DESC desc;
	hres = pxSurface->GetDesc(&desc);
	if(FAILED(hres))
	{
		Asura_Assert(0,"Failed to get backbuffer description for sample");
		goto Cleanup;
	}


	//determine the pixel format
	int iRedShift,iRedScale,iRedMask;
	int iGreenShift,iGreenScale,iGreenMask;
	int iBlueShift,iBlueScale,iBlueMask;
	int iBytesPerPixel;

	switch(desc.Format)
	{
		case D3DFMT_X1R5G5B5 :
			iRedMask = 31<<10;
			iRedShift = 10;
			iRedScale = 255/31;
			iGreenMask = 31<<5;
			iGreenShift = 5;
			iGreenScale = 255/31;
			iBlueMask = 31;
			iBlueShift = 0;
			iBlueScale = 255/31;
			iBytesPerPixel = 2;
			break;
		case D3DFMT_R5G6B5 :
			iRedMask = 31<<11;
			iRedShift = 11;
			iRedScale = 255/31;
			iGreenMask = 63<<5;
			iGreenShift = 5;
			iGreenScale = 255/63;
			iBlueMask = 31;
			iBlueShift = 0;
			iBlueScale = 255/31;
			iBytesPerPixel = 2;
			break;
		case D3DFMT_X8R8G8B8 :
		case D3DFMT_A8R8G8B8 :
			iRedMask = 255<<16;
			iRedShift = 16;
			iRedScale = 1;
			iGreenMask = 255<<8;
			iGreenShift = 8;
			iGreenScale = 1;
			iBlueMask = 255;
			iBlueShift = 0;
			iBlueScale = 1;
			iBytesPerPixel = 4;
			break;

		default :
			Asura_Assert(0,"Unexpected pixel format for screenshot");
			goto Cleanup;

	}
		

	
	unsigned char* pucBuffer;
	
	for (int y=iMinY;y<=iMaxY;y++)
	{
		pucBuffer=(unsigned char *)rect.pBits+(rect.Pitch*y) + (iMinX*iBytesPerPixel);
		for(int x=iMinX;x<=iMaxX;x++,pucBuffer+=iBytesPerPixel)
		{
			u_int uColour;
			if(iBytesPerPixel == 4)
			{
				uColour=*(unsigned int*)pucBuffer;
			}
			else
			{
				uColour=*(unsigned short*)pucBuffer;
			}
			fBlue += (float)(((uColour&iBlueMask)>>iBlueShift)*iBlueScale);
			fGreen += (float)(((uColour&iGreenMask)>>iGreenShift)*iGreenScale);
			fRed += (float)(((uColour&iRedMask)>>iRedShift)*iRedScale);
			iSamples++;
		}
	
	}

	if(iSamples)
	{
		m_fColourSample_Red = fRed/(float)iSamples;
		m_fColourSample_Green = fGreen/(float)iSamples;
		m_fColourSample_Blue = fBlue/(float)iSamples;
	}
	m_iColourSample_RequestedSize = 0;


	Cleanup :

	if(pxSurface)
	{
		pxSurface->UnlockRect();
		pxSurface->Release();
	}
}


static enum
{
	MODULESORT_NAME_UP,
	MODULESORT_NAME_DOWN,
	MODULESORT_POLY_UP,
	MODULESORT_POLY_DOWN,
	MODULESORT_DUALPASS_POLY_UP,
	MODULESORT_DUALPASS_POLY_DOWN,
} g_eModuleSortMode = MODULESORT_POLY_DOWN;

struct ToolsModuleInfo
{
	int m_iIndex;
	Asura_Mesh* m_pxMesh;
	int m_iNumDualPassTris;
};

int PolygonCountScreenSort(const void* m1,const void* m2)
{
	ToolsModuleInfo* pxModule1 = (ToolsModuleInfo*)m1;
	ToolsModuleInfo* pxModule2 = (ToolsModuleInfo*)m2;

	switch(g_eModuleSortMode)
	{
		case MODULESORT_NAME_UP:
			return pxModule1->m_pxMesh->Name.Compare(pxModule2->m_pxMesh->Name);
			break;
		case MODULESORT_NAME_DOWN:
			return -pxModule1->m_pxMesh->Name.Compare(pxModule2->m_pxMesh->Name);
			break;
		case MODULESORT_POLY_UP:
			return pxModule1->m_pxMesh->NumberOfTriangles - pxModule2->m_pxMesh->NumberOfTriangles;
			break;
		case MODULESORT_POLY_DOWN:
			return pxModule2->m_pxMesh->NumberOfTriangles - pxModule1->m_pxMesh->NumberOfTriangles;
			break;
		case MODULESORT_DUALPASS_POLY_UP:
			return pxModule1->m_iNumDualPassTris - pxModule2->m_iNumDualPassTris;
			break;
		case MODULESORT_DUALPASS_POLY_DOWN:
			return pxModule2->m_iNumDualPassTris - pxModule1->m_iNumDualPassTris;
			break;
	}

	return 0;
}


void Tools_System::ShowPolygonCounts()
{
	int iFirstShownModule = 0;
	int iMouseOverIndex = -1;
	
	const float fNameOffsetX = 10;
	const float fPolygonOffsetX = 25;
	const float fDualPolygonOffsetX = 35;
	const float fSecondColumnX = 50;
	const float fHeaderLabelOffsetX = 10.0f;
	const float fHeaderValueOffsetX = 40.0f;
	const float fHeaderHeight = 15.0f;

	//work out how many columns and rows we can display
	//get the screen size , and convert to print coordinates
	float fPrintWidth = (float)Asura_Viewport::GetWidth();
	float fPrintHeight = (float)Asura_Viewport::GetHeight();

	Asura_Text_Output::ConvertPixelsToPrintCoords(fPrintWidth,fPrintHeight);

	int iNumColumns = (int)(fPrintWidth/fSecondColumnX);
	int iNumModulesPerColumn = (int)(fPrintHeight - 10.0f - fHeaderHeight);

	int iNumModules = Asura_Module_System::GetNumberOfModules();

	//build an array of module iinfo , to be sorted by name or poly count
	ToolsModuleInfo* pxModuleInfo = new ToolsModuleInfo[iNumModules];
	for(int i=0;i<iNumModules;i++)
	{
		pxModuleInfo[i].m_iIndex = i;
		pxModuleInfo[i].m_pxMesh = Asura_Module_System::GetMeshForModule(i);
		pxModuleInfo[i].m_iNumDualPassTris = 0;

		//count the dual-pass tris
		Asura_Mesh_TextureInfo* pxTex = pxModuleInfo[i].m_pxMesh->TextureDataPtr;
		for(int j=0;j<pxModuleInfo[i].m_pxMesh->NumberOfPolygons;j++,pxTex++)
		{
			if(pxTex->m_iMaterialID == ASURA_MATERIAL_NONE) continue;
			if(Asura_Material_System::GetTextureID(pxTex->m_iMaterialID,1) != ASURA_TEXTURE_NONE)
			{
                pxModuleInfo[i].m_iNumDualPassTris += ( pxModuleInfo[i].m_pxMesh->PolygonDataPtr[j].IsQuad() ? 2 : 1 );
			}
		}
	}
	
	qsort(pxModuleInfo,iNumModules,sizeof(ToolsModuleInfo),PolygonCountScreenSort);

	// Work out the totals
	
	int iTotalPolyCount = 0;
	int iTotalTriCount = 0;
	int iTotalVertCount = 0;

	int iTotalColPolyCount = 0;
	int iTotalColTriCount = 0;
	int iTotalColVertCount = 0;

	int iTotalExportedTriCount = 0;
	int iTotalExportedPolyCount = 0;

	int iTotalRenderTriCount = 0;
	int iTotalRenderPolyCount = 0;

	for(int i = 0; i < iNumModules; i++)
	{
		Asura_Mesh* pxMesh = pxModuleInfo[i].m_pxMesh;

		iTotalPolyCount += pxMesh->NumberOfPolygons;
		iTotalTriCount += pxMesh->NumberOfTriangles;
		iTotalVertCount += pxMesh->NumberOfVertices;

		// Count the different tris/

		const int iNumMeshPolygons = pxMesh->NumberOfPolygons;

		for(int n = 0; n < iNumMeshPolygons; n++)
		{
			if(!(pxMesh->GetPolygonFlags(n) & AsuraPolygonFlag_NoCollisions))
			{
				iTotalColTriCount += (pxMesh->PolygonDataPtr[n].IsQuad()) ? 2 : 1;
				iTotalColPolyCount++;
			}

			if(!(pxMesh->GetPolygonFlags(n) & AsuraPolygonFlag_DontExport))
			{
				iTotalExportedTriCount += (pxMesh->PolygonDataPtr[n].IsQuad()) ? 2 : 1;
				iTotalExportedPolyCount++;
			}

			if(!(pxMesh->GetPolygonFlags(n) & AsuraPolygonFlag_DontRender))
			{
				iTotalRenderTriCount += (pxMesh->PolygonDataPtr[n].IsQuad()) ? 2 : 1;
				iTotalRenderPolyCount++;
			}
		}

		// Count the collision vertices

		const Asura_CollisionMesh* pxCollisionMesh = Asura_Module_System::GetCollisionMeshForModule(i);

		if(pxCollisionMesh)
		{
			iTotalColVertCount += pxCollisionMesh->GetNumberOfVertices();
		}
	}
	
	do
	{
		Asura_Windows::CheckForWindowsMessages();
		Asura_UserInput::Update();
		Asura_Cursor::OncePerFrameUpdate();

		//get the current mouse position
		int mx,my;
		Asura_Cursor::GetScreenSpaceCoords(mx,my);
		float fPrintMX = (float)mx;
		float fPrintMY = (float)my;

		Asura_Text_Output::ConvertPixelsToPrintCoords(fPrintMX,fPrintMY);

		fPrintMY -= fHeaderHeight;

		//determine which module entry the mouse is over
		iMouseOverIndex = -1;
		if(fPrintMY>=1 && fPrintMY<1+iNumModulesPerColumn)
		{
			iMouseOverIndex = (int)(fPrintMY-1);
			if(fPrintMX>=fSecondColumnX) iMouseOverIndex+=iNumModulesPerColumn;
		}

		//check user input
		if(Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_MOUSEBUTTON1))
		{
			if(iMouseOverIndex >= 0)
			{
				//goto the module the mouse is over
				int iIndex = iMouseOverIndex + iFirstShownModule;
				if(iIndex<Asura_Module_System::GetNumberOfModules())
				{
					int iModule = pxModuleInfo[iIndex].m_iIndex;
					
					//get the position of the module
					Asura_Vector_3 position =Asura_Module_System::GetCentreOfModule(iModule);

					//and put the player there
					Tools_Movement::TeleportCameraToPosition(&position,0);
					
					break;
				}
			}
			else if(fPrintMY < 1.0f)
			{
				//determine column clicked on
				float fX = (float)((int)fPrintMX % (int) fSecondColumnX);

				
					
				if(fX>fNameOffsetX-4.0f && fX<fNameOffsetX+4.0f)
				{
					//clicked on name column
					g_eModuleSortMode = (g_eModuleSortMode==MODULESORT_NAME_UP) ? MODULESORT_NAME_DOWN : MODULESORT_NAME_UP;
				}
				else if(fX>fPolygonOffsetX-4.0f && fX<fPolygonOffsetX+4.0f)
				{
					//clicked on poly column
					g_eModuleSortMode = (g_eModuleSortMode==MODULESORT_POLY_UP) ? MODULESORT_POLY_DOWN : MODULESORT_POLY_UP;
				}
				else if(fX>fDualPolygonOffsetX-4.0f && fX<fDualPolygonOffsetX+4.0f)
				{
					//clicked on poly column
					g_eModuleSortMode = (g_eModuleSortMode==MODULESORT_DUALPASS_POLY_UP) ? MODULESORT_DUALPASS_POLY_DOWN : MODULESORT_DUALPASS_POLY_UP;
				}
				
				qsort(pxModuleInfo,iNumModules,sizeof(ToolsModuleInfo),PolygonCountScreenSort);
			}
		}

		if(Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_LEFT))
		{
			//show previous modules
			iFirstShownModule -= iNumModulesPerColumn*iNumColumns;
			if(iFirstShownModule<0)
			{
				iFirstShownModule = ((Asura_Module_System::GetNumberOfModules()-1)/(iNumModulesPerColumn*iNumColumns))*(iNumModulesPerColumn*iNumColumns);
			}
		}
		
		if(Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_RIGHT))
		{
			//show next modules
			iFirstShownModule += iNumModulesPerColumn*iNumColumns;
			if(iFirstShownModule>=Asura_Module_System::GetNumberOfModules())
			{
				iFirstShownModule = 0;
			}
		}
		

		//begin rendering
		Asura_Render::BeginFrame();

		//first draw a big black poly over everything that has taken place so far...
		float width = (float)Asura_Viewport::GetWidth();
		float height = (float)Asura_Viewport::GetHeight();
		Asura_Render::Overlay.SetRectXY(0,0,width,height);
		Asura_Render::Overlay.SetRectUV(0,0,1,1);
		Asura_Render::Overlay.TranslucencyMode = ASURA_TRANSLUCENCY_OFF;
		Asura_Render::Overlay.TextureIndex = ASURA_TEXTURE_NONE;
		Asura_Render::Overlay.Colour=0xff000000;
		Asura_Render::Overlay.Render();
		Asura_Render::FlushDisplay();

		// Display the totals section at the top

		float fY = 1.0f;

		Asura_Text_Output::Print(fHeaderLabelOffsetX, fY, 0xff00ff00, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "Total Polygons:");
		Asura_Text_Output::Print(fHeaderValueOffsetX, fY, 0xffffffff, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "%d", iTotalPolyCount);
		fY += 1.2f;

		Asura_Text_Output::Print(fHeaderLabelOffsetX, fY, 0xff00ff00, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "Total Tris:");
		Asura_Text_Output::Print(fHeaderValueOffsetX, fY, 0xffffffff, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "%d", iTotalTriCount);
		fY += 1.2f;

		Asura_Text_Output::Print(fHeaderLabelOffsetX, fY, 0xff00ff00, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "Total Vertices:");
		Asura_Text_Output::Print(fHeaderValueOffsetX, fY, 0xffffffff, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "%d", iTotalVertCount);
		fY += 1.2f;

		Asura_Text_Output::Print(fHeaderLabelOffsetX, fY, 0xff00ff00, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "Total Collision Tris:");
		Asura_Text_Output::Print(fHeaderValueOffsetX, fY, 0xffffffff, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "%d", iTotalColTriCount);
		fY += 1.2f;

		Asura_Text_Output::Print(fHeaderLabelOffsetX, fY, 0xff00ff00, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "Total Collision Polygons:");
		Asura_Text_Output::Print(fHeaderValueOffsetX, fY, 0xffffffff, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "%d", iTotalColPolyCount);
		fY += 1.2f;

		Asura_Text_Output::Print(fHeaderLabelOffsetX, fY, 0xff00ff00, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "Total Collision Vertices:");
		Asura_Text_Output::Print(fHeaderValueOffsetX, fY, 0xffffffff, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "%d", iTotalColVertCount);
		fY += 1.2f;

		Asura_Text_Output::Print(fHeaderLabelOffsetX, fY, 0xff00ff00, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "Total Exported Polygons:");
		Asura_Text_Output::Print(fHeaderValueOffsetX, fY, 0xffffffff, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "%d", iTotalExportedPolyCount);
		fY += 1.2f;

		Asura_Text_Output::Print(fHeaderLabelOffsetX, fY, 0xff00ff00, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "Total Exported Tris:");
		Asura_Text_Output::Print(fHeaderValueOffsetX, fY, 0xffffffff, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "%d", iTotalExportedTriCount);
		fY += 1.2f;

		Asura_Text_Output::Print(fHeaderLabelOffsetX, fY, 0xff00ff00, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "Total Rendered Polygons:");
		Asura_Text_Output::Print(fHeaderValueOffsetX, fY, 0xffffffff, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "%d", iTotalExportedPolyCount);
		fY += 1.2f;

		Asura_Text_Output::Print(fHeaderLabelOffsetX, fY, 0xff00ff00, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "Total Rendered Tris:");
		Asura_Text_Output::Print(fHeaderValueOffsetX, fY, 0xffffffff, ASURA_TEXT_FORMAT_LEFTJUSTIFIED, "%d", iTotalRenderTriCount);
		fY += 1.2f;

		fY = fHeaderHeight;

		//display the column headings
		int i;
		for(i=0;i<iNumColumns;i++)
		{
			float x = (float)(fSecondColumnX*i);
			Asura_Text_Output::Print(x+fNameOffsetX,fY,0xff00ff00,ASURA_TEXT_FORMAT_CENTREJUSTIFIED,"Name");
			Asura_Text_Output::Print(x+fPolygonOffsetX,fY,0xff00ff00,ASURA_TEXT_FORMAT_CENTREJUSTIFIED,"Tris");
			Asura_Text_Output::Print(x+fDualPolygonOffsetX,fY,0xff00ff00,ASURA_TEXT_FORMAT_CENTREJUSTIFIED,"Dual-Pass");
		}

		
		//display the polygon counts
		for(i=0;i<iNumModulesPerColumn*iNumColumns;i++)
		{
			int mn = i+iFirstShownModule;
			if(mn>=Asura_Module_System::GetNumberOfModules()) break;


			//get the mesh for the name
			Asura_Mesh* pxMesh = pxModuleInfo[mn].m_pxMesh;
			int iDualPass = pxModuleInfo[mn].m_iNumDualPassTris;
			
			float x = (i/iNumModulesPerColumn)*fSecondColumnX;
			float y = fY + (float)(1+i%iNumModulesPerColumn);
			u_int uColour = (i == iMouseOverIndex) ? 0xffff0000 : 0xffffffff;

			
			Asura_Text_Output::Print(x+fNameOffsetX,y,uColour,ASURA_TEXT_FORMAT_CENTREJUSTIFIED,pxMesh->Name.GetString());
			Asura_Text_Output::Print(x+fPolygonOffsetX,y,uColour,ASURA_TEXT_FORMAT_CENTREJUSTIFIED,"%d",pxMesh->NumberOfTriangles);
			Asura_Text_Output::Print(x+fDualPolygonOffsetX,y,uColour,ASURA_TEXT_FORMAT_CENTREJUSTIFIED,"%d",iDualPass);
		}

		//show some instructions
		Asura_Text_Output::Print(1,fPrintHeight-6,0xffffffff,0,"Click on module to go to it");
		Asura_Text_Output::Print(1,fPrintHeight-5,0xffffffff,0,"Click on heading to change sorting");
		Asura_Text_Output::Print(1,fPrintHeight-4,0xffffffff,0,"Escape : Exit");
		Asura_Text_Output::Print(1,fPrintHeight-3,0xffffffff,0,"Left Arrow : Show previous modules");
		Asura_Text_Output::Print(1,fPrintHeight-2,0xffffffff,0,"Right Arrow : Show next modules");

		//render cursor and finish
		Asura_Cursor::SetType(ASURA_CURSOR_CROSSHAIR);
		Asura_Cursor::Render();
		Asura_Render::EndFrame();
  
	}while(!Asura_UserInput::DebouncedKeyPressed(ASURA_KEYID_ESCAPE));

	delete [] pxModuleInfo;
}


struct ToolsModuleWarningInfo
{
	int m_iNumTriangles;
	Asura_Mesh* m_pxMesh;
};

int ModuleWarningSort(const void* m1,const void* m2)
{
	ToolsModuleWarningInfo* pxModule1 = (ToolsModuleWarningInfo*)m1;
	ToolsModuleWarningInfo* pxModule2 = (ToolsModuleWarningInfo*)m2;

	return pxModule2->m_iNumTriangles - pxModule1->m_iNumTriangles;
}

bool Tools_System::WarnAboutModulesWithTooManyTriangles()
{
	Asura_Assert(This,"");

	
	int iWarningLevel = This->GetModuleTriangleWarningLevel();
	int iErrorLevel = This->GetModuleTriangleErrorLevel();
	if(!iWarningLevel && !iErrorLevel) return false;
	if(iWarningLevel == 0) iWarningLevel = iErrorLevel;

	if(iWarningLevel && iErrorLevel && iWarningLevel > iErrorLevel)
	{
		Asura_Assert(0,"Silly settings for GetModuleTriangleWarningLevel() and GetModuleTriangleErrorLevel()");
		iWarningLevel = iErrorLevel;
	}


	int iNumModules = Asura_Module_System::GetNumberOfModules();

	//allocate enough space for modules in case all are duds
	ToolsModuleWarningInfo* pxModuleInfo = new ToolsModuleWarningInfo[iNumModules];

	int iErrorCount = 0;
	int iWarningCount = 0;

	//check each module for number of triangles to be exported to render mesh
	for(int i=0;i<iNumModules;i++)
	{
		//ignore scenery modules
		if(Asura_Environment_System::GetEnvironment()->IsSceneryModule(i)) continue;
		
		Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(i);
		
		int iTriCount = 0;
		if(pxMesh->PolygonFlagDataPtr)
		{
			const int iFlagsToIgnore = AsuraPolygonFlag_DontRender|AsuraPolygonFlag_Water|AsuraPolygonFlag_DontExport;
			for(int j=0;j<pxMesh->NumberOfPolygons;j++)
			{
				if(pxMesh->PolygonFlagDataPtr[j].Flags & iFlagsToIgnore) continue;
 				iTriCount += pxMesh->PolygonDataPtr[j].NumberOfVertices()-2;
			}
		}
		else
		{
			//no polygon flags, so all triangles would be included in export
			iTriCount = pxMesh->NumberOfTriangles;
		}

		if(iTriCount>iWarningLevel)
		{
			pxModuleInfo[iWarningCount].m_pxMesh = pxMesh;
			pxModuleInfo[iWarningCount].m_iNumTriangles = iTriCount;
			iWarningCount++;

			if(iErrorLevel && iTriCount>iErrorLevel)
			{
				iErrorCount++;
			}
		}
 	}

	if(iWarningCount)
	{
		qsort(pxModuleInfo,iWarningCount,sizeof(ToolsModuleWarningInfo),ModuleWarningSort);

		//show warning dialog (but not during batch exports)
		if(!Tools_BatchProcessing::IsBatch())
		{
			char szMessage[2000] = "";

			char* pcPos = szMessage;

			if(iErrorCount)
			{
				strcpy(pcPos,"*** ERROR ***\nTHIS LEVEL WILL NOT EXPORT\n\nSome modules have too many triangles to be exported.\n");
				pcPos += strlen(pcPos);
			}
			else
			{
				strcpy(pcPos,"Warning.\nSome modules have more than the recommended triangle limit.\n");
				pcPos += strlen(pcPos);
			}

			if(iErrorLevel)
			{
				sprintf(pcPos,"The maximum allowed in a non-scenery module is %d triangles.\n",iErrorLevel);
				pcPos += strlen(pcPos);
			}
	
			if(iWarningLevel!=iErrorLevel)
			{
				sprintf(pcPos,"The recommended maximum is %d triangles.\n",iWarningLevel);
				pcPos += strlen(pcPos);
			}

			const int iMaxToShow = 10;
			
			if(iWarningCount > iMaxToShow)
			{
				sprintf(pcPos,"\nThe top %d offenders are :\n\n",iMaxToShow);
				pcPos += strlen(pcPos);
			}
			else
			{
				strcpy(pcPos,"\nThese modules are over the recommended limit :\n\n");
				pcPos += strlen(pcPos);
			}

			for(int i=0;i<iWarningCount && i<iMaxToShow;i++)
			{
				sprintf(pcPos,"%s (%d)\n",pxModuleInfo[i].m_pxMesh->Name.GetString(),pxModuleInfo[i].m_iNumTriangles);
				pcPos += strlen(pcPos);
			}

			Message_Overlay xOverlay(szMessage);
			xOverlay.DoModal();
		}
	}

	delete [] pxModuleInfo;	

	return (iErrorCount>0);
}

void Tools_System::ConvertEnvStartPositionsToEntities()
{
#ifndef ASURA_USE_TOOLS_START_POSITION_OBJECTS
	// convert start positions from the environment into start point entities.

	Asura_Environment* pxEnv = Asura_Environment_System::GetEnvironment();
	if(!pxEnv)
	{
		Asura_Assert(false, "Couldn't get environment");
		return;
	}

	for(int iSP = 0; iSP < pxEnv->NumberOfStartPositions; ++iSP)
	{
		Asura_ServerEntity_StartPoint* pxStartPoint = Asura_ServerEntity_StartPoint::Create(Asura_Entity_System::GetCreatedByToolsGuid_EntityFile());
		if(pxStartPoint)
		{
			pxStartPoint->m_xPosition = pxEnv->StartPositions[iSP].Position;
			pxStartPoint->m_xOrientation = pxEnv->StartPositions[iSP].Orientation;
		}
		else
		{
			Asura_Assert(false, "Couldn't create start point entity");
		}
	}

	// now remove environment start positions.
	delete [] pxEnv->StartPositions;
	pxEnv->StartPositions = NULL;
	pxEnv->NumberOfStartPositions = 0;
#endif //ASURA_USE_TOOLS_START_POSITION_OBJECTS
}

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

	switch(iTab)
	{
		case TOOLS_GENERALOPTIONS_MOUSE :
		{	
			pxDialog = new Asura_Tickbox_Dialog("Swap LMB/RMB",xOffset,&s_bSwapMouseButtons);
			((Asura_Tickbox_Dialog*)pxDialog)->SetClickedFunction(SwapMouseButtonsClicked);
			pxDialog->SetHelpText("Swaps the use of the left and right mouse buttons throughout tools.\n(Help text will still refer to the buttons as unswapped).");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Tickbox_Dialog("Use Windows Cursor",xOffset,&s_bUseWindowsCursor);
			((Asura_Tickbox_Dialog*)pxDialog)->SetClickedFunction(UseWindowsCursorClicked);
			pxDialog->SetHelpText("Causes the windows mouse cursor to be used , which should be more usable at low frame rates.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Tickbox_Dialog("Restrict Mouse To Window",xOffset,&s_bRestrictMouseToWindowInSubwindowTools);
			((Asura_Tickbox_Dialog*)pxDialog)->SetClickedFunction(UpdateRestrictMouseToWindow);
			pxDialog->SetHelpText("Determines whether the mouse cursor should be allowed outside of the main window.\nThis settings is only relevant in subwindow mode.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Tickbox_Dialog("Restrict Mouse To Window (In Game)",xOffset,&s_bRestrictMouseToWindowInSubwindowGame);
			pxDialog->SetHelpText("As above , but this setting will apply while in game.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Tickbox_Dialog("Restrict Mouse To Fullscreen Window",xOffset,&s_bRestrictMouseToWindowInFullScreenTools);
			((Asura_Tickbox_Dialog*)pxDialog)->SetClickedFunction(UpdateRestrictMouseToWindow);
			pxDialog->SetHelpText("Determines whether the mouse cursor should be allowed outside of the main window when running full screen.\nThis settings is only relevant in subwindow mode.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

			pxDialog = new Asura_Tickbox_Dialog("Restrict Mouse To Fullscreen Window (In Game)",xOffset,&s_bRestrictMouseToWindowInFullScreenGame);
			pxDialog->SetHelpText("As above , but this setting will apply while in game.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();

		}
		break;

		case TOOLS_GENERALOPTIONS_PERFORMANCE :
		{
			pxDialog = new Asura_Tickbox_Dialog("Idle While Minimised",xOffset,&s_bIdlePriorityWhileMinimised);
			((Asura_Tickbox_Dialog*)pxDialog)->SetClickedFunction(IdleWhileMinimisedClicked);
			pxDialog->SetHelpText("Determines whether tools will run at idle or normal priority while minimised or in the background.\nDuring the initial load tools will run at the higher priority regardless of this setting.");
			pxOverlay->AddDialog(pxDialog);
			xOffset.y+=Asura_Dialog::DefaultSpacing();
		}
		break;
	}

}

void Tools_System::ViewTextures()
{
	Tools_Overlay_ViewTextures::CreateOverlay();
}

void Tools_System::DoFirstFrameChecksIfRequired()
{
	static bool s_bDone = false;
	if(s_bDone) return;
	s_bDone = true;

	// (AW - 17.09.2003) - Don't display these warnings if we're batch exporting
	// or batch waypointing.
	if (!Tools_BatchProcessing::IsBatch())
	{
		//Check to see if we are transfering cutscenes from the .ent to the .cut file. If so , warn about it
		if(Asura_Chunk_Cutscene::s_bCutscenesLoadedFromEntityFile)
		{
			Message_Overlay xOverlay("Some cutscenes were loaded from the entity (.ent) file.\n"
									"When you save these will be saved to the cutscene (.cut) file.\n"
									"You will not be allowed to save to either of these files unless you have BOTH these files checked out."
									"(Note , the cutscene file may not actually exist yet , in which case make sure it gets added to alienbrain after you save)");
			xOverlay.DoModal();		
		}

		#if 0 //Don't think anyone cares about this anymore. RAR 04/09/2006
		// Check if the number of modules has changed. If it has, warn the artist
		// that they should force region data to be recalculated.
		if( Asura_ModuleIndex_Conversion::DidNumberOfModulesChange() )
		{
			Message_Overlay xOverlay( "The number of modules in this environment has changed. If "
									  "your project is using dynamic loading on the PS2 then you "
									  "need to go into regions mode and then select Save Current "
									  "Mode from the File menu to force region data to be updated. "
									  "You need to have the .asr file checked out in order for "
									  "this to work." );
			xOverlay.DoModal();		
		}
		#endif

#ifdef ASURA_DISABLE_DYNAMICS_WITH_PARTICLE_GENERATORS
		{
			const List<Asura_String>& xList = Asura_Chunk_ParticleTemplates::GetListOfTemplatesThatWereUsingDynamics();
			if( xList.size() )
			{
				bool bSavedOK = Asura_Chunk_ParticleTemplates::Create();

				Asura_String xMsg = "The following particle templates had Use Dynamics turned on:\n\n";
				for( CLIF<Asura_String> xIt(&xList); !xIt.done(); xIt.next() )
				{
					xMsg += xIt();
					xMsg += "\n";
				}
				xMsg += "\nThis was turned off for all templates automatically.";

				if( bSavedOK )
				{
					xMsg += " The particle templates file has been updated accordingly.";
				}
				else
				{
					xMsg += " However, the particle templates file is not writeable. "
							"You will need to exit tools, check it out, and then "
							"reload a level in order for these corrections to be "
							"saved.";
				}

				Message_Overlay xMsgOverlay( xMsg );
				xMsgOverlay.DoModal();
			}
		}

		{
			const List<Asura_Guid>& xList = Asura_ServerEntity_ParticleGenerator::GetListOfCustomPGsThatWereUsingDynamics();
			if( xList.size() )
			{
				Tools_SaveAsura::SetEntityModified( true );

				Asura_String xMsg = "The following particle generators had Use Dynamics turned on:\n\n";
				for( CLIF<Asura_Guid> xIt(&xList); !xIt.done(); xIt.next() )
				{
					const Asura_Entity_Server* pxEntity = Asura_Entity_Server::FindEntity( xIt() );
					if( !pxEntity ) { continue; }

					xMsg += pxEntity->ToolsData->Name;
					xMsg += "\n";
				}
				xMsg += "\nThis was turned off for all particle generators automatically. "
						"You will need to save the entity file (.ent) for this change to "
						"be kept.";

				Message_Overlay xMsgOverlay( xMsg );
				xMsgOverlay.DoModal();
			}
		}
#endif
		//Deal with moving the start positions to the entity file here as well. RAR 24/1/2005
		Tools_SaveAsura::HandleTransferOfStartPositionFromAsuraFileToEntityFile();

		//warning for modules with too many triangles
		if(Tools_SaveAsura::GetFileType() == AsuraFile_Environment)
		{
			WarnAboutModulesWithTooManyTriangles();
		}
	}
}

void Tools_System::CopyPositionToClipboard()
{
	const Asura_Vector_3* pxPos = Asura_Camera::GetPosition();

	//print position to a temporary buffer
	char szBuffer[100];
	Asura_PrintfToBfr(szBuffer,"%.1f, %.1f, %.1f",sizeof(szBuffer),true,pxPos->x,pxPos->y,pxPos->z);

	//copy the results to the windows clipboard	
	if( OpenClipboard(NULL) )
	{
		HGLOBAL hMem = GlobalAlloc( GMEM_MOVEABLE, strlen(szBuffer) + 1 );
		if( hMem )
		{
			char* szOut = reinterpret_cast<char*>( GlobalLock(hMem) );
			strcpy(szOut,szBuffer);
			GlobalUnlock( hMem );

			EmptyClipboard();
			SetClipboardData( CF_TEXT, hMem );

			Tools_Timed_Message_System::AddMessage(0xffffff,"Position copied to clipboard.");
			
		}

		CloseClipboard();
	}


}

void Tools_System::SetDefaultMode(const char* szExtension)
{
	if(!stricmp(szExtension,".gi") || !stricmp(szExtension,".elt") || !stricmp(szExtension,".lit"))
	{
		s_iDefaultMode = TOOLS_MODE_PHOTONMAPPING;
	}
	else if(!stricmp(szExtension,".snd"))
	{
		s_iDefaultMode = TOOLS_MODE_SOUND;
	}
	else if(!stricmp(szExtension,".mod"))
	{
		s_iDefaultMode = TOOLS_MODE_MODULELINKING;
	}
	else if(!stricmp(szExtension,".nav"))
	{
		s_iDefaultMode = TOOLS_MODE_WAYPOINTING;
	}
	else if(!stricmp(szExtension,".cut"))
	{
		s_iDefaultMode = TOOLS_MODE_CUTSCENE;
	}
	else if(!stricmp(szExtension,".ent"))
	{
		s_iDefaultMode = TOOLS_MODE_OBJECT;
	}
	#ifdef ASURA_USE_BOTANICALS
	else if(!stricmp(szExtension,".bti") || !stricmp(szExtension,".btt") || !stricmp(szExtension,".bts"))
	{
		s_iDefaultMode = TOOLS_MODE_BOTANICALS;
	}
	#endif
	#ifdef ASURA_USE_ATTRACTORS
	else if(!stricmp(szExtension,".atr"))
	{
		s_iDefaultMode = TOOLS_MODE_ATTRACTORS;
	}
	#endif
	#ifdef ASURA_USE_CARPET
	else if(!stricmp(szExtension,".cpm") || !stricmp(szExtension,".cps"))
	{
		s_iDefaultMode = TOOLS_MODE_CARPET;
	}
	#endif
	#ifdef ASURA_USE_STATIC_DECAL_SYSTEM
	else if(!stricmp(szExtension,".dec"))
	{
		s_iDefaultMode = TOOLS_MODE_DECALS;
	}
	#endif
	#ifdef ASURA_USE_GUI_MENU_SYSTEM
	else if(!stricmp(szExtension,".gui"))
	{
		s_iDefaultMode = TOOLS_MODE_GUIMENU;
	}
	#endif
}

void Tools_System::SetDefaultMode( const AsuraFileType eFileType )
{
	if( eFileType == AsuraFile_TextureTiler )
	{
		s_iDefaultMode = TOOLS_MODE_TEXTURETILER;
	}
}

void Tools_System::AddExportOptions( Asura_Menubar_Title* pxTitle )
{
	pxTitle->AddItem("Save All As",Tools_SaveAsura::SaveAllAs);
	pxTitle->AddItem("Export Level",Tools_Level_Export::CreateOverlay);
	pxTitle->AddItem("Export Characters",Tools_Level_Export::CreateAnimationOverlay);
	pxTitle->AddItem("Export Common",Tools_Level_Export::ExportCommonFile);
#ifdef ASURA_USE_STREAMING
	pxTitle->AddItem("Export Skybox",Tools_Level_Export::ExportSkybox_AllPlatforms);
#endif
	if(CanExportGlobalSoundsInCommon())
	{
		pxTitle->AddItem("Export Global Sounds For Tools",Tools_Level_Export::ExportGlobalSoundEventsForTools);
	}
	else
	{
		pxTitle->AddItem("Export Global Sounds",Tools_Level_Export::ExportGlobalSoundEvents);
	}
#ifdef ASURA_USE_AUDIO_SYSTEM
	pxTitle->AddItem("Export Streaming Sounds",Tools_Level_Export::ExportStreamingSounds);
#endif
#ifdef ASURA_USE_GUI_MENU_SYSTEM
	pxTitle->AddItem("Export Menus",Tools_Level_Export::ExportGUIMenus);
#endif
}

Tools_Modal_Overlay* Tools_System::CreateExitConfirmationOverlay(const TOOLS_MODE eNextMode) const
{
	return(new Tools_ExitConfirmationOverlay (eNextMode));
}

Tools_Modal_Overlay* Tools_System::CreateSaveConfirmationOverlay(const TOOLS_MODE eNextMode) const
{
	return (new Tools_SaveConfirmationOverlay());
}

#ifdef ASURA_USE_BOTANICALS
void Tools_System::ToggleHideBotanicals()
{
	s_bHideBotanicals=!s_bHideBotanicals;
	//set the hide flag for the botanicals tools objects as well
	Tools_Object_System::SetTypeHidden(TOT_Botanicals, ObjectHideFlag_HideByTypeOverlay, s_bHideBotanicals);
}
#endif //ASURA_USE_BOTANICALS

bool Tools_System::SoundMenuEnabled_SwitchToSoundMode()
{
	return ( Tools_System::GetCurrentMode() != TOOLS_MODE_SOUND );
}

bool Tools_System::SoundMenuEnabled_SoundOptions()
{
	return true;
}

bool Tools_System::SoundMenuEnabled_DialogueSystem()
{
	#ifdef ASURA_USE_DIALOGUE_SYSTEM
	//return (	( Tools_System::GetCurrentMode() == TOOLS_MODE_OBJECT	)
	//		||	( Tools_System::GetCurrentMode() == TOOLS_MODE_SOUND	) );
	return true;//Should be safe to use in any mode.RAR 16/04/2009
	#else
	return false;
	#endif
}

bool Tools_System::SoundMenuEnabled_DynamicMusicSystem()
{
	#ifdef ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM
	return ( Tools_System::GetCurrentMode() == TOOLS_MODE_OBJECT );
	#else
	return false;
	#endif
}

bool Tools_System::SoundMenuEnabled_DSPEffects()
{
	#ifdef ASURA_USE_AUDIO_SYSTEM
	return true;
	#else
	return false;
	#endif
}

bool Tools_System::SoundMenuEnabled_ReverbDefintions()
{
	#ifdef ASURA_USE_AUDIO_SYSTEM
	return true;
	#else
	return false;
	#endif
}

bool Tools_System::SoundMenuEnabled_StreamingSoundList()
{
	#ifdef ASURA_USE_AUDIO_SYSTEM
	return true;
	#else
	return false;
	#endif
}

bool Tools_System::SoundMenuEnabled_Mixers()
{
	return true;
}

bool Tools_System::SoundMenuTicked_SwitchToSoundMode()
{
	return false;
}

bool Tools_System::SoundMenuTicked_SoundOptions()
{
	return (	Tools_GeneralOptions::OptionsOverlayIsOn() && 
				Tools_GeneralOptions::GetSelectedOptionTab() == TOOLS_GENERALOPTIONS_SOUND );
}

bool Tools_System::SoundMenuTicked_DialogueSystem()
{
	#ifdef ASURA_USE_DIALOGUE_SYSTEM
	return Tools_Dialogue_System::OverlayIsOn();
	#else
	return false;
	#endif
}

bool Tools_System::SoundMenuTicked_DynamicMusicSystem() 
{
	#ifdef ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM
	return Tools_Overlay_DynamicMusic::IsOverlayOpen();
	#else
	return false;
	#endif
}

bool Tools_System::SoundMenuTicked_DSPEffects()
{
	#ifdef ASURA_USE_AUDIO_SYSTEM
	return Tools_Audio_DSP::IsOverlayOpen();
	#else
	return false;
	#endif
}

bool Tools_System::SoundMenuTicked_ReverbDefintions()
{
	#ifdef ASURA_USE_AUDIO_SYSTEM
	return Tools_Audio_ReverbOverlay::IsOpen();
	#else
	return false;
	#endif
}

bool Tools_System::SoundMenuTicked_StreamingSoundList()
{
	#ifdef ASURA_USE_AUDIO_SYSTEM
	return Tools_Audio_StreamingOverlay::IsOpen();
	#else
	return false;
	#endif
}

bool Tools_System::SoundMenuTicked_Mixers()
{
	return Tools_SoundMixer_Overlay::IsOpen();
}

void Tools_System::SoundMenuAction_SwitchToSoundMode ()
{
	Tools_System::RequestSoundMode ();
}

void Tools_System::SoundMenuAction_SoundOptions ()
{
	if( !Tools_GeneralOptions::OptionsOverlayIsOn() )
	{
		Tools_GeneralOptions::ToggleOptionsOverlay();
	}
	Tools_GeneralOptions::SetSelectedOptionTab( TOOLS_GENERALOPTIONS_SOUND );
}

void Tools_System::SoundMenuAction_DialogueSystem()
{
	#ifdef ASURA_USE_DIALOGUE_SYSTEM
	Tools_Dialogue_System::ToggleOverlay();
	#endif
}

void Tools_System::SoundMenuAction_DynamicMusicSystem()
{
	#ifdef ASURA_SUPPORT_DYNAMIC_MUSIC_SYSTEM
	Tools_Overlay_DynamicMusic::ToggleOverlay();
	#endif
}

void Tools_System::SoundMenuAction_DSPEffects()
{
	#ifdef ASURA_USE_AUDIO_SYSTEM
	Tools_Audio_DSP::ToggleOverlay();
	#endif
}

void Tools_System::SoundMenuAction_ReverbDefintions()
{
	#ifdef ASURA_USE_AUDIO_SYSTEM
	Tools_Sound_System::ToggleReverbOverlay();
	#endif
}

void Tools_System::SoundMenuAction_StreamingSoundList()
{
	#ifdef ASURA_USE_AUDIO_SYSTEM
	Tools_Sound_System::ToggleStreamingOverlay();
	#endif
}

void Tools_System::SoundMenuAction_Mixers()
{
	if( Tools_SoundMixer_Overlay::IsOpen() )
	{
		Tools_SoundMixer_Overlay::CloseMixersOverlay();
	}
	else
	{
		Tools_SoundMixer_Overlay::ShowMixersOverlay();
	}
}

bool Tools_System::SoundMenuEnabled_AudioMonitor()
{
	#ifdef ASURA_USE_AUDIO_SYSTEM
	return true;
	#else
	return false;
	#endif
}


bool Tools_System::SoundMenuTicked_AudioMonitor()
{
	#ifdef ASURA_USE_AUDIO_SYSTEM
	return Tools_Audio_Monitor::IsOverlayOpen();
	#else
	return false;
	#endif
}


void Tools_System::SoundMenuAction_AudioMonitor()
{
	#ifdef ASURA_USE_AUDIO_SYSTEM
	Tools_Audio_Monitor::ToggleOverlay();
	#endif
}

/// End of file. ///



