///////////////////////////////////////////////////////////////////////////////
//
// File: Tools_Overlay_Decals.h
//
// Created by Dave Reed - 8/02/2007
// 
// Copyright (C) 2006 Rebellion (Derby), All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////


#include "Core/Asura.h"

#ifdef ASURA_USE_DECAL_MANAGER

#include "Decals/Tools_Overlay_Decals.h"

// Asura
#include "Core/Asura_UserInput.h"
#include "Interface/Asura_Overlay.h"
#include "Interface/Asura_Overlay_System.h"
#include "Interface/Asura_Dialog.h"

#include "SpecialFX/Asura_Decal_Manager.h"
#include "ChunkSystem/Asura_Chunk_Decals.h"
#include "Camera/Asura_Camera.h"
#include "Rendering/Asura_Render.h"
#include "Rendering/Asura_Viewport.h"
#include "Core/Asura_LOS.h"

// Tools

#include "Misc/Tools_Timed_Messages.h"
#include "Objects/Tools_Object_System.h"
#include "PC/FileSystem/Tools_FileSystem.h"
#include "Sound/Tools_PickSoundEvent_Overlay.h"
#include "Texturing/Tools_PickTexture.h"
#include "Texturing/Tools_Texturing_Texture.h"
#include "Interface/Asura_TexturePicker_Dialog.h"
#include "Tools_Overlays.h"
#include "Materials/Tools_Overlay_PickMaterialResponse.h"
#include "Materials/Tools_MaterialResponse_System.h"
#include "Texturing/Tools_Texturing_MaterialResponse.h"

#include "Load&Save/Tools_SaveAsura.h"

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


bool Tools_Overlay_Decals::s_bIsOpen  = false;
bool Tools_Overlay_Decals::s_bUpdated = false;
int  Tools_Overlay_Decals::s_iEditingMaterial = 0;
int  Tools_Overlay_Decals::s_iSetMaterialIndex = 0;
int  Tools_Overlay_Decals::s_iEditingSet = 0;
int  Tools_Overlay_Decals::s_iSelectedDecalIndex=0;
int  Tools_Overlay_Decals::s_iReqestedNumDecalTypes=0;
bool Tools_Overlay_Decals::s_bNumDecalTypesChanged=false;
bool Tools_Overlay_Decals::s_bCurrentDecalTypeChanged=false;
bool Tools_Overlay_Decals::s_bModified=false;


Asura_Vector_2 Tools_Overlay_Decals::s_xPosition(6.0f, 6.0f);

const char**Tools_Overlay_Decals::s_pszMaterialNameList=NULL;
const char**Tools_Overlay_Decals::s_pszDecalSetNameList=NULL;

Tools_UV_Editor* Tools_Overlay_Decals::s_pxUVEditor = NULL;

const char* const g_szDecalsToolsFile = "misc\\decals.asr";

static Asura_Tabs_Dialog *s_pxTabs = NULL;
static Asura_Overlay* s_pxDecalsOverlay = NULL;
static int				  s_iTab   = 0;		

void Tools_Overlay_Decals::Initialise()
{
	// Load the data for the overlay.
	s_bUpdated = false;
}

//////////////
// Shutdown //
//////////////
void Tools_Overlay_Decals::Shutdown()
{

	// Close the overlay.
	if (IsOpen())
	{
		ToggleOverlay();
	}
}

////////////
// Update //
////////////
void Tools_Overlay_Decals::Update()
{
	// Make sure overlay is created on going into tools if needed.
	if (!s_bUpdated)
	{
		s_bUpdated = true;
		CreateOverlay();
	}

	if (!s_bIsOpen)
	{
		return;
	}

	if (IsOpen())
	{
		const bool bReadOnly = Tools_FileSystem::IsReadOnly( g_szDecalsToolsFile );		
		Asura_String xTitle = "Decals: '";
		xTitle += g_szDecalsToolsFile;
		xTitle += "'";
		if ( bReadOnly )
		{
			xTitle += " is read-only";			
		}
		else
		{
			xTitle += " is writeable";			
		}
		s_pxDecalsOverlay->SetTitle( xTitle.GetString() );

		// Update the material has in the current set
		if (s_iEditingSet>0)
		{
			Asura_DecalManager_DecalSet *pxSet = Asura_Decal_Manager::GetDecalSetByIndex(s_iEditingSet-1);			

			if (s_iSetMaterialIndex>0)
			{
				pxSet->m_uMtlNameHash = Asura_Decal_Manager::GetDecalMaterialByIndex(s_iSetMaterialIndex-1)->m_uMtlNameHash;
			}
			else
			{
				pxSet->m_uMtlNameHash = 0;
			}

			if (s_bNumDecalTypesChanged)
			{
				pxSet->ChangeNumDecalTypes(s_iReqestedNumDecalTypes);
				s_bNumDecalTypesChanged = false;
				RefreshOverlay();
			}
			else
			{
				if (s_bCurrentDecalTypeChanged)
				{
					s_bCurrentDecalTypeChanged=false;
					RefreshOverlay();
				}
			}
		}		
	}

	// 'tab' - Toggle UV edit
	if(Asura_UserInput::DebouncedKeyPressed('\t'))
	{
		if (s_pxTabs)
		{
			if (s_pxTabs->GetSelected()==1)
			{
				StartUVEdit();
			}
		}		
	}


	if (s_bModified)
	{	
		Tools_SaveAsura::SetDecalTemplatesModified(true);

		Asura_Decal_Manager::RebuildTemplates(false);

#ifdef ASURA_USE_STATIC_DECAL_SYSTEM
		uint32 uMaterial = 0;
		if (s_iTab==0)
		{
			if (s_iEditingMaterial>=0)
			{
				Asura_DecalManager_Material *pxMaterial = Asura_Decal_Manager::GetDecalMaterialByIndex(s_iEditingMaterial);

				if (pxMaterial)
				{
					uMaterial = pxMaterial->m_uMtlNameHash;
				}				
			}
		}
		else
		{
			if (s_iEditingSet>=0)
			{
				Asura_DecalManager_DecalSet *pxSet = Asura_Decal_Manager::GetDecalSet(s_iEditingSet);
				if (pxSet)
				{
					uMaterial = pxSet->m_uMtlNameHash;
				}
			}
		}

		if (uMaterial!=0)
		{
			Tools_StaticDecal_System::UpdateBuffers(false, uMaterial);	
		}		
#endif
		s_bModified = false;
	}

	UpdateUVEdit();
}



