///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
 *	OPCODE - Optimized Collision Detection
 *	Copyright (C) 2001 Pierre Terdiman
 *	Homepage: http://www.codercorner.com/Opcode.htm
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
 *	Contains a mesh interface.
 *	\file		OPC_MeshInterface.h
 *	\author		Pierre Terdiman
 *	\date		November, 27, 2002
 */
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_MESHINTERFACE_H__
#define __OPC_MESHINTERFACE_H__

	struct VertexPointers
	{
		const Point*	Vertex[3];
		
		bool BackfaceCulling(const Point& source)
		{
			const Point& p0 = *Vertex[0];
			const Point& p1 = *Vertex[1];
			const Point& p2 = *Vertex[2];

			// Compute normal direction
			Point Normal = (p2 - p1)^(p0 - p1);

			// Backface culling
			return (Normal | (source - p0)) >= 0.0f;
		}
	};

	struct VertexPointersEx
	{
		VertexPointers	vp;
		dTriIndex	Index[3];
	};

	typedef			Point				ConversionArea[3];

#ifdef OPC_USE_CALLBACKS
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	 *	User-callback, called by OPCODE to request vertices from the app.
	 *	\param		triangle_index	[in] face index for which the system is requesting the vertices
	 *	\param		triangle		[out] triangle's vertices (must be provided by the user)
	 *	\param		user_data		[in] user-defined data from SetCallback()
	 */
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	typedef void	(*RequestCallback)	(udword triangle_index, VertexPointers& triangle, void* user_data);

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/**
	*	User-callback, called by OPCODE to request vertex indices from the app.
	*	\param		triangle_index	[in] face index for which the system is requesting the vertices
	*	\param		triangle		[out] triangle's vertices with indices (must be provided by the user)
	*	\param		user_data		[in] user-defined data from SetExCallback()
	*/
	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	typedef void	(*RequestExCallback)	(udword triangle_index, VertexPointersEx& triangle, void* user_data);
