/**
*
* \file Tools_Mode_BillboardPlants.cpp
*
* Created by Andrew Weinkove - 05/12/2002
*
* Copyright (C) 2002 Rebellion, All Rights Reserved.
*
**/


#include "Core/Asura.h"
#include "BillboardPlants/Tools_Mode_BillboardPlants.h"
#include "SpecialFX/Asura_BillboardPlant_TemplateStore.h"
#include "SpecialFX/Asura_BillboardPlant_System.h"
#include "SpecialFX/Asura_BillboardPlant_Batch.h"
#include "Camera/Asura_Camera.h"
#include "Interface/Asura_Dialog.h"
#include "Rendering/Asura_Direct3D.h"
#include "Rendering/Asura_Direct3D_Shaders.h"
#include "Core/Asura_LOS.h"
#include "Interface/Asura_Menubar_System.h"
#include "Interface/Asura_Menubar.h"
#include "Mesh/Asura_Mesh_System.h"
#include "Rendering/Asura_Module.h"
#include "Core/Asura_NameTree.h"
#include "Interface/Asura_Overlay.h"
#include "Interface/Asura_Overlay_System.h"
#include "Rendering/Asura_Render.h"
#include "Core/Asura_UserInput.h"
#include "Misc/Tools_Timed_Messages.h"
#include "Misc/Tools_Modal_Overlay.h"
#include "Tools_Overlays.h"
#include "Objects/Tools_Object_System.h"
#include "Texturing/Tools_PickTexture.h"
#include "Texturing/Tools_Texturing_Find.h"
#include "Misc/Tools_LOS.h"
#include "BillboardPlants/Tools_BillboardPlant_Object.h"
#include "BillboardPlants/Tools_BillboardPlant_Scatter.h"
#include "Load&Save/Tools_SaveAsura.h"

#ifdef ASURA_USE_BILLBOARD_PLANTS
//static member variables
bool							Tools_Mode_BillboardPlants::s_bPlantEditOverlayOpen = false;
bool							Tools_Mode_BillboardPlants::s_bScatterOverlayOpen = true;
bool							Tools_Mode_BillboardPlants::s_bPlantPlacementOverlayOpen = false;
Asura_Vector_2					Tools_Mode_BillboardPlants::s_xPlantEditOverlayPosition = Asura_Vector_2(1.0f, 15.0f);
Asura_Vector_2					Tools_Mode_BillboardPlants::s_xScatterOverlayPosition = Asura_Vector_2(1.0f, 20.0f);
Asura_Vector_2					Tools_Mode_BillboardPlants::s_xPlantPlacementOverlayPosition = Asura_Vector_2(15.0f, 15.0f);
Asura_Handle					Tools_Mode_BillboardPlants::s_iMenuHandle;
Asura_BillboardPlant_Template *	Tools_Mode_BillboardPlants::s_pxCurrentTemplate;
bool							Tools_Mode_BillboardPlants::s_bViewMaxDistortion = false;
bool							Tools_Mode_BillboardPlants::s_bKeepInFrontOfCamera = true;
Asura_Vector_3					Tools_Mode_BillboardPlants::s_xCamPosForPlantRender;
Asura_Matrix_3x3				Tools_Mode_BillboardPlants::s_xOriForPlantRender;
unsigned						Tools_Mode_BillboardPlants::s_uPlantPlacementSelection = 0xffffffff;
unsigned						Tools_Mode_BillboardPlants::s_uPlantScatterSelection = 0xffffffff;
float							Tools_Mode_BillboardPlants::s_fNumberToScatter = 50.0f;
float							Tools_Mode_BillboardPlants::s_fScatterClumpiness = 0.5f;
bool							Tools_Mode_BillboardPlants::s_bTestForCollisions = false;

void Tools_Mode_BillboardPlants::Initialise(void)
{
	//Initalise polygon selection
	Tools_Polygon_Selection::Activate();

	//create the menubar
	s_iMenuHandle = Asura_Menubar_System::CreateMenuSection();
	Asura_Menubar_Title* title;

	title = Asura_Menubar_System::AddTitle(s_iMenuHandle,"Overlays");
	title->AddItem("Plant Edit",Tools_Mode_BillboardPlants::TogglePlantEditOverlay,Tools_Mode_BillboardPlants::PlantEditOverlayIsOn);
	title->AddItem("Scatter", Tools_Mode_BillboardPlants::ToggleScatterOverlay, Tools_Mode_BillboardPlants::ScatterOverlayIsOn);
	title->AddItem("Plant placement", Tools_Mode_BillboardPlants::TogglePlantPlacementOverlay, Tools_Mode_BillboardPlants::PlantPlacementOverlayIsOn);
	title->AddItem("Selection",Tools_Polygon_Selection::ToggleSelectionOverlay,Tools_Polygon_Selection::SelectionOverlayIsOn);
	title->AddItem("Find",Tools_Texturing_Find::ToggleFindOverlay,Tools_Texturing_Find::FindOverlayIsOn);

	s_pxCurrentTemplate = NULL;
	//create overlays
	CreatePlantEditOverlay();
	CreateScatterOverlay();
	CreatePlantPlacementOverlay();
	CreateToolsObjects();
	RemoveBillboardBatches();
	Tools_Object_System::EnableAllControls(true);
}

