/*****************************************************************************
*   "Irit" - the 3d polygonal solid modeller.				     *
*									     *
* Written by:  Gershon Elber				Ver 0.1, Jan. 1992   *
******************************************************************************
* (C) Gershon Elber, Technion, Israel Institute of Technology                *
******************************************************************************
* Main definition Header file  for Irit - the 3d polygonal solid modeller.   *
*****************************************************************************/

#ifndef	IRIT_SM_H
#define	IRIT_SM_H

/* Note program version should also be updated in *.c modules, in few        */
/* places, as some system can not chain strings in the pre-processor level.  */
#define  IRIT_VERSION	"Version 9.0"			 /* Program version. */
#define  IRIT_COPYRIGHT	"(C) Copyright 1989-2004 Gershon Elber"

#include <math.h>
#include <stdio.h>
#include <string.h>

#ifndef	NULL
#define	NULL	0
#endif /* NULL */

#ifndef	TRUE
#define	TRUE	1
#define	FALSE	0
#endif /* TRUE */

#ifdef VoidPtr
#undef VoidPtr
#endif /* VoidPtr */

#ifdef NO_VOID_PTR
#define VoidPtr		char *
#else
#define VoidPtr		void *
#endif /* NO_VOID_PTR */

#if !defined(IRIT_FLOAT) && !defined(IRIT_DOUBLE)
#if defined(__MSDOS__) || defined(MAKE_REAL_IRIT_FLOAT)
#define IRIT_FLOAT
typedef float           RealType;           /* On IBMPC to reserve memory... */
#else
#define IRIT_DOUBLE
typedef double          RealType;
#endif /* __MSDOS__ || MAKE_REAL_IRIT_FLOAT */
#endif /* !IRIT_FLOAT && !IRIT_DOUBLE */

#ifdef DEBUG_IRIT_MALLOC
#define DEBUG_IP_MALLOC
#define DEBUG_ATTR_MALLOC
#endif /* DEBUG_IRIT_MALLOC */

typedef	unsigned char	ByteType;

typedef	RealType	PointType[3];	/* For X, Y, Z coordinates of point. */
typedef RealType	VectorType[3]; /* For X, Y, Z coordinates of vector. */
typedef RealType	LineType[3];	      /* A, B, C in Ax + By + C = 0. */
typedef RealType	NormalType[3];	    /* Unit normalized normal coeff. */
typedef RealType	PlaneType[4];		    /* Plane equation coeff. */
typedef RealType	MatrixType[4][4];	   /* Homogeneous transform. */
typedef PointType	BBoxType[2];	      /* Axis parallel bounding box. */

#define IRIT_EPS	1e-5
#define IRIT_INFNTY	2.3197171528332553e+25

#ifndef M_PI
#define M_PI	3.14159265358979323846
#endif /* M_PI */

#ifndef M_SQRT2
#define M_SQRT2 1.41421356237309504880
#endif /* M_SQRT2 */

#define LINE_LEN_VLONG	1024		   /* Lines read from stdin/files... */
#define LINE_LEN_LONG	256		   /* Lines read from stdin/files... */
#define LINE_LEN	81		   /* Lines read from stdin/files... */
#define LINE_LEN_SHORT	31		   /* Lines read from stdin/files... */
#define OBJ_NAME_LEN	31				/* Names of objects. */
#define PATH_NAME_LEN	80		              /* Name with full Path */

/* Follows by general purpose helpfull macros: */
#ifndef MIN
#define MIN(x, y)		((x) > (y) ? (y) : (x))
#endif /* MIN */
#ifndef MAX
#define MAX(x, y)		((x) > (y) ? (x) : (y))
#endif /* MAX */
#define BOUND(x, Min, Max)	(MAX(MIN((x), Max), Min))

#define ABS(x)			((x) > 0 ? (x) : (-(x)))
#define SQR(x)			((x) * (x))
#define CUBE(x)			((x) * (x) * (x))
#define SIGN(x)			((x) > 0 ? 1 : ((x) < 0 ? -1 : 0))

#define SWAP(type, x, y)	{ type temp = (x); x = (y); y = temp; }

#define REAL_TO_INT(R)		((int) ((R) > 0.0 ? (R) + 0.5 : (R) - 0.5))
#define REAL_PTR_TO_INT(R)	REAL_TO_INT(*(R))