const char* const Tools_Overlay_Decals::GetDecalTemplatesFilename()
{
	return g_szDecalsToolsFile;
}


void Tools_Overlay_Decals::ReleaseNameLists()
{

	if (s_pszMaterialNameList)
	{
		delete [] s_pszMaterialNameList;
		s_pszMaterialNameList = NULL;
	}

	if (s_pszDecalSetNameList)
	{
		delete [] s_pszDecalSetNameList;
		s_pszDecalSetNameList = NULL;
	}	

}

void Tools_Overlay_Decals::RebuildNameLists()
{
	ReleaseNameLists();

	s_pszMaterialNameList = new const char*[Asura_Decal_Manager::GetNumDecalMaterials()+1];	
	s_pszMaterialNameList[0]= "<None>";

	for(int i=0;i<Asura_Decal_Manager::GetNumDecalMaterials();i++)
	{
		s_pszMaterialNameList[i+1] = Asura_Decal_Manager::GetDecalMaterialByIndex(i)->m_xMtlName.GetString();
	}


	s_pszDecalSetNameList = new const char*[Asura_Decal_Manager::GetNumDecalSets()+1];	
	s_pszDecalSetNameList[0]= "<None>";

	for(int i=0;i<Asura_Decal_Manager::GetNumDecalSets();i++)
	{
		s_pszDecalSetNameList[i+1] = Asura_Decal_Manager::GetDecalSetByIndex(i)->m_xSetName.GetString();
	}

	
}

///////////////////
// CreateOverlay //
///////////////////
static const char *s_ppszBlendModes[] = 
{
	"Standard (Normal Mapped)",
	"Multiply x2 (PS2-style decals)"
};

#if defined(ASURA_TARGET_SM3)
void Tools_Overlay_Decals::EditMaterialResponseCB()
{
	if (s_iEditingMaterial>0)
	{
		Asura_DecalManager_Material *pxMtl = Asura_Decal_Manager::GetDecalMaterialByIndex(s_iEditingMaterial-1);
		if (pxMtl && pxMtl->m_uMaterialResponseHash)
		{
			Tools_Texturing_MaterialResponse::EditMaterial(pxMtl->m_uMaterialResponseHash);
		}
	}

}

void Tools_Overlay_Decals::CreateMaterialResponseCB()
{
	if (s_iEditingMaterial>0)
	{
		Asura_DecalManager_Material *pxMtl = Asura_Decal_Manager::GetDecalMaterialByIndex(s_iEditingMaterial-1);

		// Create the new material
		Asura_String xFilename;
		if( !Tools_Texturing_MaterialResponse::ShowNewFileDialogue( xFilename ) ) return;

		const Asura_Hash_ID uNewMaterialHash = xFilename.GetHash();

		Tools_MaterialResponse* const pxNewMaterial = Tools_MaterialResponse_System::AddMaterial( uNewMaterialHash );
		if( !pxNewMaterial )
		{
			Tools_Timed_Message_System::AddMessage( Tools_Timed_Message_System::COLOUR_ERROR, "Failed to create new material." );
			return;
		}

		pxNewMaterial->SetName(xFilename);
		pxNewMaterial->SetNeedsSave(true);

		// No need to set m_bModified, just update the texture now
		Asura_PC_MaterialResponse_UpdateTexture();

		// Regenerate the name list in the main overlay
		Tools_Texturing_MaterialResponse::RegenerateOverlay();

		// Open the properties overlay immediately
		Tools_Texturing_MaterialResponse::EditMaterial( uNewMaterialHash );
		if (pxMtl)
		{
			pxMtl->m_uMaterialResponseHash = uNewMaterialHash;
		}
	}

}


#endif

