/*=========================================================================================
File:			Bezier.c
Prupose:		Handle a Bezier curve
Author:			Yann Le Tensorer
Creation Date:	23 january 1997
Version:		1.0
===========================================================================================
Revisions:		Version		Date				Author
                ----------------------------------------------------------------
				1.1			3 february 1997		Yann Le Tensorer
				1.2			5 february 1997		Yann Le Tensorer	
							Added the possibility of changing the sampling rate in real-time
=========================================================================================*/


/*==========================================================
Notes:

This module implements functions to create and draw bezier curves
here is an example how to use it:

{
	tdstBezierObject	BezierCurve;
	long				color;
	MTH3D_tdstVector	A,B,T1,T2;		
	ACP_tdstDynaParam	stDynaParam;	
	unsigned char		ucSamplingRate;
	
	color=0xffffffff;  // white
   
	A.xX=0;
	A.xY=0;
	A.xZ=0;
	B.xX=1;
	B.xY=1;
	B.xZ=0;
	T1.xX=0;
	T1.xY=0.25;
	T1.xZ=0;
	T2.xX=-0.25;
	T2.xY=0;
	T2.xZ=0;

	ucSamplingRate=20;	// Sampling rate

	fn_vDynamicObject_Create(&stDynaParam,ucSamplingRate,C_ucSinus,0,MTH_C_Pi,255);
	fn_vBezierObject_Create(&BezierCurve,ucSamplingRate,&A,&B,&T1,&T2,C_ucModeNoObject,&stDynaParam);
	fn_vBezierObject_SetColor(&BezierCurve,color);
	fn_vBezierObject_SetViewPortAttributes(...); // en fonction du viewport
	fn_vBezierObject_Draw(&BezierCurve);
	fn_vBezierObject_Free(&BezierCurve);
}
===========================================================*/
#ifdef _AI_LIB_
#include "AIUseCPA.h"
/*#include "acp_base.h"*/
/*#include "gli.h"*/
#include "geoobj.h"
#include "bezier.h"
#include "IAOption.h"
#include "IAMacros.h"
/* AI memory and error management */
#include "MemIA.h"
#include "ErrIA.h"
#else /*_AI_LIB_*/
#include "acp_base.h"
#include "gli.h"
#include "geoobj.h"
#include "bezier.h"
#endif /*_AI_LIB_*/

/*============================================================
Memory management macros, to be replaced with correct memory management
============================================================*/
#ifdef _AI_LIB_
#define M_malloc(pointer,cast,size) M_IAAlloc(pointer,cast,size)
#define M_free(pointer) M_IAFree(pointer)
#else /*_AI_LIB_*/
#define M_malloc(pointer,cast,size) (pointer=(cast)malloc(size))
#define M_free(pointer) (free(pointer))
#endif /*_AI_LIB_*/

/*==========================================================
Function name:	fn_vBezierObject_Create
Description:	Create Bezier curve (in ram only) between two points
Input:			p_BezierObject:	pointer to a preallocated tdstBezierObject
				ucSamplingRate:	number of segment to define the curve) 
				stStartPoint:	First vertex of the curve
				stEndPoint:		Last vertex of the curve
				stStartVector:	Tangent vector at the first point
				stEndVector:	Tangent vector at the last point
				ucObjectMode:	Creation mode (C_ucModeNoObject ou C_ucModeRealObject)
								C_ucModeNoObject does not create a geometric object 
								whereas C_ucModeRealObject does.
Output:			none
Author:			Yann Le Tensorer
Date:			23 january 1997
Revision:		YLT - 03 february 1997
==========================================================*/

void fn_vBezierObject_Create(	tdstBezierObject	*p_BezierObject,
							unsigned char		ucSamplingRate,		
							MTH3D_tdstVector*	p_stStartPoint,
							MTH3D_tdstVector*	p_stEndPoint,
							MTH3D_tdstVector*	p_stStartVector,
							MTH3D_tdstVector*	p_stEndVector,
							unsigned char		ucObjectMode,
							ACP_tdstDynaParam*	p_stDynaParams
							)