#define GEN_COPY(Dest, Src, Size) memcpy((char *) (Dest), (char *) (Src), Size)
#define GEN_CMP(Dest, Src, Size)  memcmp((char *) (Dest), (char *) (Src), Size)
#define ZAP_MEM(Dest, Size)	  memset((char *) (Dest), 0, Size);

#ifdef IRIT_QUIET_STRINGS
#    define IRIT_EXP_STR(Str)		""
#    define IRIT_FATAL_ERROR(Str)	exit(-1)
#    define IRIT_WARNING_MSG(Str)	
#    define _IRIT_PT_NORMALIZE_MSG_ZERO(Size)
#else
#    define IRIT_EXP_STR(Str)		Str
#    define IRIT_FATAL_ERROR(Str)	IritFatalError(Str)
#    define IRIT_WARNING_MSG(Str)	IritWarningError(Str)
#    define _IRIT_PT_NORMALIZE_MSG_ZERO(Size) \
	if (Size < PT_NORMALIZE_ZERO) { \
	    IritWarningError("Attempt to normalize a zero length vector\n"); \
	} \
        else
#    define CAGD_LARGE_BEZIER_CACHE
#endif /* IRIT_QUIET_STRINGS */

#define APX_EQ(x, y)		(fabs((x) - (y)) < IRIT_EPS)
#define APX_EQ_EPS(x, y, EPS)	(fabs((x) - (y)) < EPS)
#define PT_APX_EQ(Pt1, Pt2)	(APX_EQ((Pt1)[0], (Pt2)[0]) && \
				 APX_EQ((Pt1)[1], (Pt2)[1]) && \
				 APX_EQ((Pt1)[2], (Pt2)[2]))
#define PT_APX_EQ_E2(Pt1, Pt2)	(APX_EQ((Pt1)[0], (Pt2)[0]) && \
				 APX_EQ((Pt1)[1], (Pt2)[1]))
#define PT_APX_EQ_EPS(Pt1, Pt2, EPS) \
				(APX_EQ_EPS((Pt1)[0], (Pt2)[0], EPS) && \
				 APX_EQ_EPS((Pt1)[1], (Pt2)[1], EPS) && \
				 APX_EQ_EPS((Pt1)[2], (Pt2)[2], EPS))
#define PT_APX_EQ_E2_EPS(Pt1, Pt2, EPS) \
				(APX_EQ_EPS((Pt1)[0], (Pt2)[0], EPS) && \
				 APX_EQ_EPS((Pt1)[1], (Pt2)[1], EPS))
#define PLANE_APX_EQ(Pl1, Pl2)	(APX_EQ((Pl1)[0], (Pl2)[0]) && \
				 APX_EQ((Pl1)[1], (Pl2)[1]) && \
				 APX_EQ((Pl1)[2], (Pl2)[2]) && \
				 APX_EQ((Pl1)[3], (Pl2)[3]))
#define PLANE_APX_EQ_EPS(Pl1, Pl2, EPS) (APX_EQ_EPS((Pl1)[0], (Pl2)[0], EPS) && \
					 APX_EQ_EPS((Pl1)[1], (Pl2)[1], EPS) && \
					 APX_EQ_EPS((Pl1)[2], (Pl2)[2], EPS) && \
					 APX_EQ_EPS((Pl1)[3], (Pl2)[3], EPS))
#define PT_APX_EQ_ZERO_EPS(Pt, EPS) \
				(APX_EQ_EPS((Pt)[0], 0.0, EPS) && \
				 APX_EQ_EPS((Pt)[1], 0.0, EPS) && \
				 APX_EQ_EPS((Pt)[2], 0.0, EPS))
#define PT_EQ_ZERO(Pt)    ((Pt)[0] == 0.0 && (Pt)[1] == 0.0 && (Pt)[2] == 0.0)

#ifdef IRIT_DOUBLE
#define IRIT_UEPS		1e-14
#else
#define IRIT_UEPS		1e-6
#endif /* IRIT_DOUBLE */
#define IRIT_APX_EQ(x, y)		(fabs((x) - (y)) < IRIT_UEPS)
#define IRIT_PT_APX_EQ(Pt1, Pt2)	(IRIT_APX_EQ((Pt1)[0], (Pt2)[0]) && \
					 IRIT_APX_EQ((Pt1)[1], (Pt2)[1]) && \
					 IRIT_APX_EQ((Pt1)[2], (Pt2)[2]))