void Tools_Mode_BillboardPlants::Shutdown(void)
{
	Tools_BillboardPlant_Scatter::Reject();
	SaveTemplates();
	CreateBillboardBatches();
	RemoveToolsObjects();
	Tools_Polygon_Selection::Deactivate();

	//shutdown the menu
	if(s_iMenuHandle != ASURA_INVALID_HANDLE)
	{
		Asura_Menubar_System::DestroyMenuSection(s_iMenuHandle);
		s_iMenuHandle = ASURA_INVALID_HANDLE;
	}

	//close overlays
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_MODE);
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_PLANTEDIT);
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_PLANTPLACEMENT);
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_PLANTSCATTER);
	Tools_Object_System::EnableAllControls(false);
}

void Tools_Mode_BillboardPlants::PreSave()
{
	CreateBillboardBatches();
	RemoveToolsObjects();
}

void Tools_Mode_BillboardPlants::QuickSave(void)
{
	Tools_SaveAsura::SaveBillboardPlants();
	SaveTemplates();
}


void Tools_Mode_BillboardPlants::PostSave()
{
	CreateToolsObjects();
	RemoveBillboardBatches();
}


void Tools_Mode_BillboardPlants::Update(void)
{
	// Temp hack to make sure no data is lost.
	Tools_SaveAsura::SetBillboardPlantsModified();
	Tools_Polygon_Selection::Update();
	
	//act upon keyboard input
	Tools_Mode_BillboardPlants::HandleKeyboard();
}

void Tools_Mode_BillboardPlants::Render(void)
{
	Tools_Polygon_Selection::Render();
	if (PlantEditOverlayIsOn() &&
		GetCurrentTemplate())
	{
		RenderPlant();
	}
}

void Tools_Mode_BillboardPoints::RenderUI()
{
	Tools_Polygon_Selection::RenderUI();
}

void Tools_Mode_BillboardPlants::HandleKeyboard()
{
	if(Asura_Overlay_System::OverlaysHaveKeyboardFocus()) return;

	if (Asura_UserInput::KeyPressed(ASURA_KEYID_CTRL))
	{
		if (PlantPlacementOverlayIsOn() &&
			Asura_UserInput::DebouncedKeyPressed('c'))
		{
			int iPolyIndex;
			int iModuleIndex;
			Asura_Vector_3 xPosition;
			if(Tools_LOS::FindPolyAndPositionUnderCursor(iPolyIndex,iModuleIndex,xPosition))	
			{
				new Tools_BillboardPlant_Object(xPosition, s_uPlantPlacementSelection);
			}
		}
		if (PlantPlacementOverlayIsOn() &&
			Asura_UserInput::DebouncedKeyPressed('t'))
		{
			SelectAllOfType();
		}
		if (PlantPlacementOverlayIsOn() &&
			Asura_UserInput::DebouncedKeyPressed('p'))
		{
			SelectAllPlants();
		}
	}
}


void Tools_Mode_BillboardPlants::TogglePlantEditOverlay(void)
{
	s_bPlantEditOverlayOpen = !s_bPlantEditOverlayOpen;

	if (s_bPlantEditOverlayOpen)
	{
		CreatePlantEditOverlay();
	}
	else
	{
		Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_PLANTEDIT);
	}
}

void Tools_Mode_BillboardPlants::ToggleScatterOverlay()
{
	s_bScatterOverlayOpen = !s_bScatterOverlayOpen;

	if (s_bScatterOverlayOpen)
	{
		CreateScatterOverlay();
	}
	else
	{
		Tools_BillboardPlant_Scatter::Reject();
		Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_PLANTSCATTER);
	}
}

void Tools_Mode_BillboardPlants::TogglePlantPlacementOverlay(void)
{
	s_bPlantPlacementOverlayOpen = !s_bPlantPlacementOverlayOpen;

	if (s_bPlantPlacementOverlayOpen)
	{
		CreatePlantPlacementOverlay();
	}
	else
	{
		Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_PLANTPLACEMENT);
	}
}

bool Tools_Mode_BillboardPlants::PlantEditOverlayIsOn(void)
{
	return s_bPlantEditOverlayOpen;
}


bool Tools_Mode_BillboardPlants::ScatterOverlayIsOn(void)
{
	return s_bScatterOverlayOpen;
}

bool Tools_Mode_BillboardPlants::PlantPlacementOverlayIsOn()
{
	return s_bPlantPlacementOverlayOpen;
}