{
	
	GEO_tdstDoubledIndex xLineDoubleIndex;
	long xCurVertex;

	if (p_BezierObject==0) return; /* avoid crash */

	/* copies input parameters into objects parameters */
	p_BezierObject->ucObjectMode	=ucObjectMode;
	p_BezierObject->ucSamplingRate	=ucSamplingRate;
	p_BezierObject->stStartPoint	=*p_stStartPoint;
	p_BezierObject->stEndPoint		=*p_stEndPoint;
	p_BezierObject->stStartVector	=*p_stStartVector;
	p_BezierObject->stEndVector		=*p_stEndVector;
	p_BezierObject->p_stDynaParams  =p_stDynaParams;

	/* if mode is MODE_NO_OBJECT, allocates ram only for points list and dynamic parameters */
	if (ucObjectMode==C_ucModeNoObject)
	{
		M_malloc (	p_BezierObject->d_stListOfPoints,
					MTH3D_tdstVector*,
					(ucSamplingRate+1)*sizeof(MTH3D_tdstVector)
					);

		
	}
	else
	/* else mode is MODE_REAL_OBJET, creates the geometric object*/
	{
		/* This list of points is not used */
		p_BezierObject->d_stListOfPoints=0;

		/* create object with 1 element (lines only), and ucSamplingRate+1 points) */
		GEO_vCreateGeometricObject(&p_BezierObject->hObject,ucSamplingRate+1,1);	

		/* create line element*/
		GEO_xCreateElementLines(p_BezierObject->hObject,&p_BezierObject->hElement,ucSamplingRate);

		/* create lines indexes */
		for (xCurVertex=0;xCurVertex<ucSamplingRate;xCurVertex++)
		{
			/* define start and end vertex of a line */
			xLineDoubleIndex.a2_xIndex[0]=xCurVertex;
			xLineDoubleIndex.a2_xIndex[1]=xCurVertex+1;

			/* set line index */
			GEO_xSetIndexOfElementLines(p_BezierObject->hObject,p_BezierObject->hElement,xCurVertex,&xLineDoubleIndex);
		}
	}

	/* calculate points of bezier curve */
	fn_vBezierObject_Calculate(p_BezierObject);

}

/*===============================================================================
Function name:	fn_bBezierObject_SetSamplingRate
Description:	Modifies the sampling rate of a bezier object, and changes all
				the depending parameters (including dynamic sampling rate)
Input:			p_BezierObject:	pointer to a preallocated tdstBezierObject
				ucSamplingRate:	New sampling rate
Output:			return value is true if sampling rate could be modified,
				false if not.
Author:			Yann Le Tensorer
Date:			5 february 1997
Revision:		
Note:			The sampling rate can only be modified for objects that have been
				created using C_ucModeNoObject at their creation.
================================================================================*/

ACP_tdxBool fn_bBezierObject_SetSamplingRate(tdstBezierObject	*p_BezierObject,
											 unsigned char		ucSamplingRate)

{
	
	if (p_BezierObject==0) return FALSE; 

	if (p_BezierObject->ucObjectMode==C_ucModeNoObject)
	{
		/* copies new sampling rate value into objects parameters */
		p_BezierObject->ucSamplingRate	=ucSamplingRate;	
		if (p_BezierObject->ucSamplingRate<2) p_BezierObject->ucSamplingRate=2;

		/* free old list of points and allocates new one */
		if (p_BezierObject->d_stListOfPoints!=0)
			M_free(p_BezierObject->d_stListOfPoints);

		M_malloc (	p_BezierObject->d_stListOfPoints,
					MTH3D_tdstVector*,
					(p_BezierObject->ucSamplingRate+1)*sizeof(MTH3D_tdstVector)
					);

		/* calculate points of bezier curve */
		fn_vBezierObject_Calculate(p_BezierObject);

		/* checks if dynamic parameters are attached to the object
		 if yes, changes them to match the new sampling rate */
		fn_vDynamicObject_ChangeSamplingRate(p_BezierObject->p_stDynaParams,
											 p_BezierObject->ucSamplingRate);
		return TRUE;
	}
	else
		return FALSE;
	
}


