/******************************************************************************
* Cagd_loc.h - header file for the CAGD library.			      *
* This header is local to the library - it is NOT external.		      *
*******************************************************************************
* Written by Gershon Elber, Mar. 90.					      *
******************************************************************************/

#ifndef CAGD_LOC_H
#define CAGD_LOC_H

#include <math.h>

typedef enum TokenNumType {/* Tokens are returned by _CagdGetToken routines. */
    TOKEN_EOF,
    TOKEN_OPEN_PAREN,
    TOKEN_CLOSE_PAREN,
    TOKEN_BEZIER,
    TOKEN_BSPLINE,
    TOKEN_POWER,
    TOKEN_CURVE,
    TOKEN_SURFACE,
    TOKEN_PTYPE,
    TOKEN_NUM_PTS,
    TOKEN_ORDER,
    TOKEN_KV,
    TOKEN_OTHER
} TokenNumType;

#define CAGD_GEN_COPY(Dst, Src, Size) memcpy((char *) (Dst), (char *) (Src), \
					     Size)
#define CAGD_GEN_COPY_STEP(Dst, Src, Size, DstStep, SrcStep, Type) \
			{ \
			    int ii; \
			    Type *DstType = (Type *) Dst, \
				 *SrcType = (Type *) Src; \
 \
			    for (ii = 0; ii < Size; ii++) { \
				*DstType = *SrcType; \
				DstType += DstStep; \
				SrcType += SrcStep; \
			    } \
			}


/******************************************************************************
* Some lists simplifying operators.					      *
******************************************************************************/
#define CAGD_LIST_PUSH(New, List)       { (New) -> Pnext = (List); \
					  (List) = (New); }
#define CAGD_LIST_POP(Head, List)	{ (Head) = (List); \
					  (List) = (List) -> Pnext; \
					  (Head) -> Pnext = NULL; }
#define CAGD_LIST_LAST(Elem)		{ if (Elem) \
					      while ((Elem) -> Pnext) \
						  (Elem) = (Elem) -> Pnext; }

/******************************************************************************
* Some points/ectors simplifying operators.				      *
******************************************************************************/
#define	CAGD_COPY_POINT(DstPt, SrcPt)	{ (DstPt) = (SrcPt); }
#define	CAGD_RESET_POINT(DstPt) 	{ (DstPt).Pt[0] = \
					  (DstPt).Pt[1] = \
					  (DstPt).Pt[2] = 0.0; }
#define	CAGD_ADD_POINT(DstPt, SrcPt)    { (DstPt).Pt[0] += (SrcPt).Pt[0]; \
					  (DstPt).Pt[1] += (SrcPt).Pt[1]; \
					  (DstPt).Pt[2] += (SrcPt).Pt[2]; }
#define	CAGD_SUB_POINT(DstPt, SrcPt)    { (DstPt).Pt[0] -= (SrcPt).Pt[0]; \
					  (DstPt).Pt[1] -= (SrcPt).Pt[1]; \
					  (DstPt).Pt[2] -= (SrcPt).Pt[2]; }
#define	CAGD_MULT_POINT(DstPt, Scaler)  { (DstPt).Pt[0] *= (Scaler); \
					  (DstPt).Pt[1] *= (Scaler); \
					  (DstPt).Pt[2] *= (Scaler); }

#define	CAGD_COPY_VECTOR(DstVec, SrcVec) { (DstVec) = (SrcVec); }
#define	CAGD_RESET_VECTOR(DstVec) 	{ (DstVec).Vec[0] = \
					  (DstVec).Vec[1] = \
					  (DstVec).Vec[2] = 0.0; }
#define	CAGD_ADD_VECTOR(DstVec, SrcVec) { (DstVec).Vec[0] += (SrcVec).Vec[0]; \
					  (DstVec).Vec[1] += (SrcVec).Vec[1]; \
					  (DstVec).Vec[2] += (SrcVec).Vec[2]; }
#define	CAGD_SUB_VECTOR(DstVec, SrcVec) { (DstVec).Vec[0] -= (SrcVec).Vec[0]; \
					  (DstVec).Vec[1] -= (SrcVec).Vec[1]; \
					  (DstVec).Vec[2] -= (SrcVec).Vec[2]; }
#define	CAGD_MULT_VECTOR(DstVec, Scaler){ (DstVec).Vec[0] *= (Scaler); \
					  (DstVec).Vec[1] *= (Scaler); \
					  (DstVec).Vec[2] *= (Scaler); }
