///////////////////////////////////////////////////////////////////////////////
//
// File: Asura_Container.cpp
//
// Created by Martin G.Harris (6/5/2008)
// 
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

#include "Core/Asura.h"
#include "Entity/Container/Asura_Container.h"

#ifdef ASURA_USE_CONTAINER_SYSTEM

// Asura
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "Entity/Container/Asura_ClientContainerInstance.h"
#include "Entity/Container/Asura_ContainerRegistry.h"
#include "Entity/Container/Asura_Container_System.h"

//
// Register the Asura container types.
//
Asura_ContainerRegisterClass<Asura_Container_Mesh, Asura_ClientContainerInstance_Mesh> xRegisterMesh(AsuraContainerClass_Mesh);

Asura_ContainerRegisterClass<Asura_Container_SoundEvent, Asura_ClientContainerInstance_SoundEvent> xRegisterSE(AsuraContainerClass_SoundEvent);

Asura_ContainerRegisterClass<Asura_Container_Collection, Asura_ClientContainerInstance_Collection> xRegisterCollection(AsuraContainerClass_Collection);

Asura_ContainerRegisterClass<Asura_Container_Attachment, Asura_ClientContainerInstance_Attachment> xRegisterAttachment(AsuraContainerClass_Attachment);

Asura_ContainerRegisterClass<Asura_Container_PFX, Asura_ClientContainerInstance_PFX> xRegisterPFX(AsuraContainerClass_PFX);

Asura_ContainerRegisterClass<Asura_Container_Corona, Asura_ClientContainerInstance_Corona> xRegisterCorona(AsuraContainerClass_Corona);


#ifdef ASURA_TARGET_SM3
Asura_ContainerRegisterClass<Asura_Container_LightShaft, Asura_ClientContainerInstance_LightShaft> xRegisterLightShaft(AsuraContainerClass_LightShaft);
Asura_ContainerRegisterClass<Asura_Container_Projector, Asura_ClientContainerInstance_Projector> xRegisterProjector(AsuraContainerClass_Projector);
Asura_ContainerRegisterClass<Asura_Container_Photon, Asura_ClientContainerInstance_Photon> xRegisterPhoton(AsuraContainerClass_Photon);
#endif //#ifdef ASURA_TARGET_SM3

Asura_ContainerRegisterClass<Asura_Container_Strobe, Asura_ClientContainerInstance_Strobe> xRegisterStrobe(AsuraContainerClass_Strobe);

Asura_ContainerRegisterClass<Asura_Container_GraphColour, Asura_ClientContainerInstance_GraphColour> xRegisterColour(AsuraContainerClass_GraphColour);

Asura_ContainerRegisterClass<Asura_Container_Health, Asura_ClientContainerInstance_Health> xRegisterHealth(AsuraContainerClass_Health);

Asura_ContainerRegisterClass<Asura_Container_Physics, Asura_ClientContainerInstance_Physics> xRegisterPhysics(AsuraContainerClass_Physics);

Asura_ContainerRegisterClass<Asura_Container_Blueprint, Asura_ClientContainerInstance_Blueprint> xRegisterBlueprint(AsuraContainerClass_Blueprint);

///////////////////////////////////////////////////////////////////////////////
// Asura_Container
///////////////////////////////////////////////////////////////////////////////

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER = 0;

void Asura_Container::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container", iVersion));
		return;
	}
	
	xStream >> m_uContainerHash;
}

void Asura_Container::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER;

	xStream << m_uContainerHash;
}


///////////////////////////////////////////////////////////////////////////////
// Asura_Container_Mesh
///////////////////////////////////////////////////////////////////////////////

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_MESH = 1;

void Asura_Container_Mesh::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_MESH)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_Mesh", iVersion));
		return;
	}
	
	xStream >> m_uSkinHash;
	xStream >> m_uAnimationHash;
	xStream >> m_iAnimFlags;
	xStream >> m_uRenderFlags;
	xStream >> m_uContainerMeshFlags;

	if (iVersion >= 1)
	{
		xStream >> m_fSelfIlluminationContribution;
		xStream >> m_fSelfIlluminationColourise;
	}

	Asura_Container::ReadFromChunkStream(xStream);
}

void Asura_Container_Mesh::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_MESH;

	xStream << m_uSkinHash;
	xStream << m_uAnimationHash;
	xStream << m_iAnimFlags;
	xStream << m_uRenderFlags;
	xStream << m_uContainerMeshFlags;
	xStream << m_fSelfIlluminationContribution;
	xStream << m_fSelfIlluminationColourise;

	Asura_Container::WriteToChunkStream(xStream);
}

///////////////////////
// SetCollisionProxy //
///////////////////////
#ifdef ASURA_TOOLS
void Asura_Container_Mesh::SetCollisionProxy(int iCollisionProxy)
{
	Asura_Assert(iCollisionProxy <= ASURA_CONTAINER_MESH_COLLISION_PROXY_MASK, "Invalid collision proxy" );
	m_uContainerMeshFlags &= ~ASURA_CONTAINER_MESH_COLLISION_PROXY_MASK;
	m_uContainerMeshFlags |= (iCollisionProxy & ASURA_CONTAINER_MESH_COLLISION_PROXY_MASK);
}
#endif //ASURA_TOOLS

