//////////////////////////////////////////////////////////////////////////////
//
// File: Asura_Collision_Object.h
//
// Created by Martin G. Harris.
//
// Copyright (c) 2003 Rebellion. All rights reserved.
//
// Data structures for simple collision objects for dynamics and LOS.
//
//////////////////////////////////////////////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef ___ASURA_COLLISION_OBJECT_H___
#define ___ASURA_COLLISION_OBJECT_H___ 1

//////////////
// Includes //
//////////////
#include "Core/Asura_Hash.h"
#include "Core/Asura_Maths.h"

/////////////////////////
// Forward declaration //
/////////////////////////
class Asura_LOS_InputData;
class Asura_LOS_OutputData;
class Asura_CollisionMesh;

//////////////////////////
// Asura_Collision_Poly //
//////////////////////////
class Asura_Collision_Poly
{
public:
	Asura_Vector_3 Vertex[3];
    Asura_Vector_3 Normal;
};


//////////////////////////////////////////////////////////////////
// Asura_Collision_Object: base class for all collision objects //
//////////////////////////////////////////////////////////////////
class Asura_Collision_Object
{
public:
	// Bounding volumes
	const Asura_Bounding_Box& GetBoundingBox() const { return m_xBoundingBox; }

	// Typically this is the radius with respect to the centre of the BB.
	float GetBoundingRadius() const {return m_fBoundingRadius;}

	// Fill the array with collision polys.
	// iMaxNumber = max number of polys to return (= space in poly array).
	// pxPolyPtr  = pointer to next free poly (advanced as we add each poly).
	// xPosition  = position offset.
	// pxOrient   = optional rotation (or NULL for no rotation).
	// Returns the number of polys added.
	virtual int FillPolyArray(  int iMaxNumber,
								Asura_Collision_Poly*& pxPolyPtr,
								const Asura_Vector_3& xPosition,
								const Asura_Matrix_3x3* pxOrient) const;

#ifdef ASURA_TOOLS
    // for waypointing only - return the flags as well
	virtual int FillPolyArray(  int iMaxNumber,
								Asura_Collision_Poly*& pxPolyPtr,
                                u_short*& pusFlagsPtr,
								const Asura_Vector_3& xPosition,
								const Asura_Matrix_3x3* pxOrient) const;
#endif

	// LOS test. By default just tests against the BB.
	// Override for more complex behaviour, eg per poly.
	virtual bool LOSTest(const Asura_Vector_3& xPosition, 
						 const Asura_Matrix_3x3& xOrient,
						 const Asura_LOS_InputData* pxInput,
						 Asura_LOS_OutputData* pxOutput) const 
	{ 
		return LOSTestRotatedBB(xPosition, xOrient, pxInput, pxOutput);
	}

	
	// LOS test against the rotated BB only.
	bool LOSTestRotatedBB( const Asura_Vector_3& xPosition, 
						   const Asura_Matrix_3x3& xOrient,
						   const Asura_LOS_InputData* pxInput,
						   Asura_LOS_OutputData* pxOutput) const;


	// LOS test against the rotated BB only.
	bool LOSTestSphere( const Asura_Vector_3& xPosition,
						const Asura_LOS_InputData* pxInput,
						Asura_LOS_OutputData* pxOutput) const;


	// MGH 7/10/2004: If this is a mesh then return a pointer.
	virtual const Asura_CollisionMesh* GetMesh() const { return 0; }

protected:
	Asura_Collision_Object();
	virtual ~Asura_Collision_Object() {}

	void ResetBB(); // Make sure BB has a minimum size

protected:
	// Bounding volumes
	Asura_Bounding_Box m_xBoundingBox;
	float m_fBoundingRadius;

	unsigned short m_usOverallFlags;   // Overall flags for the whole thing.
#ifdef ASURA_TOOLS
    unsigned int   m_uToolsOverallFlags;
#endif
	short m_sOverallMaterial; // Overall material for the whole thing.
	Asura_Hash_ID m_uOverallMaterialResponse;
};



////////////////////////////////////////////////////
// Asura_Collision_Box: object space collision BB //
////////////////////////////////////////////////////
class Asura_Collision_Box : public Asura_Collision_Object
{
public:
	Asura_Collision_Box(float fMinX, float fMaxX,
						float fMinY, float fMaxY,
						float fMinZ, float fMaxZ);
	Asura_Collision_Box(const Asura_Bounding_Box& xBB);

	virtual ~Asura_Collision_Box() {}

	// MGH 29/4/03: Added to fix a bug during loading.
	void ChangeBB(const Asura_Bounding_Box& xBB);

protected:
	void CalculateRadius();
};


////////////////////////////////////////////////////////////////////////////////////
// Asura_Collision_HeightBox: collision box with varying height for use in tools. //
////////////////////////////////////////////////////////////////////////////////////
class Asura_Collision_HeightBox : public Asura_Collision_Box
{
public:
	Asura_Collision_HeightBox(float fMinX, float fMaxX,
							  float fMinY, float fMaxY,
							  float fMinZ, float fMaxZ);

	virtual ~Asura_Collision_HeightBox() {}

	void SetHeight(float fHeight);
};

////////////////////////////////////////////////////////////////////////////////////////
// Asura_Collision_Pane: thin collision box with varying size used by panes of glass. //
////////////////////////////////////////////////////////////////////////////////////////
class Asura_Collision_Pane : public Asura_Collision_Box
{
public:
	Asura_Collision_Pane(float fSizeX, float fSizeY);
	virtual ~Asura_Collision_Pane() {}

	// Set the size if necessary and return true if it has changed.
	bool SetSize(float fSizeX, float fSizeY);
};

#endif //___ASURA_COLLISION_OBJECT_H___