#define	CAGD_DIV_VECTOR(DstVec, Scaler) { (DstVec).Vec[0] /= (Scaler); \
					  (DstVec).Vec[1] /= (Scaler); \
					  (DstVec).Vec[2] /= (Scaler); }
#define CAGD_LEN_VECTOR(V)		sqrt(SQR((V).Vec[0]) + \
					     SQR((V).Vec[1]) + \
					     SQR((V).Vec[2]))
#define CAGD_NORMALIZE_VECTOR(V)	{ CagdRType __t = CAGD_LEN_VECTOR(V); \
					  if (!APX_EQ(__t, 0.0)) \
					      CAGD_DIV_VECTOR((V), __t); }


#define	CAGD_COPY_UVVAL(DstUV, SrcUV) { (DstUV) = (SrcUV); }
#define	CAGD_RESET_UVVAL(DstUV) 	{ (DstUV).UV[0] = \
					  (DstUV).UV[1] = 0.0; }

/******************************************************************************
* A fast macro to blend the original control polygon with the Alpha matrix.   *
******************************************************************************/
#define CAGD_ALPHA_BLEND( A, Index, OrigPts, Pt ) \
    { \
	if (A -> ColLength[Index] == 1) \
	    *Pt = OrigPts[A -> ColIndex[Index]]; \
	else { \
	    int Tmp; \
 \
	    *Pt = 0.0; \
	    for (Tmp = A -> ColLength[Index] - 1; Tmp >= 0; Tmp--) { \
		int Idx = A -> ColIndex[Index] + Tmp; \
 \
		*Pt += OrigPts[Idx] * A -> Rows[Idx][Index]; \
	    } \
	} \
    }

/* Same as CAGD_ALPHA_BLEND but Allow step for OrigPts. */
#define CAGD_ALPHA_BLEND_STEP( A, Index, OrigPts, Pt, OrigPtsStep ) \
    { \
	if (A -> ColLength[Index] == 1) \
	    *Pt = OrigPts[A -> ColIndex[Index] * OrigPtsStep]; \
	else { \
	    int Tmp; \
 \
	    *Pt = 0.0; \
	    for (Tmp = A -> ColLength[Index] - 1; Tmp >= 0; Tmp--) { \
		int Idx = A -> ColIndex[Index] + Tmp; \
 \
		*Pt += OrigPts[Idx * OrigPtsStep] * A -> Rows[Idx][Index]; \
	    } \
	} \
    }

/******************************************************************************
* This macro is called when the library has detected an unrecoverable error.  *
* Default action is to call CagdFatalError, but you may want to reroute this  *
* to invoke your handler and recover yourself (by long jump for example).     *
******************************************************************************/
#define FATAL_ERROR(Msg)	CagdFatalError(Msg)

#define INFINITY 1e6

#define W 0	 /* Positions of points in Points array (see structs below). */
#define X 1
#define Y 2
#define Z 3

#include "cagd_lib.h"		     /* Include the extrenal header as well. */

#ifdef DOUBLE
#define CAGD_FLOAT_READ "%lf"
#else
#define CAGD_FLOAT_READ "%f"
#endif /* DOUBLE */

/* Declaration of extrenal variables local to the cagd library only. */
extern int _CagdGlblLineCount;	     /* Used to locate errors in input file. */
extern CagdLin2PolyType _CagdLin2Poly;    /* Linear srf convertion to polys. */

/* Declarations of functions local to the Cagd library only. */
char *_CagdGetCurveAttributes(FILE *f);
char *_CagdGetSurfaceAttributes(FILE *f);
void _CagdUnGetToken(char *StringToken);
TokenNumType _CagdGetToken(FILE *f, char *StringToken);
char *_CagdReal2Str(CagdRType R);
CagdPolygonStruct *_CagdMakePolygon(CagdBType ComputeNormals,
				    CagdBType ComputeUV,
			            CagdPtStruct *Pt1,
				    CagdPtStruct *Pt2,
				    CagdPtStruct *Pt3,
				    CagdVecStruct *Nl1,
				    CagdVecStruct *Nl2,
			            CagdVecStruct *Nl3,
				    CagdUVStruct *UV1,
				    CagdUVStruct *UV2,
			            CagdUVStruct *UV3);

#ifdef USE_VARARGS
void _CagdFprintf(FILE *f, int Indent, char *va_alist, ...);
#else
void _CagdFprintf(FILE *f, int Indent, char *Format, ...);
#endif /* USE_VARARGS */

#endif /* CAGD_LOC_H */