#endif

	class OPCODE_API MeshInterface
	{
		public:
		// Constructor / Destructor
											MeshInterface();
											~MeshInterface();
		// Common settings
		inline_			udword				GetNbTriangles()	const	{ return mNbTris;	}
		inline_			udword				GetNbVertices()		const	{ return mNbVerts;	}
		inline_			void				SetNbTriangles(udword nb)	{ mNbTris = nb;		}
		inline_			void				SetNbVertices(udword nb)	{ mNbVerts = nb;	}

#ifdef OPC_USE_CALLBACKS
		// Callback settings

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/**
		 *	Callback control: setups object callback. Must provide triangle-vertices for a given triangle index.
		 *	\param		callback	[in] user-defined callback
		 *	\param		user_data	[in] user-defined data
		 *	\return		true if success
		 */
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
						bool				SetCallback(RequestCallback callback, void* user_data);
		inline_			void*				GetUserData()		const	{ return mUserData;		}
		inline_			RequestCallback		GetCallback()		const	{ return mObjCallback;	}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/**
		*	Callback control: setups object callback. Must provide triangle-vertices for a given triangle index.
		*	\param		callback	[in] user-defined callback
		*	\param		user_data	[in] user-defined data
		*	\return		true if success
		*/
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		bool				SetExCallback(RequestExCallback callback, void* user_data);
		inline_			void*				GetExUserData()		const	{ return mExUserData;		}
		inline_			RequestExCallback	GetExCallback()		const	{ return mObjExCallback;	}
#else
		// Pointers settings

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/**
		 *	Pointers control: setups object pointers. Must provide access to faces and vertices for a given object.
		 *	\param		tris	[in] pointer to triangles
		 *	\param		verts	[in] pointer to vertices
		 *	\return		true if success
		 */
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
						bool				SetPointers(const IndexedTriangle* tris, const Point* verts);
		inline_	const	IndexedTriangle*	GetTris()			const	{ return mTris;			}
		inline_	const	Point*				GetVerts()			const	{ return mVerts;		}

	#ifdef OPC_USE_STRIDE
		// Strides settings

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/**
		 *	Strides control
		 *	\param		tri_stride		[in] size of a triangle in bytes. The first sizeof(IndexedTriangle) bytes are used to get vertex indices.
		 *	\param		vertex_stride	[in] size of a vertex in bytes. The first sizeof(Point) bytes are used to get vertex position.
		 *	\return		true if success
		 */
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
						bool				SetStrides(udword tri_stride=sizeof(IndexedTriangle), udword vertex_stride=sizeof(Point));
		inline_			udword				GetTriStride()		const	{ return mTriStride;	}
		inline_			udword				GetVertexStride()	const	{ return mVertexStride;	}

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/**
		*	Single/Double control
		*	\param		value		[in] Indicates if mesh data is provided as array of \c single values. If \c false, data is expected to contain \c double elements.
		*/
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		inline_			void				SetSingle(bool value)
											{
												mFetchTriangle = (value ? &MeshInterface::FetchTriangleFromSingles : &MeshInterface::FetchTriangleFromDoubles);
												mFetchExTriangle = (value ? &MeshInterface::FetchExTriangleFromSingles : &MeshInterface::FetchExTriangleFromDoubles);
											}

	#else
		inline_			bool				SetStrides(udword tri_stride=sizeof(IndexedTriangle), udword vertex_stride=sizeof(Point)) { return true; }
		inline_			void				SetSingle(bool value) {}
		inline_			udword				GetTriStride()		const	{ return sizeof(IndexedTriangle);	}
		inline_			udword				GetVertexStride()	const	{ return sizeof(Point);	}
	#endif
#endif

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/**
		 *	Fetches a triangle given a triangle index.
		 *	\param		vp		[out] required triangle's vertex pointers
		 *	\param		index	[in] triangle index
		 *	\param		vc      [in,out] storage required for data conversion (pass local variable with same scope as \a vp, as \a vp may point to this memory on return)
		 */
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		inline_			void				GetTriangle(VertexPointers& vp, udword index, ConversionArea vc)	const
											{
#ifdef OPC_USE_CALLBACKS
												(mObjCallback)(index, vp, mUserData);
#else
	#ifdef OPC_USE_STRIDE
												// Since there was conditional statement "if (Single)" which was unpredictable for compiler 
												// and required both branches to be always generated what made inlining a questionable 
												// benefit, I consider it better to introduce a forced call
												// but get rig of branching and dead code injection.
												((*this).*mFetchTriangle)(vp, index, vc);
	#else
												const Point* Verts = GetVerts();
												const IndexedTriangle* T = &mTris[index];
												vp.Vertex[0] = &Verts[T->mVRef[0]];
												vp.Vertex[1] = &Verts[T->mVRef[1]];
												vp.Vertex[2] = &Verts[T->mVRef[2]];
	#endif
#endif
											}

		inline_			bool				GetExTriangle(VertexPointersEx& vpe, udword index, ConversionArea vc)	const
											{
#ifdef OPC_USE_CALLBACKS
												if (mObjExCallback) { (mObjExCallback)(index, vpe, mUserData); return true; }
												else { (mObjCallback)(index, vpe.vp, mUserData); return false; }
#else
	#ifdef OPC_USE_STRIDE
												// Since there was conditional statement "if (Single)" which was unpredictable for compiler 
												// and required both branches to be always generated what made inlining a questionable 
												// benefit, I consider it better to introduce a forced call
												// but get rig of branching and dead code injection.
												((*this).*mFetchExTriangle)(vpe, index, vc);
												return true;
	#else
												const Point* Verts = GetVerts();
												const IndexedTriangle* T = &mTris[index];
												dTriIndex VertIndex0 = T->mVRef[0];
												vpe.Index[0] = VertIndex0;
												vpe.vp.Vertex[0] = &Verts[VertIndex0];
												dTriIndex VertIndex1 = T->mVRef[1];
												vpe.Index[1] = VertIndex1;
												vpe.vp.Vertex[1] = &Verts[VertIndex1];
												dTriIndex VertIndex2 = T->mVRef[2];
												vpe.Index[2] = VertIndex2;
												vpe.vp.Vertex[2] = &Verts[VertIndex2];
												return true;
	#endif
#endif
											}

		private:
#ifndef OPC_USE_CALLBACKS
	#ifdef OPC_USE_STRIDE
		void				FetchTriangleFromSingles(VertexPointers& vp, udword index, ConversionArea vc) const;
		void				FetchTriangleFromDoubles(VertexPointers& vp, udword index, ConversionArea vc) const;
		void				FetchExTriangleFromSingles(VertexPointersEx& vpe, udword index, ConversionArea vc) const;
		void				FetchExTriangleFromDoubles(VertexPointersEx& vpe, udword index, ConversionArea vc) const;
	#endif
#endif

		public:
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/**
		 *	Remaps client's mesh according to a permutation.
		 *	\param		nb_indices	[in] number of indices in the permutation (will be checked against number of triangles)
		 *	\param		permutation	[in] list of triangle indices
		 *	\return		true if success
		 */
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		bool				RemapClient(udword nb_indices, const dTriIndex* permutation)	const;

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/**
		 *	Checks the mesh interface is valid, i.e. things have been setup correctly.
		 *	\return		true if valid
		 */
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
						bool				IsValid()		const;

		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/**
		 *	Checks the mesh itself is valid.
		 *	Currently we only look for degenerate faces.
		 *	\return		number of degenerate faces
		 */
		///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
						udword				CheckTopology()	const;
		private:

						udword				mNbTris;			//!< Number of triangles in the input model
						udword				mNbVerts;			//!< Number of vertices in the input model
#ifdef OPC_USE_CALLBACKS
		// User callback
						void*				mUserData;			//!< User-defined data sent to callback
						RequestCallback		mObjCallback;		//!< Object callback
						void*				mExUserData;		//!< User-defined data sent to ex-callback
						RequestExCallback	mObjExCallback;		//!< Object ex-callback
#else
		// User pointers
	#ifdef OPC_USE_STRIDE
						udword				mTriStride;			//!< Possible triangle stride in bytes [Opcode 1.3]
						udword				mVertexStride;		//!< Possible vertex stride in bytes [Opcode 1.3]
				typedef	void (MeshInterface:: *TriangleFetchProc)(VertexPointers& vp, udword index, ConversionArea vc) const;
						TriangleFetchProc	mFetchTriangle;
				typedef	void (MeshInterface:: *ExTriangleFetchProc)(VertexPointersEx& vpe, udword index, ConversionArea vc) const;
						ExTriangleFetchProc	mFetchExTriangle;
	#endif
						const	IndexedTriangle*	mTris;				//!< Array of indexed triangles
						const	Point*				mVerts;				//!< Array of vertices
#endif
	};

#endif //__OPC_MESHINTERFACE_H__