#define PT_SCALE(Pt, Scalar)	{ (Pt)[0] *= Scalar; \
				  (Pt)[1] *= Scalar; \
				  (Pt)[2] *= Scalar; \
			        }
#define PLANE_SCALE(Pl, Scalar)	{ (Pl)[0] *= Scalar; \
				  (Pl)[1] *= Scalar; \
				  (Pl)[2] *= Scalar; \
				  (Pl)[3] *= Scalar; \
			        }

#define PT_SCALE2(Res, Pt, Scalar) \
				{ (Res)[0] = (Pt)[0] * Scalar; \
				  (Res)[1] = (Pt)[1] * Scalar; \
				  (Res)[2] = (Pt)[2] * Scalar; \
			        }

/* The memcpy is sometimes defined to get (char *) pointers and sometimes    */
/* (void *) pointers. To be compatible with both it is coerced to (char *).  */
#define PT_COPY(PtDest, PtSrc)	  memcpy((char *) (PtDest), (char *) (PtSrc), \
							3 * sizeof(RealType))
#define PLANE_COPY(PlDest, PlSrc) memcpy((char *) (PlDest), (char *) (PlSrc), \
							4 * sizeof(RealType))
#define MAT_COPY(Dest, Src)	  memcpy((char *) (Dest), (char *) (Src), \
							16 * sizeof(RealType))

#define PT_SQR_LENGTH(Pt)      (SQR((Pt)[0]) + SQR((Pt)[1]) + SQR((Pt)[2]))
#define PT_LENGTH(Pt)	       sqrt(PT_SQR_LENGTH(Pt))

#define PT_RESET(Pt)	       ZAP_MEM((Pt), 3 * sizeof(RealType))
#define PLANE_RESET(Pl)        ZAP_MEM((Pl), 4 * sizeof(RealType))

#define PT_NORMALIZE_ZERO	1e-30

#define PT_NORMALIZE(Pt)	{ \
				     RealType Size = PT_LENGTH((Pt)); \
				     _IRIT_PT_NORMALIZE_MSG_ZERO(Size) \
				     { \
					 Size = 1.0 / Size; \
				         PT_SCALE(Pt, Size); \
				     } \
				}
#define PT_SAFE_NORMALIZE(Pt)	{ \
				     RealType Size = PT_LENGTH((Pt)); \
				     if (Size > PT_NORMALIZE_ZERO) { \
					 Size = 1.0 / Size; \
				         PT_SCALE(Pt, Size); \
				     } \
				}
#define PT_CLEAN_NORMALIZE(Pt)	{ \
				     if (fabs(Pt[0]) < IRIT_UEPS) Pt[0] = 0; \
				     if (fabs(Pt[1]) < IRIT_UEPS) Pt[1] = 0; \
				     if (fabs(Pt[2]) < IRIT_UEPS) Pt[2] = 0; \
				}
#define PT_NORMALIZE_FLOAT(Pt)	{ \
				     float Size = (float) PT_LENGTH((Pt)); \
				     _IRIT_PT_NORMALIZE_MSG_ZERO(Size) \
				     { \
					 Size = 1.0F / Size; \
				         PT_SCALE(Pt, Size); \
				     } \
				}


#define	PT_SET(Pt, Pt1, Pt2, Pt3) \
				{ (Pt)[0] = (Pt1); \
				  (Pt)[1] = (Pt2); \
				  (Pt)[2] = (Pt3); \
			        }

#define PT_BLEND(Res, Pt1, Pt2, t) \
			{ (Res)[0] = (Pt1)[0] * t + (Pt2)[0] * (1 - t); \
			  (Res)[1] = (Pt1)[1] * t + (Pt2)[1] * (1 - t); \
			  (Res)[2] = (Pt1)[2] * t + (Pt2)[2] * (1 - t); \
			}

