//
// Asura_Chunk_PhysicsEnvironment.cpp
//
// Created by KJFL - 07 September 2004
//
// Copyright (C) 2004 Rebellion, All Rights Reserved.
//

#include "Core/Asura.h"

#include <string.h>

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

// Asura headers
#include "ChunkSystem/Asura_Chunk_Macros.h"
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "ChunkSystem/Asura_SaveBlock.h"
#include "Core/Asura_Material_System.h"
#include "Core/Memory/Asura_Mem.h"
#include "Core/Memory/Asura_ResourceAllocator.h"
#include "Debugging/Asura_Assert.h"
#include "Debugging/Asura_Logfile.h"
#include "FileAccess/Asura_FileAccess.h"
#include "Physics/Asura_Physics_Environment.h"

#ifdef ASURA_TOOLS
#include "Load&Save/Tools_AsrFileManager.h"
#endif


bool Asura_Physics_Zone::Process (Asura_Handle hFile,
								  const Asura_Chunk_PhysicsEnvironment& xChunk)
{
	#ifdef ASURA_TOOLS
	if(Tools_AsrFileManager::IsUsingMultipleAsrFiles())
	{
		//If the environment is split across multiple asr files then the physics environment from each
		//file won't be much use for the environment as a whole. So skip the chunk and allow this
		//to be recalculated later.
		//RAR 18/10/2007
		return false;
	}
	#endif	

	#ifdef ASURA_TOOLS
	m_bInvalid = false;
	#endif

//	if(m_uNumberOfSectors)
//	{
//		//Already been initialised
//		//RAR 30/08/2007
//		Asura_Assertf(0,("Loading a physics environment chunk when it has already been set up.\nThis may happen when loading a skin file that has been saved as an environment by mistake.\nFile being loaded :%s",Asura_FileAccess::GetFilename(hFile)));
//		return false;
//	}
	
	if (xChunk.m_uNumberOfSectors)
	{
		Asura_Physics_Environment_Face*			pxFaces;
		Asura_Physics_Environment_FaceFlags*	pxFaceFlags;
		Asura_Physics_Environment_Sector*		pxSectors;
		Asura_Physics_Environment_Vertex*		pxVertices;
		u_short*								pusPolygonFlags;

		Asura_ResourcePushType(ASURA_RESOURCE_COLLISION_MESH);
		{

			// allocate space for sector data
			Asura_ResourceAllocateArray(pxSectors, xChunk.m_uNumberOfSectors);

			// and load data in one go
			for (u_int s = 0; s < xChunk.m_uNumberOfSectors; s++)
			{
				Asura_FileAccess::ReadData	(hFile,	&pxSectors [s].m_uFaceIndexOffset,			sizeof(u_int));
				Asura_FileAccess::ReadData	(hFile,	&pxSectors [s].m_uVertexIndexOffset,			sizeof(u_int));
				Asura_FileAccess::ReadData	(hFile,	&pxSectors [s].m_uNumberOfFaces,				sizeof(u_int));

				Asura_FileAccess::ReadData	(hFile,	&pxSectors [s].m_xFaceTree.m_uNumberOfNodes,	sizeof(u_int));
				Asura_FileAccess::ReadData	(hFile,	&pxSectors [s].m_xFaceTree.m_xRootBoundingBox,sizeof(Asura_Bounding_Box));

				Asura_FileAccess::ReadData	(hFile,	&pxSectors [s].m_uPolygonFlagOffset,			sizeof(u_int));
				Asura_FileAccess::ReadData	(hFile,	&pxSectors [s].m_uMaterialIDOffset,			sizeof(u_int));
				Asura_FileAccess::ReadData	(hFile,	&pxSectors [s].m_usFlags,						sizeof(u_short));
				Asura_FileAccess::SkipData	(hFile, sizeof(u_int) - sizeof(u_short));

				Asura_ChunkLoading_System::YieldBackgroundProcessing();
			}

			// then vertex data...
			Asura_ResourceAllocateArray(pxVertices, xChunk.m_uNumberOfVertices);

			// (MH - 08.11.2005) used to read this all in one go, but now need to cope with vertex
			// size being different depending on whether platform is using aligned vectors.
			Asura_Physics_Environment_Vertex* pxVertex = pxVertices;
			for (u_int u = 0; u < xChunk.m_uNumberOfVertices; ++u)
			{
#if 1
				Asura_Vector_3 xFileVector;
				Asura_FileAccess::ReadData
					(
					hFile,
					&xFileVector,
					sizeof(Asura_Vector_3)
					);
				#if defined( ASURA_ASSERT)
					const float fAssertRange = 1e20f;
					Asura_Assertf( -fAssertRange < xFileVector.GetX() && xFileVector.GetX() < fAssertRange, ("Bad Float %f", Asura_Maths::FtoD(xFileVector.GetX())));
					Asura_Assertf( -fAssertRange < xFileVector.GetY() && xFileVector.GetY() < fAssertRange, ("Bad Float %f", Asura_Maths::FtoD(xFileVector.GetY())));
					Asura_Assertf( -fAssertRange < xFileVector.GetZ() && xFileVector.GetZ() < fAssertRange, ("Bad Float %f", Asura_Maths::FtoD(xFileVector.GetZ())));
				#endif
				pxVertex->m_xPosition = xFileVector;
				pxVertex++;
#else
				Asura_FileAccess::ReadData
					(
					hFile,
					pxVertex++,
					sizeof(Asura_Vector_3)
					);
#endif
				Asura_ChunkLoading_System::YieldBackgroundProcessing();
			}

			// then faces data...
			Asura_ResourceAllocateArray(pxFaces, xChunk.m_uNumberOfFaces);

			Asura_FileAccess::ReadData
				(
				hFile,
				pxFaces,
				sizeof(Asura_Physics_Environment_Face) * xChunk.m_uNumberOfFaces
				);

			Asura_ChunkLoading_System::YieldBackgroundProcessing();

			// then face flags data...
			Asura_ResourceAllocateArray(pxFaceFlags, xChunk.m_uNumberOfFaces);

			Asura_FileAccess::ReadData
				(
				hFile,
				pxFaceFlags,
				sizeof(Asura_Physics_Environment_FaceFlags) * xChunk.m_uNumberOfFaces
				);

			Asura_ChunkLoading_System::YieldBackgroundProcessing();

			// KOR - 20/10/2005 - another zero byte skip check
			u_int uBytesToSkip = ((4 - (sizeof(Asura_Physics_Environment_FaceFlags) * xChunk.m_uNumberOfFaces)) & 3);
			if(uBytesToSkip) Asura_FileAccess::SkipData	(hFile, uBytesToSkip);

			Asura_ChunkLoading_System::YieldBackgroundProcessing();

			// then poly flags data...
			Asura_ResourceAllocateArray(pusPolygonFlags, xChunk.m_uNumberOfPolyFlags);

			Asura_FileAccess::ReadData
				(
				hFile,
				pusPolygonFlags,
				sizeof(u_short) * xChunk.m_uNumberOfPolyFlags
				);

			Asura_ChunkLoading_System::YieldBackgroundProcessing();

			// KOR - 22/09/2005 - this was asserting about skipping zero bytes.
			// I've put this check in for now; when we move over to Asura_Chunk_Stream then alignment should be handled automatically
			uBytesToSkip = ((4 - (sizeof(u_short) * xChunk.m_uNumberOfPolyFlags)) & 3);
			if(uBytesToSkip) Asura_FileAccess::SkipData	(hFile, uBytesToSkip);

			Asura_ChunkLoading_System::YieldBackgroundProcessing();

			// then material IDs data...
#ifdef ASURA_USE_MATERIAL_RESPONSE_SYSTEM

			Asura_ResourceAllocateArray( m_puMaterialResponseHashIDs, xChunk.m_uNumberOfMaterialIDs );

			if( xChunk.Flags & Asura_Chunk_PhysicsEnvironment::ChunkFlag_HasMaterialResponseHashIDs )
			{
				Asura_FileAccess::ReadData( hFile, m_puMaterialResponseHashIDs, sizeof( Asura_Hash_ID ) * xChunk.m_uNumberOfMaterialIDs );
			}
			else
			{
				Asura_Assert( false, "Warning: this is a material response project, but a physics "
									 "environment chunk doesn't contain material response IDs. "
									 "This should be fixed by re-saving the file." );

				Asura_Mem::Set( m_puMaterialResponseHashIDs, 0, sizeof( Asura_Hash_ID ) * xChunk.m_uNumberOfMaterialIDs );
			}

#else // !defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

			// If the response IDs are present, just skip them
			if( xChunk.Flags & Asura_Chunk_PhysicsEnvironment::ChunkFlag_HasMaterialResponseHashIDs )
			{
				Asura_FileAccess::SkipData( hFile, sizeof( Asura_Hash_ID ) * xChunk.m_uNumberOfMaterialIDs );
			}

#endif // !defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

			Asura_ResourceAllocateArray(m_psMaterialIDs, xChunk.m_uNumberOfMaterialIDs);

			Asura_FileAccess::ReadData
				(
				hFile,
				m_psMaterialIDs,
				sizeof(short) * xChunk.m_uNumberOfMaterialIDs
				);

			Asura_ChunkLoading_System::YieldBackgroundProcessing();

			// KOR - 08/12/2005 - materials were not being converted
			for(u_int uMaterial = 0; uMaterial < xChunk.m_uNumberOfMaterialIDs; ++uMaterial)
			{
				m_psMaterialIDs[uMaterial] = static_cast<short>(Asura_Material_System::ConvertIndex(m_psMaterialIDs[uMaterial]));
			}

			Asura_ChunkLoading_System::YieldBackgroundProcessing();

			// KOR - 22/09/2005 - see above comment
			uBytesToSkip = ((4 - (sizeof(short) * xChunk.m_uNumberOfMaterialIDs)) & 3);
			if(uBytesToSkip) Asura_FileAccess::SkipData	(hFile, uBytesToSkip);

			Asura_ChunkLoading_System::YieldBackgroundProcessing();

			// Sectors tree... (without its nodes, since they're in the next block)
			Asura_FileAccess::ReadData	(hFile,	&m_xSectorsTree.m_uNumberOfNodes,	sizeof(u_int));
			Asura_FileAccess::ReadData	(hFile,	&m_xSectorsTree.m_xRootBoundingBox,	sizeof(Asura_Bounding_Box));

			Asura_ChunkLoading_System::YieldBackgroundProcessing();

			// LBAABB tree nodes, all in one go
			m_bTreesUseOneHugeNodeArray = true;
			Asura_ResourceAllocateArray(m_pxOneHugeNodeArray, xChunk.m_uNumberOfDoubleNodes);

			if (xChunk.m_uNumberOfDoubleNodes)
			{
				Asura_FileAccess::ReadData
					(
					hFile,
					m_pxOneHugeNodeArray,
					sizeof(Asura_LBAABB_Tree_Double_Node) * xChunk.m_uNumberOfDoubleNodes
					);
			}

			Asura_ChunkLoading_System::YieldBackgroundProcessing();

			// patch up the node pointers in all the trees...
			Asura_LBAABB_Tree_Double_Node* pxNodes = m_pxOneHugeNodeArray;

			m_xSectorsTree.m_pxNodes = pxNodes;
			pxNodes += m_xSectorsTree.GetNumberOfDoubleNodes();

			for (u_int u=0; u<xChunk.m_uNumberOfSectors; u++)
			{
				pxSectors[u].m_xFaceTree.m_pxNodes = pxNodes;
				pxNodes += 	pxSectors[u].m_xFaceTree.GetNumberOfDoubleNodes();
			}
		}
		Asura_ResourcePopType();

		// ART - 26/07/07 - These are now assigned here because its possible to
		// process chunks in parts and we don't want to use any chunk data until
		// we have processed the entire chunk.
		m_pxFaces = pxFaces;
		m_pxFaceFlags = pxFaceFlags;
		m_pxSectors = pxSectors;
		m_pxVertices = pxVertices;
		m_pusPolygonFlags = pusPolygonFlags;

		m_uNumberOfSectors = xChunk.m_uNumberOfSectors;
		m_uTotalNumberOfVertices = xChunk.m_uNumberOfVertices;
		m_uTotalNumberOfFaces = xChunk.m_uNumberOfFaces;
		m_uTotalNumberOfPolygonFlags = xChunk.m_uNumberOfPolyFlags;
		m_uTotalNumberOfMaterialIDs = xChunk.m_uNumberOfMaterialIDs;

// (AAM - 18.01.2008) This assert pops up on lots of levels, and it isn't actally that helpful.
// Speaking with KJFL et al., we're just going to remove it. There's Tools functionality for finding
// tiny triangles anyway, and this slowed down level loads

#if 0
		// quick hacky check for tiny-area faces
		const float fAreaTolerance = 0.5f * 1e-5f; // half the value for quads in MaxPlugin_DoExport.cpp
		for (u_int uSector = 0; uSector < m_uNumberOfSectors; ++uSector)
		{
			const Asura_Physics_Environment_Sector& xSector = m_pxSectors[uSector];

			for (u_int uFace = 0; uFace < xSector.m_uNumberOfFaces; ++uFace)
			{
				const Asura_Physics_Environment_Face& xFace = m_pxFaces[xSector.m_uFaceIndexOffset + uFace ];

				const u_int uOffset = xSector.m_uVertexIndexOffset;
				const u_int uVertex0Index = xFace.m_usVertexID[0] + uOffset;
				const u_int uVertex1Index = xFace.m_usVertexID[1] + uOffset;
				const u_int uVertex2Index = xFace.m_usVertexID[2] + uOffset;

				const Asura_AVector3& xV0 = m_pxVertices[ uVertex0Index ].GetPosition();
				const Asura_AVector3& xV1 = m_pxVertices[ uVertex1Index ].GetPosition();
				const Asura_AVector3& xV2 = m_pxVertices[ uVertex2Index ].GetPosition();

				Asura_AVector3 xCrossProduct = (xV1 - xV0)^(xV2 - xV0);
				float fTriArea = xCrossProduct.Magnitude() * 0.5f;
				Asura_Assert(fTriArea >= fAreaTolerance, "tiny physics triangle - were tiny polys allowed in the MAX export?");
			}
		}
#endif
	} 
	else // no sectors - no data to load; set to zero values
	{
		m_pxSectors = 0;
		m_pxVertices = 0;
		m_pxFaces = 0;
		m_pxFaceFlags = 0;
		m_pxOneHugeNodeArray = 0;

		m_uNumberOfSectors = 0;
		m_uTotalNumberOfVertices = 0;
		m_uTotalNumberOfFaces = 0;
		m_uTotalNumberOfPolygonFlags = 0;
		m_uTotalNumberOfMaterialIDs = 0;
	}

	return(true);
}