void Tools_Mode_BillboardPlants::CreatePlantEditOverlay(void)
{
	if(!s_bPlantEditOverlayOpen) return;

	Asura_Overlay* newOverlay;
	newOverlay = new Asura_Overlay("Plant Edit",false,&s_xPlantEditOverlayPosition);
	Asura_Dialog* newDialog;
	Asura_Vector_2 offset = Asura_Vector_2(1.0f,3.0f);
			
	char szText[255];
	if(!GetCurrentTemplate())
		strcpy(szText,"Current Selection : *Not Set*");
	else
		sprintf(szText,"Current Selection : %s",GetCurrentTemplate()->m_szTemplateName);
	newDialog = new Asura_Function_Dialog(szText,offset,ChangeSelection);
	newOverlay->AddDialog(newDialog);
	offset.y+=Asura_Dialog::DefaultSpacing();
	
	newDialog = new Asura_Function_Dialog("Create new type",offset,Tools_Mode_BillboardPlants::CreateNewTemplate);
	newOverlay->AddDialog(newDialog);
	offset.y+=Asura_Dialog::DefaultSpacing();

	if (GetCurrentTemplate())
	{
		newDialog = new Asura_Function_Dialog("Delete current",offset,Tools_Mode_BillboardPlants::DeleteCurrentTemplate);
		newOverlay->AddDialog(newDialog);
		offset.y+=Asura_Dialog::DefaultSpacing();

		newDialog = new Asura_Function_Dialog("Rename",offset,Tools_Mode_BillboardPlants::RenameCurrentTemplate);
		newOverlay->AddDialog(newDialog);
		offset.y+=Asura_Dialog::DefaultSpacing();

		if (!GetCurrentTemplate()->m_szTextureName)
			strcpy(szText, "Texture : *None*");
		else
			sprintf(szText, "Texture : %s", GetCurrentTemplate()->m_szTextureName);
		newDialog = new Asura_Function_Dialog(szText, offset, ChangeTexture);
		newOverlay->AddDialog(newDialog);
		offset.y+=Asura_Dialog::DefaultSpacing();

		newDialog = new Asura_Numerical_Dialog("Top left U", offset, &GetCurrentTemplate()->m_fTopLeftU, 0.0f, 1.0f, 0.01f, "%.3f");
		newOverlay->AddDialog(newDialog);
		offset.y+=Asura_Dialog::DefaultSpacing();

		newDialog = new Asura_Numerical_Dialog("Top left V", offset, &GetCurrentTemplate()->m_fTopLeftV, 0.0f, 1.0f, 0.01f, "%.3f");
		newOverlay->AddDialog(newDialog);
		offset.y+=Asura_Dialog::DefaultSpacing();

		newDialog = new Asura_Numerical_Dialog("Bottom right U", offset, &GetCurrentTemplate()->m_fBottomRightU, 0.0f, 1.0f, 0.01f, "%.3f");
		newOverlay->AddDialog(newDialog);
		offset.y+=Asura_Dialog::DefaultSpacing();

		newDialog = new Asura_Numerical_Dialog("Bottom right V", offset, &GetCurrentTemplate()->m_fBottomRightV, 0.0f, 1.0f, 0.01f, "%.3f");
		newOverlay->AddDialog(newDialog);
		offset.y+=Asura_Dialog::DefaultSpacing();
	
		newDialog = new Asura_Numerical_Dialog("Height", offset, &GetCurrentTemplate()->m_fHeight, 0.0f, 10.0f, 0.01f, "%.3f");
		newOverlay->AddDialog(newDialog);
		offset.y+=Asura_Dialog::DefaultSpacing();

		newDialog = new Asura_Numerical_Dialog("Width", offset, &GetCurrentTemplate()->m_fWidth, 0.0f, 10.0f, 0.01f, "%.3f");
		newOverlay->AddDialog(newDialog);
		offset.y+=Asura_Dialog::DefaultSpacing();

		newDialog = new Asura_Numerical_Dialog("Max distortion",offset,&GetCurrentTemplate()->m_fMaxDistortion, 0.0f, 1.0f, 0.01f, "%.3f");
		newOverlay->AddDialog(newDialog);
		offset.x += newDialog->MaxCoord.x;

 		newDialog = new Asura_Tickbox_Dialog("View",offset,&s_bViewMaxDistortion);
		newOverlay->AddDialog(newDialog);
		offset.x = 1.0f;
		offset.y+=Asura_Dialog::DefaultSpacing();

		newDialog = new Asura_Numerical_Dialog("Stiffness",offset,&GetCurrentTemplate()->m_fStiffness, 0.0f, 1.0f, 0.001f, "%.3f");
		newOverlay->AddDialog(newDialog);
		offset.y+=Asura_Dialog::DefaultSpacing();

		newDialog = new Asura_FlagTickbox_Dialog("Don't turn to face camera", offset, &GetCurrentTemplate()->m_uFlags, ASURA_BILLBOARDPLANT_DONTTURNTOFACE_POSITION);
		newOverlay->AddDialog(newDialog);
		offset.y+=Asura_Dialog::DefaultSpacing();

		newDialog = new Asura_FlagTickbox_Dialog("Use Random offset", offset, &GetCurrentTemplate()->m_uFlags, ASURA_BILLBOARDPLANT_USERANDOMOFFSET_POSITION);
		newOverlay->AddDialog(newDialog);
		offset.y+=Asura_Dialog::DefaultSpacing();

		newDialog = new Asura_Tickbox_Dialog("Keep plant in front of camera", offset, &s_bKeepInFrontOfCamera);
		newOverlay->AddDialog(newDialog);
		offset.y+=Asura_Dialog::DefaultSpacing();
	}

	newDialog = new Asura_Function_Dialog("Save templates", offset, SaveTemplates);
	newOverlay->AddDialog(newDialog);
	offset.y+=Asura_Dialog::DefaultSpacing();

	newOverlay->ID = TOOLS_OVERLAY_PLANTEDIT;

	Asura_Overlay_System::SubmitNewOverlay(newOverlay, false);
}