/*==========================================================
Function name:	fn_vBezierObject_Free
Description:	Free memory allocated by the bezier objet
Input:			p_BezierObject:	pointer to a tdstBezierObject
Output:			none
Author:			Yann Le Tensorer
Date:			29 january 1997
Revision:
==========================================================*/

void fn_vBezierObject_Free(tdstBezierObject	*p_BezierObject)
{
	if (p_BezierObject!=0)
	{
		if (p_BezierObject->d_stListOfPoints!=0)
			M_free(p_BezierObject->d_stListOfPoints);

		/* if dynamic parameters are present, free memory too */

		if (p_BezierObject->p_stDynaParams!=0)
			fn_vDynamicObject_Free(p_BezierObject->p_stDynaParams);
	
	}
}



/*==========================================================
Function name:	fn_vBezierObject_Calculate
Description:	Calculates the points of the bézier curve according to the 
				parameters specified when creating the object.
Input:			p_BezierObject:	Pointer to a pre-created bezier object
Output:			none
Author:			Yann Le Tensorer
Date:			23 january 1997
Revision:
==========================================================*/
void fn_vBezierObject_Calculate(tdstBezierObject *p_BezierObject)

{
	
	double				xt,endxt,t,c0,c1,c2,c3,c4,c5,c6;
	MTH3D_tdstVector	A,B,T1,T2;
	MTH3D_tdstVector	*p_stPointList;


	if (p_BezierObject==0) return; /* avoid crash */

	if (p_BezierObject->ucObjectMode==C_ucModeRealObject)
		p_stPointList=((p_BezierObject->hObject) -> d_stListOfPoints);
	else
		p_stPointList=(p_BezierObject->d_stListOfPoints);

	A	 = p_BezierObject->stStartPoint;		
	B	 = p_BezierObject->stEndPoint;		
	MTH3D_M_vAddVector(&T1,&p_BezierObject->stStartVector,&p_BezierObject->stStartPoint);		
	MTH3D_M_vAddVector(&T2,&p_BezierObject->stEndVector,&p_BezierObject->stEndPoint);
	endxt= p_BezierObject->ucSamplingRate;

	for (xt=0;xt<=endxt;xt++)
	{
		t=xt/endxt;

		c0=1-t;			/* 1-t */
		c2=c0*c0;       /* (1-t)^2 */
		c1=3*t*c2;	    /* 3t*((1-t)^2) */
		c3=t*t;			/* t^2 */
		c4=3*c3*c0;		/* 3t^2*(1-t) */
		c5=c0*c2;		/* (1-t)^3 */
		c6=c3*t;		/* t^3 */

		p_stPointList->xX=(c5*A.xX)+(c1*T1.xX)+(c4*T2.xX)+(c6*B.xX);
		p_stPointList->xY=(c5*A.xY)+(c1*T1.xY)+(c4*T2.xY)+(c6*B.xY);
		p_stPointList->xZ=(c5*A.xZ)+(c1*T1.xZ)+(c4*T2.xZ)+(c6*B.xZ);

		p_stPointList++;
	}
}


/*==========================================================
Function name:	fn_vBezierObject_SetColor
Description:	Set the color of a bezier object.
Input:			p_BezierObject:	pointer to a pre-created tdstBezierObject
				color:			24 bit color of object. (0->7=B;  8->15=G; 16->23=R ; 24->32=Unused) 
Output:			none
Author:			Yann Le Tensorer
Date:			24 january 1997
Revision:
==========================================================*/

void fn_vBezierObject_SetColor(tdstBezierObject *p_BezierObject,long color)
{
	if (p_BezierObject==0) return; /* avoid crash */
	p_BezierObject->color=color;
}




/*==========================================================
Function name:	fn_vBezierObject_SetViewPortAttributes
Description:	Set the viewportattributes for drawing.
Input:			p_BezierObject:			pointer to a pre-created tdstBezierObject
				p_ViewPortAttributes:	pointer to  pre-defined viewport attributes
Output:			none
Author:			Yann Le Tensorer
Date:			24 january 1997
Revision:
==========================================================*/

