//
// Tools_Botanicals_Object.cpp
//
// Created by DaveReed (04/11/05)
// 
// Copyright (C) 2002 Rebellion (Derby), All Rights Reserved.
//

#include "Core/Asura.h"

#ifdef ASURA_USE_BOTANICALS

#include "Debugging/Asura_Assert.h"
#include "Camera/Asura_Camera.h"
#include "Interface/Asura_Dialog.h"
#include "Mesh/Asura_Mesh.h"
#include "Mesh/Asura_Mesh_System.h"
#include "Rendering/Asura_Module.h"
#include "Interface/Asura_Overlay.h"
#include "Interface/Asura_Overlay_System.h"
#include "Rendering/Asura_Render.h"
#include "Interface/Asura_Interface.h"
#include "Shapes/Asura_Shape_System.h"
#include "Tools_Overlays.h"
#include "MeshEdit/Tools_Mode_MeshEdit.h"
#include "Misc/Tools_Render.h"
#include "Misc/Tools_Render_Options.h"
#include "Misc/Tools_Modal_Overlay.h"
#include "Misc/Tools_Timed_Messages.h"
#include "Misc/Tools_MessageLog.h"
#include "Objects/Tools_Object_System.h"
#include "Rendering/Asura_Direct3d.h"
#include "Rendering/Asura_Direct3D_Shaders.h"
#include "Shapes/Tools_Shapes.h"
#include "Tools_System.h"
#include "Core/Asura_UserInput.h"
#include "Load&Save/Tools_SaveAsura.h"

#include "Botanical/Asura_Direct3D_Botanicals_Game_Render_Manager.h"
#include "Botanical/Asura_Direct3D_Botanicals_Game_Render.h"
#include "Botanicals/Asura_Botanicals_InstanceManager.h"
#include "Botanicals/Asura_Botanicals_TemplateManager.h"
#include "Botanicals/Tools_Botanicals_Object.h"
#include "Botanicals/Tools_Mode_Botanicals.h"

#include "Tools_Overlays.h"
#include "Objects/Tools_Object.h"
#include "Camera/Asura_Camera.h"


static Tools_Botanicals_Object*	g_pxThisObj = NULL;
Asura_Vector_2					Tools_Mode_Botanicals::s_xInstanceOverlayPosition = Asura_Vector_2(70,10);

List<Tools_Botanicals_Object*> Tools_Botanicals_Object::s_xObjectList;


Tools_Botanicals_Object::Tools_Botanicals_Object(const Asura_Vector_3& xPosition, int iTemplateIdx,u_int uInstanceID) : Tools_Object(TOT_Botanicals)
{
	s_xObjectList.add_entry(this);

	Position = xPosition;
	Orientation.Identity();
	m_fInstanceScale=1.0f;
	m_fInstanceBrightness=1.0f;
	m_pxShapeInstance=NULL;
	m_pxBotanicalShape=NULL;
	SetTemplateIdx(iTemplateIdx);
	m_bScaleModified = false;
	m_bBrightnessModified = false;
	m_iModuleIdx = -2;	// This indicates no module assigned yet
	m_bRecalculateModuleIndex = true;

	m_uInstanceID = uInstanceID ? uInstanceID : Asura_Botanicals_InstanceManager::GenerateInstanceID();
	m_uBotanicalFlags = 0;
	
#if defined( ASURA_BOTANICALS_BGR_IN_EDIT)
	this->m_pxBGRInstanceHeader = NULL;
	this->m_uBGRInstanceHeaderInstanceIndex = 0;
#endif
}

void Tools_Botanicals_Object::Destroy()
{
#if defined( ASURA_BOTANICALS_BGR_IN_EDIT)
	if( NULL != this->m_pxBGRInstanceHeader)
	{
		Asura_Direct3D_BGR_Instance* pxBGRInstance = this->m_pxBGRInstanceHeader->GetDirect3DInstance( this->m_uBGRInstanceHeaderInstanceIndex);
		pxBGRInstance->SetActive( false);
		
		Asura_Direct3D_BGR_Manager& xBGRManager = Asura_Direct3D_Botanicals_Game_Render::GetDirect3DBGRManager();
		xBGRManager.InvalidateDirect3DData();
	}
#endif

	UnmergePolygonsFromEnvironment();
	Tools_Object::Destroy();
}




const char* Tools_Botanicals_Object::GetName()
{
	Asura_Botanicals_Template* pxTemplate=Asura_Botanicals_TemplateManager::GetTemplate(m_iTemplateIdx);

	if (pxTemplate)
	{
		return pxTemplate->xTemplateName.GetString();
	}
	else
	{
		return "<Botanical>";
	}
}



void Tools_Botanicals_Object::Copy(const Tools_Object* pxObject)
{
	const Tools_Botanicals_Object* pxFrom = (const Tools_Botanicals_Object*) pxObject;

	SetScale(pxFrom->GetScale());
	SetBrightness(pxFrom->GetBrightness());
	SetTemplateIdx(pxFrom->GetTemplateIdx());

#if defined( ASURA_BOTANICALS_BGR_IN_EDIT)
	RegenerateBGRInstance();
#endif

	Tools_SaveAsura::SetBotanicalsModified(true);
}