void Tools_Overlay_Decals::CreateOverlay()
{
	if (!IsOpen()) return;

	Asura_Overlay* pxNewOverlay = new Asura_Overlay("Decals", false, &s_xPosition);
	pxNewOverlay->m_uID = TOOLS_OVERLAY_DECALS;
	
	Asura_Vector_2 xOffset = Asura_Vector_2(1.0f, 3.0f);
	Asura_Dialog* pxNewDialog = NULL;

	s_pxDecalsOverlay = pxNewOverlay;

	// Add the decal material section
	// ------------------------------------------------------------------------------------

	const char* aszTabNames[] = { "Decal Materials", "Decal Sets"};
	Asura_Tabs_Dialog *pxTabs = NULL;
	pxNewDialog = s_pxTabs = pxTabs = new Asura_Tabs_Dialog(xOffset, aszTabNames, 2, 30);
	pxNewOverlay->AddDialog(pxNewDialog);
	pxTabs->SelectTab(0);
	float fTabTopY = xOffset.y = pxNewDialog->m_xMaxCoord.y + 0.5f;
	
	// Rebuild the name list
	RebuildNameLists();	

	pxNewDialog = new Asura_Dialog("Decal Material:", xOffset);
	pxTabs->AddDialog(pxNewDialog);

	int iNumMaterials = Asura_Decal_Manager::GetNumDecalMaterials();
	xOffset.x+= 10;
	pxNewDialog = new Asura_DropDown_List_Dialog(xOffset, s_pszMaterialNameList, &s_iEditingMaterial, iNumMaterials+1, iNumMaterials+1, SelectedMaterialChanged, NULL );	
	pxTabs->AddDialog(pxNewDialog);
	xOffset.x-= 10;	

	// Add/Del buttons
	xOffset.x += 30;
	pxNewDialog = new Asura_Function_Dialog("Add", xOffset, AddDecalMaterial);
	pxTabs->AddDialog(pxNewDialog);
	xOffset.x+= 10;
	if (Asura_Decal_Manager::GetNumDecalMaterials()>0)
	{
		pxNewDialog = new Asura_Function_Dialog("Remove", xOffset, RemoveDecalMaterial);
		pxTabs->AddDialog(pxNewDialog);
	}
	xOffset.x -= 40;
	xOffset.y += Asura_Dialog::LargeSpacing();

	// Material properties
	if (s_iEditingMaterial>0)
	{
		Asura_DecalManager_Material *pxMtl = Asura_Decal_Manager::GetDecalMaterialByIndex(s_iEditingMaterial-1);


#if !defined(ASURA_TARGET_SM3)
		// Blend Mode drop-down
		pxNewDialog = new Asura_Dialog("Blend Mode:", xOffset);
		pxTabs->AddDialog(pxNewDialog);
		xOffset.x += 10;
		pxNewDialog = new Asura_DropDown_List_Dialog(xOffset, s_ppszBlendModes, &pxMtl->m_iBlendMode, 2, 2, NULL,  &s_bModified);
		pxTabs->AddDialog(pxNewDialog);		
		xOffset.x -= 10;
		xOffset.y += Asura_Dialog::LargeSpacing();				

		// Textures
	
		static const float			fTEXTURE_PICKER_SIZE = 64.0f;

		pxNewDialog = new Asura_TexturePicker_Dialog( "Texture", xOffset, NULL, &pxMtl->m_xTextureHash, &pxMtl->m_xTextureName, fTEXTURE_PICKER_SIZE, fTEXTURE_PICKER_SIZE, &s_bModified);
		pxTabs->AddDialog( pxNewDialog );
		xOffset.y += 12.0f;
#else

		pxNewDialog = new Asura_Dialog("MaterialResponse:", xOffset);
		pxTabs->AddDialog(pxNewDialog);
		xOffset.x += 12;				
		pxNewDialog = new Tools_MaterialResponse_Dialog(xOffset, &pxMtl->m_uMaterialResponseHash, &s_bModified);
		pxTabs->AddDialog( pxNewDialog );
		xOffset.y += 2.0f;
		pxNewDialog = new Asura_Function_Dialog("Edit", xOffset, EditMaterialResponseCB);
		pxTabs->AddDialog( pxNewDialog );
		xOffset.x += 12;				
		pxNewDialog = new Asura_Function_Dialog("Create New", xOffset, CreateMaterialResponseCB);
		pxTabs->AddDialog( pxNewDialog );

		xOffset.y += 2.0f;
		xOffset.x -= 24;				
#endif

		// DYNAMIC DECAL PARAMS
		pxNewDialog = new Asura_Dialog("Dynamic Decal parameters", xOffset);
		pxTabs->AddDialog(pxNewDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();				

		// Max decals
		pxNewDialog = new Asura_Numerical_Dialog("Decal Buffer Size",xOffset, &pxMtl->m_iMaxDecals, 4, 4096, 8, "%d", &s_bModified);
		pxNewDialog->SetHelpText("This was mis-named as 'max decals' before, but as verts-per-decal varies massively, it's actually the size of the vertex buffer used for this decal type, in multiples of 8 verts");
		pxTabs->AddDialog(pxNewDialog);
		xOffset.y += Asura_Dialog::LargeSpacing();				

		// Fade times
		pxNewDialog = new Asura_Numerical_Dialog("Lifetime (secs)",xOffset, &pxMtl->m_fLifeTime, 0.0f, 600.0f, 1.0f, "%0.1f", &s_bModified);
		pxTabs->AddDialog(pxNewDialog);
		
		xOffset.x += 26;
		pxNewDialog = new Asura_Tickbox_Dialog("Enable fades and limited lifetime",xOffset, &pxMtl->m_bEnableFades, &s_bModified);
		pxTabs->AddDialog(pxNewDialog);
		xOffset.x -= 26;
		xOffset.y += Asura_Dialog::DefaultSpacing();	
		
		pxNewDialog = new Asura_Numerical_Dialog("FadeIn Duration (secs)",xOffset, &pxMtl->m_fFadeInLength, 0.0f, 100.0f, 0.1f, "%0.1f", &s_bModified);
		pxTabs->AddDialog(pxNewDialog);		
		xOffset.y += Asura_Dialog::DefaultSpacing();	

		pxNewDialog = new Asura_Numerical_Dialog("FadeOut Duration (secs)",xOffset, &pxMtl->m_fFadeOutLength, 0.0f, 100.0f, 0.1f, "%0.1f", &s_bModified);
		pxTabs->AddDialog(pxNewDialog);		
		xOffset.y += Asura_Dialog::LargeSpacing();	

		// STATIC DECAL PARAMS
		pxNewDialog = new Asura_Dialog("Static Decal parameters",xOffset);
		pxTabs->AddDialog(pxNewDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();				
	
		pxNewDialog = new Asura_Tickbox_Dialog("Back-face Culling",		xOffset, &pxMtl->m_bStaticDecalBackFaceCull, &s_bModified);
		pxTabs->AddDialog(pxNewDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();				
		
		pxNewDialog = new Asura_Tickbox_Dialog("Back-face Projection",  xOffset, &pxMtl->m_bStaticDecalBackFaceProject, &s_bModified);
		pxTabs->AddDialog(pxNewDialog);
		xOffset.y += Asura_Dialog::LargeSpacing();				
		
		pxNewDialog = new Asura_Dialog("UV Scrolling", xOffset);
		pxTabs->AddDialog( pxNewDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();				
		pxNewDialog = new Asura_Numerical_Dialog("U Speed", xOffset, &pxMtl->m_fUScrollSpeed , 0.0f, 99.0f, 0.01f, "%0.02f", &s_bModified);
		pxTabs->AddDialog( pxNewDialog);
		xOffset.x += 24.0f;				
		pxNewDialog = new Asura_Numerical_Dialog("U Range", xOffset, &pxMtl->m_fUScrollRange , 0.0f, 5.0f, 0.001f, "%0.03f", &s_bModified);
		pxTabs->AddDialog( pxNewDialog);				
		xOffset.x -= 24.0f;				
		xOffset.y += Asura_Dialog::DefaultSpacing();				
		pxNewDialog = new Asura_Numerical_Dialog("V Speed", xOffset, &pxMtl->m_fVScrollSpeed , 0.0f, 99.0f, 0.01f, "%0.02f", &s_bModified);
		pxTabs->AddDialog( pxNewDialog);				
		xOffset.x += 24.0f;				
		pxNewDialog = new Asura_Numerical_Dialog("V Range", xOffset, &pxMtl->m_fVScrollRange , 0.0f, 5.0f, 0.001f, "%0.03f", &s_bModified);
		pxTabs->AddDialog( pxNewDialog);
		xOffset.x -= 24.0f;						
		xOffset.y += Asura_Dialog::LargeSpacing();				

		
		pxNewDialog = new Asura_Tickbox_Dialog("Export as Static Decal (textures into level .asr, only when used)",	xOffset, &pxMtl->m_bExportAsStaticDecal, &s_bModified);
		pxTabs->AddDialog(pxNewDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();				
		
#ifdef ASURA_DECAL_MANAGER_USE_COMMON_ASR
		pxNewDialog = new Asura_Dialog("(Decal definitions go in common.asr - remember to export it)", xOffset);
		pxTabs->AddDialog(pxNewDialog);
		xOffset.y += Asura_Dialog::DefaultSpacing();				
#endif

	}


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

	// Add the decal set section
	// ------------------------------------------------------------------------------------
	pxTabs->SelectTab(1);
	xOffset.y = fTabTopY;

	pxNewDialog = new Asura_Dialog("Decal Set:", xOffset);
	pxTabs->AddDialog(pxNewDialog);

	int iNumSets = Asura_Decal_Manager::GetNumDecalSets();
	xOffset.x+= 10;
	pxNewDialog = new Asura_DropDown_List_Dialog(xOffset, s_pszDecalSetNameList, &s_iEditingSet, iNumSets+1, iNumSets+1, SelectedDecalSetChanged, NULL );	
	pxTabs->AddDialog(pxNewDialog);
	
	xOffset.x+= 20;	
	// Add/Del buttons
	pxNewDialog = new Asura_Function_Dialog("Add", xOffset, AddDecalSet);
	pxTabs->AddDialog(pxNewDialog);
	xOffset.x+= 10;
	if (Asura_Decal_Manager::GetNumDecalMaterials()>0)
	{
		pxNewDialog = new Asura_Function_Dialog("Remove", xOffset, RemoveDecalSet);
		pxTabs->AddDialog(pxNewDialog);
	}
	xOffset.x -= 40;
	xOffset.y += Asura_Dialog::LargeSpacing();


	// Set properties
	if (s_iEditingSet>0)
	{	
		Asura_DecalManager_DecalSet *pxSet = Asura_Decal_Manager::GetDecalSetByIndex(s_iEditingSet-1);
		
		// Find the matching material, from it's name hash
		s_iSetMaterialIndex = 0;
		for(int i=0;i<iNumMaterials;i++)
		{
			if (pxSet->m_uMtlNameHash == Asura_Decal_Manager::GetDecalMaterialByIndex(i)->m_uMtlNameHash)
			{			
				s_iSetMaterialIndex = i+1;
			}
		}

		// Find the material index for the current set
		pxNewDialog = new Asura_Dialog("Material Used:", xOffset);
		pxTabs->AddDialog(pxNewDialog);
		xOffset.x += 10;
		pxNewDialog = new Asura_DropDown_List_Dialog(xOffset, s_pszMaterialNameList, &s_iSetMaterialIndex, iNumMaterials+1, iNumMaterials+1, FinishUVEdit, &s_bModified );			
		pxTabs->AddDialog(pxNewDialog);		
		xOffset.x -= 10;
		xOffset.y += Asura_Dialog::DefaultSpacing();

		

		// Num decals in set
		if (s_iSelectedDecalIndex>=pxSet->m_iNumDecals)
		{
			s_iSelectedDecalIndex = pxSet->m_iNumDecals-1;
			if (s_iSelectedDecalIndex<0)
			{
				s_iSelectedDecalIndex=0;
			}
		}

		s_iReqestedNumDecalTypes = pxSet->m_iNumDecals;
		pxNewDialog = new Asura_Numerical_Dialog("Number of Decal Types", xOffset,  &s_iReqestedNumDecalTypes, 0, 32, 1,"%d",&s_bNumDecalTypesChanged);
		pxTabs->AddDialog(pxNewDialog);		
		xOffset.y += Asura_Dialog::LargeSpacing();

		if (pxSet->m_iNumDecals>0 && s_iSelectedDecalIndex<=pxSet->m_iNumDecals)
		{
			pxNewDialog = new Asura_Numerical_Dialog("Selected Decal Type", xOffset,  &s_iSelectedDecalIndex, 0, pxSet->m_iNumDecals, 1,"%d", &s_bCurrentDecalTypeChanged);
			pxTabs->AddDialog(pxNewDialog);		
			xOffset.y += Asura_Dialog::LargeSpacing();
			
			pxNewDialog = new Asura_Numerical_Dialog("Decal Width (metres)",xOffset, &pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fWidth, 0.0f, 10.0f, 0.01f, "%0.02f", &s_bModified);
			pxTabs->AddDialog(pxNewDialog);		
			xOffset.y += Asura_Dialog::DefaultSpacing();	

			pxNewDialog = new Asura_Numerical_Dialog("Decal Height (metres)",xOffset, &pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fHeight, 0.0f, 10.0f, 0.01f, "%0.02f", &s_bModified);
			pxTabs->AddDialog(pxNewDialog);		
			xOffset.y += Asura_Dialog::DefaultSpacing();	

			pxNewDialog = new Asura_FlagTickbox_Dialog("U Flipped",xOffset, &pxSet->m_pxDecals[s_iSelectedDecalIndex].m_iFlags, ASURA_DECALMANAGER_FLAG_UFLIP, &s_bModified);
			pxTabs->AddDialog(pxNewDialog);
			xOffset.y += Asura_Dialog::DefaultSpacing();	

			pxNewDialog = new Asura_FlagTickbox_Dialog("V Flipped",xOffset, &pxSet->m_pxDecals[s_iSelectedDecalIndex].m_iFlags, ASURA_DECALMANAGER_FLAG_VFLIP, &s_bModified);
			pxTabs->AddDialog(pxNewDialog);			
			xOffset.y += Asura_Dialog::DefaultSpacing();	

			pxNewDialog = new Asura_Tickbox_Dialog("Random Orientation", xOffset, &pxSet->m_bRandomOrientation, &s_bModified);
			pxTabs->AddDialog(pxNewDialog);			
			xOffset.y += Asura_Dialog::DefaultSpacing();

			pxNewDialog = new Asura_Function_Dialog("Edit UVs", xOffset, StartUVEdit);
			pxTabs->AddDialog(pxNewDialog);					
			xOffset.y += Asura_Dialog::LargeSpacing();	

			pxNewDialog = new Asura_Function_Dialog("Place Test Decal",xOffset, PlaceTestDecal);
			pxTabs->AddDialog(pxNewDialog);		
			xOffset.y += Asura_Dialog::DefaultSpacing();	
		}
	}

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

	
	xOffset.y = pxTabs->GetMaxCoords().y + Asura_Dialog::DefaultSpacing();	
	pxNewDialog = new Asura_Function_Dialog("Close", xOffset, Close);	
	pxNewOverlay->AddDialog(pxNewDialog);

	pxTabs->SelectTab(s_iTab);
	Asura_Overlay_System::SubmitNewOverlay(pxNewOverlay, false);
}


void Tools_Overlay_Decals::AddDecalMaterial()
{		
	GetString_Overlay overlay("Enter name for the new decal material","");
	if(!overlay.DoModal()) return;
	if(!overlay.GetString()) return;
	Asura_String xName = overlay.GetString();	

	if (xName=="") return;

	Asura_Decal_Manager::AddDecalMaterial(xName);

	// Select the new one
	s_iEditingMaterial = Asura_Decal_Manager::GetNumDecalMaterials();

	SelectedMaterialChanged();	
}


void Tools_Overlay_Decals::RemoveDecalMaterial()
{
	if (s_iEditingMaterial>0)
	{			
		Asura_Decal_Manager::RemoveDecalMaterial(s_iEditingMaterial-1);
		s_iEditingMaterial=0;

		SelectedMaterialChanged();	
	}
}


void Tools_Overlay_Decals::AddDecalSet()
{	
	GetString_Overlay overlay("Enter name for the new decal set","");
	if(!overlay.DoModal()) return;
	if(!overlay.GetString()) return;		
	Asura_String xName = overlay.GetString();	

	if (xName=="") return;

	Asura_Decal_Manager::AddDecalSet(xName);

	// Select the new one
	s_iEditingSet = Asura_Decal_Manager::GetNumDecalSets();

	SelectedDecalSetChanged();	
}


void Tools_Overlay_Decals::RemoveDecalSet()
{
	if (s_iEditingSet>0)
	{	
		Asura_Decal_Manager::RemoveDecalSet(s_iEditingSet-1);
		s_iEditingSet=0;

		SelectedDecalSetChanged();	
	}
}


void Tools_Overlay_Decals::SelectedMaterialChanged(void)
{
	FinishUVEdit();
	RefreshOverlay();	
}


void Tools_Overlay_Decals::SelectedDecalSetChanged(void)
{
	FinishUVEdit();
	s_iSelectedDecalIndex = 0;
	RefreshOverlay();		
}


void Tools_Overlay_Decals::RefreshOverlay(void)
{
	// Re-create the overlay
	if (s_pxTabs)
	{
		s_iTab = s_pxTabs->GetSelected();
	}
	Asura_Overlay_System::CloseOverlays( TOOLS_OVERLAY_DECALS );
	CreateOverlay();

	if (s_pxTabs)
	{
		s_pxTabs->SelectTab(s_iTab);
	}
}


#if defined(ASURA_TARGET_SM3)
void Tools_Overlay_Decals::ClearDecalTexture(int i)
{
//	Asura_DecalManager_Material *pxMtl = Asura_Decal_Manager::GetDecalMaterialByIndex(s_iEditingMaterial-1);

	FinishUVEdit();
	RefreshOverlay();		
}


void Tools_Overlay_Decals::ChangeDecalTexture(int i)
{
	char *aszNames[3]= {"Select Texture", "Select Normal Map", "Select Specular Map"};

	Asura_String *pxName = NULL;
//	Asura_DecalManager_Material *pxMtl = Asura_Decal_Manager::GetDecalMaterialByIndex(s_iEditingMaterial-1);

	if (pxName==NULL)
	{
		return;
	}

	int iTextureID = Asura_Texture_Management::GetIndexFromHashID(Asura_GetHashID_IgnoreExtension(pxName->GetString()));

	int iSelected = Tools_PickTexture::PickTexture(aszNames[i], iTextureID,PICKTEXTURE_ALLTEXTURES);

	if ( iSelected != ASURA_TEXTURE_NONE && iSelected != iTextureID )
	{				
		*pxName = *Asura_Texture_Management::GetTextureName(iSelected);		
		FinishUVEdit();
		RefreshOverlay();		
	}
}
#else

void Tools_Overlay_Decals::ClearDecalTexture()
{
	Asura_DecalManager_Material *pxMtl = Asura_Decal_Manager::GetDecalMaterialByIndex(s_iEditingMaterial-1);

	pxMtl->m_xTextureName = "";
	
	FinishUVEdit();
	RefreshOverlay();		
}

void Tools_Overlay_Decals::ChangeDecalTexture()
{
	char *szName= {"Select Texture"};

	Asura_String *pxName = NULL;
	Asura_DecalManager_Material *pxMtl = Asura_Decal_Manager::GetDecalMaterialByIndex(s_iEditingMaterial-1);

	pxName = &pxMtl->m_xTextureName;

	if (pxName==NULL)
	{
		return;
	}

	int iTextureID = Asura_Texture_Management::GetIndexFromHashID(Asura_GetHashID_IgnoreExtension(pxName->GetString()));

	int iSelected = Tools_PickTexture::PickTexture(szName, iTextureID,PICKTEXTURE_ALLTEXTURES);

	if ( iSelected != ASURA_TEXTURE_NONE && iSelected != iTextureID )
	{				
		*pxName = *Asura_Texture_Management::GetTextureName(iSelected);		
		FinishUVEdit();
		RefreshOverlay();		
	}
}
#endif


///////////////////
// ToggleOverlay //
///////////////////
void Tools_Overlay_Decals::ToggleOverlay()
{
	s_bUpdated = true;
	s_bIsOpen = !s_bIsOpen;

	if (IsOpen())
	{
		CreateOverlay();
	}
	else
	{
		Close();
	}
}


void Tools_Overlay_Decals::Close(void)
{
	FinishUVEdit();
	ReleaseNameLists();
	

	Asura_Overlay_System::CloseOverlays( TOOLS_OVERLAY_DECALS);

	Asura_Decal_Manager::RebuildTemplates();

	s_bIsOpen = false;
}


bool Tools_Overlay_Decals::SaveDecalTemplates()
{
	return Asura_Chunk_Decals::Save( g_szDecalsToolsFile );	
}


void Tools_Overlay_Decals::Render(void)
{
	if(s_bIsOpen)
	{
		if (s_pxUVEditor)
		{		
			s_pxUVEditor->Render();
		}
		else if (s_pxTabs)
		{
			// If on the materials tab, show the material textures
			if (s_pxTabs->GetSelected()==0)
			{
				if (s_iEditingMaterial>0)
				{
					Asura_DecalManager_Material *pxMtl = Asura_Decal_Manager::GetDecalMaterialByIndex(s_iEditingMaterial-1);
					
					float fWidth  = 192;
					float fHeight = 192;
					int iTexIndex;
											
					Asura_Render::Overlay.Colour = 0xffffffff;
					Asura_Render::Overlay.SetRectUV(0,0,1,1);
					Asura_Render::Overlay.TranslucencyMode = ASURA_TRANSLUCENCY_OFF;

#if !defined(ASURA_TARGET_SM3)

					iTexIndex = Asura_Texture_Management::GetIndexFromHashID(Asura_GetHashID_IgnoreExtension(pxMtl->m_xTextureName.GetString()));					
					if ( iTexIndex != ASURA_TEXTURE_NONE )
					{
						Asura_Render::Overlay.TextureIndex = iTexIndex;
						Asura_Render::Overlay.SetRectXY(Asura_Viewport::GetWidth()-fWidth,
														Asura_Viewport::GetHeight()-(3.15f*fHeight),
														fWidth, fHeight);		
						Asura_Render::Overlay.Render();					
					}

#else
					const Tools_MaterialResponse* pxMaterial = Tools_MaterialResponse_System::GetMaterialByHashID(pxMtl->m_uMaterialResponseHash);
					if(pxMaterial)
					{
						iTexIndex = pxMaterial->GetTexture(Asura_MaterialResponse::ALBEDO_TEXTURE);
						if ( iTexIndex != ASURA_TEXTURE_NONE )
						{
							Asura_Render::Overlay.TextureIndex = iTexIndex;
							Asura_Render::Overlay.SetRectXY(Asura_Viewport::GetWidth()-fWidth,
								Asura_Viewport::GetHeight()-(3.15f*fHeight),
								fWidth, fHeight);		
							Asura_Render::Overlay.Render();					
						}
						iTexIndex = pxMaterial->GetTexture(Asura_MaterialResponse::NORMAL_MAP);
						if ( iTexIndex != ASURA_TEXTURE_NONE )
						{
							Asura_Render::Overlay.TextureIndex = iTexIndex;
							Asura_Render::Overlay.SetRectXY(Asura_Viewport::GetWidth()-fWidth,
								Asura_Viewport::GetHeight()-(2.1f*fHeight),
								fWidth, fHeight);		
							Asura_Render::Overlay.Render();					
						}
						iTexIndex = pxMaterial->GetTexture(Asura_MaterialResponse::SPECULAR_MAP);
						if ( iTexIndex != ASURA_TEXTURE_NONE )
						{
							Asura_Render::Overlay.TextureIndex = iTexIndex;
							Asura_Render::Overlay.SetRectXY(Asura_Viewport::GetWidth()-fWidth,
								Asura_Viewport::GetHeight()-(fHeight),
								fWidth, fHeight);		
							Asura_Render::Overlay.Render();					
						}
					}
#endif //defined(ASURA_TARGET_SM3)
				}
			}				
			else
			{
				if (s_iEditingSet>0)
				{				
					Asura_DecalManager_DecalSet *pxSet = Asura_Decal_Manager::GetDecalSetByIndex(s_iEditingSet-1);
					Asura_DecalManager_Material *pxMtl = Asura_Decal_Manager::GetMaterial(pxSet->m_uMtlNameHash);

					if (pxMtl)
					{					
						float fWidth  = 256;
						float fHeight = 256;

						// Render the whole texture
						Asura_Render::Overlay.Colour = 0xffffffff;
						Asura_Render::Overlay.SetRectUV(0,0,1,1);
						Asura_Render::Overlay.TranslucencyMode = ASURA_TRANSLUCENCY_OFF;

#if !defined(ASURA_TARGET_SM3)
						Asura_Render::Overlay.TextureIndex = Asura_Texture_Management::GetIndexFromHashID(Asura_GetHashID_IgnoreExtension(pxMtl->m_xTextureName.GetString()));
#else
						const Tools_MaterialResponse* pxMaterial = Tools_MaterialResponse_System::GetMaterialByHashID(pxMtl->m_uMaterialResponseHash);
						Asura_Render::Overlay.TextureIndex = pxMaterial ?pxMaterial ->GetTexture(Asura_MaterialResponse::ALBEDO_TEXTURE) : ASURA_TEXTURE_NONE;
#endif
						Asura_Render::Overlay.SetRectXY((Asura_Viewport::GetWidth()-fWidth)-2.0f,
														(Asura_Viewport::GetHeight()-fHeight)-2.0f,
														fWidth, fHeight);
						Asura_Render::Overlay.Render();					

						// Darken it
						Asura_Render::Overlay.TranslucencyMode = ASURA_TRANSLUCENCY_NORMAL;
						Asura_Render::Overlay.TextureIndex = ASURA_TEXTURE_NONE;
						Asura_Render::Overlay.Colour = 0x90808080;
						Asura_Render::Overlay.Render();			
						Asura_Render::FlushDisplay();

						// Now show the used areas
#if !defined(ASURA_TARGET_SM3)
						Asura_Render::Overlay.TextureIndex = Asura_Texture_Management::GetIndexFromHashID(Asura_GetHashID_IgnoreExtension(pxMtl->m_xTextureName.GetString()));
#else
						Asura_Render::Overlay.TextureIndex = pxMaterial ? pxMaterial ->GetTexture(Asura_MaterialResponse::ALBEDO_TEXTURE) : ASURA_TEXTURE_NONE;
#endif
						Asura_Render::Overlay.Colour = 0xffffffff;
						Asura_Render::Overlay.TranslucencyMode = ASURA_TRANSLUCENCY_OFF;

						for(int i=0; i<pxSet->m_iNumDecals; i++)
						{
							Asura_DecalManager_Decal *pxDecal = &pxSet->m_pxDecals[i];
						
							float fX = (Asura_Viewport::GetWidth()-fWidth)   + (fWidth * pxDecal->m_fU)  -2.0f;
							float fY = (Asura_Viewport::GetHeight()-fHeight) + (fHeight * pxDecal->m_fV) -2.0f;
							float fW = fWidth * pxDecal->m_fDeltaU;
							float fH = fHeight * pxDecal->m_fDeltaV;
							
							Asura_Render::Overlay.SetRectXY(fX,fY,fW,fH);														
							Asura_Render::Overlay.SetRectUV(pxDecal->m_fU, pxDecal->m_fV, pxDecal->m_fDeltaU, pxDecal->m_fDeltaV);
							Asura_Render::Overlay.Render();		

							uint32 uColour = 0xff888888;

							if (i == s_iSelectedDecalIndex)
							{
								uColour = 0xffffffff;
							}
							
							Asura_Render::Render2DLine(Asura_Vector_2(fX,fY),Asura_Vector_2(fX+fW,fY), uColour);
							Asura_Render::Render2DLine(Asura_Vector_2(fX+fW,fY),Asura_Vector_2(fX+fW,fY+fH), uColour);
							Asura_Render::Render2DLine(Asura_Vector_2(fX+fW,fY+fH),Asura_Vector_2(fX,fY+fH), uColour);
							Asura_Render::Render2DLine(Asura_Vector_2(fX,fY+fH),Asura_Vector_2(fX,fY), uColour);
						}		
					}
				}
			}		
		}
	}
}








void Tools_Overlay_Decals::StartUVEdit(void)
{	
	Asura_DecalManager_DecalSet *pxSet = Asura_Decal_Manager::GetDecalSetByIndex(s_iEditingSet-1);

	if (!pxSet)
	{
		return;
	}

	if (pxSet->m_iNumDecals==0)
	{		
		return;
	}

	Asura_DecalManager_Material *pxMtl = Asura_Decal_Manager::GetMaterial(pxSet->m_uMtlNameHash);
	
	if (!pxMtl)
	{
		return;
	}

	if(s_pxUVEditor)
	{
		// Make this function work as a toggle
		FinishUVEdit();
		return;
	}

	// Stop object system mouse controls interfering
	Tools_Object_System::EnableAllControls(false);

	// Create the UV editor
	s_pxUVEditor = new Tools_UV_Editor;
#if !defined(ASURA_TARGET_SM3)
	s_pxUVEditor->SetTextureID(Asura_Texture_Management::GetIndexFromHashID(Asura_GetHashID_IgnoreExtension(pxMtl->m_xTextureName.GetString())));
#else
	const Tools_MaterialResponse* pxMaterial = Tools_MaterialResponse_System::GetMaterialByHashID(pxMtl->m_uMaterialResponseHash);
	s_pxUVEditor->SetTextureID(pxMaterial ? pxMaterial ->GetTexture(Asura_MaterialResponse::ALBEDO_TEXTURE) : ASURA_TEXTURE_NONE);
#endif


	// Init the uv coordinates
	int i = s_iSelectedDecalIndex;
	s_pxUVEditor->Nodes[0].x = pxSet->m_pxDecals[i].m_fU;
	s_pxUVEditor->Nodes[0].y = pxSet->m_pxDecals[i].m_fV;
	s_pxUVEditor->Nodes[1].x = pxSet->m_pxDecals[i].m_fU + pxSet->m_pxDecals[i].m_fDeltaU;
	s_pxUVEditor->Nodes[1].y = pxSet->m_pxDecals[i].m_fV;
	s_pxUVEditor->Nodes[2].x = pxSet->m_pxDecals[i].m_fU + pxSet->m_pxDecals[i].m_fDeltaU;
	s_pxUVEditor->Nodes[2].y = pxSet->m_pxDecals[i].m_fV + pxSet->m_pxDecals[i].m_fDeltaV;
	s_pxUVEditor->Nodes[3].x = pxSet->m_pxDecals[i].m_fU;
	s_pxUVEditor->Nodes[3].y = pxSet->m_pxDecals[i].m_fV + pxSet->m_pxDecals[i].m_fDeltaV;

	s_pxUVEditor->CreateMouseModeOverlay();

}							  


void Tools_Overlay_Decals::FinishUVEdit(void)
{
	if(s_pxUVEditor)
	{
		s_pxUVEditor->CloseMouseModeOverlay();
		delete s_pxUVEditor;
		s_pxUVEditor = 0;
		Tools_Object_System::EnableAllControls(true);
	}
}

void Tools_Overlay_Decals::UpdateUVEdit(void)
{
	if(!s_pxUVEditor) return;
	
	Asura_DecalManager_DecalSet *pxSet = Asura_Decal_Manager::GetDecalSetByIndex(s_iEditingSet-1);

	if (pxSet->m_iNumDecals==0)
	{
		FinishUVEdit();
		return;
	}

	s_pxUVEditor->HandleMouse();

	if(s_pxUVEditor->NodesMoved)
	{

		//make sure the nodes stay in rectangular formation
		s_pxUVEditor->EnsureNodesAreStillOkayForTextureWrap();

		s_pxUVEditor->Nodes[1].x = s_pxUVEditor->Nodes[2].x;
		s_pxUVEditor->Nodes[1].y = s_pxUVEditor->Nodes[0].y;
		s_pxUVEditor->Nodes[3].x = s_pxUVEditor->Nodes[0].x;
		s_pxUVEditor->Nodes[3].y = s_pxUVEditor->Nodes[2].y;

		s_pxUVEditor->NodesMoved = false;

		
		pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fU = s_pxUVEditor->Nodes[0].x; 
		pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fV = s_pxUVEditor->Nodes[0].y; 
		pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fDeltaU = s_pxUVEditor->Nodes[2].x-s_pxUVEditor->Nodes[0].x; 
		pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fDeltaV = s_pxUVEditor->Nodes[2].y-s_pxUVEditor->Nodes[0].y; 
	}
	else
	{
		//make sure the uv coordinates being edited match those on the overlay
		s_pxUVEditor->Nodes[0].x = pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fU;
		s_pxUVEditor->Nodes[0].y = pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fV;
		s_pxUVEditor->Nodes[1].x = pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fU+pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fDeltaU;
		s_pxUVEditor->Nodes[1].y = pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fV;
		s_pxUVEditor->Nodes[2].x = pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fU+pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fDeltaU;
		s_pxUVEditor->Nodes[2].y = pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fV+pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fDeltaV;
		s_pxUVEditor->Nodes[3].x = pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fU;
		s_pxUVEditor->Nodes[3].y = pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fV+pxSet->m_pxDecals[s_iSelectedDecalIndex].m_fDeltaV;

	}
}



void Tools_Overlay_Decals::PlaceTestDecal()
{
	// Rebuild the templates (this will reset the decal system, removing any existing decals)
	Asura_Decal_Manager::RebuildTemplates();

	// Place a decal, using camera pos/dir
	Asura_Vector_3 xPos   = *Asura_Camera::GetPosition();
	Asura_Vector_3 xLOSDir;
	Asura_Camera::GetForwardVector(xLOSDir);

	const Asura_LOS_InputData		xInput =Asura_LOS_InputData(xPos, xLOSDir ,ASURA_GUID_UNREGISTERED, 50.0f);					
	const Asura_LOS_OutputData		*pxOutput = Asura_LOS::TestAgainstEnvironment( &xInput );

	if (pxOutput->m_bHitEnvironment)
	{
		Asura_DecalManager_DecalSet *pxSet = Asura_Decal_Manager::GetDecalSetByIndex(s_iEditingSet-1);
		int iTemplate = pxSet->m_iFirstAsuraDecalTemplate + s_iSelectedDecalIndex;

		Asura_Vector_3 xHit = xPos+ (xLOSDir*pxOutput->m_fDistanceToIntersection);
		Asura_Decal_System::AddDecal(xHit,pxOutput->m_xNormal,iTemplate,1.0f,Asura_Random::GetFloat(0,6.284f));
	}	
}


#endif //#ifdef ASURA_USE_DECAL_MANAGER