#define Malloc(Object,N)        ((Object *)myMalloc((N)*sizeof(Object)))
#define FREE(Object)            (free((Ptr)(Object)))
#define ABS(x)                          ( ((x) >= (REAL)0.0) ? (x) : -(x))
#define REAL                            double
#define ROUND(x)                        ((int)((x)+0.5))
#define NEGATIVE(x)                     ((x) < 0.0)
#define POSITIVE(x)                     ((x) >= 0.0)
#define BOOLEAN                         Boolean
#define TRUE                            true
#define FALSE                           false
#define EXIT                            exit(0)


#define TOL                                     (1.0e-4)

#define NOSHADING                       ((Shading *)0)
#define NOCOLOUR                        ((Colour){0.0,0.0,0.0})
#define NOINDEX                         ((Index *)0)
#define NOPLANEQ                        ((PlaneEq *)0)
#define NOFACE                          ((Face *)0)
#define NOPOINT                         ((Point3D *)0)
#define EMPTYTREE                       ((Tree *)0)

/*faces*/
#define VERTEXOfFace(poly)              (poly->vertex)
#define PLANEQOfFace(poly)              (poly->coeff)
#define SHADINGOfFace(poly)             (poly->shading)
#define REFLECTIONOfFace(poly)  (poly->shading->reflection)
#define REDReflectionOf(poly)   (poly->shading->reflection.red)
#define GREENReflectionOf(poly) (poly->shading->reflection.green)
#define BLUEReflectionOf(poly)  (poly->shading->reflection.blue)
#define COLOUROfFace(poly)              (poly->shading->colour)
#define REDOfFace(poly)                 (poly->shading->colour.red)
#define GREENOfFace(poly)               (poly->shading->colour.green)
#define BLUEOfFace(poly)                (poly->shading->colour.blue)
#define FIRSTOfFace(poly)               (poly->first)
#define LASTOfFace(poly)                (poly->last)
#define SIZEOfFace(poly)                (poly->size)
#define TRANSFORMFace(poly,m)   traversePtrFace((poly),&transformVertex,(m))
#define REDLightOfFace(poly,i)          (poly->shading->colourOfLight[i].red)
#define GREENLightOfFace(poly,i)        (poly->shading->colourOfLight[i].green)
#define BLUELightOfFace(poly,i)         (poly->shading->colourOfLight[i].blue)

#define REDShading(shade)               (shading->colour.red)
#define GREENShading(shade)             (shading->colour.green)
#define BLUEShading(shade)              (shading->colour.blue)



#define ADDClassification(a,b,c) {      \
	switch(a){      \
		case FRONT : c = (b==BACK?FRONT_BACK:FRONT); break;  \
		case BACK  : c = (b==FRONT?BACK_FRONT:BACK);break; \
		case ON    : c = (b);break;default: break;}}



#define CLASSIFYPoint3D(plane,point,d,c) {      \
	d =  APL(plane)*X(point) + BPL(plane)*Y(point)  \
					+ CPL(plane)*Z(point) - DPL(plane); \
	c = CLASSIFY(d);        }


#define atVertex(v,i)                           (*((v)->vertex+(i)))


/*points*/
#define X(p)                            ((p).x)
#define Y(p)                            ((p).y)
#define Z(p)                            ((p).z)
#define MAKEPoint3D(p,a,b,c)    {p.x=a; p.y=b; p.z=c;}

/*vertices*/
#define GETPointFromIndex(vertex,ind)   (atVertex((vertex),(ind)->i))
#define NEXTFreeVertex(v)                               (v->n)
#define TRANSFORMVertex(v,i,m)          transformPoint3D(atVertex((v),(i)),(m))

/*index*/
#define NEXT(index)                     ((index)->next)
#define INDEX(index)            ((index)->i)

/*face list*/
#define NEXTFreeFaceList(f)	((f)->n)
#define ADDToFaceList(f,poly)   (atPutFaceList((f),(f)->n,poly)
#define SIZEOfFaceList(f)               (f->size)

/*trees*/
#define FACESETOfTree(t)        ((t)->faceSet)
#define FRONTNODEOfTree(t)      ((t)->frontNode)
#define BACKNODEOfTree(t)       ((t)->backNode)


/*#define CLASSIFY(d)                   ((d)>0.0?FRONT:((d)<0.0?BACK:ON))*/
							/*if d>0 FRONT else if d<0 then BACK else ON*/