Tools_Object* Tools_Botanicals_Object::CreateObjectOfThisType() const
{
	return new Tools_Botanicals_Object(*Asura_Camera::GetPosition(), 0);
}



void Tools_Botanicals_Object::SetTemplateIdx(int iTemplateIdx)
{
	Asura_Botanicals_Template* pxTemplate = Asura_Botanicals_TemplateManager::GetTemplate(iTemplateIdx);	

	m_iTemplateIdx=iTemplateIdx;
	m_iTemplateID=pxTemplate->iUID;
	
	// Clear any existing mesh references, and pick a default selection shape
	if (m_pxShapeInstance)
	{
		delete m_pxShapeInstance;
		m_pxShapeInstance=NULL;
	}

	Asura_String xMeshName = "ToolsShape_Diamond"; 
	
	if (pxTemplate->uSelectionShapeID!=ASURA_HASH_ID_UNSET)
	{			
		char szTmp[256];
		Asura_Shape *pxShape=Asura_Shape_System::GetShape(pxTemplate->uSelectionShapeID);		

		// Not quite sure what's causing this to happen... but we'd better handle it without
		// crashing...
		if (pxShape!=NULL)
		{		
			pxShape->GetShapeName(szTmp,256);
			xMeshName=szTmp;
		}
		else
		{
			pxTemplate->uSelectionShapeID=ASURA_HASH_ID_UNSET;
		}
	}


	Mesh = Asura_Mesh_System::GetMesh(xMeshName);
	
	m_pxBotanicalShape= NULL;
	

	if (pxTemplate->eType==ASURA_BOTANICALS_TEMPLATE_SHAPE)
	{
		if (pxTemplate->uShapeID!=ASURA_HASH_ID_UNSET)
		{		
			m_pxShapeInstance = new Asura_Shape_Instance(pxTemplate->uShapeID);
			m_pxShapeInstance->SetNewPosAndOri(Position,Orientation);	
			m_pxShapeInstance->AddFlags(ASURA_SHAPE_INSTANCE_NO_SHADOW);

			char szTmp[256];
			Asura_Shape* pxShape=(Asura_Shape *)m_pxShapeInstance->GetShape();

			if (pxShape!=0)
			{			
				pxShape->GetShapeName(szTmp,256);
				Mesh = Asura_Mesh_System::GetMesh(szTmp);
			}
		}
	}	

	if (!Tools_Mode_Botanicals::AllowSelectionOfTemplate(m_iTemplateIdx))
	{
		//PAZ : we shouldn't select this object
		if( g_pxThisObj != NULL )
		{
			Tools_Object_System::DeselectObject( g_pxThisObj );
		}
		Mesh = NULL;
	}
	
}



Tools_Botanicals_Object::~Tools_Botanicals_Object()
{
	if (m_pxShapeInstance)
	{
		delete m_pxShapeInstance;
		m_pxShapeInstance=NULL;
	}

	s_xObjectList.delete_entry(this);
}



void Tools_Botanicals_Object::OnDeselection()
{
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_BOTANICALS_INSTANCE);
	g_pxThisObj = NULL;
	Tools_Object::OnDeselection();
}


void Tools_Botanicals_Object::OnSelection()
{	
	if (Asura_UserInput::KeyPressed(ASURA_KEYID_CTRL))
	{		
		Tools_Mode_Botanicals::ChangeActiveTemplateTo(m_iTemplateIdx);
	}

	g_pxThisObj = this;	
	Tools_Object::OnSelection();	
	Tools_Mode_Botanicals::CreateInstanceOverlay(g_pxThisObj);
}

bool Tools_Botanicals_Object::IsSelectable()
{	
	if( !Tools_Object::IsSelectable() )
	{
		return( false );
	}
	return( Tools_Mode_Botanicals::AllowSelectionOfTemplate(m_iTemplateIdx) );
}

void Tools_Botanicals_Object::UpdateWhileSelected()
{
	Tools_Object::UpdateWhileSelected();

	Tools_Mode_Botanicals::SetModifiedFlag(true);

	if(m_bScaleModified)
	{	
#if defined( ASURA_BOTANICALS_BGR_IN_EDIT)
		this->UpdateBGRInstance();
#endif
		UnmergePolygonsFromEnvironment();
		m_bScaleModified = false;
	}

	if(m_bBrightnessModified)
	{	
#if defined( ASURA_BOTANICALS_BGR_IN_EDIT)
		this->UpdateBGRInstance();
#endif
		m_bBrightnessModified = false;
	}

}

void Tools_Botanicals_Object::Update()
{
}


