//
// Asura_Chunk_ResourceFile_PSP_Botanicals.cpp
//
// Created by JG - Monday, October 09, 2006
//
// Copyright (C) 2004 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"

// This file's header.
#include "ChunkSystem/Asura_Chunk_ResourceFile_PSP_Botanicals.h"

// Asura files
#include "Core/Asura_Handle.h"

#if defined ASURA_USE_BOTANICALS

// Asura files
#include "FileAccess/Asura_FileAccess.h"
#include "Core/Asura_List.h"
#include "Core/Asura_Material_System.h"
#include "Light/Asura_Lighting_Solution.h"
#include "ChunkSystem/Asura_Chunk_Stream.h"

// Platform specific headers
#include "Rendering/Asura_PSP_BotanicalRenderer_Internal.h"
#include "Botanicals/Asura_PSP_BotanicalsElement.h"
#include "Botanicals/Asura_PSP_BotanicalsShape.h"
#include "Botanicals/Asura_PSP_BotanicalsTemplate.h"
#include "Botanicals/Asura_Botanical_Game_Render_Instance.h"
#include "Botanicals/Asura_PSP_BotanicalsSystem.h"

unsigned int Asura_Chunk_ResourceFile_PSP_Botanicals::ProcessShapes( Asura_Handle hFile, unsigned int uNumberOfShapes, unsigned int uCurrentShape, void** xTemplateList )
{
	for( unsigned int uShape = 0; uShape < uNumberOfShapes; ++uShape )
	{
		Asura_PSP_BotanicalsShape* xCurrShape = &Asura_PSP_BotanicalsSystem::s_pxShapes[uCurrentShape];
		unsigned int uHash; 
		unsigned int uType; 

		Asura_FileAccess::ReadData( hFile, &uHash, sizeof(u_int) ); 
		Asura_FileAccess::ReadData( hFile, &uType, sizeof(u_int) ); 

		// Material hash ID
		unsigned int uMaterialID; 

		Asura_FileAccess::ReadData( hFile, &uMaterialID, sizeof(u_int) ); 

		// Geometry mesh size
		// Number of indices and vertices are used for array management
		// Number of triangles is used for rendering
		unsigned int uNumberOfIndices; 
		unsigned int uNumberOfTriangles; 
		unsigned int uNumberOfVertices;

		Asura_FileAccess::ReadData( hFile, &uNumberOfIndices, sizeof(u_int) ); 
		Asura_FileAccess::ReadData( hFile, &uNumberOfTriangles, sizeof(u_int) ); 
		Asura_FileAccess::ReadData( hFile, &uNumberOfVertices, sizeof(u_int) ); 

		// Remember what loading index is what template, to fix the instances later
		xTemplateList[uCurrentShape++] = xCurrShape;

		xCurrShape->m_pxElements = new Asura_PSP_BotanicalsElement[1];
		Asura_Assert( xCurrShape->m_pxElements, "Failed to create botanicals shape element array." );
		if(xCurrShape->m_pxElements)
		{
			xCurrShape->m_pxElements->m_pxLODData = new Asura_PSP_BotanicalsLODData[1];
			Asura_Assert( xCurrShape->m_pxElements->m_pxLODData, "Failed to create botanicals element LOD array." );
			xCurrShape->m_pxElements->m_pxLODData->Initialise(ASURA_PSP_BOTANICALS_NORMAL_MESH);

			// Get a pointer to the current strip
			Asura_PSP_Botanicals_LOD_Geometry*	xGeometry = xCurrShape->m_pxElements->m_pxLODData->m_pxGeometryLODs;
			
			// Fill the information we just read
			xGeometry->m_uNumIndices	= uNumberOfIndices;
			xGeometry->m_uNumTriangles	= uNumberOfTriangles;
			xGeometry->m_uNumVertices	= uNumberOfVertices;
			xGeometry->m_iMaterial		= Asura_Material_System::ConvertIndex( uMaterialID );

			// allocate space for vertices & indices
			if( uNumberOfVertices )
			{
				Asura_ResourceAllocateArray( xGeometry->m_pxVertices, uNumberOfVertices );
				Asura_Assert( xGeometry->m_pxVertices, "Failed to allocate array for the botanicals vertices." );
				if( xGeometry->m_pxVertices )
				{
					Asura_FileAccess::ReadData(hFile, xGeometry->m_pxVertices, sizeof(Asura_PSP_BotanicalStrip_Vertex)*uNumberOfVertices);
				}
				else
				{
					Asura_FileAccess::SkipData( hFile, sizeof(Asura_PSP_BotanicalStrip_Vertex)*uNumberOfVertices );
				}
			}

			if( uNumberOfIndices )
			{
				Asura_ResourceAllocateArray( xGeometry->m_pusIndices, uNumberOfIndices );
				Asura_Assert( xGeometry->m_pusIndices, "Failed to allocate array for the botanicals indices." );
				if(xGeometry->m_pusIndices)
				{
					Asura_FileAccess::ReadData(hFile, xGeometry->m_pusIndices, sizeof(u_short)*uNumberOfIndices);
				}
				else
				{
					Asura_FileAccess::SkipData( hFile, sizeof(u_short)*uNumberOfIndices );
				}
			}

			// Prebake the 'draw array' command
			
			// CMD_VTYPE: Set the vertex format 
			xGeometry->m_uDrawArrayDisplayList[0]	= (0x12000000) | ((0x00FFFFFF) & uBOTANICAL_STRIP_VERTEX_FORMAT);											
			
			// CMD_BASE: Set the vertex buffer base address higher bits
			xGeometry->m_uDrawArrayDisplayList[1]	= (0x10000000) | ((0x00FF0000) & ((unsigned int)xGeometry->m_pxVertices >> 8));	

			// CMD_VADR: Set the vertex buffer base address lower bits 
			xGeometry->m_uDrawArrayDisplayList[2]	= (0x01000000) | ((0x00FFFFFF) & (unsigned int)xGeometry->m_pxVertices);			

			// CMD_BASE: Set the index buffer base address higher bits
			xGeometry->m_uDrawArrayDisplayList[3]	= (0x10000000) | ((0x00FF0000) & ((unsigned int)xGeometry->m_pusIndices >> 8));	

			// CMD_IADR: Set the index buffer base address lower bits 
			xGeometry->m_uDrawArrayDisplayList[4]	= (0x02000000) | ((0x00FFFFFF) & (unsigned int)xGeometry->m_pusIndices);			
			
			// CMD_PRIM: Set the primitive to be render (actual draw function)
			xGeometry->m_uDrawArrayDisplayList[5]	= (0x04000000) | (uBOTANICAL_STRIP_PRIM_TYPE << 16) | ((0x0000FFFF) & (uNumberOfTriangles + 2));					
			
			// CMD_RET: Jump back to the calling display list
			xGeometry->m_uDrawArrayDisplayList[6]	= (0x0B000000);

			// Culling sphere
			float fCentre; 
			float fRadius; 

			Asura_FileAccess::ReadData( hFile, &fCentre, sizeof(float) ); 
			Asura_FileAccess::ReadData( hFile, &fRadius, sizeof(float) ); 

			xCurrShape->m_pxElements->m_fCentre	= fCentre;
			xCurrShape->m_pxElements->m_fRadius	= fRadius;
		}
		else
		{
			Asura_FileAccess::SkipData( hFile, sizeof(Asura_PSP_BotanicalStrip_Vertex)*uNumberOfVertices );
			if(uNumberOfIndices > 0)
			{
				Asura_FileAccess::SkipData( hFile, sizeof(u_short)*uNumberOfIndices );
			}

			// Also centre and radius
			Asura_FileAccess::SkipData(hFile, sizeof(float));
			Asura_FileAccess::SkipData(hFile, sizeof(float));
		}
	}
	return uCurrentShape;
}