bool Asura_Chunk_PhysicsEnvironment::Process( Asura_Handle hFile ) const 
{
	// first check the validity of the chunk 


	// Too new?
    if( Version > CHUNK_VERSION )
    {
        Asura_Assert( false, "Chunk version is too new. You need a new executable." );
        return false;
    }
	
	// Too old?
	if (Version < 6)
	{
		// (AW - 19/08/05) - Version 6 changes the format of the LBAABB tree, previous versions are no
		// longer handled.
#ifndef ASURA_TOOLS
		Asura_Assert( false, "Physics environment chunk version is too old. You need to re-export");
#endif //#ifndef ASURA_TOOLS
		return false;
	}
    if( Version < CHUNK_VERSION ) 
    {
        Asura_OutputToDebugger(( "INFO: Loading chunk v%i (current version is v%i.)\n", Version, CHUNK_VERSION ));
    }

	// Process the data itself...
	return(Asura_Physics_Environment::GetCurrentZone().Process(hFile, *this));

}

#if defined(ASURA_TOOLS)

bool Asura_Chunk_PhysicsEnvironment::Create( Asura_SaveBlock& xSaveBlock,const int* piMaterialIDToIndexConversion )
{
	Asura_Chunk_SaveBlock_Stream xStream(&xSaveBlock);
	return Create(xStream, piMaterialIDToIndexConversion);
}