void Tools_Botanicals_Object::Render()
{

	Asura_Botanicals_Template* pxTemplate=GetTemplate();

	// We don't have support for wireframe botanical rendering
	if(Tools_Render_Options::GetWireframeMode() == TOOLS_WIREFRAME_ON)
	{
		return;
	}

	//If render mesh is merged into environment , then we won't want to render the mesh ourselves
	bool bRenderMeshMerged = m_uBotanicalFlags & ASURA_BOTANICAL_FLAG_RENDERMESHMERGED;

	if (pxTemplate->eType==ASURA_BOTANICALS_TEMPLATE_SHAPE)
	{

		if (!pxTemplate->bVisible)
		{
			Mesh = NULL;
			if (IsSelected() || IsGroupSelected())
			{
				Tools_Object_System::DeselectObject(this);
			}
		}
		else
		{			
			// Could do with using real extends of the object here...
			if (!Asura_Camera::IsSphereInFrustum(Position, 8.0f))
				return;	

			Tools_Object::SetScale(m_fInstanceScale);
			SetTemplateIdx(m_iTemplateIdx);

			if (IsGroupSelected() || !m_pxShapeInstance)
			{
				Tools_Object::Render();	
			}
			else
			{	
				if (m_pxShapeInstance && !bRenderMeshMerged)
				{	

					Asura_Matrix_3x3 xOrientationAndScale;
					xOrientationAndScale.Identity();			
					xOrientationAndScale[0][0]=m_fInstanceScale;
					xOrientationAndScale[1][1]=m_fInstanceScale;
					xOrientationAndScale[2][2]=m_fInstanceScale;
					xOrientationAndScale=Orientation*xOrientationAndScale;

					// Apply the scale before rendering
					m_pxShapeInstance->SetNewPosAndOri(Position,xOrientationAndScale);	
					m_pxShapeInstance->Render();					
				}
			}
		}
	}


#if defined( ASURA_BOTANICALS_BGR_IN_EDIT)
	if (pxTemplate->eType==ASURA_BOTANICALS_TEMPLATE_BOTANICALSHAPE)
	{
		if (!pxTemplate->bVisible)
		{
			Mesh = NULL;
			if (IsSelected() || IsGroupSelected())
			{
				Tools_Object_System::DeselectObject(this);
			}
		}
		else
		{
			// Do we need to render the selection object?
			if (IsSelected() || IsGroupSelected())
			{
				Tools_Object::SetScale(m_fInstanceScale);
				SetTemplateIdx(m_iTemplateIdx);

				// Outline only
				if( Mesh != NULL )
				{
					Tools_Render::RenderMeshOutline(Mesh,&Position,&Orientation,0xffff0000,true,m_fInstanceScale);		
				}
			}	
		}
	}
#else
	if (pxTemplate->eType==ASURA_BOTANICALS_TEMPLATE_BOTANICALSHAPE)
	{
		bool bRenderToolsObject=true;		
		
		if (!pxTemplate->bVisible)
		{
			Mesh = NULL;
			if (IsSelected() || IsGroupSelected())
			{
				Tools_Object_System::DeselectObject(this);
			}
		}
		else
		{
			Tools_Object::SetScale(m_fInstanceScale);
			SetTemplateIdx(m_iTemplateIdx);

			if (pxTemplate->pxBotanicalShape)
			{
				Tools_BotanicalShape *pxToolsBotShape=pxTemplate->pxBotanicalShape->GetToolsShape();

				if(!bRenderMeshMerged)
				{
					if(m_bRecalculateModuleIndex)
					{
						//Stagger the module index recalculations to avoid having to reduce the amount being done each
						//frame when moving multiple botanicals. It shouldn't matter much if they don't get updated
						//immediately.
						//RAR 24/07/2008
						if(((int)Asura_Timers::GetFrameNumber() & 0x3f) == (GetToolsID() & 0x3f))
						{
							m_iModuleIdx = -2;
						}
					}
					
					// JAT 11/04/2006
					// Catch special case of module index of -2 meaning the value hasn't been computed yet
					if ( m_iModuleIdx == -2)
					{
						m_iModuleIdx = Asura_Botanicals_InstanceManager::GetModuleIndexFromPosition( Position, Orientation );
						m_bRecalculateModuleIndex = false;
					}
					if (m_iModuleIdx<0)
					{
						// Not in a module - display it in bright red
						pxToolsBotShape->Render(&Position, &Orientation, m_fInstanceScale, TOOLS_BOTANICALSHAPE_RENDERFLAG_BRIGHTRED);
					}
					else
					{	
						if (Asura_Module_System::IsModuleVisible(m_iModuleIdx))
						{						
							pxToolsBotShape->Render(&Position, &Orientation, m_fInstanceScale);
						}
					}
				}
				
				// If we've rendered this, don't render the selection object unless the
				// shape is selected
				if (pxToolsBotShape)
				{
					bRenderToolsObject=false;
				}
			}

			// Do we need to render the selection object?
			if (IsSelected() || IsGroupSelected())
			{
				bRenderToolsObject=true;
			}

			if (bRenderToolsObject)
			{
				// Outline only
				Tools_Render::RenderMeshOutline(Mesh,&Position,&Orientation,0xffff0000,true,m_fInstanceScale);		
			}	
		}
	}
#endif	
}

void Tools_Botanicals_Object::UpdatePositionInAsuraData(bool bUpdateLinkedObjects)
{
	//Need to unmerge polygons if moving this. RAR 20/02/2006
	UnmergePolygonsFromEnvironment();	
#if defined( ASURA_BOTANICALS_BGR_IN_EDIT)
	this->UpdateBGRInstance();
#endif
	m_bRecalculateModuleIndex = true;
}

#if defined( ASURA_BOTANICALS_BGR_IN_EDIT)
void Tools_Botanicals_Object::UpdateBGRInstance()
{
	if( NULL == this->m_pxBGRInstanceHeader)
	{
		return;
	}

	Asura_Direct3D_BGR_Manager& xBGRManager = Asura_Direct3D_Botanicals_Game_Render::GetDirect3DBGRManager();
	
	xBGRManager.MoveInstanceTo( this, this->m_pxBGRInstanceHeader, this->m_uBGRInstanceHeaderInstanceIndex);
	xBGRManager.InvalidateDirect3DData();
}
#endif


