//
// Asura_Physics_Contact.h
//
// Created by KJFL - 2004-03-23 10:32:06
//
// Copyright (C) 2004 Rebellion, All Rights Reserved.
//

#ifdef ASURA_USE_PRAGMA_ONCE
	#pragma once
#endif

#ifndef __ASURA_PHYSICS_CONTACT_H__
#define __ASURA_PHYSICS_CONTACT_H__

#include "Core/Asura_Maths.h"


//! Awkward concept - when a face of an object touches something like a static vertex
//! we need to make a temporary vertex on the face that will move with the object
//! and follow the same linkage rules as a usual object vertex. However, when the
//! contact is over this new vertex can be destroyed. 
//!
//! This will want to go into a mempool, so no public constructor/destructors.
//!
//! KJFL - 17 August 2004 - currently thinking it will always be part of another class.

class Asura_Physics_RigidBody_ContactVertex
{
	public:

		// non static data members

		//! vertex position data for Verlet stuff
		Asura_AVector3							m_xPosition;
		Asura_AVector3							m_xPrevPosition;
		//float									m_afBaseDistance[5];

		//! normal away from the collision 'surface'
		Asura_AVector3							m_xNormal;
		
		//! contacts often stored in a linked list
		Asura_Physics_RigidBody_ContactVertex*	m_pxNext;
	
};


//! Generic contact class, designed to cope with a variety of contact types 
//! (e.g. vertex-to-face, face-to-vertex, edge-to-edge).
//!
//! Note no public constructor since this class is used with a mempool.
//!
class Asura_Physics_Contact
{
	public:

		//! Initialise(), Reset() and Shutdown() handle this class's mempool, and should 
		//! only be called by the Asura_Physics_System
		static void Initialise( void );
		static void Reset( void );
		static void Shutdown( void );

		//! Create function that will take a Contact from the mempool and return a pointer
		//! to it. 
		static Asura_Physics_Contact* Create( void );
		
		//! Puts a Contact back into the mempool for reuse.
		static void Destroy( Asura_Physics_Contact* pxContact );

		
		//
		// Query methods
		//

		inline bool IsBroken( void )
		{
			return m_bBroken;
		}

		inline Asura_Physics_RigidBody_ContactVertex& GetContactVertex( void )
		{
			return m_xVertex;
		}
		
		inline Asura_Physics_RigidBody_ContactVertex* GetContactVertexPointer( void )
		{
			return &m_xVertex;
		}

		inline const Asura_AVector3& GetContactPosition( void ) const
		{
			return m_xContactPosition;
		}

		inline float GetMaxPenetration( void ) const
		{
			return m_fMaxPenetration;
		}

		// object vertex - environment face contact
		inline u_int GetEnvironmentFace( void ) const
		{
			return m_uEnvironmentFaceIndex;
		}

		// environment vertex - object face contact
		inline u_int GetObjectFace( void ) const
		{
			return m_uObjectFaceIndex;
		}

		// environment edge - object edge contact
		inline u_int GetObjectEdge( void ) const
		{
			return m_uObjectEdgeIndex;
		}



		//
		// Set methods
		//
		
		inline void SetContactPosition( const Asura_AVector3& xPosition )
		{
			m_xContactPosition = xPosition;
		}

		inline void SetMaxPenetration( const float fPenetration )
		{
			m_fMaxPenetration = fPenetration;
		}

		inline void DecayPenetration( void )
		{
			m_fMaxPenetration *= 0.80f;
		}


		// object vertex - environment face contact
		inline void SetEnvironmentFace( u_int uEnvironmentFaceIndex )
		{
			m_uEnvironmentFaceIndex = uEnvironmentFaceIndex;
		}

		// environment vertex - object face contact
		inline void SetObjectFace( u_int uObjectFaceIndex )
		{
			m_uObjectFaceIndex = uObjectFaceIndex;
		}

		// environment edge - object edge contact
		inline void SetObjectEdge( u_int uObjectEdgeIndex )
		{
			m_uObjectEdgeIndex = uObjectEdgeIndex;
		}

		inline void SetBrokenStatus( bool b )
		{
			m_bBroken = b;
		}


	private:

		//
		// static members
		//

		//! Static mempool to contain all Contacts
		//! Using Asura_Mempool* means I don't have to #include any other headers
		//! in this file and so minimise compile and link time.
		static class Asura_ResizingMempool*	s_pxContactPool;


		//! Private constructor/destructor so people can't new/delete this class directly.
		//! Since the contacts will be drawn from a mempool we don't actually want to use
		//! the constructor/destructor either...
		Asura_Physics_Contact(){};
		~Asura_Physics_Contact(){};

		//
		// non static data members
		//

		//! position where contact FIRST occurred 
		Asura_AVector3							m_xContactPosition;

		Asura_Physics_RigidBody_ContactVertex	m_xVertex;

		float									m_fMaxPenetration;

		bool									m_bBroken;

		//! data specific to the contact type
		union
		{
			// object vertex - environment face contact
			u_int m_uEnvironmentFaceIndex;

			// environment vertex - object face contact
			u_int m_uObjectFaceIndex;

			// environment edge - object edge contact
			u_int m_uObjectEdgeIndex;
		};

	public:
		Asura_Physics_Contact* m_pxPrev;
		Asura_Physics_Contact* m_pxNext;

};

#endif//__ASURA_PHYSICS_CONTACT_H__