void Tools_Mode_BillboardPlants::CreateScatterOverlay(void)
{
	if(!s_bScatterOverlayOpen) return;

	Asura_Overlay* newOverlay;
	newOverlay = new Asura_Overlay("Scatter",false,&s_xScatterOverlayPosition);
	
	Asura_Dialog* newDialog;
	Asura_Vector_2 offset = Asura_Vector_2(1.0f,3.0f);

	char szText[255];
	if(s_uPlantScatterSelection == 0xffffffff)
		strcpy(szText,"Plant Type : *Not Set*");
	else
	{
		int iIndex = Asura_BillboardPlant_TemplateStore::GetIndexFromUniqueID(s_uPlantScatterSelection);
		if (iIndex == -1)
			strcpy(szText,"Plant Type : *Not Set*");
		else
			sprintf(szText,"Plant Type : %s",Asura_BillboardPlant_TemplateStore::GetTemplate(iIndex)->m_szTemplateName);
	}
	newDialog = new Asura_Function_Dialog(szText,offset,ChangeScatterSelection);
	newOverlay->AddDialog(newDialog);
	offset.y+=Asura_Dialog::DefaultSpacing();

	newDialog = new Asura_Numerical_Dialog("Number to create: ", offset, &s_fNumberToScatter, 0.0f, 1024.0f, 1.0f, "%.0f");
	newOverlay->AddDialog(newDialog);
	offset.y+=Asura_Dialog::DefaultSpacing();

	newDialog = new Asura_Numerical_Dialog("Clumpiness: ", offset, &s_fScatterClumpiness, 0.0f, 1.0f, 0.01f, "%.2f");
	newOverlay->AddDialog(newDialog);
	offset.y+=Asura_Dialog::DefaultSpacing();

	newDialog = new Asura_Tickbox_Dialog("Test for environment collisions?", offset, &s_bTestForCollisions);
	newOverlay->AddDialog(newDialog);
	offset.y+=Asura_Dialog::DefaultSpacing();

	newDialog = new Asura_Function_Dialog("Randomise", offset, Randomise);
	newOverlay->AddDialog(newDialog);
	offset.y+=Asura_Dialog::DefaultSpacing();

	newDialog = new Asura_Function_Dialog("Accept", offset, Accept);
	newOverlay->AddDialog(newDialog);
	offset.y+=Asura_Dialog::DefaultSpacing();

	newDialog = new Asura_Function_Dialog("Reject", offset, Reject);
	newOverlay->AddDialog(newDialog);
	offset.y+=Asura_Dialog::DefaultSpacing();

	newOverlay->ID = TOOLS_OVERLAY_PLANTSCATTER;

	Asura_Overlay_System::SubmitNewOverlay(newOverlay,false);
}

void Tools_Mode_BillboardPlants::CreatePlantPlacementOverlay(void)
{
	if(!s_bPlantPlacementOverlayOpen) return;

	Asura_Overlay* newOverlay;
	newOverlay = new Asura_Overlay("Plant placement",false,&s_xPlantPlacementOverlayPosition);
	
	Asura_Dialog* newDialog;
	Asura_Vector_2 offset = Asura_Vector_2(1.0f,3.0f);

	char szText[255];
	if(s_uPlantPlacementSelection == 0xffffffff)
		strcpy(szText,"Plant Type : *Not Set*");
	else
	{
		int iIndex = Asura_BillboardPlant_TemplateStore::GetIndexFromUniqueID(s_uPlantPlacementSelection);
		if (iIndex == -1)
			strcpy(szText,"Plant Type : *Not Set*");
		else
			sprintf(szText,"Plant Type : %s",Asura_BillboardPlant_TemplateStore::GetTemplate(iIndex)->m_szTemplateName);
	}
	newDialog = new Asura_Function_Dialog(szText,offset,ChangePlacementSelection);
	newOverlay->AddDialog(newDialog);
	offset.y+=Asura_Dialog::DefaultSpacing();

	newDialog = new Asura_Function_Dialog("Create (Ctrl+c)", offset, Create);
	newOverlay->AddDialog(newDialog);
	offset.y+=Asura_Dialog::DefaultSpacing();

	newDialog = new Asura_Function_Dialog("Select all of type (Ctrl+t)", offset, SelectAllOfType);
	newOverlay->AddDialog(newDialog);
	offset.y+=Asura_Dialog::DefaultSpacing();

	newDialog = new Asura_Function_Dialog("Select all plants (Ctrl+p)", offset, SelectAllPlants);
	newOverlay->AddDialog(newDialog);
	offset.y+=Asura_Dialog::DefaultSpacing();

	newDialog = new Asura_Function_Dialog("Delete all selected plants that hit environment", offset, DeleteSelectedPlantsThatCollide);
	newOverlay->AddDialog(newDialog);

	newOverlay->ID = TOOLS_OVERLAY_PLANTPLACEMENT;

	Asura_Overlay_System::SubmitNewOverlay(newOverlay,false);
}