Asura_Botanicals_Template* Tools_Botanicals_Object::GetTemplate()
{
	return Asura_Botanicals_TemplateManager::GetTemplate(m_iTemplateIdx);
}

Asura_Botanicals_Template* Tools_Botanicals_Object::GetTemplate() const
{
	return Asura_Botanicals_TemplateManager::GetTemplate(m_iTemplateIdx);
}




void Tools_Mode_Botanicals::CreateInstanceOverlay(Tools_Botanicals_Object* pxObj)
{
	static char szTemplateName[256]="";	

	Asura_Overlay* pxNewOverlay;
	pxNewOverlay = new Asura_Overlay("Botanical Instance",false,&s_xInstanceOverlayPosition);
	
	Asura_Dialog*  pxNewDialog;
	Asura_Vector_2 xOffset = Asura_Vector_2(1.0f,3.0f);

	// Type name
	Asura_Botanicals_Template* pxTemplate=g_pxThisObj->GetTemplate();
	
	if (pxTemplate)
	{	
		Asura_PrintfToBfr(szTemplateName,"Template: %s",256,true,pxTemplate->xTemplateName.GetString());
		pxNewDialog = new Asura_Dialog(szTemplateName,xOffset);
		pxNewOverlay->AddDialog(pxNewDialog);
		xOffset.y+=1.2f*Asura_Dialog::DefaultSpacing();
	}

	// Change Template
	pxNewDialog = new Asura_Function_Dialog("Change Template",xOffset,ChangeInstanceTemplate);
	pxNewOverlay->AddDialog(pxNewDialog);
	xOffset.y+=1.5f*Asura_Dialog::DefaultSpacing();

	// Adjust scale	
	pxNewDialog = new Asura_Numerical_Dialog("Instance Scale", xOffset, g_pxThisObj->GetScalePtr(), 0.1f, 4.0f, 0.01f, "%.2f",g_pxThisObj->GetScaleModifiedPtr());
	pxNewOverlay->AddDialog(pxNewDialog);	
	xOffset.y+=1.5f*Asura_Dialog::DefaultSpacing();

	// Brightness
	pxNewDialog = new Asura_Numerical_Dialog("Instance Brightness", xOffset, g_pxThisObj->GetBrightnessPtr(), 0.0f, 2.0f, 0.05f, "%.2f",g_pxThisObj->GetBrightnessModifiedPtr());
	pxNewDialog->SetHelpText("Note: Only affects prelighting! - use this to compensate for inaccurate GI samples");
	pxNewOverlay->AddDialog(pxNewDialog);	
	xOffset.y+=1.5f*Asura_Dialog::DefaultSpacing();

	// Close
	pxNewDialog = new Asura_Function_Dialog("Close",xOffset,CloseInstanceOverlay);
	pxNewOverlay->AddDialog(pxNewDialog);
	xOffset.y+=1.0f*Asura_Dialog::DefaultSpacing();

	// Create it
	pxNewOverlay->m_uID = TOOLS_OVERLAY_BOTANICALS_INSTANCE;
	Asura_Overlay_System::SubmitNewOverlay(pxNewOverlay,false);	
}



void Tools_Mode_Botanicals::ChangeInstanceTemplate(void)
{
	ListSelection_Overlay xOverlay("Select Botanical Template: ");
	bool bAddedOne = false;

	for (int i=0;i<Asura_Botanicals_TemplateManager::GetNumTemplates();i++)	
	{
		xOverlay.AddItem(Asura_Botanicals_TemplateManager::GetTemplateName(i), i);
		bAddedOne = true;
	}

	if (!bAddedOne)
	{
		Tools_Timed_Message_System::AddMessage(0xff8000, "No Botanical Templates Exist");
		return;
	}

	if (!xOverlay.DoModal()) return;

	int iIdx=xOverlay.GetSelectionData();

	Asura_Botanicals_Template *pxTemplate=Asura_Botanicals_TemplateManager::GetTemplate(iIdx);

	if (pxTemplate && g_pxThisObj)
	{
		g_pxThisObj->SetTemplateIdx(iIdx);
		g_pxThisObj->UnmergePolygonsFromEnvironment();

		// Update the overlay
		Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_BOTANICALS_INSTANCE);
		Tools_Mode_Botanicals::CreateInstanceOverlay(g_pxThisObj);

		#if defined( ASURA_BOTANICALS_BGR_IN_EDIT)
		g_pxThisObj->RegenerateBGRInstance();
		#endif
	}
}




void Tools_Mode_Botanicals::CloseInstanceOverlay(void)
{
	Asura_Overlay_System::CloseOverlays(TOOLS_OVERLAY_BOTANICALS_INSTANCE);
}



void Tools_Botanicals_Object::UnmergePolygonsFromEnvironment(bool bForceUnmerge /*= false*/)
{
	//Unmerge if any of the merged flags are set , or if ForceUnmerge is set
	if(bForceUnmerge || (m_uBotanicalFlags & (ASURA_BOTANICAL_FLAGS_ANYMERGE)))
	{
		Tools_Mode_MeshEdit::DeleteEntityPolygons(GetMergeGuid());
		m_uBotanicalFlags &=~ (ASURA_BOTANICAL_FLAGS_ANYMERGE);

		Tools_Mode_Botanicals::SetModifiedFlag(true);
	}
}