///////////////////////
// GetCollisionProxy //
///////////////////////
int Asura_Container_Mesh::GetCollisionProxy() const
{
	return (m_uContainerMeshFlags & ASURA_CONTAINER_MESH_COLLISION_PROXY_MASK);
}


///////////////////////////////////////////////////////////////////////////////
// Asura_Container_SoundEvent
///////////////////////////////////////////////////////////////////////////////

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_SOUNDEVENT = 1;

void Asura_Container_SoundEvent::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_SOUNDEVENT)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_SoundEvent", iVersion));
		return;
	}

	xStream >> m_uSoundEventHash;

	if (iVersion >= 1)
	{
		xStream >> m_uSEFlags;
	}

	Asura_Container::ReadFromChunkStream(xStream);
}

void Asura_Container_SoundEvent::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_SOUNDEVENT;

	xStream << m_uSoundEventHash;
	xStream << m_uSEFlags;

	Asura_Container::WriteToChunkStream(xStream);
}

///////////////////////////////////////////////////////////////////////////////
// Asura_Container_Collection 
///////////////////////////////////////////////////////////////////////////////
Asura_Container_Collection::Asura_Container_Collection()
: m_uNumChildren(0)
, m_puChildren(0)
{
}

Asura_Container_Collection::~Asura_Container_Collection()
{
	Reset();
}

void Asura_Container_Collection::Reset()
{
	delete [] m_puChildren;
	m_puChildren = 0;
	m_uNumChildren = 0;

	// Clear cached data.
	m_xCachedData.Reset();
}

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_COLLECTION = 1;

void Asura_Container_Collection::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_COLLECTION)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_Collection", iVersion));
		return;
	}

	// Make sure that we have deallocated the memory.
	Reset();

	xStream >> m_uNumChildren;
	Asura_Assertf(m_uNumChildren<1024, ("Unexpectedly large number of children (%d) in collection!", m_uNumChildren));

	if (m_uNumChildren)
	{
		m_puChildren = new Asura_Hash_ID[m_uNumChildren];

		Asura_ReadFromStream_Array_Wrapper<Asura_Hash_ID> xArray(m_uNumChildren, m_puChildren);
		xStream >> xArray;
	}

	if (iVersion >= 1)
	{
		m_xStateMachine.ReadFromChunkStream(xStream);
	}

	Asura_Container::ReadFromChunkStream(xStream);
}

void Asura_Container_Collection::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_COLLECTION;

	xStream << m_uNumChildren;

	if (m_uNumChildren)
	{
		xStream << Asura_WriteToStream_Array_Wrapper<Asura_Hash_ID>(m_uNumChildren, m_puChildren);
	}

	m_xStateMachine.WriteToChunkStream(xStream);

	Asura_Container::WriteToChunkStream(xStream);
}

//////////////////////
// UpdateCachedData //
//////////////////////
void Asura_Container_Collection::UpdateCachedData() const
{
	m_xCachedData.m_sHealthIndex	= -1;
	m_xCachedData.m_sFirstBlueprint = -1;
	m_xCachedData.m_sLastBlueprint  = -1;

	for (u_int u=0; u<m_uNumChildren; ++u)
	{
		const Asura_Hash_ID uHash = m_puChildren[u];
		const Asura_Container* const pxContainer = Asura_Container_System::FindContainer(uHash);
		if (pxContainer)
		{
			const u_int uClass = pxContainer->GetClassification();
			if (uClass == AsuraContainerClass_Health)
			{
				m_xCachedData.m_sHealthIndex = static_cast<short>(u);
			}
			else if (uClass == AsuraContainerClass_Blueprint)
			{
				if (m_xCachedData.m_sFirstBlueprint == -1)
				{
					m_xCachedData.m_sFirstBlueprint = static_cast<short>(u);
				}
				m_xCachedData.m_sLastBlueprint = static_cast<short>(u);
			}
		}
	}
}

/////////////////////
// FindHealthIndex //
/////////////////////
// Find index of health container. There should be at most one in the collection.
// Return -1 if no health container was found. The result is cached.
int Asura_Container_Collection::FindHealthIndex() const
{
	if (m_xCachedData.m_sHealthIndex == -2)
	{
		UpdateCachedData();
	}

	return m_xCachedData.m_sHealthIndex;
}

////////////////////////////
// FindBlueprintContainer //
////////////////////////////
// Look for a blueprint contained in this collection.
// Return the blueprint container found (or NULL if none found).
// If uBlueprintTypeHash != ASURA_HASH_ID_UNSET, then only return blueprints of the specified type.
const Asura_Container_Blueprint* Asura_Container_Collection::FindBlueprintContainer(Asura_Hash_ID uBlueprintTypeHash) const
{
	u_int uFirst = 0;
	u_int uLast  = 0;

	if (!FindBlueprintIndices(uFirst, uLast))
	{
		return 0; // No blueprints.
	}

	// TODO this would be much more efficient if we sorted the children so that the blueprints were continguous.
	for (u_int u = uFirst; u <= uLast; ++u)
	{
		const Asura_Hash_ID uHash = m_puChildren[u];
		const Asura_Container* const pxContainer = Asura_Container_System::FindContainer(uHash);
		if (pxContainer && pxContainer->GetClassification() == AsuraContainerClass_Blueprint)
		{
			const Asura_Container_Blueprint* const pxBPContainer = static_cast<const Asura_Container_Blueprint*>(pxContainer);
			if (uBlueprintTypeHash == ASURA_HASH_ID_UNSET ||
				uBlueprintTypeHash == pxBPContainer->GetBlueprintTypeHash())
			{
				return pxBPContainer;
			}
		}
	}

	// No blueprints of the correct type.
	return 0;
}

