/*
 GraphicsGems.h
 Version 1.0 - Andrew Glassner
 from "Graphics Gems", Academic Press, 1990
 */

#ifndef GG_H

#define GG_H 1

/*********************/
/* 2d geometry types */
/*********************/

typedef struct IntPoint2Struct {
	/* 2d integer point */
	int x, y;
} IntPoint2;

typedef struct Matrix3Struct {
	/* 3-by-3 matrix */
	double element[3][3];
} Matrix3;

typedef struct Box2dStruct {
	/* 2d box */
	NSPoint min, max;
} Box2;

/*********************/
/* 3d geometry types */
/*********************/

typedef struct Point3Struct {
	/* 3d point */
	double x, y, z;
} Point3;
typedef Point3 Vector3;

typedef struct IntPoint3Struct {
	/* 3d integer point */
	int x, y, z;
} IntPoint3;

typedef struct Matrix4Struct {
	/* 4-by-4 matrix */
	double element[4][4];
} Matrix4;

typedef struct Box3dStruct {
	/* 3d box */
	Point3 min, max;
} Box3;

/***********************/
/* one-argument macros */
/***********************/

/* absolute value of a */
//#define ABS(a)		  (((a)<0) ? -(a) : (a))

/* round a to nearest int */
//#define ROUND(a)	floor((a)+0.5)

/* take sign of a, either -1, 0, or 1 */
#define ZSGN(a) (((a) < 0) ? -1 : (a) > 0 ? 1 : 0)

/* take binary sign of a, either -1, or 1 if >= 0 */
#define SGN(a) (((a) < 0) ? -1 : 1)

/* shout if something that should be true isn't */
#define ASSERT(x) \
	if (!(x))     \
		fprintf(stderr, " Assert failed: x\n");

/* square a */
//#define SQR(a)		  ((a)*(a))

/***********************/
/* two-argument macros */
/***********************/

/* find minimum of a and b */
//#define MIN(a,b)		(((a)<(b))?(a):(b))

/* find maximum of a and b */
//#define MAX(a,b)		(((a)>(b))?(a):(b))

// This (unused!) `SWAP` macro conflicts with the macro of same name in `NSBezierPath+OAExtensions.h`.
/* swap a and b (see Gem by Wyvill) */
//#define SWAP(a, b) \
//    {              \
//        a ^= b;    \
//        b ^= a;    \
//        a ^= b;    \
//    }

/* linear interpolation from l (when a=0) to h (when a=1)*/
/* (equal to (a*h)+((1-a)*l) */
#define LERP(a, l, h) ((l) + (((h) - (l)) * (a)))

/* clamp the input to the specified range */
#define CLAMP(v, l, h) ({ \
	__typeof__(v) _v = (v); \
	__typeof__(v) _l = (__typeof__(v))(l); \
	_v < _l ? _l : ({ \
		__typeof__(v) _h = (__typeof__(v))(h); \
		_v > _h ? _h : _v; \
	}); \
})

/****************************/
/* memory allocation macros */
/****************************/

/* create a new instance of a structure (see Gem by Hultquist) */
#define NEWSTRUCT(x) (struct x *)(malloc((unsigned)sizeof(struct x)))

/* create a new instance of a type */
#define NEWTYPE(x) (x *)(malloc((unsigned)sizeof(x)))

/********************/
/* useful constants */
/********************/

#define PITIMES2 6.283185	  /* 2 * pi */
#define PIOVER2 1.570796	  /* pi / 2 */
#define E 2.718282			  /* the venerable e */
#define SQRT2 1.414214		  /* sqrt(2) */
#define SQRT3 1.732051		  /* sqrt(3) */
#define GOLDEN 1.618034		  /* the golden ratio */
#define DTOR 0.01745329251994 /* convert degrees to radians */
#define RTOD 57.29578		  /* convert radians to degrees */

/************/
/* booleans */
/************/

#define TRUE 1
#define FALSE 0
#define ON 1
#define OFF 0
typedef int boolean;
/* boolean data type */
typedef boolean flag;

/* flag data type */

extern double V2SquaredLength(const NSPoint *a);
extern double V2Length(const NSPoint *a);

extern double V2Dot(const NSPoint *a, const NSPoint *b);
extern double V2DistanceBetween2Points(const NSPoint *a, const NSPoint *b);

extern void V2Negate(NSPoint *v);

extern void V2Normalize(NSPoint *v);
extern NSPoint *V2Scale(NSPoint *v, double newlen);
extern NSPoint *V2Add(NSPoint *a, NSPoint *b, NSPoint *c);
extern NSPoint *V2Sub(NSPoint *a, NSPoint *b, NSPoint *c);

extern NSPoint *V2Lerp(NSPoint *lo, NSPoint *hi, double alpha, NSPoint *result);
extern NSPoint *V2Combine(NSPoint *a, NSPoint *b, NSPoint *result, double ascl, double bscl);
extern NSPoint *V2Mul(NSPoint *a, NSPoint *b, NSPoint *result);
extern NSPoint *V2MakePerpendicular(NSPoint *a, NSPoint *ap);

// extern NSPoint *V2New(), *V2Duplicate();
extern NSPoint *V2MulPointByProjMatrix(NSPoint *pin, Matrix3 *m, NSPoint *pout);

extern Matrix3 *V2MatMul(Matrix3 *a, Matrix3 *b, Matrix3 *c);
extern Matrix3 *TransposeMatrix3(Matrix3 *a, Matrix3 *b);

#if 0
extern double V3SquaredLength(), V3Length();

extern double V3Dot(), V3DistanceBetween2Points();

extern Vector3* V3Normalize(), * V3Scale(), * V3Add(), * V3Sub();

extern Vector3* V3Lerp(), * V3Combine(), * V3Mul(), * V3Cross();

//extern Vector3 *V3New(), *V3Duplicate();
extern Point3* V3MulPointByMatrix(), * V3MulPointByProjMatrix();

extern Matrix4* V3MatMul();

extern double RegulaFalsi(), NewtonRaphson(), findroot();
#endif
#endif