bool Asura_Chunk_PhysicsEnvironment::Create( Asura_Chunk_Stream& xStream,const int* piMaterialIDToIndexConversion )
{
	if(Tools_AsrFileManager::IsUsingMultipleAsrFiles() && !Tools_Level_Export::IsExport())
	{
		//Skipping this when using multiple asr files for an environment , because it should
		//probably just save the data that goes with the meshes in that file , but that is more
		//hassle than its worth , since we are going to ignore it anyway.
		//RAR 18/10/2007
		return true;
	}

	// make sure the data is up-to-date
	Asura_Physics_Environment::Tools_Create();

	const Asura_Physics_Zone& xZone = Asura_Physics_Environment::GetCurrentZone();

	// Write the data...
	xZone.WriteToChunkStream(xStream, piMaterialIDToIndexConversion);

	return true;
}




////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Physics_Environment_Face::WriteToChunkStream
// Author       : Andy Tate
// Date         : 14-Jul-2005
//
// Description  : Write the physics-environment face data to the specified
//				  chunk-stream.
//
// Parameters   : A reference to the chunk-stream to write to.
//
// Return value : None.
////////////////////////////////////////////////////////////////////////////////

void Asura_Physics_Environment_Face::WriteToChunkStream (Asura_Chunk_Stream& xStream) const
{
	// Write the array...

	xStream << Asura_WriteToStream_Array_Wrapper<u_short> (4, m_usVertexID);
}