// Get the indices of the first and last blueprints.
// Return true, if there are some blueprints, in which case set the index parameters.
// Return false, if there are no blueprints, leave index parameters alone.
bool Asura_Container_Collection::FindBlueprintIndices(u_int& uFirst, u_int& uLast) const
{
	// Set up the cached data.
	if (m_xCachedData.m_sFirstBlueprint == -2)
	{
		UpdateCachedData();
	}

	if (m_xCachedData.m_sFirstBlueprint < 0)
	{
		// No blueprints.
		return false;
	}

	// Some blueprints exist. Return the indices.
	uFirst = static_cast<u_int>(m_xCachedData.m_sFirstBlueprint);
	uLast  = static_cast<u_int>(m_xCachedData.m_sLastBlueprint);
	
	Asura_Assert(uFirst<m_uNumChildren, "Invalid first blueprint index");
	Asura_Assert(uLast<m_uNumChildren,  "Invalid last blueprint index");
	return true;
}


#ifdef ASURA_TOOLS
void Asura_Container_Collection::AllocateSize(u_int uSize)
{
	Reset();
	
	m_uNumChildren = uSize;
	if (m_uNumChildren)
	{
		m_puChildren = new Asura_Hash_ID[m_uNumChildren];
		for (u_int u=0; u<m_uNumChildren; ++u)
		{
			m_puChildren[u] = ASURA_HASH_ID_UNSET;
		}
	}
}

void Asura_Container_Collection::SetChild(Asura_Hash_ID uChildHash, u_int uIndex)
{
	if (m_puChildren && uIndex < m_uNumChildren)
	{
		m_puChildren[uIndex] = uChildHash;
	}
}

// Find the child with the specified index or return -1 if not found.
// If iMultiplicity is set to be greater than zero, then skip that number of matching entries before returning a match.
int Asura_Container_Collection::FindChildIndex(Asura_Hash_ID uChildHash, int iMultiplicity) const
{
	for (u_int u=0; u<m_uNumChildren; ++u)
	{
		if (m_puChildren[u] == uChildHash)
		{
			if (iMultiplicity > 0)
			{
				--iMultiplicity;
			}
			else
			{
				return static_cast<int>(u);
			}
		}
	}

	return -1;
}
#endif //ASURA_TOOLS


///////////////////////////////////////////////////////////////////////////////
// Asura_Container_Attachment
///////////////////////////////////////////////////////////////////////////////

Asura_Container_Attachment::Asura_Container_Attachment()
: m_uChildContainerHash(ASURA_HASH_ID_UNSET)
, m_uMarkerPointHash(ASURA_HASH_ID_UNSET)
, m_xAttachPosition(Asura_Maths::ZeroVector3)
, m_xAttachQuat(Asura_Maths::IdentityQuat)
, m_bHasOffset(true)
, m_bAttachToPhysicsObject(false)
, m_uCachedChildClass(AsuraContainerClass_NotSet)
{
}

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_ATTACHMENT = 2;

void Asura_Container_Attachment::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_ATTACHMENT)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_Attachment", iVersion));
		return;
	}

	xStream >> m_uChildContainerHash;
	xStream >> m_xAttachPosition;
	xStream >> m_xAttachQuat;

	if (iVersion >= 1)
	{
		xStream >> m_uMarkerPointHash;
	}
	else
	{
		m_uMarkerPointHash = ASURA_HASH_ID_UNSET;
	}

	if (iVersion >= 2)
	{
		xStream >> m_bAttachToPhysicsObject;
		xStream.Skip4BytePadding();
	}

	UpdateHasOffsetFlag();

	Asura_Container::ReadFromChunkStream(xStream);
}

void Asura_Container_Attachment::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_ATTACHMENT;

	xStream << m_uChildContainerHash;
	xStream << m_xAttachPosition;
	xStream << m_xAttachQuat;

	xStream << m_uMarkerPointHash;

	xStream << m_bAttachToPhysicsObject;
	xStream.Write4BytePadding();
	
	Asura_Container::WriteToChunkStream(xStream);
}

//////////////////
// GetNumInputs //
//////////////////
// Number of state inputs is same as for the child container.
u_int Asura_Container_Attachment::GetNumInputs() const
{
	if (GetChildClassification() == AsuraContainerClass_Collection)
	{
		const Asura_Container* const pxContainer = Asura_Container_System::FindContainer(m_uChildContainerHash);
		Asura_Assertf(pxContainer, ("Container not found (0x%08x)", m_uChildContainerHash));
		if (pxContainer)
		{
			return pxContainer->GetNumInputs();
		}
	}

	return 1;
}

////////////////////////////
// GetChildClassification //
////////////////////////////
// Return the classification of the child. Cache the result.
u_int Asura_Container_Attachment::GetChildClassification() const
{
	if (m_uCachedChildClass == AsuraContainerClass_NotSet &&
		m_uChildContainerHash != ASURA_HASH_ID_UNSET)
	{
		const Asura_Container* const pxContainer = Asura_Container_System::FindContainer(m_uChildContainerHash);
		Asura_Assertf(pxContainer, ("Container not found (0x%08x)", m_uChildContainerHash));
		if (pxContainer)
		{
			m_uCachedChildClass = pxContainer->GetClassification();
		}
	}

	return m_uCachedChildClass;
}

