/**
 * Alib -- Basic 2-D drawing routines with Z-buffer for polygons.
 * Nobody knows what that "A" stands for.
 * 
 * @file
 */

#ifndef _ALIB_H
#define _ALIB_H

#include <stdio.h>
#include "Vlibmath.h"
#include "VPoly.h"
#include "../util/gui.h"

#ifdef Alib_IMPORT
	#define EXTERN
#else
	#define EXTERN extern
#endif

typedef struct {
    short x, y;
} Alib_Point;


typedef struct {
	short x1, y1, x2, y2;
} Alib_Segment;

/**
 * A Rect is exactly (b.x - a.x) pixels wide and (b.y - a.y) pixels tall,
 * being a,b two geometrical points.
 * 
 * This library assumes a.x < b.x and a.y < b.y, otherwise the Rect
 * is considered empty.
 * 
 * Please note that the pixel "a" is inside, while "b" is outside.
 */
typedef struct {
	Alib_Point a, b;
} Alib_Rect;


/**
 * 2D transformation (misleading name as it is not properly a "matrix").
 */
typedef struct {
	double rxx, rxy, ryx, ryy, tx, ty;
} Alib_Matrix;


/**
 * Expandable polygon. Last point implicitly joined with the the first to close.
 */
typedef struct {
	/** Number of points of the polygon. */
	int npts;
	/** Number of points allocated in memory. */
	int allocated_pts;
	/** Allocated points. */
	Alib_Point *pts;
} Alib_Polygon;


typedef unsigned short Alib_Pixel;

typedef struct Alib_ZInfo Alib_ZInfo;

typedef struct Alib_Window Alib_Window;


EXTERN void Alib_setPoint(Alib_Point *p, int x, int y);

/**
 * Set the rectangle.
 */
EXTERN void Alib_setRect(Alib_Rect *r, int ax, int ay, int bx, int by);

/**
 * Return true if the given rectangle is empty, false otherwise.
 */
EXTERN int Alib_isEmptyRect(Alib_Rect *r);

/**
 * Return in res the intersection between r1,r2. If the result is empty,
 * return (Rect){{0,0},{0,0}}. Rectangles may overlap in memory.
 */
EXTERN void Alib_intersectRect(Alib_Rect *r1, Alib_Rect *r2, Alib_Rect *res);

/**
 * Expands the given rectangle around its center so that it becomes 2*dx
 * pixels wider and 2*dy pixel taller.
 */
EXTERN void Alib_expandRect(Alib_Rect *r, int dx, int dy);

#define RectWidth(r) ((r).b.x - (r).a.x)
#define RectHeight(r) ((r).b.y - (r).a.y)
#define RectMiddleX(r) (((r).b.x + (r).a.x)/2)
#define RectMiddleY(r) (((r).b.y + (r).a.y)/2)

/**
 * Create a new z-buffer rectangular area in the content area of the window.
 * @param gui
 * @return A new z-buffer rectangular area in the content area of the window.
 * Can be released with memory_dispose().
 */
EXTERN Alib_Window * Alib_new(gui_Type *gui);

/**
 * Resize the AWindow, intersection the current clipping rectangle
 * with the new area.
 */
EXTERN void Alib_resize(Alib_Window * w, int width, int height);

/**
 * Enables depth cueing feature.
 * @param w Involved window.
 * @param value True to enable depth cueing, false to disable.
 */
EXTERN void Alib_setDepthCueing(Alib_Window *w, int value);

/**
 * Set visibility (meters), haze color and number of steps for color
 * depth-cueing.
 */
EXTERN void Alib_setVisibility(Alib_Window *w, double visibility, VColor_Type * haze_color);

/**
 * Set the clipping rectangle w->clip as the intersection between r and
 * the whole available drawing area (0,0)-(w->width,w->height). Drawing
 * will never be performed outside this rectangle.
 */
EXTERN void Alib_setClipRect(Alib_Window *w, Alib_Rect *r);

