/***********************************************************************************************
 *
 * Copyright © DreamWorks Interactive. 1996
 *
 * Contents:
 *		CClipPlane
 *
 * To do:
 *
 ***********************************************************************************************
 *
 * $Log:: /JP2_PC/Source/Lib/Renderer/Clip.hpp                                                 $
 * 
 * 9     98.08.13 4:26p Mmouni
 * Changes for VC++ 5.0sp3 compatibility.
 * 
 * 8     1/07/98 4:05p Pkeet
 * Added the clip region function and globals.
 * 
 * 7     12/23/97 1:55p Pkeet
 * Added a parameter to use when splitting polygons to move the coordinate slightly outwards to
 * avoid a crack due to T-junctions.
 * 
 * 6     97/07/23 18:03 Speter
 * Replaced CCamera argument to clipping functions with b_perspective flag.  Added similar
 * clipping functions for mesh polygons.
 * 
 * 5     97/06/10 15:47 Speter
 * Now takes camera as an argument (for new vertex projection).
 * 
 * 4     97/05/23 6:24p Pkeet
 * Untemplatized CPlaneDef.
 * 
 * 3     97-04-21 17:26 Speter
 * Totally rewrote CClipPlane interface, based more cleanly on templates, and inherited from
 * CPlane.  Removed InterpolateVertex(), now use SRenderVertex constructor.
 * 
 * 1     97-04-14 20:41 Speter
 * Contains code moved from GeomTypes.hpp.
 * 
 **********************************************************************************************/

#ifndef HEADER_LIB_RENDERER_CLIP_HPP
#define HEADER_LIB_RENDERER_CLIP_HPP

#include "ScreenRender.hpp"
#include "PipelineHeap.hpp"
#include "Lib/GeomDBase/Plane.hpp"
#include "Lib/GeomDBase/Mesh.hpp"

//**********************************************************************************************
//
class CClipPlane
//
// Abstract class which provides plane clipping functions.
//
// Prefix: clp
//
//**************************************
{
public:

	//******************************************************************************************
	//
	virtual TReal rEdgeT
	(
		const CVector3<>& v3_0,			// Vectors describing edge to intersect.
		const CVector3<>& v3_1
	) const = 0;
	//
	// Calculate the point of intersection between an edge and this plane.
	//
	// Returns:
	//		The parameter of the point of intersection between the edge and the bounding
	//		volume. (e.g this value will be 0 if the point of intersection falls at the
	//		starting point of the edge and 1 if it falls at the end point.)
	//
	// Cross-references:
	//		Invoked by bClipPolygon... functions, to create new vertices on the plane when
	//		clipping.  Must be implemented by derived class.
	//
	//**********************************

	//
	// Clipping functions for CRenderPolygons.
	//

	//******************************************************************************************
	//
	virtual ESideOf esfIntersectPolygon
	(
		CPArray<SRenderVertex*> paprv_poly,	// Polygon to test, in this volume's space.
		ESideOf aesf_sides[]				// Array of ESideOf codes to set.
	) const = 0;
	//
	// Calculates the side codes of each vertex, and stores them in the array.
	//
	// Returns:
	//		Where this polygon is in relation to the volume (the combination of the side codes
	//		of the vertices).
	//
	// Cross-references:
	//		Invoked by bClipPolygon... functions, where the array of side codes is used to clip 
	//		the polygon if it intersects the plane.  Must be implemented by derived class.
	//
	//**********************************

	//******************************************************************************************
	//
	virtual ESideOf esfClipPolygonInside
	(
		CRenderPolygon& rpoly,			// The render polygon to clip.
		CPipelineHeap& plh,				// The heap object to allocate new vertices on.
		bool b_perspective = true		// Whether to interpolate the screen coords as projected.
	) const;
	//
	// Clips the polygon against this volume.  If the polygon intersects the boundary of the
	// volume, this function converts it to a new polygon lying entirely inside the volume.
	// Otherwise (it is entirely inside or outside the volume), it leaves it unchanged.
	//
	// Returns:
	//		The side code of the original polygon.  If esfOUTSIDE or esfINSIDE, the polygon 
	//		is unchanged; if esfINTERSECT, it was clipped, and is now inside the plane.
	//
	//**********************************

	//******************************************************************************************
	//
	virtual ESideOf esfSplitPolygon
	(
		CRenderPolygon& rpoly,				// The render polygon to split.
		CPipelineHeap& plh,					// The heap object to allocate new objects on.
		bool b_perspective = true,			// Whether to interpolate the screen coords as projected.
		CRenderPolygon** pprpoly_out = 0,	// Returns the outside polygon, if split.
		float f_adjust_out = 0.0f
	) const;
	//
	// Splits the polygon by this plane, if it intersects: the original polygon is converted
	// to one lying inside the plane; a new polygon is created on the pipeline heap, lying 
	// outside the plane.  If the polygon does not intersect the plane, nothing happens.
	//
	// Returns:
	//		The intersection code of the polygon; if esfINTERSECT, it was split.
	// 
	//**********************************

	//
	// Similar functions for CMesh::SPolygons.
	//

	//******************************************************************************************
	//
	virtual ESideOf esfIntersectPolygonMesh
	(
		CPArray<CMesh::SVertex*> papmv_poly,	// Polygon to test, in this volume's space.
		ESideOf aesf_sides[]					// Array of ESideOf codes to set.
	) const = 0;
	//
	//**********************************

	//******************************************************************************************
	//
	virtual ESideOf esfClipPolygon
	(
		CMesh::SPolygon& mp,			// The mesh polygon to clip.
		CMesh::CHeap& mh,				// Where to allocate new mesh data.
		ESideOf esf_sides				// Which sides to keep: esfINSIDE or esfOUTSIDE;
										// if both, creates the outside polygon on the heap.
	) const;
	//
	//**********************************
};