/////////////////////////
// UpdateHasOffsetFlag //
/////////////////////////
// Marker point attachments often have no extra offset.
// This flag allows us to optimise that case slightly.
void Asura_Container_Attachment::UpdateHasOffsetFlag()
{
	m_bHasOffset = ( (m_xAttachPosition != Asura_Maths::ZeroVector3) ||
					 (m_xAttachQuat != Asura_Maths::IdentityQuat) );
}

/////////////////
// ApplyOffset //
/////////////////
// Apply offset to specified initial position/orientation,
// writing out new position/orientation to different variables.
bool Asura_Container_Attachment::ApplyOffset(const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOri,
											 Asura_Vector_3& xNewPosition, Asura_Matrix_3x3& xNewOri,
											 const Asura_ClientContainerInstance_Attachment* pxInstance) const
{
	bool bFailed = false;

	if (pxInstance)
	{
		const Asura_ClientContainerInstance_Mesh* const pxMesh = pxInstance->GetParentMeshForMarker();
		if (pxMesh || m_bAttachToPhysicsObject)
		{
			// Find the base position/orientation from the marker or physics object.
			if (m_bHasOffset)
			{
				Asura_Vector_3 xMarkerPos;
				Asura_Matrix_3x3 xMarkerOri;

				const bool bOk = pxInstance->GetBasePosOriForAttachment(xMarkerPos, xMarkerOri);
				if (bOk)
				{
					// Rotate and translate attachment offset.
					xNewPosition = m_xAttachPosition * xMarkerOri + xMarkerPos;
					m_xAttachQuat.ToMatrix(xNewOri);
					xNewOri = xMarkerOri * xNewOri;
					return true;
				}	
			}
			else
			{
				const bool bOk = pxInstance->GetBasePosOriForAttachment(xNewPosition, xNewOri);
				if (bOk)
				{
					return true;
				}
			}
		
			// Failed to find the base position/orientation.
			bFailed = true;
			Asura_Assertf(pxMesh == 0, ("Failed to get marker (0x%08x) location", m_uMarkerPointHash));
			Asura_Assertf(!m_bAttachToPhysicsObject, ("Failed to find shared dynamic physics object"));
		}
	}


	if (!bFailed && m_bHasOffset)
	{
		// Rotate and translate attachment offset in to world space.
		xNewPosition = m_xAttachPosition * xOri + xPosition;
		m_xAttachQuat.ToMatrix(xNewOri);
		xNewOri = xOri * xNewOri;
	}
	else
	{
		// No offset to apply (or failed to find marker).
		// Just copy the input to the output.
		xNewPosition = xPosition;
		xNewOri = xOri;
	}

	return !bFailed;
}


/////////////////////////////////////////////////////////////////////
// Asura_Container_PFX
/////////////////////////////////////////////////////////////////////

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_PFX = 1;

void Asura_Container_PFX::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_PFX)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_PFX", iVersion));
		return;
	}

	// TODO remove this dummy information from the chunkstream.
	Asura_Vector_3 xDummyPos;
	Asura_Matrix_3x3 xDummyOri;
	m_xPFXData.ReadFromChunkStream(xStream, xDummyPos, xDummyOri);

	if (iVersion >= 1)
	{
		xStream >> m_uPFXFlags;
	}

	Asura_Container::ReadFromChunkStream(xStream);
}

void Asura_Container_PFX::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_PFX;

	// TODO remove this dummy information from the chunkstream.
	Asura_Vector_3 xDummyPos(Asura_Maths::ZeroVector3);
	Asura_Matrix_3x3 xDummyOri(Asura_Maths::IdentityMatrix3x3);
	m_xPFXData.WriteToChunkStream(xStream, xDummyPos, xDummyOri);

	xStream << m_uPFXFlags;

	Asura_Container::WriteToChunkStream(xStream);
}



/////////////////////////////////////////////////////////////////////
// Asura_Container_Corona
/////////////////////////////////////////////////////////////////////
// Asura_Container_Corona_Param
void Asura_Container_Corona_Param::ResetToDefaults()
{
	m_uCoronaTextureHash = ASURA_HASH_ID_UNSET;
	m_fCoronaSize   = 1.0f;
	m_fCoronaDepth  = 2.0f;
	m_xCoronaColour = Asura_RGBA(1.0f, 1.0f, 1.0f, 1.0f);
	m_uCoronaFlags  = ASURA_CONTAINER_CORONA_FLAG_USE_VISIBILTY_TEST |
					  ASURA_CONTAINER_CORONA_FLAG_USE_STROBE;
}

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_CORONA_PARAM = 0;

void Asura_Container_Corona_Param::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_CORONA_PARAM)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_Corona_Param", iVersion));
		return;
	}

	xStream >> m_uCoronaTextureHash;
	xStream >> m_fCoronaSize;
	xStream >> m_fCoronaDepth;
	xStream >> m_xCoronaColour;
	xStream >> m_uCoronaFlags;
}

void Asura_Container_Corona_Param::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_CORONA_PARAM;
	xStream << m_uCoronaTextureHash;
	xStream << m_fCoronaSize;
	xStream << m_fCoronaDepth;
	xStream << m_xCoronaColour;
	xStream << m_uCoronaFlags;
}