void Tools_Mode_BillboardPlants::ChangeSelection()
{
	ListSelection_Overlay xOverlay("Select plant : ");
	bool bAddedOne = false;
	for (int i=0;i<Asura_BillboardPlant_TemplateStore::GetNumberOfTemplates();i++)
	{
		xOverlay.AddItem(Asura_BillboardPlant_TemplateStore::GetTemplate(i)->m_szTemplateName, i);
		bAddedOne = true;
	}
	if (!bAddedOne)
		return;
	if (!xOverlay.DoModal())
		return;
	SetCurrentTemplate(Asura_BillboardPlant_TemplateStore::GetTemplate(xOverlay.GetSelectionData()));
}


void Tools_Mode_BillboardPlants::CreateNewTemplate()
{
	Asura_String xName;
	if (!Tools_Object_System::AskForName(xName, "Enter name for new plant"))
		return;
	if (xName.IsBlank())
		return;
	Asura_BillboardPlant_Template *pxTemplate = Asura_BillboardPlant_TemplateStore::CreateNewTemplate(xName);
	SetCurrentTemplate(pxTemplate);
}

void Tools_Mode_BillboardPlants::DeleteCurrentTemplate()
{
	if (!GetCurrentTemplate())
		return;
	YesNo_Overlay xDlg("Are you sure you want to delete this template?");
	if(!xDlg.DoModal()) return;
	Asura_BillboardPlant_TemplateStore::DeleteTemplate(GetCurrentTemplate());
	SetCurrentTemplate(NULL);
}

void Tools_Mode_BillboardPlants::SetCurrentTemplate(Asura_BillboardPlant_Template *pxTemplate)
{
	s_pxCurrentTemplate = pxTemplate;
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_PLANTEDIT);
	CreatePlantEditOverlay();
}

Asura_BillboardPlant_Template *Tools_Mode_BillboardPlants::GetCurrentTemplate()
{
	return s_pxCurrentTemplate;
}

void Tools_Mode_BillboardPlants::RenameCurrentTemplate()
{
	if (!GetCurrentTemplate())
		return;
	Asura_String xName(GetCurrentTemplate()->m_szTemplateName);
	if (!Tools_Object_System::AskForName(xName, "Enter new name for new plant"))
		return;
	if (xName.IsBlank())
		return;
	delete[] GetCurrentTemplate()->m_szTemplateName;
	GetCurrentTemplate()->m_szTemplateName = new char[xName.GetLength() + 1];
	strcpy(GetCurrentTemplate()->m_szTemplateName, xName.GetString());
	SetCurrentTemplate(GetCurrentTemplate());
}

void Tools_Mode_BillboardPlants::ChangeTexture()
{
	if (!GetCurrentTemplate())
		return;
	int iNewTexture = Tools_PickTexture::PickTexture();
	if (iNewTexture != ASURA_TEXTURE_NONE)
	{
		const Asura_String *pxTextureName = Asura_Texture_Management::GetTextureName(iNewTexture);
		delete[] GetCurrentTemplate()->m_szTextureName;
		GetCurrentTemplate()->m_szTextureName = new char[pxTextureName->GetLength() + 1];
		GetCurrentTemplate()->m_iTextureIndex = iNewTexture;
		strcpy(GetCurrentTemplate()->m_szTextureName, pxTextureName->GetString());
		SetCurrentTemplate(GetCurrentTemplate());
	}
}

void Tools_Mode_BillboardPlants::SaveTemplates()
{
	Tools_Timed_Message_System::AddMessage(0xffffff, "Saved templates");
	Asura_BillboardPlant_TemplateStore::Save();
}