void Asura_Chunk_ResourceFile_PSP_Botanicals::Process2And1SidedMesh( Asura_Handle hFile, Asura_PSP_BotanicalsElement* pxCurrentElement, unsigned int uType, unsigned int uLOD )
{
	pxCurrentElement->m_pxLODData[uLOD].Initialise(static_cast<Asura_PSP_Botanicals_Mesh_Type>( uType ));
	// Get a pointer to the current strip
	Asura_PSP_Botanicals_LOD_Geometry*	xGeometry = pxCurrentElement->m_pxLODData[uLOD].m_pxGeometryLODs;
	unsigned int uMaterialID;
	Asura_FileAccess::ReadData( hFile, &uMaterialID, sizeof(u_int) );

	// Read the geometry size related values
	unsigned int uNumberOfIndices;
	unsigned int uNumberOfTriangles;
	unsigned int uNumberOfVertices;

	Asura_FileAccess::ReadData( hFile, &uNumberOfIndices, sizeof(u_int) );
	Asura_FileAccess::ReadData( hFile, &uNumberOfTriangles, sizeof(u_int) );
	Asura_FileAccess::ReadData( hFile, &uNumberOfVertices, sizeof(u_int) );

	xGeometry->m_iMaterial		= Asura_Material_System::ConvertIndex(uMaterialID);
	xGeometry->m_uNumIndices	= uNumberOfIndices;
	xGeometry->m_uNumTriangles	= uNumberOfTriangles;
	xGeometry->m_uNumVertices	= uNumberOfVertices;

	// allocate space for vertices & indices
	if( uNumberOfVertices )
	{
		Asura_ResourceAllocateArray( xGeometry->m_pxVertices, uNumberOfVertices );
		Asura_Assert( xGeometry->m_pxVertices, "Failed to allocate array for the botanicals vertices." );
		if( xGeometry->m_pxVertices )
		{
			Asura_FileAccess::ReadData(hFile, xGeometry->m_pxVertices, sizeof(Asura_PSP_BotanicalStrip_Vertex)*uNumberOfVertices);
		}
		else
		{
			Asura_FileAccess::SkipData( hFile, sizeof(Asura_PSP_BotanicalStrip_Vertex)*uNumberOfVertices );
		}
	}

	if( uNumberOfIndices )
	{
		Asura_ResourceAllocateArray( xGeometry->m_pusIndices, uNumberOfIndices );
		Asura_Assert( xGeometry->m_pusIndices, "Failed to allocate array for the botanicals indices." );
		if(xGeometry->m_pusIndices)
		{
			Asura_FileAccess::ReadData(hFile, xGeometry->m_pusIndices, sizeof(u_short)*uNumberOfIndices);
		}
		else
		{
			Asura_FileAccess::SkipData( hFile, sizeof(u_short)*uNumberOfIndices );
		}
	}

	// Prebake the 'draw array' command
	
	// CMD_VTYPE: Set the vertex format
	xGeometry->m_uDrawArrayDisplayList[0]	= (0x12000000) | ((0x00FFFFFF) & uBOTANICAL_STRIP_VERTEX_FORMAT);											
	
	// CMD_BASE: Set the vertex buffer base address higher bits
	xGeometry->m_uDrawArrayDisplayList[1]	= (0x10000000) | ((0x00FF0000) & ((unsigned int)xGeometry->m_pxVertices >> 8));	

	// CMD_VADR: Set the vertex buffer base address lower bits 
	xGeometry->m_uDrawArrayDisplayList[2]	= (0x01000000) | ((0x00FFFFFF) & (unsigned int)xGeometry->m_pxVertices);			

	// CMD_BASE: Set the vertex buffer base address higher bits
	xGeometry->m_uDrawArrayDisplayList[3]	= (0x10000000) | ((0x00FF0000) & ((unsigned int)xGeometry->m_pusIndices >> 8));	

	// CMD_IADR: Set the index buffer base address lower bits 
	xGeometry->m_uDrawArrayDisplayList[4]	= (0x02000000) | ((0x00FFFFFF) & (unsigned int)xGeometry->m_pusIndices);			
	
	// CMD_PRIM: Set the primitive to be render (actual draw function)
	xGeometry->m_uDrawArrayDisplayList[5]	= (0x04000000) | (uBOTANICAL_STRIP_PRIM_TYPE << 16) | ((0x0000FFFF) & (uNumberOfTriangles + 2));					
	
	// CMD_RET: Jump back to the calling display list
	xGeometry->m_uDrawArrayDisplayList[6]	= (0x0B000000);
}