// Asura_Container_Corona

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_CORONA = 0;

void Asura_Container_Corona::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_CORONA)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_Corona", iVersion));
		return;
	}

	m_xParam.ReadFromChunkStream(xStream);

	Asura_Container::ReadFromChunkStream(xStream);
}

void Asura_Container_Corona::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_CORONA;

	m_xParam.WriteToChunkStream(xStream);

	Asura_Container::WriteToChunkStream(xStream);
}


///////////////////////////////////////////////////////////////////////////////
// Asura_Container_LightShaft
///////////////////////////////////////////////////////////////////////////////
#ifdef ASURA_TARGET_SM3

// Asura_Container_LightShaft_Param
void Asura_Container_LightShaft_Param::ResetToDefaults()
{
	m_afRadius[0] = 0.0f;
	m_afRadius[1] = 2.5f;

	m_afDistance[0] = 0.0f;
	m_afDistance[1] = 10.0f;

	m_axColour[0] = Asura_RGBA(1.0f, 1.0f, 1.0f, 1.0f);
	m_axColour[1] = Asura_RGBA(0.0f, 0.0f, 0.0f, 1.0f);

	m_auTextureHash[0] = ASURA_HASH_ID_UNSET;
	m_auTextureHash[1] = ASURA_HASH_ID_UNSET;

	m_afTextureUScale[0] = 1.0f;
	m_afTextureUScale[1] = 1.0f;

	m_afTextureScrollRate[0] = 0.0f;
	m_afTextureScrollRate[1] = 0.0f;

	m_fDistFadeStart = 150.0f;
	m_fDistFadeRange = 10.0f;
	m_fCloseFadeStart = 0.0f;
	m_fCloseFadeRange = 10.0f;

	m_fCoronaAngleRange = 0.6f;
	m_xCoronaParam.ResetToDefaults();
}

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_LIGHTSHAFT_PARAM = 1;

void Asura_Container_LightShaft_Param::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_LIGHTSHAFT_PARAM)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_LightShaft_Param", iVersion));
		return;
	}

	for (int i=0; i<2; ++i)
	{
		xStream >> m_afRadius[i];
		xStream >> m_afDistance[i];
		xStream >> m_axColour[i];

		xStream >> m_auTextureHash[i];
		xStream >> m_afTextureUScale[i];
		xStream >> m_afTextureScrollRate[i];
	}

	xStream >> m_fDistFadeStart;
	xStream >> m_fDistFadeRange;

	if (iVersion >= 1)
	{
		xStream >> m_fCloseFadeStart;
		xStream >> m_fCloseFadeRange;
	}


	xStream >> m_fCoronaAngleRange;
	m_xCoronaParam.ReadFromChunkStream(xStream);
}

void Asura_Container_LightShaft_Param::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_LIGHTSHAFT_PARAM;

	for (int i=0; i<2; ++i)
	{
		xStream << m_afRadius[i];
		xStream << m_afDistance[i];
		xStream << m_axColour[i];

		xStream << m_auTextureHash[i];
		xStream << m_afTextureUScale[i];
		xStream << m_afTextureScrollRate[i];
	}

	xStream << m_fDistFadeStart;
	xStream << m_fDistFadeRange;
	xStream << m_fCloseFadeStart;
	xStream << m_fCloseFadeRange;

	xStream << m_fCoronaAngleRange;
	m_xCoronaParam.WriteToChunkStream(xStream);
}


// Asura_Container_LightShaft

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_LIGHTSHAFT = 0;

void Asura_Container_LightShaft::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_LIGHTSHAFT)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_LightShaft", iVersion));
		return;
	}

	m_xParam.ReadFromChunkStream(xStream);

	Asura_Container::ReadFromChunkStream(xStream);
}

void Asura_Container_LightShaft::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_LIGHTSHAFT;

	m_xParam.WriteToChunkStream(xStream);

	Asura_Container::WriteToChunkStream(xStream);
}
#endif //#ifdef ASURA_TARGET_SM3


///////////////////////////////////////////////////////////////////////////////
// Asura_Container_Projector
///////////////////////////////////////////////////////////////////////////////
#ifdef ASURA_TARGET_SM3

// Asura_Container_Projector_Param
void Asura_Container_Projector_Param::ResetToDefaults()
{
	// Textures
	m_uTextureHash		 = ASURA_HASH_ID_UNSET;
	m_uDetailTextureHash = ASURA_HASH_ID_UNSET;

	// Projection
	m_fFoV			 = Asura_Maths::Deg90/2.0f;
	m_fMinRange		 = 1.0f;
	m_fMaxRange		 = 20.0f;
	m_fParallelScale = 1.0f;

	// Colour
	m_afRGB[0] = 1.0f;
	m_afRGB[1] = 1.0f;
	m_afRGB[2] = 1.0f;

	// Fall-off
	m_fInnerFoV				= Asura_Maths::Deg90 / 4.0f;
	m_fFalloffInnerRatio	= 0.0f;
	m_fFalloffPower			= 1.0f;

	// Detail texture scrolling
	m_fUScrollSpeed = 0.0f;
	m_fVScrollSpeed = 0.0f;
	m_fUScrollRange = 0.0f;
	m_fVScrollRange = 0.0f;

	// Texture params
	m_fDetailTextureScale = 4.0f;
	m_fUVAspect			  = 1.0f;

	// Limiting plane
	m_xLimitingPlanePos    = Asura_Vector_3(0.0f,  0.0f, 0.0f);
	m_xLimitingPlaneNormal = Asura_Vector_3(0.0f, -1.0f, 0.0f);

	// Flags from ASURA_CONTAINER_PROJECTOR_FLAGS
	m_uFlags =	ASURA_CONTAINER_PROJECTOR_FLAG_FAKE_LIGHT |
				ASURA_CONTAINER_PROJECTOR_FLAG_USE_STROBE;

	// Distance fade out
	m_fDistFadeStart = 150.0f;
	m_fDistFadeRange = 10.0f;
}

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_PROJECTOR_PARAM = 0;