void Tools_Mode_BillboardPlants::RenderPlant()
{
	Asura_Assert(GetCurrentTemplate(), "Sanity check");
	// Render a tools cutscene bloke in front of the camera (to give scale).
	Asura_Mesh *pxMesh = Asura_Mesh_System::GetMesh("ToolsShape_CutsceneActor");
	if (s_bKeepInFrontOfCamera)
	{
		s_xCamPosForPlantRender = *Asura_Camera::GetPosition();;
		s_xOriForPlantRender = *Asura_Camera::GetOrientation();;
	}
	Asura_Vector_3 xPos = s_xCamPosForPlantRender;
	Asura_Matrix_3x3 xMat = s_xOriForPlantRender ;
	xPos += Asura_Vector_3(1.0f, 0.0f, 5.0f) * xMat;
	Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_NORMAL);
	Asura_Mesh_System::PlatformRenderMesh(pxMesh,&xPos,&xMat);
	// Render the plant that you are editing.
	xPos -= Asura_Vector_3(1.0f, 0.0f, 0.0f) * xMat;
	Asura_Vector_3 xPositions[4];
	for (int i=0;i<4;i++)
	{
		xPositions[i] = Asura_Vector_3(0.0f, 0.0f, 0.0f);
		if (i < 2)
			xPositions[i].y -= GetCurrentTemplate()->m_fHeight; 
		if (!(i % 2))
			xPositions[i].x -= GetCurrentTemplate()->m_fWidth;
		if (s_bViewMaxDistortion)
		{
			if (i < 2)
				xPositions[i].x -= GetCurrentTemplate()->m_fWidth * GetCurrentTemplate()->m_fMaxDistortion;
		}
/*		if (s_bViewMaxYDistortion)
		{
			if (i < 2)
				xPositions[i].z -= GetCurrentTemplate()->m_fWidth * GetCurrentTemplate()->m_fMaxYDistortion;
		}*/
		xPositions[i] = xPositions[i] * xMat;
		xPositions[i] += xPos;
	}
	{
		D3DGenericVertex v[4];
		for (int i=0;i<4;i++)
		{
			v[i].U = (i % 2) ? GetCurrentTemplate()->m_fBottomRightU : GetCurrentTemplate()->m_fTopLeftU;
			v[i].V = (i < 2) ? GetCurrentTemplate()->m_fTopLeftV : GetCurrentTemplate()->m_fBottomRightV;
			v[i].X = xPositions[i].x;
			v[i].Y = xPositions[i].y;
			v[i].Z = xPositions[i].z;
			v[i].Diffuse = 0xffffffff;
		}

		Asura_Direct3D_Shaders::RequestFixedFunctionVertexShader(D3DFVF_GENERICVERTEX);
		Asura_Direct3D::D3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
		Asura_Render::CurrentStates.RequestTranslucencyMode(ASURA_TRANSLUCENCY_NORMAL);
		Asura_Render::CurrentStates.RequestTextureOpMode(ASURA_TEXTUREOP_SINGLE_PASS);
		Asura_Render::CurrentStates.RequestTextureIndex(0,GetCurrentTemplate()->m_iTextureIndex);
		// Request an alpha test - this prevents alpha pixels from obscuring non-alpha in
		// the z-test.
		Asura_Render::CurrentStates.RequestAlphaTest( true );
		Asura_Render::CurrentStates.RequestZBufferWriteEnabled(true);
		
		D3DXMATRIX matWorld;

		matWorld._12 = matWorld._13 = matWorld._14 = matWorld._21 = matWorld._23 = matWorld._24 = 0.0f;
		matWorld._31 = matWorld._32 = matWorld._34 = matWorld._41 = matWorld._42 = matWorld._43 = 0.0f;
		matWorld._11 = matWorld._22 = matWorld._33 = 1.0f;
		matWorld._44 = 1.0f;
		matWorld._41 = 0.0f;
		matWorld._42 = 0.0f;
		matWorld._43 = 0.0f;

		Asura_Direct3D::D3DDevice->SetTransform( D3DTS_WORLD,      &matWorld );


		// Only render the front facing triangles because we can guarantee that the
		// backs will never be visible (the billboards turn to face the camera).
		short indices[6] = 
		{
			0,1,2,
			1,2,3,
		};
		Asura_Direct3D::D3DDevice->DrawIndexedPrimitiveUP
		(
		D3DPT_TRIANGLELIST,
			0,
			4,
			2,
			(void*)indices,
			D3DFMT_INDEX16,
			(void*)v,
			sizeof(D3DGenericVertex)
		);
	}
}


void Tools_Mode_BillboardPlants::ChangePlacementSelection()
{
	ListSelection_Overlay xOverlay("Select plant : ");
	bool bAddedOne = false;
	for (int i=0;i<Asura_BillboardPlant_TemplateStore::GetNumberOfTemplates();i++)
	{
		xOverlay.AddItem(Asura_BillboardPlant_TemplateStore::GetTemplate(i)->m_szTemplateName, i);
		bAddedOne = true;
	}
	if (!bAddedOne)
		return;
	if (!xOverlay.DoModal())
		return;
	s_uPlantPlacementSelection = Asura_BillboardPlant_TemplateStore::GetTemplate(xOverlay.GetSelectionData())->m_uUniqueID;
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_PLANTPLACEMENT);
	CreatePlantPlacementOverlay();
}

void Tools_Mode_BillboardPlants::Create()
{
	Tools_BillboardPlant_Object *pxToolsObject = new Tools_BillboardPlant_Object(*Asura_Camera::GetPosition(), s_uPlantPlacementSelection);
	Tools_Object_System::SelectObject(pxToolsObject);
}

void Tools_Mode_BillboardPlants::SelectAllOfType()
{
	Tools_Object_System::DeselectAllObjects();
	for(LIF<Tools_Object*> olif(&Tools_Object_System::ObjectList);!olif.done();olif.next())
	{
		if (olif()->Type == TOT_Billboard_Plant)
		{
			Tools_BillboardPlant_Object *pxObject = (Tools_BillboardPlant_Object *)olif();
			if (pxObject->m_uPlantType == s_uPlantPlacementSelection)
				Tools_Object_System::SelectObject(pxObject, true);
		}
	}
}