void fn_vBezierObject_SetViewPortAttributes(tdstBezierObject *p_BezierObject,GLD_tdstViewportAttributes *p_ViewPortAttributes)
{
	if (p_BezierObject==0) return; /* avoid crash */
	p_BezierObject->p_ViewPortAttributes=p_ViewPortAttributes;
}




/*==========================================================
Function name:	fn_vBezierObject_Draw
Description:	Draw Bezier object on screen
Input:			p_BezierObject:	pointer to a pre-created tdstBezierObject
Output:			none
Author:			Yann Le Tensorer
Date:			24 january 1997
Revision:
==========================================================*/
void fn_vBezierObject_Draw(tdstBezierObject *p_BezierObject)
{
	POS_tdstCompletePosition stMatrix;
	GEO_tdstColor		ColBidon;
	MTH3D_tdstVector	*p_stPointList;
	MTH3D_tdstVector    *p_stPointListEnd;

	POS_fn_vSetIdentityMatrix(&stMatrix);
	if (p_BezierObject==0) return; /* avoid crash */

	/*unsigned long color; */

	ColBidon.xR=(float)0.5;
	ColBidon.xG=(float)0.5;
	ColBidon.xB=(float)0.5;
	ColBidon.xA=(float)0.5;

	if (p_BezierObject->ucObjectMode==C_ucModeRealObject)
		p_stPointList=((p_BezierObject->hObject) -> d_stListOfPoints);
	else
		p_stPointList=(p_BezierObject->d_stListOfPoints);


	if (p_stPointList==0) return;

	GLI_xGetCameraMatrix(((GLI_tdstSpecificAttributesFor3D*)((p_BezierObject->p_ViewPortAttributes)->p_vSpecificToXD))->p_stCam,&stMatrix);
	GLI_xLoadMatrix(&stMatrix);
	GLI_vSetFog(100,100,&ColBidon);
	p_stPointListEnd=p_stPointList+p_BezierObject->ucSamplingRate;
	

	for (;p_stPointList<p_stPointListEnd;p_stPointList++)
		{
			GLI_xDraw3DLine16(
				(struct GLD_tdstViewportAttributes_*)(p_BezierObject->p_ViewPortAttributes),
				p_stPointList,
				p_stPointList+1,
				p_BezierObject->color);

		}

	
    GLI_xPopMatrix();
	

}

/*==========================================================
Function name:	fn_vBezierObject_ChangeParams
Description:	Changes the parameters of a bezier objet and recalculates the coordinates
				of the points.
Input:			p_BezierObject:	Pointer to a pre-created bezier object
				p_stStartPoint: Pointer to the start point 
				p_stEndPoint:	Pointer to the end Point	
				p_stStartVector:Pointer to the start vector	
				p_stEndVector:	Pointer to the end vector
Output:			none
Author:			Yann Le Tensorer
Date:			28 january 1997
Revision:

Notes:			If an input parameter is 0, this parameter is simply not
				affected. This enables to change easily only one parameter
==========================================================*/
void fn_vBezierObject_ChangeParams(tdstBezierObject	*p_BezierObject,
							MTH3D_tdstVector*	p_stStartPoint,
							MTH3D_tdstVector*	p_stEndPoint,
							MTH3D_tdstVector*	p_stStartVector,
							MTH3D_tdstVector*	p_stEndVector)
{
	if (p_BezierObject==0) return; /* avoid crash */
	/* copies input parameters into objects parameters */
	
	if (p_stStartPoint!=0)	p_BezierObject->stStartPoint	=*p_stStartPoint;
	if (p_stEndPoint!=0)	p_BezierObject->stEndPoint		=*p_stEndPoint;
	if (p_stStartVector!=0)	p_BezierObject->stStartVector	=*p_stStartVector;
	if (p_stEndVector!=0)	p_BezierObject->stEndVector		=*p_stEndVector;
	fn_vBezierObject_Calculate(p_BezierObject);
}



