#ifndef _VPOLY_H
#define _VPOLY_H

#include <stdio.h>
#include "Vlibmath.h"
#include "VColor.h"
#include "../util/units.h"

#ifdef VPoly_IMPORT
	#define EXTERN
#else
	#define EXTERN extern
#endif

#define VmaxVP  2048            /* max # of vertices in a polygon */
#define NUM_ASPECTS 10


/*
	(VPolygon)->flags:
*/

#define PolyClipBackface    0x01    /* Polygon is "one-sided" */
#define PolyUseBackColor    0x02    /* should be rendered using backColor */
#define PolyNormalValid     0x04    /* "normal" contains valid info */
#define PolyUseCullDistance 0x08    /* cullDistance should be tested before plotting */

typedef struct {
	short     flags;            /* (see flags above) */
	short     numVtces;         /* vertex count */
	VPoint    normal;           /* normal vector, available only if PolyNormalValid flag is set */
	VPoint   *vertex;           /* pointer to array of vertices (& normal) */
	VColor_Type   *color;       /* pointer to color descriptor */
	VColor_Type   *backColor;   /* pointer to back's color (sometimes NULL) */
	double    cullDistance;     /* this polygon is ignored beyond this distance */
} VPolygon;


struct _euler {
	double    yaw;
	double    pitch;
};


/*
	Views corresponding to each of the eight defined major aspects
*/

EXTERN struct _euler view[]
	#ifdef VPoly_IMPORT
	= {
		{units_DEGtoRAD(90.0), units_DEGtoRAD(0.0)},        /* 0 - right */
		{units_DEGtoRAD(-90.0), units_DEGtoRAD(0.0)},       /* 1 - left */
		{units_DEGtoRAD(45.0), units_DEGtoRAD(45.0)},       /* 2 - front right bottom */
		{units_DEGtoRAD(45.0), units_DEGtoRAD(-45.0)},      /* 3 - front right top    */
		{units_DEGtoRAD(-45.0), units_DEGtoRAD(45.0)},      /* 4 - front left bottom  */
		{units_DEGtoRAD(-45.0), units_DEGtoRAD(-45.0)},     /* 5 - front left top     */
		{units_DEGtoRAD(135.0), units_DEGtoRAD(45.0)},      /* 6 - aft right bottom   */
		{units_DEGtoRAD(135.0), units_DEGtoRAD(-45.0)},     /* 7 - aft right top      */
		{units_DEGtoRAD(-135.0), units_DEGtoRAD(45.0)},     /* 8 - aft left bottom    */
		{units_DEGtoRAD(-135.0), units_DEGtoRAD(-45.0)},    /* 9 - aft left top       */
	}
	#endif
	;

EXTERN char *VGetAspectName (int aspect);

EXTERN VPolygon *VCreatePolygon (int npts, VPoint * pts, VColor_Type *);

#define VDestroyPolygon(a)  {if((a)!=NULL){memory_dispose(a->vertex); memory_dispose(a);}}

/**
 * VPolySet data type is a set that can contain zero or more VPolygon(s).
 * Polygons can be added but cannot be removed. Typical usage:
 */
typedef struct VPolySet VPolySet;

/**
 * Allocates a new set of polygons.
 */
EXTERN VPolySet * VPolySet_New(void);

/**
 * Release the set from memory. The flag says if also the VPolygon(s) the
 * set points to have to be released with VDestroyPolygon().
 */
EXTERN void VPolySet_Free(VPolySet *s, int release_polygons_too);

/**
 * Empties the set to zero elements without actually releasing the memory,
 * so the set can be re-used several times. The flag says if the polygons
 * have to released with VDestroyPolygon().
 */
EXTERN void VPolySet_Empty(VPolySet *s, int release_polygons_too);

/**
 * Add the polygon to the set. Polygons are not copied, only their pointer
 * it is.
 */
EXTERN void VPolySet_Add(VPolySet *s, VPolygon *p);

/**
 * Start a new scanning sequence of the set, and return the first polygon
 * of this sequence. Return NULL if the set is empty.
 */
EXTERN VPolygon * VPolySet_First(VPolySet *s);

/**
 * Return the pointer to the next polygon in set, or NULL if the scanning
 * sequence is terminated and all the polygons scanned.
 */
EXTERN VPolygon * VPolySet_Next(VPolySet *s);

/**
 * Set the value of the current entry with a new one.
 */
EXTERN void VPolySet_Set(VPolySet *s, VPolygon *poly);

/**
 * Return the number of polygons in the set.
 */
EXTERN int VPolySet_Count(VPolySet *s);

EXTERN VPolygon *VCreatePolygonFromTemplate (int npts, VPoint * pts, VPolygon * templ);

EXTERN VPolygon *VCopyPolygon (VPolygon *);

EXTERN void VPrintPolygon (FILE * file, VPolygon * p);

EXTERN VPolygon * VTransformPolygon (VPolygon * poly, VMatrix * m);

EXTERN VPolygon * VClipPolygon(VPolygon * poly, VPolygon * clipPoly);

/**
 * Clip polygon 'poly' against the view frustum 'clipPoly'. The original
 * polygon gets destroyed and released and the new clipped one is
 * returned. Return NULL if not visible at all.
 */
EXTERN VPolygon * VClipSidedPolygon(VPolygon * poly, VPolygon * clipPoly);

EXTERN VPolygon * ScalePolygon(VPolygon * in, VPoint * offset, VPoint * scale,
	VPoint *e, double r);

#undef EXTERN
#endif