#define CLASSIFY(d)                     (ABS((d))<TOL?ON:((d)>0.0?FRONT:BACK))
					/*if |d|<TOL then ON else if d>0 then FRONT else BACK*/

/*plane equation*/
#define APL(p)                          ((p)->a)
#define BPL(p)                          ((p)->b)
#define CPL(p)                          ((p)->c)
#define DPL(p)                          ((p)->d)

/*lights*/
#define MAXLIGHT 10

typedef char *Ptr;

typedef enum{
	  false,true
  } Boolean;

typedef struct{
	REAL x,y,z;
} Point3D, *Point3DPtr;

typedef struct{
	Point3DPtr *vertex; /*array of pointers to points*/
	int n;  /*current index*/
	int size;
} Vertex;

typedef struct{
	REAL a,b,c,d;
} PlaneEq;

typedef struct{
	REAL red,green,blue;
} Colour;

typedef struct{
	Colour reflection;      /*coefficients of diffuse reflection*/
	Colour colour;          /*actual computed colour*/
	int    noOfLights;  /*no of lights defined so far*/
	Colour colourOfLight[MAXLIGHT]; /*colour for each light*/
} Shading;

typedef struct _index{
	int i;
	struct _index *next;
} Index, *IndexPtr;


typedef struct{
	Vertex *vertex;
	Index *first;
	Index *last;
	int size;
	PlaneEq *coeff;
	Shading *shading;
	Index *lightsAway; /*if I am a shadow then the absense of lights which I represent?*/
	int noOfShadows;
	Index *shadow;          /*list of indices into facelist*/
	Index *lastShadow;      /*last index*/
} Face, *FacePtr;

typedef enum{
	FRONT,BACK,ON,FRONT_BACK,BACK_FRONT
} Classification;

typedef struct{
	FacePtr *face; /*array of pointers to faces*/
	int n;  /*current index*/
	int size;
} FaceList;

typedef struct tree{
	Index *faceSet; /*set of faces at a node - all sharing same plane*/
	struct tree *frontNode,*backNode;
} Tree, *TreePtr;

/*mymalloc.c*/
extern char *myMalloc();

/*face.c*/
extern Face *newFace();
extern void addToFrontFace();
extern void addToBackFace();
extern Index *firstIndexInFace();
extern Index *lastIndexInFace();
extern int sizeOfFace();
extern void traverseFace();
extern int getnVerticesOfFace();
extern int sizeOfFace();
extern Vertex *vertexOfPoly();
extern void setPlaneEqOfFace();
extern Classification classifyFace();
extern void splitFace();
extern void getCentreOfFace();
extern void setDirectionalLightingOfFace();
extern void setPositionalLightingOfFace();
extern void getColourAtPointOnFace();
extern void setAverageLightingOfFace();
extern void setAmbientLightingOnFace();
extern void setCentreColourOfFace();
extern void getCentreColourOfFace();
extern Classification classificationOfFace();
extern BOOLEAN commonVertexWithFace();
extern PlaneEq *copyPlaneEqOfFace();
extern Shading *copyShadingOfFace();
extern Classification addClassification();

/*polygon.c*/
extern void shadowPolygonOfFace();


/*index.c*/
extern Index *newIndex();
extern Index *addToFrontIndex();
extern Index *addToBackIndex();
extern Index *nextIndex();
extern void deleteIndex();
extern void traverseIndex();
extern BOOLEAN memberOfIndex();
extern void appendToIndex();
extern Index *copyIndex();

/*point.c*/
extern Point3D *newPoint3D();
extern REAL detFor3Point3D();
extern void normalPoint3D();
extern Classification classifyPoint3D();
extern void transformPoint3D();
extern REAL distanceOfPoint();

/*vertex.c*/
extern Vertex *newVertex();
/*
extern Point3D *atVertex();
*/
extern void atPutVertex();
extern Point3D *getPointFromIndex();
extern void setNextFreeVertex();
extern void transformVertex();

/*facelist.c*/
extern FaceList *newFaceList();
extern Face *atFaceList();
extern void setNextFreeFaceList();
extern void atPutFaceList();
extern Index *makeSetFromFaceList();

/*tree.c*/
extern Tree *makeRoot();
extern Tree *combineTree();
extern Tree *makeTree();
extern void traverseTree();
extern void printTree();
extern void setShadowsOnTree();