void Tools_Botanicals_Object::MergePolygonsIntoEnvironmentIfNeeded(bool bPermanentMerge)
{
	//Compare the template's merge requirements with the current merged status
	Asura_Botanicals_Template* pxTemplate=Asura_Botanicals_TemplateManager::GetTemplate(m_iTemplateIdx);
	if(!pxTemplate) return;

	bool bRenderIsMerged = (m_uBotanicalFlags & ASURA_BOTANICAL_FLAG_RENDERMESHMERGED) ? true : false;
	bool bCollisionIsMerged  = (m_uBotanicalFlags & ASURA_BOTANICAL_FLAG_COLLISIONMESHMERGED) ? true : false;

	if(!bPermanentMerge)
	{
		if(bRenderIsMerged == pxTemplate->bMergeRenderMeshWithEnv && bCollisionIsMerged == pxTemplate->bMergeCollisionMeshWithEnv)
		{
			//up to date
			return;
		}
	}

	UnmergePolygonsFromEnvironment();
	if(!bPermanentMerge)
	{
		if(!pxTemplate->bMergeRenderMeshWithEnv && !pxTemplate->bMergeCollisionMeshWithEnv)
		{
			//No merge needed
			return;
		}
	}

	//Get module to merge to. going to cheat on the centre calculation , to simplify things when using  botanical shapes.
	//(Its only used for getting a position for an LOS test down anyway , so shouldn't matter.. hopefully)
	//RAR 17/03/2006
	Asura_Vector_3 xCentre = Position;
	xCentre.y -= 0.5f;

	int iModule = Tools_Mode_MeshEdit::GetModuleForObjectMerge(Position,xCentre);
	if(iModule < 0) return;


	u_int uChecksum = GetChecksumForMerge();

	u_int uMergeFlags = 0;
	if(!bPermanentMerge)
	{
		if(!pxTemplate->bMergeRenderMeshWithEnv) uMergeFlags |= TOOLS_MERGEOBJECT_IGNORERENDERMESH;
		if(!pxTemplate->bMergeCollisionMeshWithEnv) uMergeFlags |= TOOLS_MERGEOBJECT_IGNORECOLLISIONMESH;
	}

	u_int uPolyFlagsToAdd = 0;

	bool bOkay = true;

	Asura_Guid uMergeGuid = bPermanentMerge ? ASURA_GUID_UNREGISTERED : GetMergeGuid();
	
	//Merge the shape (or shapes)
	if(pxTemplate->eType == ASURA_BOTANICALS_TEMPLATE_SHAPE)
	{
		
		Asura_Hash_ID uShapeHash = pxTemplate->uShapeID;
		Asura_Mesh* pxMesh = Tools_ShapeTable::GetMeshByHashID(uShapeHash);
		if(!pxMesh) return;

		Asura_Vector_3 xScale(m_fInstanceScale,m_fInstanceScale,m_fInstanceScale);
		bOkay &= Tools_Mode_MeshEdit::MergeObjectIntoModule(iModule,pxMesh,Orientation,Position,uMergeGuid,uChecksum,xScale,uPolyFlagsToAdd,uMergeFlags);
	}
	else if(pxTemplate->eType == ASURA_BOTANICALS_TEMPLATE_BOTANICALSHAPE)
	{
		Asura_Assert(pxTemplate->pxBotanicalShape, "template has no botanicals shape");
		if (!pxTemplate->pxBotanicalShape) return;

		//merge all the shapes
		Tools_BotanicalShape* pxToolsShape = pxTemplate->pxBotanicalShape->GetToolsShape();
		if(!pxToolsShape) return;

		
		//merge render meshes
		if(pxTemplate->bMergeRenderMeshWithEnv || bPermanentMerge)
		{
			List<Asura_Mesh*> xMeshList;
			ListMeshesToMerge(pxTemplate,pxToolsShape,xMeshList,false);

			if(!Tools_Mode_MeshEdit::CanMergeMeshesIntoModule(iModule, xMeshList, uMergeFlags|TOOLS_MERGEOBJECT_IGNORECOLLISIONMESH, bPermanentMerge))
			{
				bOkay = false;
			}
			
			if(bOkay)
			{
				for(LIF<Asura_Mesh*> xMeshLIF(&xMeshList);!xMeshLIF.done();xMeshLIF.next())
				{

					Asura_Vector_3 xScale(m_fInstanceScale,m_fInstanceScale,m_fInstanceScale);
					bOkay &= Tools_Mode_MeshEdit::MergeObjectIntoModule(iModule,xMeshLIF(),Orientation,Position,uMergeGuid,uChecksum,xScale,uPolyFlagsToAdd,uMergeFlags|TOOLS_MERGEOBJECT_IGNORECOLLISIONMESH);
				}
				Asura_Assert(bOkay, "Not expecting to fail at this point");
			}
		}
		//merge collision meshes
		if(pxTemplate->bMergeCollisionMeshWithEnv && !bPermanentMerge && bOkay)
		{
			List<Asura_Mesh*> xMeshList;
			ListMeshesToMerge(pxTemplate,pxToolsShape,xMeshList,true);

			if(!Tools_Mode_MeshEdit::CanMergeMeshesIntoModule(iModule, xMeshList, uMergeFlags|TOOLS_MERGEOBJECT_IGNORERENDERMESH, bPermanentMerge))
			{
				bOkay = false;
			}

			if(bOkay)
			{
				for(LIF<Asura_Mesh*> xMeshLIF(&xMeshList);!xMeshLIF.done();xMeshLIF.next())
				{

					Asura_Vector_3 xScale(m_fInstanceScale,m_fInstanceScale,m_fInstanceScale);
					
					// MGH 29/4/2008: I've taken out the AsuraPolygonFlag_DontRender flag as we want bullets to be stopped by boulders
					// and tree trunks. This works fine so long as the collision meshes are flagged with the correct material and
					// follow the render mesh quite closely.
					bOkay &= Tools_Mode_MeshEdit::MergeObjectIntoModule(iModule,xMeshLIF(),Orientation,Position,uMergeGuid,uChecksum,xScale, AsuraPolygonFlag_DontRender | uPolyFlagsToAdd, uMergeFlags|TOOLS_MERGEOBJECT_IGNORERENDERMESH);
				}
				Asura_Assert(bOkay, "Not expecting to fail at this point");

			}
		}

	}
	else
	{
		Asura_Assert(0,"Unexpected botanicals template type");
		return;
	}

	//Update the merged flags
	if(pxTemplate->bMergeRenderMeshWithEnv) m_uBotanicalFlags |= ASURA_BOTANICAL_FLAG_RENDERMESHMERGED;
	if(pxTemplate->bMergeCollisionMeshWithEnv) m_uBotanicalFlags |= ASURA_BOTANICAL_FLAG_COLLISIONMESHMERGED;

	if(!bOkay)
	{
		//Failed on one or more of the merged
		//Unmerge whatever was merged
		UnmergePolygonsFromEnvironment();

		//TBD put some error message somewhere
	}
	else if(bPermanentMerge)
	{
		Destroy();
	}
	
	Tools_Mode_Botanicals::SetModifiedFlag(true);

	
}

