///////////////////////////////////////////////////////////////////////////////
//
// File: Asura_CollisionFX_Messages.h
//
// Created by Martin G.Harris (19/01/2009)
// 
// Copyright (C) 2009 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef __ASURA_COLLISIONFX_MESSAGES_H__
#define __ASURA_COLLISIONFX_MESSAGES_H__

// Includes
#include "Core/Asura_Maths.h"
#include "SpecialFx/Asura_CFX_Effect.h"

// Forward declarations
class Asura_BitPacker;
class Asura_BitUnpacker;

// The maximum number of entries to send to the remote client machine.
const u_int uASURA_CFX_MAX_NUM_ENTRIES_FOR_CLIENT = 32;

// The number of bits required to store one less than this number.
const u_int uASURA_CFX_MAX_NUM_ENTRIES_FOR_CLIENT_NUMBITS = 5;

//////////////////////////////////////////
// Asura_Message_CFX_ClientUpdate_Entry //
//////////////////////////////////////////
// Information about an entry in the server CFX table (only contains
// that subset of all the available data that the client needs).
class Asura_Message_CFX_ClientUpdate_Entry
{
public:
	Asura_Message_CFX_ClientUpdate_Entry() { Reset(); }

	void Reset()
	{
		m_uGuid1 = ASURA_GUID_UNREGISTERED;
		m_uGuid2 = ASURA_GUID_SERVER;
		m_iType  = 0;
		m_uStateFlags = 0;

		m_uSEHash = ASURA_HASH_ID_UNSET;
		m_fVolumeScale = 1.0f;

		m_uPFXHash = ASURA_HASH_ID_UNSET;
		m_uPFXFlags = 0;

		m_xPosition.Zero();
		m_xNormal = Asura_Vector_3(0.0f, -1.0f, 0.0f);
	}

	bool GetCreatedSE() const		{ return (m_uStateFlags & ASURA_CFX_FLAG_STATE_CREATED_SE)  != 0; }
	bool GetCreatedPFX() const		{ return (m_uStateFlags & ASURA_CFX_FLAG_STATE_CREATED_PFX) != 0; }
	bool GetUpdatedPosition() const	{ return (m_uStateFlags & ASURA_CFX_FLAG_STATE_UPDATED_POSITION) != 0; }
	bool GetUpdatedNormal() const	{ return (m_uStateFlags & ASURA_CFX_FLAG_STATE_UPDATED_NORMAL) != 0; }
	bool GetUpdatedVolume() const	{ return (m_uStateFlags & ASURA_CFX_FLAG_STATE_UPDATED_VOLUME) != 0; }

#ifdef ASURA_SUPPORT_NETMSG_SYSTEM
	void Pack(Asura_BitPacker& xPacker) const;
	void Unpack(Asura_BitUnpacker& xUnpacker);
#endif //ASURA_SUPPORT_NETMSG_SYSTEM

	// Identification
	Asura_Guid m_uGuid1;
	Asura_Guid m_uGuid2;	// ASURA_GUID_SERVER for environment.
	int m_iType;

	// Flags
	u_int m_uStateFlags;	// ASURA_CFX_FLAG_STATE_* flags

	// Sound event information
	Asura_Hash_ID m_uSEHash;
	float m_fVolumeScale;

	// PFX information
	Asura_Hash_ID m_uPFXHash;
	u_int m_uPFXFlags;

	// Misc data
	Asura_Vector_3 m_xPosition;
	Asura_Vector_3 m_xNormal;
};

////////////////////////////////////
// Asura_Message_CFX_ClientUpdate //
////////////////////////////////////
// Update the client machine with information about a CFX effect.
// Uncompressed version of client update.
class Asura_Message_CFX_ClientUpdate
{
public:
	Asura_Message_CFX_ClientUpdate() : m_uNumEntries(0) {}

#ifdef ASURA_SUPPORT_NETMSG_SYSTEM
	void Pack(Asura_BitPacker& xPacker) const;
	void Unpack(Asura_BitUnpacker& xUnpacker);
#endif //ASURA_SUPPORT_NETMSG_SYSTEM

	u_int m_uNumEntries; // Actual number of entries sent.

	Asura_Message_CFX_ClientUpdate_Entry m_axEntry[uASURA_CFX_MAX_NUM_ENTRIES_FOR_CLIENT];
};


/////////////////////////////////////////
// Asura_Message_CFX_ClientCreateDecal //
/////////////////////////////////////////
// Create a CFX decal effect on the remote client machines.
class Asura_Message_CFX_ClientCreateDecal
{
public:
	Asura_Message_CFX_ClientCreateDecal() { Reset(); }

	void Reset()
	{
		m_uDecalSetHash = ASURA_HASH_ID_UNSET;
		m_iDecalIndex = 0;
		m_fScale = 1.0f;
		m_fOrientation = 0.0f;
		m_xPosition.Zero();
		m_xNormal = Asura_Vector_3(0.0f, -1.0f, 0.0f);
		m_bAlignWithVelocity = false;
		m_xTopDirection = Asura_Vector_3(1.0f, 0.0f, 0.0f);
	}

#ifdef ASURA_SUPPORT_NETMSG_SYSTEM
	void Pack(Asura_BitPacker& xPacker) const;
	void Unpack(Asura_BitUnpacker& xUnpacker);
#endif //ASURA_SUPPORT_NETMSG_SYSTEM


	Asura_Hash_ID m_uDecalSetHash;
	int m_iDecalIndex;
	float m_fScale;
	float m_fOrientation;

	Asura_Vector_3 m_xPosition;
	Asura_Vector_3 m_xNormal;

	bool m_bAlignWithVelocity;
	Asura_Vector_3 m_xTopDirection;
};


////////////////////////////
// Asura_Compressed_Float //
////////////////////////////
// Float in specified inclusive range [min, max], compressed to the specified number of bits.
// Represent min and max values exactly. Clamp the float to the range.
class Asura_Compressed_Float
{
public:
	Asura_Compressed_Float(float fMin, float fMax, u_int uNumBits)
		: m_uData(0), m_fMin(fMin), m_fMax(fMax), m_uNumBits(uNumBits)
	{}

	float GetMin() const { return m_fMin; }
	float GetMax() const { return m_fMax; }

	u_int GetNumberOfBits() const { return m_uNumBits; } // Max of 32 bits
	u_int GetNumBins() const { return (1<<GetNumberOfBits()); }

	inline void Pack(Asura_BitPacker& xBitPacker) const
	{
		xBitPacker.Pack(m_uData, GetNumberOfBits());
	}
	inline void Unpack(Asura_BitUnpacker& xUnpacker)
	{
		m_uData = xUnpacker.Unpack(GetNumberOfBits());
	}

	void FromFloat(float fValue, bool bAssertIfOutOfRange = true);
	void ToFloat(float& fValue) const;

private:
	u_int m_uData;

	float m_fMin;
	float m_fMax;
	u_int m_uNumBits;
};

#endif //__ASURA_COLLISIONFX_MESSAGES_H__

