/*****************************************************************************
*   "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 7.0"			 /* Program version. */
#define  IRIT_COPYRIGHT	"(C) Copyright 1989/90-97 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 */

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. */

#ifdef IRIT_EPS
#undef IRIT_EPS
#endif /* IRIT_EPS */
#define IRIT_EPS		1e-5

#ifdef IRIT_INFNTY
#undef IRIT_INFNTY
#endif /*  IRIT_INFNTY */
#define IRIT_INFNTY	1e6

#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 FILE_NAME_LEN	13		   /* Name (8) + Type (3) + Dot (1). */
#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 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 APX_EQ(x, y)		(ABS((x) - (y)) < IRIT_EPS)
#define APX_EQ_EPS(x, y, EPS)	(ABS((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_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 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 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)		(ABS((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_CLEAR(Pt)		{ Pt[0] = Pt[1] = Pt[2] = 0.0; }

#define PT_SCALE(Pt, Scalar)	{ Pt[0] *= Scalar; \
				  Pt[1] *= Scalar; \
				  Pt[2] *= 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 UV_COPY(PtDest, PtSrc)	  memcpy((char *) (PtDest), (char *) (PtSrc), \
							2 * sizeof(RealType))
#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 GEN_COPY(Dest, Src, Size) memcpy((char *) (Dest), (char *) (Src), Size)
#define ZAP_MEM(Dest, Size)	  memset((char *) (Dest), 0, Size);

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

#define PT_RESET(Pt)		Pt[0] = Pt[1] = Pt[2] = 0.0
#define UV_RESET(Uv)		Uv[0] = Uv[1] = 0.0

#define PT_NORMALIZE_ZERO	1e-30
#define PT_NORMALIZE(Pt)	{    RealType Size = PT_LENGTH(Pt); \
				     if (Size < PT_NORMALIZE_ZERO) { \
					 fprintf(stderr, "Attempt to normalize a zero length vector\n"); \
				     } \
				     else { \
					 Pt[0] /= Size; \
					 Pt[1] /= Size; \
				         Pt[2] /= Size; \
				     } \
				}

#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_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]))

#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 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(_AIX) || defined(sgi) || defined(SUN4) || defined(DJGCC) || defined(OS2GCC) || defined(__WINNT__) || defined(AMIGA) || defined(_INCLUDE_HPUX_SOURCE) || defined(OSF1DEC) || defined(__FreeBSD__) || defined(__osf__)
#    include <stdlib.h>

#    if defined(OSF1DEC) || defined(sgi) || defined(SUN4) || defined(OS2GCC)
#	ifdef OSF1DEC
#	   ifdef _XOPEN_SOURCE
#	       undef _XOPEN_SOURCE /* For usleep */
#	   endif /*  _XOPEN_SOURCE */
#	endif /* OSF1DEC */
#	include <unistd.h>
#    endif /* OSF1DEC || sgi || SUN4 || OS2GCC */
#    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__ || AMIGA || _INCLUDE_HPUX_SOURCE || OSF1DEC || __FreeBSD__ */

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

#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif

char *IritStrdup(char *s);
void IritSleep(int MiliSeconds);
void IritRandomInit(long Seed);
RealType IritRandom(RealType Min, RealType Max);
RealType IritCPUTime(int Reset);
char *IritRealTimeDate(void);

#ifndef AMIGA
void movmem(VoidPtr Src, VoidPtr Dest, int Len);
#endif /* AMIGA */
char *searchpath(char *Name);

#ifdef STRICMP
int strnicmp(char *s1, char *s2, int n);
int stricmp(char *s1, char *s2);
#else
#if !(defined(__WINNT__) || defined(OS2GCC) || defined(AMIGA))
#define strnicmp(s1, s2, n) strncasecmp((s1), (s2), (n))
#define stricmp(s1, s2)     strcasecmp((s1), (s2))
#endif /* !(__WINNT__ || OS2GCC || AMIGA) */
#endif /* STRICMP */

#ifdef STRSTR
char *strstr(char *s, char *Pattern);
#endif /* STRSTR */

#ifdef GETCWD
char *getcwd(char *s, int Len);
#endif /* GETCWD */

void IritFatalError(char *Msg);
void IritWarningError(char *Msg);

#if defined(__cplusplus) || defined(c_plusplus)
}
#endif

#endif	/* IRIT_SM_H */