void Asura_Container_Projector_Param::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_PROJECTOR_PARAM)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_Projector_Param", iVersion));
		return;
	}

	// Textures
	xStream >> m_uTextureHash;
	xStream >> m_uDetailTextureHash;

	// Projection
	xStream >> m_fFoV;
	xStream >> m_fMinRange;
	xStream >> m_fMaxRange;
	xStream >> m_fParallelScale;

	// Colour
	xStream >> m_afRGB[0];
	xStream >> m_afRGB[1];
	xStream >> m_afRGB[2];

	// Fall-off
	xStream >> m_fInnerFoV;
	xStream >> m_fFalloffInnerRatio;
	xStream >> m_fFalloffPower;

	// Detail texture scrolling
	xStream >> m_fUScrollSpeed;
	xStream >> m_fVScrollSpeed;
	xStream >> m_fUScrollRange;
	xStream >> m_fVScrollRange;

	// Texture params
	xStream >> m_fDetailTextureScale;
	xStream >> m_fUVAspect;

	// Limiting plane
	xStream >> m_xLimitingPlanePos;
	xStream >> m_xLimitingPlaneNormal;

	// Flags from ASURA_CONTAINER_PROJECTOR_FLAGS
	xStream >> m_uFlags;

	// Distance fade out
	xStream >> m_fDistFadeStart;
	xStream >> m_fDistFadeRange;
}

void Asura_Container_Projector_Param::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_PROJECTOR_PARAM;

	// Textures
	xStream << m_uTextureHash;
	xStream << m_uDetailTextureHash;

	// Projection
	xStream << m_fFoV;
	xStream << m_fMinRange;
	xStream << m_fMaxRange;
	xStream << m_fParallelScale;

	// Colour
	xStream << m_afRGB[0];
	xStream << m_afRGB[1];
	xStream << m_afRGB[2];

	// Fall-off
	xStream << m_fInnerFoV;
	xStream << m_fFalloffInnerRatio;
	xStream << m_fFalloffPower;

	// Detail texture scrolling
	xStream << m_fUScrollSpeed;
	xStream << m_fVScrollSpeed;
	xStream << m_fUScrollRange;
	xStream << m_fVScrollRange;

	// Texture params
	xStream << m_fDetailTextureScale;
	xStream << m_fUVAspect;

	// Limiting plane
	xStream << m_xLimitingPlanePos;
	xStream << m_xLimitingPlaneNormal;

	// Flags from ASURA_CONTAINER_PROJECTOR_FLAGS
	xStream << m_uFlags;

	// Distance fade out
	xStream << m_fDistFadeStart;
	xStream << m_fDistFadeRange;
}

// Asura_Container_Projector

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_PROJECTOR = 1;

void Asura_Container_Projector::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_PROJECTOR)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_Projector", iVersion));
		return;
	}

	m_xParam.ReadFromChunkStream(xStream);
	
	if (iVersion >= 1)
	{
		m_xShadowParam.ReadFromChunkStream(xStream);
	}
	else
	{
		m_xShadowParam.m_uFlags = 0; // Turn shadows off.
	}

	Asura_Container::ReadFromChunkStream(xStream);
}

void Asura_Container_Projector::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_PROJECTOR;

	m_xParam.WriteToChunkStream(xStream);
	m_xShadowParam.WriteToChunkStream(xStream);

	Asura_Container::WriteToChunkStream(xStream);
}

#endif //ASURA_TARGET_SM3


///////////////////////////////////////////////////////////////////////////////
// Asura_Container_Photon
///////////////////////////////////////////////////////////////////////////////
#ifdef ASURA_TARGET_SM3

// Asura_Container_Photon_Param
void Asura_Container_Photon_Param::ResetToDefaults()
{
	// Colour
	m_afRGB[0] = 1.0f;
	m_afRGB[1] = 1.0f;
	m_afRGB[2] = 1.0f;

	// Range
	m_fPhotonRange = 10.0f;
	
	// Light volume
	m_xLightVolume.Reset();
	m_xLightVolumeOrient.Identity();

	// Limiting angle
	m_fLimitingAngleInner = Asura_Maths::Deg180;
	m_fLimitingAngleOuter = Asura_Maths::DegToRad(200.0f);

	// Textures
	m_uProjCubeTextureHash		  = ASURA_HASH_ID_UNSET;
	m_uProjCubeBlurredTextureHash = ASURA_HASH_ID_UNSET;

	m_fProjCubeLerpDist	= 5.0f;

	// Fall off
	m_fFalloffInnerRatio = 0.0f;
	m_fFalloffPower		 = 1.0f;

	// Flags from ASURA_CONTAINER_PHOTON_FLAGS
	m_uFlags =	ASURA_CONTAINER_PHOTON_FLAG_USE_STROBE;

	// Distance fade out
	m_fDistFadeStart = 150.0f;
	m_fDistFadeRange = 10.0f;
}

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_PHOTON_PARAM = 0;