/// End of function 'Asura_Physics_Environment_Face::WriteToChunkStream'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Physics_Environment_FaceFlags::WriteToChunkStream
// Author       : Andy Tate
// Date         : 14-Jul-2005
//
// Description  : Write the physics-environment face flags to the specified
//				  chunk-stream.
//
// Parameters   : A reference to the chunk-stream to write to.
//
// Return value : None.
////////////////////////////////////////////////////////////////////////////////

void Asura_Physics_Environment_FaceFlags::WriteToChunkStream (Asura_Chunk_Stream& xStream) const
{
	Asura_WriteToStream_Bitfield_Wrapper<u_char>	xFlagsBitfield (m_ucFlags);


	// Add the data to the bitfield...

	xFlagsBitfield.Add	(m_bEdge0IsConvex,		1);
	xFlagsBitfield.Add	(m_bEdge1IsConvex,		1);
	xFlagsBitfield.Add	(m_bEdge2IsConvex,		1);
	xFlagsBitfield.Add	(m_bEdge3IsConvex,		1);

	xFlagsBitfield.Add	(m_bVertex0IsConvex,	1);
	xFlagsBitfield.Add	(m_bVertex1IsConvex,	1);
	xFlagsBitfield.Add	(m_bVertex2IsConvex,	1);
	xFlagsBitfield.Add	(m_bVertex3IsConvex,	1);


	// Write the bitfield...

	xStream << xFlagsBitfield;
}