#define PT_BLEND_BARYCENTRIC(Res, Pt1, Pt2, Pt3, W) { \
	Res[0] = Pt1[0] * W[0] + Pt2[0] * W[1] + Pt3[0] * W[2]; \
	Res[1] = Pt1[1] * W[0] + Pt2[1] * W[1] + Pt3[1] * W[2]; \
	Res[2] = Pt1[2] * W[0] + Pt2[2] * W[1] + Pt3[2] * W[2]; } \

#define PT_ADD(Res, Pt1, Pt2)	{ (Res)[0] = (Pt1)[0] + (Pt2)[0]; \
				  (Res)[1] = (Pt1)[1] + (Pt2)[1]; \
				  (Res)[2] = (Pt1)[2] + (Pt2)[2]; \
			        }

#define PT_SUB(Res, Pt1, Pt2)	{ (Res)[0] = (Pt1)[0] - (Pt2)[0]; \
				  (Res)[1] = (Pt1)[1] - (Pt2)[1]; \
				  (Res)[2] = (Pt1)[2] - (Pt2)[2]; \
				}

#define PT_SWAP(Pt1, Pt2)	{ SWAP(RealType, (Pt1)[0], (Pt2)[0]); \
				  SWAP(RealType, (Pt1)[1], (Pt2)[1]); \
				  SWAP(RealType, (Pt1)[2], (Pt2)[2]); \
				}

#define PT_PT_DIST(Pt1, Pt2)    sqrt(SQR((Pt1)[0] - (Pt2)[0]) + \
				     SQR((Pt1)[1] - (Pt2)[1]) + \
				     SQR((Pt1)[2] - (Pt2)[2]))

#define PT_PT_DIST_SQR(Pt1, Pt2) (SQR((Pt1)[0] - (Pt2)[0]) + \
				  SQR((Pt1)[1] - (Pt2)[1]) + \
				  SQR((Pt1)[2] - (Pt2)[2]))

/* Now the same thing but for 2D points. */

#define PT2D_SCALE(Pt, Scalar)	{ (Pt)[0] *= Scalar; \
				  (Pt)[1] *= Scalar; \
			        }
#define PT2D_COPY(PtDest, PtSrc) memcpy((char *) (PtDest), (char *) (PtSrc), \
							2 * sizeof(RealType))

#define PT2D_SQR_LENGTH(Pt)     (SQR((Pt)[0]) + SQR((Pt)[1]))
#define PT2D_LENGTH(Pt)	        sqrt(PT2D_SQR_LENGTH(Pt))

#define PT2D_RESET(Pt)	        ZAP_MEM((Pt), 2 * sizeof(RealType))

#define PT2D_NORMALIZE(Pt)	{ \
				     RealType Size = PT2D_LENGTH((Pt)); \
				     _IRIT_PT_NORMALIZE_MSG_ZERO(Size) \
				     { \
					 Size = 1.0 / Size; \
				         PT2D_SCALE(Pt, Size); \
				     } \
				}
#define PT2D_SAFE_NORMALIZE(Pt)	{ \
				     RealType Size = PT2D_LENGTH((Pt)); \
				     if (Size > PT_NORMALIZE_ZERO) { \
					 Size = 1.0 / Size; \
				         PT2D_SCALE(Pt, Size); \
				     } \
				}
#define PT2D_NORMALIZE_FLOAT(Pt)	{ \
				     float Size = (float) PT2D_LENGTH((Pt)); \
				     _IRIT_PT_NORMALIZE_MSG_ZERO(Size) \
				     { \
					 Size = 1.0F / Size; \
				         PT2D_SCALE(Pt, Size); \
				     } \
				}

#define	PT2D_SET(Pt, Pt1, Pt2, Pt3) \
				{ (Pt)[0] = (Pt1); \
				  (Pt)[1] = (Pt2); \
			        }

#define PT2D_BLEND(Res, Pt1, Pt2, t) \
			{ (Res)[0] = (Pt1)[0] * t + (Pt2)[0] * (1 - t); \
			  (Res)[1] = (Pt1)[1] * t + (Pt2)[1] * (1 - t); \
			}

#define PT2D_ADD(Res, Pt1, Pt2)	{ (Res)[0] = (Pt1)[0] + (Pt2)[0]; \
				  (Res)[1] = (Pt1)[1] + (Pt2)[1]; \
			        }