/*==========================================================
Function name:	fn_xBezierObject_GetSpeed
Description:	returns the speed at a given sample (n° of the point) of a bezier object
Input:			p_stDynaParam:	pointer to a pre-created tdstDynaParam structure
				ucSampleNo:		n° of the point to get the speed from.
Output:			return value is the speed.
Author:			Yann Le Tensorer
Date:			03 february 1997
Revision:
==========================================================*/
MTH_tdxReal fn_xBezierObject_GetSpeed(tdstBezierObject	*p_BezierObject,unsigned char ucSampleNo)
{
	if (p_BezierObject==0) return 0;

	return fn_xDynamicObject_GetSpeed(p_BezierObject->p_stDynaParams,ucSampleNo);
}

/*==========================================================
Function name:	fn_vBezierObject_GetPoint
Description:	returns the coordinates in the global repère of the point at a 
				given sample (n° of the point) of a bezier object.
Input:			p_stDynaParam:	pointer to a pre-created tdstDynaParam structure
				ucSampleNo:		n° of the point to get the coordinates from.
				p_ReturnVector: pointer to a vector to be returned.
Output:			*p_ReturnVector is a vector countaining the.coordinates of the point.
Author:			Yann Le Tensorer
Date:			03 february 1997
Revision:
==========================================================*/
void fn_vBezierObject_GetPoint(tdstBezierObject	*p_BezierObject,unsigned char ucSampleNo,MTH3D_tdstVector* p_ReturnVector)
{
	MTH3D_tdstVector	*p_stPointList;

	if (p_BezierObject==0) return; 

	if (p_BezierObject->ucObjectMode==C_ucModeRealObject)
		p_stPointList=((p_BezierObject->hObject) -> d_stListOfPoints);
	else
		p_stPointList=(p_BezierObject->d_stListOfPoints);

	if (p_stPointList!=0)
		*p_ReturnVector=p_stPointList[ucSampleNo];

}

/*==========================================================
Function name:	fn_vBezierObject_GetParams
Description:	Gets the parameters of a bezier objet
Input:			p_BezierObject:	Pointer to a pre-created bezier object
				p_stStartPoint: Pointer to the start point 
				p_stEndPoint:	Pointer to the end Point	
				p_stStartVector:Pointer to the start vector	
				p_stEndVector:	Pointer to the end vector
Output:			*p_stStartPoint:start point 
				*p_stEndPoint:	end Point	
				*p_stStartVectorstart vector	
				*p_stEndVector:	end vector

Author:			Yann Le Tensorer
Date:			4 february 1997
Revision:

Notes:			If an input pointer is null, this parameter is simply not
				affected. 
==========================================================*/
void fn_vBezierObject_GetParams(tdstBezierObject	*p_BezierObject,
							MTH3D_tdstVector*	p_stStartPoint,
							MTH3D_tdstVector*	p_stEndPoint,
							MTH3D_tdstVector*	p_stStartVector,
							MTH3D_tdstVector*	p_stEndVector)
{
	if (p_BezierObject==0) return; /* avoid crash */
	
	if (p_stStartPoint!=0)	*p_stStartPoint	= p_BezierObject->stStartPoint;
	if (p_stEndPoint!=0)	*p_stEndPoint	= p_BezierObject->stEndPoint;
	if (p_stEndVector!=0)	*p_stEndVector	= p_BezierObject->stEndVector;
	if (p_stStartVector!=0) *p_stStartVector= p_BezierObject->stStartVector;

}

/*==========================================================
Function name:	fn_ucBezierObject_GetSamplingRate
Description:	Gets the sampling rate of a BezierObject objet
Input:			p_BezierObject:	Pointer to a pre-created Bezier object
Output:			return value is the sampling rate of the circle arc object
Author:			Yann Le Tensorer
Date:			5 february 1997
Revision:
==========================================================*/
unsigned char fn_ucBezierObject_GetSamplingRate(tdstBezierObject	*p_BezierObject)
							
{
	if (p_BezierObject==0) 
		return 0; 
	else
		return p_BezierObject->ucSamplingRate;
}