void Asura_Chunk_ResourceFile_PSP_Botanicals::ProcessBillboards( Asura_Handle hFile, Asura_PSP_BotanicalsElement* pxCurrentElement, unsigned int uType, unsigned int uLOD )
{
	pxCurrentElement->m_pxLODData[uLOD].Initialise(static_cast<Asura_PSP_Botanicals_Mesh_Type>( uType ));
	Asura_PSP_Botanicals_LOD_Billboards* pxBillboard = pxCurrentElement->m_pxLODData[uLOD].m_pxBillboardLODs;

	// Material hash ID
	unsigned int uMaterialID; 
	Asura_FileAccess::ReadData( hFile, &uMaterialID, sizeof( u_int )); 

	// Number of billboards and vertices exported
	unsigned int uNumberOfBillboards; 
	unsigned int uNumberOfVertices; 
	Asura_FileAccess::ReadData( hFile, &uNumberOfBillboards, sizeof( u_int )); 
	Asura_FileAccess::ReadData( hFile, &uNumberOfVertices, sizeof( u_int )); 

	// Fill in the material info
	pxBillboard->m_iMaterial				= Asura_Material_System::ConvertIndex(uMaterialID);;
	// Size of the billboard cluster
	pxBillboard->m_uNumberOfRectangles		= uNumberOfBillboards;
	pxBillboard->m_uNumberOfVertices		= uNumberOfVertices;

	if( uNumberOfVertices )
	{
		// allocate space for vertices & position 
		Asura_ResourceAllocateArray(pxBillboard->m_pxVertices, uNumberOfVertices);
		Asura_FileAccess::ReadData(hFile, pxBillboard->m_pxVertices, sizeof(Asura_PSP_BotanicalBillboard_Data)*uNumberOfVertices);
	}

	// Billboard center positions 
	pxBillboard->m_pxPositions = new Asura_Vector_3[uNumberOfBillboards]; 
	Asura_FileAccess::ReadData( hFile, pxBillboard->m_pxPositions, uNumberOfBillboards * 3 * sizeof(float)); 

	// Billboards normal information
	pxBillboard->m_pxNormals = new Asura_Vector_3[uNumberOfBillboards]; 
	Asura_FileAccess::ReadData( hFile, pxBillboard->m_pxNormals, uNumberOfBillboards * 3 * sizeof(float)); 
}