void Tools_Botanicals_Object::MergeObjectsIntoEnvironmentIfNeeded(bool bForceUpdateAll)
{
	for(LIF<Tools_Botanicals_Object*> xObjectLIF(&s_xObjectList);!xObjectLIF.done();xObjectLIF.next())
	{
		if (bForceUpdateAll)
		{		
			xObjectLIF()->UnmergePolygonsFromEnvironment();
		}

		xObjectLIF()->MergePolygonsIntoEnvironmentIfNeeded(false);
	}
}

void Tools_Botanicals_Object::PermanentlyMergeSelectedObjects()
{
	//get a list of selected botanicals
	List<Tools_Botanicals_Object*> xMergeList;

	for(LIF<Tools_Botanicals_Object*> xObjectLIF(&s_xObjectList);!xObjectLIF.done();xObjectLIF.next())
	{
		if(xObjectLIF()->IsSelected() || xObjectLIF()->IsGroupSelected())
		{
			xMergeList.add_entry(xObjectLIF());
		}
	}

	if(!xMergeList.size()) return;
	if(!ShowYesNoOverlay("Permanently merge the %d selected botanicals into the environment?",xMergeList.size())) return;

	for(LIF<Tools_Botanicals_Object*> xMergeLIF(&xMergeList); !xMergeLIF.done(); xMergeLIF.next())
	{
		xMergeLIF()->MergePolygonsIntoEnvironmentIfNeeded(true);
	}
}

void Tools_Botanicals_Object::PermanentlyMergeFlaggedObjects()
{
	if(!ShowYesNoOverlay("This will permanently merge into the environment any instances of templates that have been flagged to do so.\nAny such instances will be deleted after doing this.\nProceed?")) return;

	//Need to have everything as tools objects first
	Asura_Botanicals_InstanceManager::ConvertToToolObjects();

	//get a list of all suitably flagged botanicals
	List<Tools_Botanicals_Object*> xMergeList;
	for(LIF<Tools_Botanicals_Object*> xObjectLIF(&s_xObjectList);!xObjectLIF.done();xObjectLIF.next())
	{
		Asura_Botanicals_Template* pxTemplate=Asura_Botanicals_TemplateManager::GetTemplate(xObjectLIF()->m_iTemplateIdx);
		if(pxTemplate && pxTemplate->bPermanentlyMergeMesh)
		{
			xMergeList.add_entry(xObjectLIF());
		}
	}

	for(LIF<Tools_Botanicals_Object*> xMergeLIF(&xMergeList); !xMergeLIF.done(); xMergeLIF.next())
	{
		xMergeLIF()->MergePolygonsIntoEnvironmentIfNeeded(true);
	}
	
}


