/*======================================================================*/
/* 3DLib								*/
/*									*/
/* Splines header file							*/
/*									*/
/* AUTHOR:	Gabor Nagy						*/
/* DATE:	1996-Nov-23 23:58:38					*/
/*									*/
/* 3DLib(TM) Copyright (C) 1995 by Gabor Nagy. All rights reserved.	*/
/*======================================================================*/
#ifndef _E3DSpline_h
#define _E3DSpline_h


#ifndef _E3DModel_h
#include <E3D/Model.h>
#endif


#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
extern "C" {
#endif

#define	E3dCVALLOC_INCREMENT	4


// Edge flags
//
#define E3dEDGE_ACTIVE		0x0001		// Mouse pointer is on edge
#define E3dEDGE_SELECTED	0x0002		// Edge is selected


typedef struct
{
 unsigned int		Start, End;		// Index of starting and ending Vertex
 E3dGLCoordinate	GLStart[3], GLEnd[3];	// 3 floats for a coordinate
 unsigned int		Flags;			// Color of the edge in ARGB
} E3dEdge;

typedef struct
{
 unsigned int	NumOfVertices;
 unsigned int*	VertexIDs;
 E3dGLType*	GLVertices;		// It is NumOfVertices*3 floats for GL speedup
 unsigned long	RGBColor;		// Color of the edge in RGBA
 int		ColorIndex;		// Color index (number of palette entry) of the edge for colorindex mode
} E3dPolyLine;

#define E3dBEZ_DEFAULT	0

// Segment type
//
#define E3dBEZ_CURVE	1
#define E3dBEZ_LINEAR	2
#define E3dBEZ_ARC	3

// Constraint
//
// Geometric continuity: defined in terms of the directions of tangent vectors only 
//   G0: endpoints meet 
//   G1: direction of tangent vectors agree 
//
// Parametric continuity: defined in terms of direction and magnitude of tangent vectors 
//   C0: endpoints meet 
//   C1: tangent vectors (velocity) are equal 
//   C2: derivative of tangents (acceleration) are equal 
//
#define E3dBEZ_C0	1
#define E3dBEZ_C1	2
#define E3dBEZ_C2	3
#define E3dBEZ_G1	4
#define E3dBEZ_G2	5

enum
{
 E3dBEZ_PREVIOUS=1,
 E3dBEZ_POSITION,
 E3dBEZ_NEXT
};


#define E3dKEYF_TAGGED			1
#define E3dKEYF_PREV_ACTIVE		(1<<1)	// On a Bezier curve, the 'Previous' position is active (for moving etc.)
#define E3dKEYF_ACTIVE			(1<<2)
#define E3dKEYF_NEXT_ACTIVE		(1<<3)	// On a Bezier curve, the 'Next' position is active (for moving etc.)
#define E3dKEYF_SEGMENT_SELECTED	(1<<4)
#define E3dKEYF_ALL			0x1F


#define	_E3dSplineCVCore()\
 E3d3DPosition	Position;\
 int		NumOfDrawSteps;		/* Number of drawing steps (linear segments) for this segment	*/\
 E3dCoordinate	SegmentLength;\
 int		NumOfStepsForLength;	/* # of steps (linear segments) used for determining (approximating) the length of this segment	*/\
 E3dVector*	StepsForLength;		/* Linear segments used for determining (approximating) the length of this segment.	*/\
					/* The Vector's length component is the cumulative length at the end of a linear segment	*/\
 int		Flags\

typedef struct E3dSplineCV
{
 _E3dSplineCVCore();
} E3dSplineCV;


typedef struct E3dBezierCV
{
 _E3dSplineCVCore();

 E3d3DPosition	Previous;
 E3d3DPosition	Next;
 int		Constraint;
 int		Segment;	// Segment type
} E3dBezierCV;



// This structure is used for taking "snapshots" of SplineCVs for interactive
// transforming and for Undo/Redo of transforming and deleting SplineCVs
//
typedef struct
{
 E3d3DPosition	Position;
 unsigned int	Flags;
 unsigned int	Index;		// Index in the original array
} E3dSnapshotSplineCV;


// This structure is used for taking "snapshots" of BezierCVs for interactive
// transforming and for Undo/Redo of transforming and deleting BezierCVs
//
typedef struct
{
 E3d3DPosition	Position;
 E3d3DPosition	Previous;
 E3d3DPosition	Next;
 unsigned int	Flags;
 unsigned int	Index;		// Index in the original array
} E3dSnapshotBezierCV;


enum
{
 E3dSPL_NONE=0,
 E3dSPL_LINEAR,
 E3dSPL_BEZIER,
 E3dSPL_BSPLINE,
 E3dSPL_NURBS,
 E3dSPL_CARDINAL
};




typedef struct
{
// E3dGeometry part
//
 E3dGeometryCore();


// E3dSpline part
//
 int			SplineType;		// Type of the curve
 unsigned int		NumOfCVs;		// Number of CVs in the array

 void*			CVs;			// A.k.a: CVs

 E3dCoordinate		Length;			// Total length of the spline
 int			NumOfDrawSteps;		// Number of linear segments between 2 keys, for drawing the Spline.

 int			NumOfStepsForLength;	// # of steps (linear segments) used for determining (approximating) the length of segments

 unsigned int		NumOfLinSegments;	// Linearized form for drawing
#ifdef USEOpenGL
 E3dGLCoordinate*	GLLinSegments;		// For fast display...
#endif // USEOpenGL


 int			Phantom;		// Automatic phantom key (extremity) (CARDINAL, B-SPLINE)
 float			Tension;		// Tension of the curve (CARDINAL)
 int			Constraint;		// Default key constraint (BEZIER)
 int			Segment;		// Default segment for key (BEZIER)


 EBool			UniformSteps;		// Use Steps field of Spline for all segments
 EBool			Closed;			// Curve is closed (wrap-around)
} E3dSpline;





// Coordinate modes for E3dVectorInfo
//
enum
{
 E3dVTM_P1_P2=0,
 E3dVTM_P1_LENGTH
};


typedef struct
{
// E3dGeometryInfo part
//
 E3dGeometryClass*	Class;

// E3dVectorInfo part
//
 E3dVector		Vector;
 E3d3DPosition		Position;
 char			CoordinateMode;
 EBool			ArrowOn;
} E3dVectorInfo;


#define E3dM_InitSplineCV(mSplineCV)\
    mSplineCV->NumOfDrawSteps=4;\
    mSplineCV->SegmentLength=-1.0;\
    mSplineCV->NumOfStepsForLength=0;\
    mSplineCV->StepsForLength=NULL;\
    mSplineCV->Flags=0


#define E3dM_InitBezierCV(mBezierCV)\
 mBezierCV->NumOfDrawSteps=4;\
 mBezierCV->SegmentLength=-1.0;\
 mBezierCV->NumOfStepsForLength=0;\
 mBezierCV->StepsForLength=NULL;\
 mBezierCV->Flags=0;\
 mBezierCV->Constraint=E3dBEZ_C1;\
 mBezierCV->Segment=E3dBEZ_CURVE



/*------------------------------------------------------*/
/* Function prototypes					*/
/*------------------------------------------------------*/
extern void		E3d_SplineInvert(E3dSpline* LSpline);
extern int		E3d_SplineNumOfTaggedCVs(E3dSpline* LSpline);

extern void		E3d_SplineCVDefault(int LSplineType, void* LCV);
extern void*		E3d_SplineCVsAllocate(int LSplineType, unsigned int LNumOfCVs);
extern void*		E3d_SplineAddCV(E3dSpline* LSpline);

extern void		E3d_SplineFreeCVs(E3dSpline* LSpline);


extern EBool		E3d_SplineGetBoundingBox(E3dSpline* LSpline, E3d3DPosition* LBBMin, E3d3DPosition* LBBMax, unsigned int LWhatToInclude);
extern EBool		E3d_SplineGetTransformedBoundingBox(E3dSpline* LSpline, E3dMatrix LMatrix, E3d3DPosition* LBBMin, E3d3DPosition* LBBMax, unsigned int LWhatToInclude);
extern EBool		E3d_SplineGetPerspectiveProjectedBoundingBox(E3dSpline* LSpline, E3dMatrix LMatrix, E3d2DPosition* LBBMin, E3d2DPosition* LBBMax, E3dHPosition* LMaxProjectedXYAbsValPoint, unsigned int LWhatToInclude);

extern E3dEdge*		E3d_EdgesAllocate(unsigned int LEdgeNum);
extern E3dPolyLine*	E3d_PolyLinesAllocate(unsigned int LPolyLineNum);
extern void		E3d_PolyLineAllocateVertices(E3dPolyLine* LIPolyLine, unsigned int LVertexNum, int LFlags);
extern void		E3d_PolyLineFreeVertices(E3dPolyLine* LPolyLine);

extern E3dSpline*	E3d_SplineAllocate(int LType);
extern void		E3d_SplineFree(E3dSpline* LSpline);

extern E3dSpline*	E3d_SplineClone(E3dSpline* LSpline);

extern EBool		E3d_SplineCreateLinearSegments(E3dSpline* LSpline);
extern void		E3d_SplineFreeRenderData(E3dSpline* LSpline);

extern E3dCoordinate	E3d_SplineUpdateSegmentLengths(E3dSpline* LSpline, unsigned int LSteps);
extern int		E3d_SplineGet3DPosition(E3dSpline* LSpline, double LTime, E3d3DPosition* L3DPosition);

extern void		E3d_SplineUnselect(E3dSpline* LSpline, int LFlags);

extern void		E3d_SplineTransform(E3dSpline* LSpline, E3dMatrix LMatrix);

extern void		E3d_CreateVectorArrow(register E3dSplineCV* LCV, double LX2, double LY2, double LZ2);
extern E3dModel*	E3d_VectorTest(double LX1, double LY1, double LZ1, double LX2, double LY2, double LZ2, EBool LCreateArrow);






/*------------------------------------------------------*/
/* Macros						*/
/*------------------------------------------------------*/
#define E3dM_CurvePrecision(p)	LStepsF=(float)(p), LStepsF2=LStepsF*LStepsF, LStepsF3=LStepsF*LStepsF*LStepsF,\
				LPrecMatrix[M00]=6.0/LStepsF3, LPrecMatrix[M01]=0.0, LPrecMatrix[M02]=0.0, LPrecMatrix[M03]=0.0,\
				LPrecMatrix[M10]=6.0/LStepsF3, LPrecMatrix[M11]=2.0/LStepsF2, LPrecMatrix[M12]=0.0, LPrecMatrix[M13]=0.0,\
				LPrecMatrix[M20]=1.0/LStepsF3, LPrecMatrix[M21]=1.0/LStepsF2, LPrecMatrix[M22]=1.0/LStepsF, LPrecMatrix[M23]=0.0,\
				LPrecMatrix[M30]=0.0, LPrecMatrix[M31]=0.0, LPrecMatrix[M32]=0.0, LPrecMatrix[M33]=1.0

#define E3dM_CurveBasis(b, k0, k1, k2, k3)	LGMatrix[M00]=(k0).X, LGMatrix[M01]=(k0).Y, LGMatrix[M02]=(k0).Z, LGMatrix[M03]=1.0,\
					LGMatrix[M10]=(k1).X, LGMatrix[M11]=(k1).Y, LGMatrix[M12]=(k1).Z, LGMatrix[M13]=1.0,\
					LGMatrix[M20]=(k2).X, LGMatrix[M21]=(k2).Y, LGMatrix[M22]=(k2).Z, LGMatrix[M23]=1.0,\
					LGMatrix[M30]=(k3).X, LGMatrix[M31]=(k3).Y, LGMatrix[M32]=(k3).Z, LGMatrix[M33]=1.0,\
					E3d_MatrixMult(b, LGMatrix),\
					E3d_MatrixMult(LPrecMatrix, LGMatrix)




#if defined (__cplusplus) && (!(defined (__CPLUSLIBS)))
}	// Close scope of 'extern "C"' declaration which encloses file.
#endif

#endif	// _E3DSpline_h