void Asura_Chunk_ResourceFile_PSP_Botanicals::ProcessImposters( Asura_Handle hFile, Asura_PSP_BotanicalsElement* pxCurrentElement, unsigned int uType, unsigned int uLOD )
{
	pxCurrentElement->m_pxLODData[uLOD].Initialise(static_cast<Asura_PSP_Botanicals_Mesh_Type>( uType ));
	Asura_PSP_Botanicals_LOD_Imposters* pxImposter = pxCurrentElement->m_pxLODData[uLOD].m_pxImpostersLODs;

	int iLoadData; 
	Asura_FileAccess::ReadData( hFile, &iLoadData, sizeof( u_int )); 
	pxImposter->m_iMaterial = Asura_Material_System::ConvertIndex( iLoadData );
	Asura_FileAccess::ReadData( hFile, &iLoadData, sizeof( u_int )); 
	pxImposter->m_iNumAngles = iLoadData;

	pxImposter->m_pxAngles = new Asura_PSP_BotanicalsImposter_Data[ pxImposter->m_iNumAngles ];
	Asura_FileAccess::ReadData( hFile, pxImposter->m_pxAngles, pxImposter->m_iNumAngles * sizeof(Asura_PSP_BotanicalsImposter_Data)); 
}

unsigned int Asura_Chunk_ResourceFile_PSP_Botanicals::ProcessBotanicalsShapes( Asura_Handle hFile, unsigned int uNumberOfBotanicalShapes, unsigned int uCurrentShape, void** xTemplateList )
{
	for ( unsigned int uBotanicalShape = 0; uBotanicalShape < uNumberOfBotanicalShapes; ++uBotanicalShape )
	{
		// Read the botanical shape hash ID
		unsigned int uHash; 
		Asura_FileAccess::ReadData( hFile, &uHash, sizeof(u_int) ); 
		
		// How many elements form this botanical?
		unsigned int uNumElements;
		Asura_FileAccess::ReadData( hFile, &uNumElements, sizeof(u_int) ); 

		Asura_PSP_BotanicalsShape* xCurrShape = &Asura_PSP_BotanicalsSystem::s_pxShapes[uCurrentShape];
		xCurrShape->SetType( Asura_BGR_TypeID( uCurrentShape ) );
		xCurrShape->m_uHashID = uHash;

		xTemplateList[uCurrentShape++] = xCurrShape;

		xCurrShape->m_pxElements = new Asura_PSP_BotanicalsElement[uNumElements];
		Asura_Assert( xCurrShape->m_pxElements, "Failed to create botanicals shape element array." );

		if(xCurrShape->m_pxElements)
		{
			xCurrShape->m_uNumElements = uNumElements;
			for( unsigned int uElement = 0; uElement < uNumElements; ++uElement )
			{
				// What type of element is this?
				unsigned int uType; 
				Asura_FileAccess::ReadData( hFile, &uType, sizeof(u_int) ); 

				// How many LoDs has this element?
				unsigned int uNumLODs; 
				Asura_FileAccess::ReadData( hFile, &uNumLODs, sizeof( u_int ) ); 

				// Allocate space for that number of LoDs
				Asura_PSP_BotanicalsElement* pxCurrentElement		= &xCurrShape->m_pxElements[uElement];
				pxCurrentElement->m_pxLODData						= new Asura_PSP_BotanicalsLODData[ uNumLODs ];
				pxCurrentElement->m_iNumLODs						= uNumLODs;
				
#if defined( ASURA_BOTANICAL_SUPPORT_SECTION_VERSIONS) && 1 == ASURA_BOTANICAL_SUPPORT_SECTION_VERSIONS
				{
					Asura_Chunk_File_Stream xStream( hFile );
					xStream >> pxCurrentElement->m_xSectionID;
					xStream >> pxCurrentElement->m_xVersionID;
				}
#endif
				Asura_Assert( pxCurrentElement->m_pxLODData, "Failed to create LOD Data element array." );
				if( pxCurrentElement->m_pxLODData )
				{
					for( unsigned int uLOD = 0; uLOD < uNumLODs; ++uLOD)
					{
						// Is it normal (or double sided) mesh?
						switch(uType)
						{
						case ASURA_PSP_BOTANICALS_NORMAL_MESH:
						case ASURA_PSP_BOTANICALS_2SIDED_MESH:
							{
								Process2And1SidedMesh( hFile, pxCurrentElement, uType, uLOD );
								break;
							}
						case ASURA_PSP_BOTANICALS_BILLBOARDS:
							{
								ProcessBillboards( hFile, pxCurrentElement, uType, uLOD );
								break;
							}
						case ASURA_PSP_BOTANICALS_IMPOSTER:
							{
								ProcessImposters( hFile, pxCurrentElement, uType, uLOD );
								break;
							}
						default:
							{
								pxCurrentElement->m_pxLODData[uLOD].Initialise(static_cast<Asura_PSP_Botanicals_Mesh_Type>( uType ));
								break;
							}
						}
					}// for loop (LODs)
					// Culling sphere for this element
					float fCentre; 
					float fRadius; 

					Asura_FileAccess::ReadData( hFile, &fCentre, sizeof(float) ); 
					Asura_FileAccess::ReadData( hFile, &fRadius, sizeof(float) ); 

					pxCurrentElement->m_fCentre		= fCentre;
					pxCurrentElement->m_fRadius		= fRadius;

					// LoD graphs, for LoD swapping and blending
					for( unsigned int uLOD = 0; uLOD < uNumLODs; ++uLOD )
					{
						float fMin;				// Min distance the LoD start to be drawn
						float fMinFull;			// Min distance the LoD gets fully drawn
						float fMaxFull;			// Max distance the LoD gets fully drawn
						float fMax;				// Max distance before the LoD disappers
						
						// Read the LoD table
						Asura_FileAccess::ReadData( hFile, &fMin, sizeof(float) ); 
						Asura_FileAccess::ReadData( hFile, &fMinFull, sizeof(float) ); 
						Asura_FileAccess::ReadData( hFile, &fMaxFull, sizeof(float) ); 
						Asura_FileAccess::ReadData( hFile, &fMax, sizeof(float) ); 

						unsigned int uVisible;  //	TODO: not neeeded
						Asura_FileAccess::ReadData( hFile, &uVisible, sizeof(u_int) ); 

						pxCurrentElement->m_pxLODData[uLOD].m_fMinDistance			= fMin;
						pxCurrentElement->m_pxLODData[uLOD].m_fMinFullAlphaDistance	= fMinFull;
						pxCurrentElement->m_pxLODData[uLOD].m_fMaxDistance			= fMax;
						pxCurrentElement->m_pxLODData[uLOD].m_fMaxFullAlphaDistance	= fMaxFull;
					}
				}
			}
		}
		{
			Asura_Chunk_File_Stream xStream( hFile );
#if defined( ASURA_BOTANICAL_SUPPORT_DYNAMIC_DATA) && 1 == ASURA_BOTANICAL_SUPPORT_DYNAMIC_DATA
			xCurrShape->Process( xStream );
#endif
		}
	}// Botanical shapes
	return uCurrentShape;
}