u_int Tools_Botanicals_Object::GetChecksumForMerge() const
{
	u_int uChecksum = 0;

	uChecksum += *(u_int*) &Position.x;
	uChecksum += *(u_int*) &Position.y;
	uChecksum += *(u_int*) &Position.z;

	Asura_Euler_3 xOrientEuler;
	xOrientEuler.FromMatrix(Orientation);

	uChecksum += *(u_int*) &xOrientEuler.x;
	uChecksum += *(u_int*) &xOrientEuler.y;
	uChecksum += *(u_int*) &xOrientEuler.z;

	uChecksum += *(u_int*) &m_fInstanceScale;

	Asura_Botanicals_Template* pxTemplate=Asura_Botanicals_TemplateManager::GetTemplate(m_iTemplateIdx);
	Asura_Assert(pxTemplate,"Failed to get botanical template");
	if(pxTemplate)
	{
		//add in (purely abritrary) values based on the merge flags
		if(pxTemplate->bMergeRenderMeshWithEnv)
		{
			uChecksum += 0x46B3B22E;
		}
		if(pxTemplate->bMergeCollisionMeshWithEnv)
		{
			uChecksum += 0x67217F7E;
		}
	

		//Add checksum for shape / meshes
		if(pxTemplate->eType == ASURA_BOTANICALS_TEMPLATE_SHAPE)
		{
			Asura_Hash_ID uShapeHash = pxTemplate->uShapeID;
			if(uShapeHash)
			{
				uChecksum += Tools_ShapeTable::GetChecksumForShape(uChecksum);
			}
		}
		else if(pxTemplate->eType == ASURA_BOTANICALS_TEMPLATE_BOTANICALSHAPE)
		{

			Asura_Assert(pxTemplate->pxBotanicalShape, "template has no botanicals shape");

			if (pxTemplate->pxBotanicalShape)
			{
				Tools_BotanicalShape* pxToolsShape = pxTemplate->pxBotanicalShape->GetToolsShape();
				if(pxToolsShape)
				{
					//get checksum of render meshes to merge
					if(pxTemplate->bMergeRenderMeshWithEnv)
					{
						List<Asura_Mesh*> xMeshList;
						ListMeshesToMerge(pxTemplate,pxToolsShape,xMeshList,false);

						for(LIF<Asura_Mesh*> xMeshLIF(&xMeshList);!xMeshLIF.done();xMeshLIF.next())
						{
							uChecksum += xMeshLIF()->m_uChecksum;
						}
					}

					//and collision meshes
					if(pxTemplate->bMergeCollisionMeshWithEnv)
					{
						List<Asura_Mesh*> xMeshList;
						ListMeshesToMerge(pxTemplate,pxToolsShape,xMeshList,true);

						for(LIF<Asura_Mesh*> xMeshLIF(&xMeshList);!xMeshLIF.done();xMeshLIF.next())
						{
							uChecksum += xMeshLIF()->m_uChecksum;
						}
					}
				}
			}
		}
		else
		{
			Asura_Assert(0,"Unexpected botanicals template type");
		}
	}

	return uChecksum;
}

void Tools_Botanicals_Object::CheckAllMerging()
{
	if(Asura_Botanicals_InstanceManager::GetNumInstances())
	{
		//If there are still some instances in the asura system , then we need to convert them to tools objects first
		Asura_Botanicals_InstanceManager::ConvertToToolObjects();
	}



	//get a list of all botanicals guids attached to the environment
	List<Asura_Mesh_MergedEntity> xMergeList;
	LIF<Asura_Mesh_MergedEntity> xMergeLIF(&xMergeList);

	for(int i=0;i<Asura_Module_System::GetNumberOfModules();i++)
	{
		Asura_Mesh* pxMesh = Asura_Module_System::GetMeshForModule(i);

		for(int j=0;j<pxMesh->m_iNumberOfMergedEntities;j++)
		{
			Asura_Mesh_MergedEntity xMerge = pxMesh->m_pxMergedEntities[j];
			
			//Botanicals guids start after end of tools guids
			if(xMerge.m_uGuid > ASURA_GUID_TOOLSCREATEDENTITY_END)
			{
				xMergeList.add_entry(xMerge);
			}
		}
	}


	//check each botanical to see if the merged with env flags corresponds with the guid list
	for(LIF<Tools_Botanicals_Object*> xObjectLIF(&s_xObjectList);!xObjectLIF.done();xObjectLIF.next())
	{
		Tools_Botanicals_Object* pxObject = xObjectLIF();

		//search for guid in list
		Asura_Guid uGuid = pxObject->GetMergeGuid();
		bool bIsMerged = false;
		for(xMergeLIF.restart();!xMergeLIF.done();xMergeLIF.next())
		{
			if(xMergeLIF().m_uGuid == uGuid)
			{
				bIsMerged =  true;
				break;
			}
		}
	

		if(bIsMerged)
		{
			
			Asura_Botanicals_Template* pxTemplate=Asura_Botanicals_TemplateManager::GetTemplate(pxObject->m_iTemplateIdx);

			if(pxTemplate && (pxTemplate->bMergeRenderMeshWithEnv || pxTemplate->bMergeCollisionMeshWithEnv))
			{
							
				//Correct the merged flags as needed
				pxObject->m_uBotanicalFlags &=~ ASURA_BOTANICAL_FLAGS_ANYMERGE;
				if(pxTemplate->bMergeRenderMeshWithEnv) pxObject->m_uBotanicalFlags |= ASURA_BOTANICAL_FLAG_RENDERMESHMERGED;
				if(pxTemplate->bMergeCollisionMeshWithEnv) pxObject->m_uBotanicalFlags |= ASURA_BOTANICAL_FLAG_COLLISIONMESHMERGED;


				if(xMergeLIF().m_uChecksum != pxObject->GetChecksumForMerge())
				{
					//object out of date... unmerge the polygons , and remerge below
					pxObject->UnmergePolygonsFromEnvironment();
				}
			}
			else
			{
				//object is merged with environment , but shouldn't be... remove the polygons
				pxObject->UnmergePolygonsFromEnvironment(true);				
			}

			xMergeLIF.delete_current();
		}
		else
		{
			//Not merged , so update the flags to reflect that
			pxObject->m_uBotanicalFlags &=~ ASURA_BOTANICAL_FLAGS_ANYMERGE;
  		}
		pxObject->MergePolygonsIntoEnvironmentIfNeeded(false);
	}

	//Delete the polygons for any guids left in the list , since these botanicals no longer exist
	while(xMergeList.size())
	{
		Tools_Mode_MeshEdit::DeleteEntityPolygons(xMergeList.first_entry().m_uGuid);
		xMergeList.delete_first_entry();
	}

	//If this was being done outside of botanicals mode ,then we need to transfer the objects back to the asura system
	if(Tools_System::GetCurrentMode() != TOOLS_MODE_BOTANICALS)
	{
		Asura_Botanicals_InstanceManager::ConvertFromToolObjects();
	}
	
}