/*
 * Basic 2-D drawing routines that draw on the given window and perform
 * clipping to the current clipping rectangle as set by AlibSetClip().
 */
EXTERN void Alib_drawLine(Alib_Window *w, int x1, int y1, int x2, int y2, Alib_Pixel color);
EXTERN void Alib_drawArc(Alib_Window *w, int x, int y,
	int width, int height,
	int angle1, int angle2, Alib_Pixel color);
EXTERN void Alib_drawSegments(Alib_Window *w, Alib_Segment * seg, int nseg, Alib_Pixel color);
EXTERN void Alib_drawRect(Alib_Window *w, Alib_Rect *r, Alib_Pixel color);
EXTERN void Alib_fillRect(Alib_Window *w, Alib_Rect *r, Alib_Pixel color);
EXTERN void Alib_fillPolygon(Alib_Window *w, Alib_Point * pts, int npts, Alib_Pixel color);

/*
 * Basic 3-D drawing routines with color z-buffer that draw on the given
 * window and perform clipping to the current clipping rectangle as set by
 * AlibSetClip().
 */

/**
 * Returns next pre-allocated ZInfo with specified color set.
 * @param w
 * @param color
 * @return Next pre-allocated ZInfo with specified color set.
 */
EXTERN Alib_ZInfo * Alib_nextZInfo(Alib_Window * w, Alib_Pixel color);

EXTERN void Alib_draw3DPoint(Alib_Window * w, int x, int y, Alib_ZInfo * zinfo);
EXTERN void Alib_draw3DLine(Alib_Window * w, int x1, int y1, int x2, int y2, Alib_ZInfo * zinfo);
EXTERN void Alib_fill3DRect(Alib_Window * w, Alib_Rect *r, Alib_ZInfo * zinfo);
EXTERN void Alib_fill3DPolygon(Alib_Window * w, Alib_Point * pts, int npts, Alib_ZInfo * zinfo);

/**
 * Draw differences between this frame and the last drawn frame.
 */
EXTERN void Alib_drawDifferences(Alib_Window *w);

/**
 * Invalidate the current frame's drawing information so that it will be fully
 * redrawn at next update. This function typically invoked after a window
 * redraw event.
 */
EXTERN void Alib_invalidate(Alib_Window *w);

/**
 * Returns the faded color of the polygon given the current visibility range,
 * distance from the origin, and haze color. The "distance" is arbitrarily
 * calculated from the first point of the polygon, assuming the polygon be
 * much smaller than the visibility range. Beyond the visibility range the
 * haze color is returned. If the depth cueing is turned off, or the color of
 * the polygon is not marked as depth cued, simply returns the color of the
 * polygon.
 * @param w
 * @param poly
 * @return Faded color of the polygon.
 */
EXTERN Alib_Pixel Alib_computePolygonColor(Alib_Window *w, VPolygon * poly);


EXTERN void Alib_MatrixIdentity(Alib_Matrix *m);

EXTERN void Alib_MatrixScale(Alib_Matrix *m, double s);

EXTERN void Alib_MatrixRotate(Alib_Matrix *m, double a);

EXTERN void Alib_MatrixTranslate(Alib_Matrix *m, double dx, double dy);

EXTERN void Alib_MatrixTransformPoint(Alib_Point *p, Alib_Matrix *m, Alib_Point *q);

EXTERN void Alib_fillPolygonWithMatrix(Alib_Window *w, Alib_Point * pts, int npts, Alib_Matrix *m, Alib_Pixel color);

EXTERN Alib_Polygon * Alib_Polygon_new(void);

EXTERN void Alib_Polygon_addPointXY(Alib_Polygon *poly, int x, int y);

EXTERN void Alib_Polygon_addPoint(Alib_Polygon *poly, Alib_Point *p);

EXTERN Alib_Polygon * Alib_Polygon_clone(Alib_Polygon *poly);

#undef EXTERN
#endif