void Asura_Container_Photon_Param::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_PHOTON_PARAM)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_Photon_Param", iVersion));
		return;
	}

	// Colour
	xStream >> m_afRGB[0];
	xStream >> m_afRGB[1];
	xStream >> m_afRGB[2];

	// Range
	xStream >> m_fPhotonRange;
	
	// Light volume
	xStream >> m_xLightVolume;
	xStream >> m_xLightVolumeOrient;

	// Limiting angle
	xStream >> m_fLimitingAngleInner;
	xStream >> m_fLimitingAngleOuter;

	// Textures
	xStream >> m_uProjCubeTextureHash;
	xStream >> m_uProjCubeBlurredTextureHash;

	xStream >> m_fProjCubeLerpDist;

	// Fall off
	xStream >> m_fFalloffInnerRatio;
	xStream >> m_fFalloffPower;

	// Flags from ASURA_CONTAINER_PHOTON_FLAGS
	xStream >> m_uFlags;

	// Distance fade out
	xStream >> m_fDistFadeStart;
	xStream >> m_fDistFadeRange;
}

void Asura_Container_Photon_Param::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_PHOTON_PARAM;

	// Colour
	xStream << m_afRGB[0];
	xStream << m_afRGB[1];
	xStream << m_afRGB[2];

	// Range
	xStream << m_fPhotonRange;
	
	// Light volume
	xStream << m_xLightVolume;
	xStream << m_xLightVolumeOrient;

	// Limiting angle
	xStream << m_fLimitingAngleInner;
	xStream << m_fLimitingAngleOuter;

	// Textures
	xStream << m_uProjCubeTextureHash;
	xStream << m_uProjCubeBlurredTextureHash;

	xStream << m_fProjCubeLerpDist;

	// Fall off
	xStream << m_fFalloffInnerRatio;
	xStream << m_fFalloffPower;

	// Flags from ASURA_CONTAINER_PHOTON_FLAGS
	xStream << m_uFlags;

	// Distance fade out
	xStream << m_fDistFadeStart;
	xStream << m_fDistFadeRange;
}

// Asura_Container_Photon

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_PHOTON = 1;

void Asura_Container_Photon::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_PHOTON)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_Photon", iVersion));
		return;
	}

	m_xParam.ReadFromChunkStream(xStream);

	if (iVersion >= 1)
	{
		m_xShadowParam.ReadFromChunkStream(xStream);
	}
	else
	{
		m_xShadowParam.m_uFlags = 0; // Turn shadows off.
	}

	Asura_Container::ReadFromChunkStream(xStream);
}

void Asura_Container_Photon::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_PHOTON;

	m_xParam.WriteToChunkStream(xStream);
	m_xShadowParam.WriteToChunkStream(xStream);

	Asura_Container::WriteToChunkStream(xStream);
}

#endif //ASURA_TARGET_SM3

///////////////////////////////////////////////////////////////////////////////
// Asura_Container_Strobe
///////////////////////////////////////////////////////////////////////////////
Asura_Container_Strobe::Asura_Container_Strobe()
: m_fMinTimeOff(1.0f)
, m_fMaxTimeOff(1.0f)
, m_fMinTimeOn(1.0f)
, m_fMaxTimeOn(1.0f)
{
}

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_STROBE = 0;

void Asura_Container_Strobe::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_STROBE)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_Strobe", iVersion));
		return;
	}

	xStream >> m_fMinTimeOff;
	xStream >> m_fMaxTimeOff;
	xStream >> m_fMinTimeOn;
	xStream >> m_fMaxTimeOn;

	Asura_Container::ReadFromChunkStream(xStream);
}

void Asura_Container_Strobe::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_STROBE;

	xStream << m_fMinTimeOff;
	xStream << m_fMaxTimeOff;
	xStream << m_fMinTimeOn;
	xStream << m_fMaxTimeOn;

	Asura_Container::WriteToChunkStream(xStream);
}

///////////////////////////////////////////////////////////////////////////////
// Asura_Container_GraphColour
///////////////////////////////////////////////////////////////////////////////

// Asura_Container_GraphColour_Param
Asura_Container_GraphColour_Param::Asura_Container_GraphColour_Param()
{
#ifdef ASURA_TOOLS
	// Initialise everything (including the graphs) to valid defaults.
	ResetToDefaults(true);
#else
	// For non-Tools builds we are always going to initialise this class
	// from a chunskstream. There is no point in setting up the graphs twice.
	ResetToDefaults(false);
#endif
}

void Asura_Container_GraphColour_Param::ResetToDefaults(bool bInitialiseGraphs)
{
	m_uFlags = ASURA_CONTAINER_GRAPHCOLOUR_FLAG_GRAPH_IS_LOOPED;
	m_fGraphDuration = 10.0f;
	
	if (bInitialiseGraphs)
	{
		const Asura_RGBA xColour(1.0f, 1.0f, 1.0f, 1.0f);
		m_xColourRangeGraph.Initialise(16, xColour, xColour);
		m_xFlickerGraph.Initialise(16, 0.0f, 0.0f);
	}
}

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_GRAPHCOLOUR_PARAM = 0;