/// End of function 'Asura_Physics_Environment_FaceFlags::WriteToChunkStream'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Physics_Environment_Vertex::WriteToChunkStream
// Author       : Andy Tate
// Date         : 14-Jul-2005
//
// Description  : Write the physics-environment vertex data to the specified
//				  chunk-stream.
//
// Parameters   : A reference to the chunk-stream to write to.
//
// Return value : None.
////////////////////////////////////////////////////////////////////////////////

void Asura_Physics_Environment_Vertex::WriteToChunkStream (Asura_Chunk_Stream& xStream) const
{
	// Write the data...
	Asura_AVector3 xPosition = m_xPosition;
	#ifdef ASURA_TOOLS
	xPosition -= Asura_AVector3(Tools_Level_Export::GetExportCentre());
	#endif

	xStream << xPosition;
}

/// End of function 'Asura_Physics_Environment_Vertex::WriteToChunkStream'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Physics_Environment_Sector::WriteToChunkStream
// Author       : Andy Tate
// Date         : 14-Jul-2005
//
// Description  : Write the physics-environment sector data to the specified
//				  chunk-stream.
//
// Parameters   : A reference to the chunk-stream to write to.
//
// Return value : None.
////////////////////////////////////////////////////////////////////////////////

void Asura_Physics_Environment_Sector::WriteToChunkStream (Asura_Chunk_Stream& xStream) const
{


	Asura_WriteToStream_Bitfield_Wrapper<u_short>	xFlagsBitfield (m_usFlags);


	// Add the data to the bitfield...

	xFlagsBitfield.Add	(m_bAllFacesUseSamePolygonFlag,	1);
	xFlagsBitfield.Add	(m_bAllFacesUseSameMaterialID,	1);


	// Write the data...

	xStream << m_uFaceIndexOffset;
	xStream << m_uVertexIndexOffset;

	xStream << m_uNumberOfFaces;

	#ifdef ASURA_TOOLS
	Asura_Vector_3 xPositionOffset = Tools_Level_Export::GetExportCentre();
	#else
	Asura_Vector_3 xPositionOffset = Asura_Maths::ZeroVector3;
	#endif

	m_xFaceTree.WriteHeaderToChunkStream	(xStream,-xPositionOffset);

	xStream << m_uPolygonFlagOffset;
	xStream << m_uMaterialIDOffset;

	xStream << xFlagsBitfield;

	xStream.Write4BytePadding	();
}

/// End of function 'Asura_Physics_Environment_Sector::WriteToChunkStream'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Physics_Zone::WriteToChunkStream
// Author       : Andy Tate
// Date         : 17-Mar-2006
//
// Description  : Write the physics-environment zone data to the specified
//				  chunk-stream.
//
// Parameters   : A reference to the chunk-stream to write-to.
//
// Return value : None.
////////////////////////////////////////////////////////////////////////////////