void Tools_Mode_BillboardPlants::DeleteSelectedPlantsThatCollide()
{
	List <Tools_Object*> listToDelete;
	for(LIF<Tools_Object*> olif(&Tools_Object_System::SelectedObjectList);!olif.done();olif.next())
	{
		if (olif()->Type == TOT_Billboard_Plant)
		{
			Tools_BillboardPlant_Object *pxObject = (Tools_BillboardPlant_Object *)olif();
			if (DoesPlantHitEnvironment(pxObject->Position, pxObject->m_uPlantType))
			{
				listToDelete.add_entry(olif());
			}
		}
	}
	while (listToDelete.size())
	{
		Tools_Object_System::DeselectObject(listToDelete.first_entry());
		Tools_Object_System::DeleteObject(listToDelete.first_entry());
		listToDelete.delete_first_entry();
	}
}


void Tools_Mode_BillboardPlants::SelectAllPlants()
{
	Tools_Object_System::DeselectAllObjects();
	for(LIF<Tools_Object*> olif(&Tools_Object_System::ObjectList);!olif.done();olif.next())
	{
		if (olif()->Type == TOT_Billboard_Plant)
			Tools_Object_System::SelectObject(olif(), true);
	}
}

void Tools_Mode_BillboardPlants::ChangeScatterSelection()
{
	ListSelection_Overlay xOverlay("Select plant : ");
	bool bAddedOne = false;
	for (int i=0;i<Asura_BillboardPlant_TemplateStore::GetNumberOfTemplates();i++)
	{
		xOverlay.AddItem(Asura_BillboardPlant_TemplateStore::GetTemplate(i)->m_szTemplateName, i);
		bAddedOne = true;
	}
	if (!bAddedOne)
		return;
	if (!xOverlay.DoModal())
		return;
	s_uPlantScatterSelection = Asura_BillboardPlant_TemplateStore::GetTemplate(xOverlay.GetSelectionData())->m_uUniqueID;
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_PLANTSCATTER);
	CreateScatterOverlay();
}

void Tools_Mode_BillboardPlants::Randomise()
{
	Tools_BillboardPlant_Scatter::Scatter(s_uPlantScatterSelection, s_fNumberToScatter, s_fScatterClumpiness);
}

void Tools_Mode_BillboardPlants::Accept()
{
	Tools_BillboardPlant_Scatter::Accept();
}

void Tools_Mode_BillboardPlants::Reject()
{
	Tools_BillboardPlant_Scatter::Reject();
}

bool Tools_Mode_BillboardPlants::TestForCollisions()
{
	return s_bTestForCollisions;
}

bool Tools_Mode_BillboardPlants::DoesPlantHitEnvironment(const Asura_Vector_3& xPosition, const unsigned uPlantType)
{
	// Get plant template
	int iPlantIndex = Asura_BillboardPlant_TemplateStore::GetIndexFromUniqueID(uPlantType);
	if (iPlantIndex == -1)
		return false;
	Asura_BillboardPlant_Template *pxTemplate = Asura_BillboardPlant_TemplateStore::GetTemplate(iPlantIndex);
	// Test an octagon on top of the plant.
	Asura_Vector_3 xPositions[8];
	for (int i=0;i<8;i++)
	{
		Asura_Euler_3 xEuler;
		xEuler.x = xEuler.z = 0.0f;
		xEuler.y = ((float)i/8.0f) * Asura_Maths::Pi * 2.0f;
		Asura_Matrix_3x3 xMat;
		xEuler.ToMatrix(xMat);
		xPositions[i] = xPosition;
		xPositions[i].y -= pxTemplate->m_fHeight;
		Asura_Vector_3 xOffset = Asura_Vector_3(pxTemplate->m_fWidth * 0.5f, 0.0f, 0.0f);
		xOffset = xOffset * xMat;
		xPositions[i] += xOffset;
	}
	// Test the line of sight from each position to the next.
	for (int i=0;i<8;i++)
	{
		int iOtherIndex = i+1;
		if (iOtherIndex == 8)
			iOtherIndex = 0;
		Asura_Vector_3 xDirection = xPositions[iOtherIndex] - xPositions[i];
		float fDistance = xDirection.Magnitude();
		xDirection.Normalise();
		Asura_LOS_InputData xLOSInput = Asura_LOS_InputData(xPositions[i], xDirection, 0, fDistance);
		const Asura_LOS_OutputData* pxLOSData = Asura_LOS::TestAgainstEverything( &xLOSInput);
		if (pxLOSData->m_bHitEnvironment)
			return true;
	}
	return false;
}

void Tools_Mode_BillboardPlants::CreateToolsObjects()
{
	for (unsigned i=0;i<Asura_BillboardPlant_System::GetNumberOfBatches();i++)
	{
		Asura_BillboardPlant_Batch *pxBatch = Asura_BillboardPlant_System::GetBillboardPlantBatch(i);
		Asura_Assert(pxBatch->m_uNumberOfPlants, "Found plant batch with no plants");
		for (unsigned i=0;i<pxBatch->m_uNumberOfPlants;i++)
		{
			new Tools_BillboardPlant_Object(pxBatch->m_pxPlants[i].m_xPosition, pxBatch->m_uPlantType);
		}
	}
}