void Asura_Container_GraphColour_Param::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_GRAPHCOLOUR_PARAM)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_GraphColour_Param", iVersion));
		return;
	}

	xStream >> m_uFlags;
	xStream >> m_fGraphDuration;

	m_xColourRangeGraph.ReadFromChunkStream(xStream);
	m_xFlickerGraph.ReadFromChunkStream(xStream);
}

void Asura_Container_GraphColour_Param::WriteToChunkStream(Asura_Chunk_Stream& xStream, bool bExporting) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_GRAPHCOLOUR_PARAM;

	xStream << m_uFlags;
	xStream << m_fGraphDuration;

	// If exporting then only write out samples.
	m_xColourRangeGraph.WriteToChunkStream(xStream, bExporting);
	m_xFlickerGraph.WriteToChunkStream(xStream, bExporting);
}

// Asura_Container_GraphColour

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_GRAPHCOLOUR = 0;

void Asura_Container_GraphColour::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_GRAPHCOLOUR)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_GraphColour", iVersion));
		return;
	}

	m_xParam.ReadFromChunkStream(xStream);

	Asura_Container::ReadFromChunkStream(xStream);
}

void Asura_Container_GraphColour::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_GRAPHCOLOUR;

	// Asura_Containers are only written out during export (and shouldn't contain the spline data).
	m_xParam.WriteToChunkStream(xStream, true);

	Asura_Container::WriteToChunkStream(xStream);
}


///////////////////////////////////////////////////////////////////////////////
// Asura_Container_Health
///////////////////////////////////////////////////////////////////////////////
Asura_Container_Health::Asura_Container_Health()
: m_fInitialHealth(100.0f)
, m_fMaxHealth(100.0f)
{
}

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_HEALTH = 0;

void Asura_Container_Health::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_HEALTH)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_Health", iVersion));
		return;
	}

	xStream >> m_fInitialHealth;
	xStream >> m_fMaxHealth;

	Asura_Container::ReadFromChunkStream(xStream);
}

void Asura_Container_Health::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_HEALTH;

	xStream << m_fInitialHealth;
	xStream << m_fMaxHealth;

	Asura_Container::WriteToChunkStream(xStream);
}


///////////////////////////////////////////////////////////////////////////////
// Asura_Container_Physics
///////////////////////////////////////////////////////////////////////////////

// MGH 16/9/2008: I just copied the defaults from Asura_Physics_RigidBody.cpp.
static const float fDEFAULT_AIR_DRAG = 0.999f;
static const float fDEFAULT_ELASTICITY = 0.5f;
static const float fDEFAULT_FRICTION = 1.0f;
static const float fDEFAULT_ANGULAR_DRAG = 0.99f;

// Asura_Container_Physics_Param
void Asura_Container_Physics_Param::ResetToDefaults()
{
	m_fGravityScale = 1.0f;
	m_fElasticity	= fDEFAULT_ELASTICITY;
	m_fFriction		= fDEFAULT_FRICTION;
	m_fDrag			= 1.0f - fDEFAULT_AIR_DRAG;
	m_fAngularDrag	= 1.0f - fDEFAULT_ANGULAR_DRAG;
	m_fMass			= 1.0f;
}

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_PHYSICS_PARAM = 0;

void Asura_Container_Physics_Param::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_PHYSICS_PARAM)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_Physics_Param", iVersion));
		return;
	}

	xStream >> m_fGravityScale;
	xStream >> m_fElasticity;
	xStream >> m_fFriction;
	xStream >> m_fDrag;
	xStream >> m_fAngularDrag;
	xStream >> m_fMass;
}
	
void Asura_Container_Physics_Param::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_PHYSICS_PARAM;

	xStream << m_fGravityScale;
	xStream << m_fElasticity;
	xStream << m_fFriction;
	xStream << m_fDrag;
	xStream << m_fAngularDrag;
	xStream << m_fMass;
}

// Asura_Container_Physics

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_PHYSICS = 0;

void Asura_Container_Physics::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_PHYSICS)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_Physics", iVersion));
		return;
	}

	m_xParam.ReadFromChunkStream(xStream);

	Asura_Container::ReadFromChunkStream(xStream);
}

void Asura_Container_Physics::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_PHYSICS;

	m_xParam.WriteToChunkStream(xStream);

	Asura_Container::WriteToChunkStream(xStream);
}

// Asura_Container_Blueprint

// Chunkstream code
const int iCHUNK_VERSION_ASURA_CONTAINER_BLUEPRINT = 0;

void Asura_Container_Blueprint::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
	int iVersion = -1;
	xStream >> iVersion;

	if (iVersion < 0 || iVersion > iCHUNK_VERSION_ASURA_CONTAINER_BLUEPRINT)
	{
		Asura_Assertf(0, ("Unknown chunk version (%d) in Asura_Container_Blueprint", iVersion));
		return;
	}

	xStream >> m_uBlueprintTypeHash;
	xStream >> m_uBlueprintHash;

	Asura_Container::ReadFromChunkStream(xStream);
}

void Asura_Container_Blueprint::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
	xStream << iCHUNK_VERSION_ASURA_CONTAINER_BLUEPRINT;

	xStream << m_uBlueprintTypeHash;
	xStream << m_uBlueprintHash;

	Asura_Container::WriteToChunkStream(xStream);
}


#endif //#ifdef ASURA_USE_CONTAINER_SYSTEM