#endif //#if defined ASURA_USE_BOTANICALS

// Process botanical chunks, loading relevant structures and adding them to the appropiate managers
void Asura_Chunk_ResourceFile_PSP_Botanicals::Process( Asura_Handle hFile )
{
#if defined ASURA_USE_BOTANICALS
	Asura_ResourcePushType(ASURA_RESOURCE_BOTANICAL_MESH);
	{
		// How many shapes?
		unsigned int uCurrentShape = 0;
		unsigned int uNumberOfShapes;
		Asura_FileAccess::ReadData( hFile, &uNumberOfShapes, sizeof(u_int) );

		// How many botanical shapes?
		unsigned int uNumberOfBotanicalShapes;
		Asura_FileAccess::ReadData( hFile, &uNumberOfBotanicalShapes, sizeof(u_int) );

		// How many templates?
		unsigned int uNumberOfTemplates; 
		Asura_FileAccess::ReadData( hFile, &uNumberOfTemplates, sizeof(u_int) );

		// Check that shapes and botanicals add to the total number of templates, otherwise something went wrong with the export
		unsigned int uTotalNumberOfShapes = uNumberOfShapes + uNumberOfBotanicalShapes; 
		Asura_Assert(uTotalNumberOfShapes == uNumberOfTemplates, "Wrong number of templates in exported file!"); 

		Asura_PSP_BotanicalsSystem::s_uNumShapes	= uNumberOfShapes;
		Asura_PSP_BotanicalsSystem::s_uNumTemplates	= uNumberOfTemplates;

		Asura_PSP_BotanicalsSystem::s_pxShapes		= new Asura_PSP_BotanicalsShape[ uTotalNumberOfShapes ];
		Asura_Assert( Asura_PSP_BotanicalsSystem::s_pxShapes, "Failed to create botanicals shape array." );
		Asura_PSP_BotanicalsSystem::s_uNumShapes	= uTotalNumberOfShapes;

		Asura_PSP_BotanicalsSystem::s_pxTemplates	= new Asura_PSP_BotanicalsTemplate[ uNumberOfTemplates ];
		Asura_Assert( Asura_PSP_BotanicalsSystem::s_pxTemplates, "Failed to create botanicals template array." );

		void** xTemplateList = new void*[uTotalNumberOfShapes];

		//Shapes
		uCurrentShape = ProcessShapes( hFile, uNumberOfShapes, uCurrentShape, xTemplateList);
		// Botanical shapes
		uCurrentShape = ProcessBotanicalsShapes( hFile, uNumberOfBotanicalShapes, uCurrentShape, xTemplateList);

		// Instances to botanicals shapes
		for (unsigned int uTemplate = 0; uTemplate < uNumberOfTemplates; ++uTemplate)
		{
			// Read the shape index
			unsigned int uShapeIndex; 
			Asura_FileAccess::ReadData( hFile, &uShapeIndex, sizeof(u_int) ); 

			// Get a pointer to the template definition
			void* pxTemplate = xTemplateList[uShapeIndex];
			Asura_PSP_BotanicalsShape* pxShape = (Asura_PSP_BotanicalsShape*)pxTemplate;
			ASURA_PSP_BOTANICALS_TEMPLATE_TYPE eTemplateType = ASURA_PSP_BOTANICALS_TEMPLATE_BOTANICALSHAPE; 
			Asura_PSP_BotanicalsSystem::s_pxTemplates[uTemplate].SetType( Asura_BGR_TypeID( uShapeIndex ) );
			
			// Fix the template type based on the position in the list
			if (uShapeIndex < uNumberOfShapes)
			{
				eTemplateType = ASURA_PSP_BOTANICALS_TEMPLATE_SHAPE;
			}

			Asura_Bounding_Box xTemplateBoundingBox;
			Asura_FileAccess::ReadData( hFile, &xTemplateBoundingBox, sizeof(Asura_Bounding_Box) ); 
			xTemplateBoundingBox.Grow( pxShape->GetBoundingRadius());
			Asura_PSP_BotanicalsSystem::s_pxTemplates[ uTemplate ].SetBoundingBox( xTemplateBoundingBox);

			// Read the number of instances using this template
			unsigned int uNumberOfInstances; 
			Asura_FileAccess::ReadData( hFile, &uNumberOfInstances, sizeof(u_int) ); 

			Asura_PSP_BotanicalsSystem::s_pxTemplates[ uTemplate ].m_pxShape = (Asura_PSP_BotanicalsShape*) pxTemplate;

			// Instances
			Asura_PSP_BotanicalsSystem::s_pxTemplates[ uTemplate ].m_pxInstances = new Asura_PSP_BotanicalsInstance[uNumberOfInstances];
			Asura_PSP_BotanicalsSystem::s_pxTemplates[ uTemplate ].m_iNumInstances = uNumberOfInstances;

#if defined( ASURA_BOTANICAL_SUPPORT_DYNAMIC_DATA) && 1 == ASURA_BOTANICAL_SUPPORT_DYNAMIC_DATA
		Asura_PSP_BotanicalsSystem::s_pxTemplates[ uTemplate ].SetDynamicDataLayout( Asura_PSP_BotanicalsSystem::s_pxTemplates[ uTemplate ].m_pxShape->GetDynamicDataLayout());
		Asura_PSP_BotanicalsSystem::s_pxTemplates[ uTemplate ].AllocateDynamicData( Asura_PSP_BotanicalsSystem::s_pxTemplates[ uTemplate ].m_iNumInstances);
#endif
			for (unsigned int uInstance = 0; uInstance < uNumberOfInstances; ++uInstance)
			{	
				Asura_PSP_BotanicalsInstance* pxBotanicalInstance = &Asura_PSP_BotanicalsSystem::s_pxTemplates[ uTemplate ].m_pxInstances[ uInstance ]; 
				
				// Matrix transformation for this instance (already a diplay list)
				Asura_FileAccess::ReadData( hFile, &(pxBotanicalInstance->uStart), 14 * sizeof(u_int) ); 

				// Pointer to the actual geometry for this instance
				pxBotanicalInstance->eType		= eTemplateType; 
				pxBotanicalInstance->pxTemplate = pxTemplate;
				
				// Realtime lighting object
				pxBotanicalInstance->pxLightingSolution = new Asura_Lighting_Solution(true, false); 
				
				// Read spherical harmonics
				Asura_FileAccess::ReadData( hFile, &(pxBotanicalInstance->afSHRed), 4 * sizeof(float) ); 
				Asura_FileAccess::ReadData( hFile, &(pxBotanicalInstance->afSHGreen), 4 * sizeof(float) ); 
				Asura_FileAccess::ReadData( hFile, &(pxBotanicalInstance->afSHBlue), 4 * sizeof(float) ); 

				// Scale value, used by billboards
				float fScale; 
				Asura_FileAccess::ReadData( hFile, &fScale, sizeof(float) ); 

				pxBotanicalInstance->fScale = fScale; 

				// CPU friendly culling info
				Asura_FileAccess::ReadData( hFile, &(pxBotanicalInstance->afCull), 3 * sizeof(float) ); 

				// Moule information, index to the module where this instance live in
				int iModule;
				Asura_FileAccess::ReadData( hFile, &iModule, sizeof(int) ); 
				pxBotanicalInstance->iModule = iModule; 

				//TODO: Convert orientation to floats and store it to fOrientation
			}
		}// Templates

		// Release this temporary list once we've finished importing botanicals
		delete[] xTemplateList; 
	}
	Asura_ResourcePopType();
#endif // #if defined ASURA_USE_BOTANICALS
}