void Tools_Mode_BillboardPlants::RemoveBillboardBatches()
{
	Asura_BillboardPlant_System::RemoveAllBatches();
}

void Tools_Mode_BillboardPlants::CreateBillboardBatches()
{
	// Create all the client billboard entities from the tools objects.
	int iNumberOfModules = Asura_Module_System::GetNumberOfModules();
	int iNumberOfPlantTypes = Asura_BillboardPlant_TemplateStore::GetNumberOfTemplates();
	static const int iExpectedMaxTypesPerModule = 1024;
	// Enormous memory allocations ahoy (hope you've got a lot of memory!)
	unsigned **ppuNumberOfTypes = new unsigned*[iNumberOfModules];
	for (int i=0;i<iNumberOfModules;i++)
	{
		ppuNumberOfTypes[i] = new unsigned[iNumberOfPlantTypes];
		for (int j=0;j<iNumberOfPlantTypes;j++)
		{
			ppuNumberOfTypes[i][j] = 0;
		}
	}
	Asura_Vector_3 ***pppxPositions = new Asura_Vector_3**[iNumberOfModules];
	for (int i=0;i<iNumberOfModules;i++)
	{
		pppxPositions[i] = new Asura_Vector_3*[iNumberOfPlantTypes];
		for (int j=0;j<iNumberOfPlantTypes;j++)
		{
			pppxPositions[i][j] = new Asura_Vector_3[iExpectedMaxTypesPerModule];
		}
	}
	for(LIF<Tools_Object*> olif(&Tools_Object_System::ObjectList);!olif.done();olif.next())
	{
		if (olif()->Type == TOT_Billboard_Plant)
		{	
			Tools_BillboardPlant_Object *pxToolsObject = (Tools_BillboardPlant_Object *)olif();
			int iTypeIndex = Asura_BillboardPlant_TemplateStore::GetIndexFromUniqueID(pxToolsObject->m_uPlantType);
			if (iTypeIndex == -1)
				iTypeIndex = 0;	// Set an arbitrary type if we don't know what it is.
			Asura_Vector_3 xPosition = pxToolsObject->Position;
			int iModuleIndex = Asura_Module_System::GetModuleIndexFromPosition(xPosition);
			if (iModuleIndex == -1)
			{
				Tools_Timed_Message_System::AddMessage(0xff0000, "Error - found billboard plant that wasn't in any module - will ignore it!");
				continue;
			}
			Asura_Assert(ppuNumberOfTypes[iModuleIndex][iTypeIndex] < (unsigned)iExpectedMaxTypesPerModule, "Exceeded arbitrary maximum for plants within a single module - Ignoring surplus");
			if (ppuNumberOfTypes[iModuleIndex][iTypeIndex] >= (unsigned)iExpectedMaxTypesPerModule)
				continue;
			pppxPositions[iModuleIndex][iTypeIndex][ppuNumberOfTypes[iModuleIndex][iTypeIndex]] = xPosition;
			ppuNumberOfTypes[iModuleIndex][iTypeIndex]++;
		}
	}
	for (int i=0;i<iNumberOfModules;i++)
	{
		for (int j=0;j<iNumberOfPlantTypes;j++)
		{
			if (ppuNumberOfTypes[i][j])
			{
				Asura_BillboardPlant_Template *pxTemplate = Asura_BillboardPlant_TemplateStore::GetTemplate(j);
				unsigned uUniquePlantID = pxTemplate->m_uUniqueID;
				Asura_BillboardPlant_Batch *pxBatch = new Asura_BillboardPlant_Batch(uUniquePlantID, ppuNumberOfTypes[i][j], pppxPositions[i][j], i);
				Asura_BillboardPlant_System::AddNewBatch(pxBatch);
			}
		}
	}
	for (int i=0;i<iNumberOfModules;i++)
	{
		for (int j=0;j<iNumberOfPlantTypes;j++)
		{
			delete[] pppxPositions[i][j];
		}
		delete[] ppuNumberOfTypes[i];
		delete[] pppxPositions[i];
	}
	delete[] ppuNumberOfTypes;
	delete[] pppxPositions;
}

void Tools_Mode_BillboardPlants::RemoveToolsObjects()
{
	// Get rid of temporary ones first.
	Tools_BillboardPlant_Scatter::Reject();
	// Destroy all of the tools objects.
	List<Tools_Object*>xListToDestroy;
	for(LIF<Tools_Object*> olif(&Tools_Object_System::ObjectList);!olif.done();olif.next())
	{
		if (olif()->Type == TOT_Billboard_Plant)
			xListToDestroy.add_entry(olif());
	}
	while (xListToDestroy.size())
	{
		xListToDestroy.first_entry()->Destroy();
		xListToDestroy.delete_first_entry();
	}

}


#endif //ASURA_USE_BILLBOARD_PLANTS