//**********************************************************************************************
//
template<class P> class CClipPlaneT : public CClipPlane, public CPlaneT<P>
//
// Implements CClipPlane by extending a CPlaneT<P>.
//
//**************************************
{
public:

	//******************************************************************************************
	//
	// Constructors.
	//

	// Use plane's default constructor.
	CClipPlaneT()
	{
	}

	// Initialise with a plane object.
	CClipPlaneT(const P& p)
		: CPlaneT<P>(p)
	{
	}

	//******************************************************************************************
	TReal rEdgeT(const CVector3<>& v3_0, const CVector3<>& v3_1) const
	{
		// Implemented with rDistance().
		TReal r_0 = rDistance(v3_0);
		TReal r_1 = rDistance(v3_1);
		return r_0 / (r_0 - r_1);
	}

	//******************************************************************************************
	virtual ESideOf esfIntersectPolygon(CPArray<SRenderVertex*> paprv_poly, ESideOf aesf_sides[]) const
	{
		// Return combination of all points.  Use esfSideOf, to return esfON when appropriate,
		// for storage in array.
		ESideOf esf = esfON;

		for (uint u = 0; u < paprv_poly.uLen; u++)
		{
			aesf_sides[u] = esfSideOf(paprv_poly[u]->v3Cam);
			esf |= aesf_sides[u];
		}
		return esf;
	}

	//******************************************************************************************
	virtual ESideOf esfIntersectPolygonMesh(CPArray<CMesh::SVertex*> papmv_poly, ESideOf aesf_sides[]) const
	{
		// Return combination of all points.  Use esfSideOf, to return esfON when appropriate,
		// for storage in array.
		ESideOf esf = esfON;

		for (uint u = 0; u < papmv_poly.uLen; u++)
		{
			aesf_sides[u] = esfSideOf(*papmv_poly[u]->pv3Point);
			esf |= aesf_sides[u];
		}
		return esf;
	}
};


//
// Typedefs for general purpose plane classes
//

typedef CClipPlaneT<CPlaneDef> CClipPlaneGeneral;

//**********************************************************************************************
//
class CClipPlaneTolerance: public CClipPlaneT<CPlaneDefTolerance>
//
// Inherit rather than typedef, to add a convenient constructor.
//
//**************************************
{
public:

	//******************************************************************************************
	//
	// Constructors.
	//

	// Use plane's default constructor.
	CClipPlaneTolerance(const CPlane& pl, TReal r_tolerance = fPLANE_TOLERANCE)
		: CClipPlaneT<CPlaneDefTolerance>(CPlaneTolerance(pl, r_tolerance))
	{
	}
};


//**********************************************************************************************
//
void SetClipRegion
(
	float f_x_0,
	float f_y_0,
	float f_x_1,
	float f_y_1
);
//
// Sets the clip region globally. Currently the clip region is only used for polygons "grown" by
// the depth sort.
//
//**************************************

#endif