void Tools_Botanicals_Object::ListMeshesToMerge(const Asura_Botanicals_Template* pxTemplate,Tools_BotanicalShape* pxToolsShape,List<Asura_Mesh*>& xOutputList,bool bCollMeshes) const
{
	if(!pxTemplate) return;

	if( true == bCollMeshes)
	{
		if( 0 != pxTemplate->uSelectionShapeID)
		{
			//get the collision mesh from the selection shape. RAR 23/05/2006
			Asura_Mesh* pxMesh = Tools_ShapeTable::GetMeshByHashID(pxTemplate->uSelectionShapeID);
			if(pxMesh)
			{
				xOutputList.add_entry(pxMesh);
			}
			
			return;
		}
		
		// DLH - 07 December 2006 13:11:58 - To get to here the SelectionShapeID must be unset ( 0 )
		// DLH - 07 December 2006 13:11:58 - If the Filename is set that implys that the shape file was not loaded
		// DLH - 07 December 2006 13:11:58 - Do not allow the render mesh to be use as this could add large amounts of data to be merged
		if( 0 != pxTemplate->xSelectionShapeName.Compare(""))
		{
			Tools_MessageLog::AddMessage( "Botanicals",
										  "Not Merged Mesh Selection Shape",
										  "Template '%s' did not load Selection Shape '%s' but was considered for merging.\nThe merge was not performed.",
										  pxTemplate->xTemplateName.GetString(),
										  pxTemplate->xSelectionShapeName.GetString() );

			Tools_MessageLog::ShowOverlay();
			return;
		}
	}
	
	{
		//Going to take the LOD with the highest number of polygons from each element for now.
		//RAR 20/03/2006
		if(!pxToolsShape) return;
	
		for(int i=0;i<pxToolsShape->GetNumElements();i++)
		{
			Tools_BotanicalElement* pxElement = pxToolsShape->GetElementByIndex(i);
			if(!pxElement->GetNumLODs()) continue;

			//Only get meshes from the more meshey types of element. RAR 31/05/2006
			if(	pxElement->m_eType != TOOLS_BOTANICALS_ELEMENTTYPE_1SIDED_MESH &&
				pxElement->m_eType != TOOLS_BOTANICALS_ELEMENTTYPE_2SIDED_MESH)
			{
				continue;
			}


			int iMaxPoly = 0;
			Asura_Mesh* pxMesh = 0;

			for(int j=0;j<pxElement->GetNumLODs();j++)
			{
				Tools_BotanicalElementLOD* pxLOD = pxElement->GetLODByIndex(j);
				Asura_Mesh* pxLODMesh = pxLOD->m_pxMesh;
				if(pxLODMesh && pxLODMesh->NumberOfPolygons > iMaxPoly)
				{
					pxMesh = pxLODMesh;
					iMaxPoly = pxLODMesh->NumberOfPolygons;
				}
					
			}

			if(!pxMesh) continue;

			xOutputList.add_entry(pxMesh);
		}
	}

}

#if defined( ASURA_BOTANICALS_BGR_IN_EDIT)
void Tools_Botanicals_Object::RegenerateBGRInstance()
{
	//Delete the old instance of the render data for this botanical
	if( NULL != m_pxBGRInstanceHeader)
	{
		Asura_Direct3D_BGR_Instance* pxBGRInstance = m_pxBGRInstanceHeader->GetDirect3DInstance( m_uBGRInstanceHeaderInstanceIndex);
		pxBGRInstance->SetActive( false);
		m_pxBGRInstanceHeader = 0;
		m_uBGRInstanceHeaderInstanceIndex = 0;
	}
	//and  create a new one.
	Asura_Botanicals_InstanceManager::CreateToolObjectInBGR(this);

	Asura_Direct3D_BGR_Manager& xBGRManager = Asura_Direct3D_Botanicals_Game_Render::GetDirect3DBGRManager();
	xBGRManager.InvalidateDirect3DData();
}
#endif //defined( ASURA_BOTANICALS_BGR_IN_EDIT)

#endif //ASURA_USE_BOTANICALS