#define PT2D_SUB(Res, Pt1, Pt2)	{ (Res)[0] = (Pt1)[0] - (Pt2)[0]; \
				  (Res)[1] = (Pt1)[1] - (Pt2)[1]; \
				}

#define PT2D_SWAP(Pt1, Pt2)	{ SWAP(RealType, (Pt1)[0], (Pt2)[0]); \
				  SWAP(RealType, (Pt1)[1], (Pt2)[1]); \
				}

#define PT2D_PT2D_DIST(Pt1, Pt2)  sqrt(SQR((Pt1)[0] - (Pt2)[0]) + \
				       SQR((Pt1)[1] - (Pt2)[1]))

#define PT2D_PT2D_DIST_SQR(Pt1, Pt2) (SQR((Pt1)[0] - (Pt2)[0]) + \
				      SQR((Pt1)[1] - (Pt2)[1]))


#define VEC_COPY(VDest, VSrc)      PT_COPY(VDest, VSrc)
#define VEC_SCALE(V, Scalar)       PT_SCALE(V, Scalar)
#define VEC_SCALE2(Res, V, Scalar) PT_SCALE2(Res, V, Scalar)
#define VEC_SQR_LENGTH(V)	   PT_SQR_LENGTH(V)
#define VEC_LENGTH(V)              PT_LENGTH(V)
#define VEC_RESET(V)               PT_RESET(V)
#define VEC_NORMALIZE(V)	   PT_NORMALIZE(V)
#define VEC_SAFE_NORMALIZE(V)	   PT_SAFE_NORMALIZE(V)
#define	VEC_SET(V, V1, V2, V3)     PT_SET(V, V1, V2, V3)
#define VEC_BLEND(VRes, V1, V2, t) PT_BLEND(VRes, V1, V2, t)
#define VEC_ADD(VRes, V1, V2)	   PT_ADD(VRes, V1, V2)
#define VEC_SUB(VRes, V1, V2)	   PT_SUB(VRes, V1, V2)
#define VEC_SWAP(V1, V2)	   PT_SWAP(V1, V2)

/* Now the same thing but for 2D vectors. */

#define VEC2D_COPY(VDest, VSrc)      PT2D_COPY(VDest, VSrc)
#define VEC2D_SCALE(V, Scalar)       PT2D_SCALE(V, Scalar)
#define VEC2D_SCALE2(Res, V, Scalar) PT2D_SCALE2(Res, V, Scalar)
#define VEC2D_SQR_LENGTH(V)	     PT2D_SQR_LENGTH(V)
#define VEC2D_LENGTH(V)              PT2D_LENGTH(V)
#define VEC2D_RESET(V)               PT2D_RESET(V)
#define VEC2D_NORMALIZE(V)	     PT2D_NORMALIZE(V)
#define VEC2D_SAFE_NORMALIZE(V)	     PT2D_SAFE_NORMALIZE(V)
#define	VEC2D_SET(V, V1, V2, V3)     PT2D_SET(V, V1, V2, V3)
#define VEC2D_BLEND(VRes, V1, V2, t) PT2D_BLEND(VRes, V1, V2, t)
#define VEC2D_ADD(VRes, V1, V2)	     PT2D_ADD(VRes, V1, V2)
#define VEC2D_SUB(VRes, V1, V2)	     PT2D_SUB(VRes, V1, V2)
#define VEC2D_SWAP(V1, V2)	     PT2D_SWAP(V1, V2)

#define UV_COPY(UVDst, UVSrc)      GEN_COPY(UVDst, UVSrc, 2 * sizeof(RealType))
#define UV_RESET(Uv)	           ZAP_MEM((Uv), 2 * sizeof(RealType))
#define UV_BLEND(UVRes, UV1, UV2, t) \
			{ (UVRes)[0] = (UV1)[0] * t + (UV2)[0] * (1 - t); \
			  (UVRes)[1] = (UV1)[1] * t + (UV2)[1] * (1 - t); \
			}

#define VEC_BLEND_BARYCENTRIC(Res, Pt1, Pt2, Pt3, W) \
			PT_BLEND_BARYCENTRIC(Res, Pt1, Pt2, Pt3, W)