void Asura_Physics_Zone::WriteToChunkStream (Asura_Chunk_Stream& xStream,const int* piMaterialIDToIndexConversion) const
{
	//If everything is flagged as no collisions and no LOS there may be no sectors (partially dependent on project settings
	//for eliminating unwanted polygons from the collision mesh)
	//RAR 12/06/2006
	if(!m_uNumberOfSectors) return;
	
	const u_int	uNumberOfDoubleNodes		= m_xSectorsTree.GetNumberOfDoubleNodes();
	u_int		uTotalNumberOfDoubleNodes	= uNumberOfDoubleNodes;

	// Update the total number of nodes...
	for (u_int s = 0; s < m_uNumberOfSectors; s++)
	{
		uTotalNumberOfDoubleNodes	+= m_pxSectors [s].m_xFaceTree.GetNumberOfDoubleNodes();
	}

#ifdef ASURA_USE_MATERIAL_RESPONSE_SYSTEM
	const int iChunkFlags = Asura_Chunk_PhysicsEnvironment::ChunkFlag_HasMaterialResponseHashIDs;
#else
	const int iChunkFlags = 0;
#endif

	// Write the data...
	xStream.WriteChunk_Start(ASURA_CHUNK_PHYSICSENVIRONMENT, Asura_Chunk_PhysicsEnvironment::CHUNK_VERSION, iChunkFlags);

	xStream << m_uNumberOfSectors;
	xStream << m_uTotalNumberOfVertices;
	xStream << m_uTotalNumberOfFaces;
	xStream << m_uTotalNumberOfPolygonFlags;
	xStream << m_uTotalNumberOfMaterialIDs;
	xStream << uTotalNumberOfDoubleNodes;

	//RAR 08/03/2006 For recentreing during level exports :
	const Asura_Vector_3& xPositionOffset = Tools_Level_Export::GetExportCentre();

	for (u_int s = 0; s < m_uNumberOfSectors; s++)
	{
		m_pxSectors [s].WriteToChunkStream(xStream);
	}

	for (u_int v = 0; v < m_uTotalNumberOfVertices; v++)
	{
		m_pxVertices [v].WriteToChunkStream(xStream);
	}

	for (u_int f = 0; f < m_uTotalNumberOfFaces; f++)
	{
		m_pxFaces [f].WriteToChunkStream(xStream);
	}

	for (u_int f = 0; f < m_uTotalNumberOfFaces; f++)
	{
		m_pxFaceFlags [f].WriteToChunkStream(xStream);
	}

	xStream.Write4BytePadding();

	for (u_int p = 0; p < m_uTotalNumberOfPolygonFlags; p++)
	{
		xStream << m_pusPolygonFlags [p];
	}

	xStream.Write4BytePadding();

#ifdef ASURA_USE_MATERIAL_RESPONSE_SYSTEM

	for (u_int m = 0; m < m_uTotalNumberOfMaterialIDs; m++)
	{
		xStream << m_puMaterialResponseHashIDs[m];
	}

#endif // !defined ASURA_USE_MATERIAL_RESPONSE_SYSTEM

	for (u_int m = 0; m < m_uTotalNumberOfMaterialIDs; m++)
	{
		xStream << (short) Asura_Material_System::ConvertIDToIndex(m_psMaterialIDs[m], piMaterialIDToIndexConversion);
	}

	xStream.Write4BytePadding();

	{
		m_xSectorsTree.WriteHeaderToChunkStream(xStream,-xPositionOffset);

		// first copy the sectors tree nodes
		for (u_int n = 0; n < uNumberOfDoubleNodes; n++)
		{
			m_xSectorsTree.m_pxNodes [n].WriteToChunkStream(xStream);
		}

		// then the nodes of all the sectors in turn
		for (u_int s = 0; s < m_uNumberOfSectors; s++)
		{
			for (u_int n = 0; n < m_pxSectors [s].m_xFaceTree.GetNumberOfDoubleNodes(); n++)
			{
				m_pxSectors [s].m_xFaceTree.m_pxNodes [n].WriteToChunkStream(xStream);
			}
		}
	}

	xStream.WriteChunk_End	();
}

/// End of function 'Asura_Physics_Zone::WriteToChunkStream'. ///


#endif	// defined(ASURA_TOOLS)


/// End of file. ///