#define DOT_PROD(Pt1, Pt2)	((Pt1)[0] * (Pt2)[0] + \
				 (Pt1)[1] * (Pt2)[1] + \
				 (Pt1)[2] * (Pt2)[2])

#define CROSS_PROD(PtRes, Pt1, Pt2) \
		{ (PtRes)[0] = (Pt1)[1] * (Pt2)[2] - (Pt1)[2] * (Pt2)[1]; \
		  (PtRes)[1] = (Pt1)[2] * (Pt2)[0] - (Pt1)[0] * (Pt2)[2]; \
		  (PtRes)[2] = (Pt1)[0] * (Pt2)[1] - (Pt1)[1] * (Pt2)[0]; }

#define DOT_PROD_2D(Pt1, Pt2)	((Pt1)[0] * (Pt2)[0] + (Pt1)[1] * (Pt2)[1])

#define CROSS_PROD_2D(Pt1, Pt2) ((Pt1)[0] * (Pt2)[1] - (Pt1)[1] * (Pt2)[0])

#define LIST_PUSH(New, List)       { (New) -> Pnext = (List); (List) = (New); }
#define LIST_POP(Head, List)	   { (Head) = (List); \
				     (List) = (List) -> Pnext; \
				     (Head) -> Pnext = NULL; }
#define LIST_LAST_ELEM(Elem)	   { if (Elem) \
					 while ((Elem) -> Pnext) \
					     (Elem) = (Elem) -> Pnext; }

#define DEG2RAD(Deg)		((Deg) * M_PI / 180.0)
#define RAD2DEG(Rad)		((Rad) * 180.0 / M_PI)

#if defined(__WINNT__) && defined(WINNT_LOCAL_THREAD_VARS)
#   define STATIC_DATA __declspec(thread) static
#   define GLOBAL_DATA __declspec(thread) 
#else
#   define STATIC_DATA static
#   define GLOBAL_DATA
#endif /* __WINNT__ */

#if defined(_AIX) || defined(sgi) || defined(SUN4) || defined(DJGCC) || defined(OS2GCC) || defined(__WINNT__) || defined(__WINCE__) || defined(AMIGA) || defined(_INCLUDE_HPUX_SOURCE) || defined(OSF1DEC) || defined(__FreeBSD__) || defined(__osf__) || defined(_AlphaLinux) || defined(LINUX386) || defined(__CYGWIN__)
#    include <stdlib.h>

#    if defined(OSF1DEC) || defined(sgi) || defined(SUN4) || defined(OS2GCC) || defined(__FreeBSD__)
#	ifdef OSF1DEC
#	   ifdef _XOPEN_SOURCE
#	       undef _XOPEN_SOURCE /* For usleep */
#	   endif /*  _XOPEN_SOURCE */
#	endif /* OSF1DEC */
#	include <unistd.h>
#    endif /* OSF1DEC || sgi || SUN4 || OS2GCC || FreeBSD */
#    ifdef __WINNT__
#	include <direct.h>
#	define mkdir(Dir, Permit)	mkdir(Dir)
#    endif /* __WINNT__ */
#else
    VoidPtr malloc(unsigned int Size);
    void free(VoidPtr p);
    char *getenv(char *Name);
    int atoi(char *str);
#endif /* _AIX || sgi || SUN4 || DJGCC || OS2GCC || __WINNT__ || __WINCE__ || AMIGA || _INCLUDE_HPUX_SOURCE || OSF1DEC || __FreeBSD__ || _AlphaLinux || LINUX386 ||__CYGWIN__ */

#ifdef SGI64  /* Machine with 64 bit longs */
#   define sizeof(x)	((unsigned int) sizeof(x))
#   define strlen(x)	((unsigned int) strlen(x))
#endif /* SGI64 */

#ifdef __WINCE__
#   define getenv(Str)	NULL
#   define putenv(Str)
#   define signal(x, y)
#   define getcwd(s, l)	strcpy(s, ".")
#   define chdir(s)
#   define system(s)	0
#   define popen(s, rw)	fopen(s, rw)
#   define time(x)	0
#   define ctime(x)	""
#   define unlink(s)
#   define strerror(x)	0
#   define time_t       int
#else
#   include <signal.h>
#endif /* __WINCE__ */

#endif	/* IRIT_SM_H */
