//	Drawer.h - Base class for different drawing backends.
//  ----------------------------------------------------------------------------
//	This file is part of 'The Future Will Only Be Dystopian if Capitalism
//	Remains Undefeated', a game.
//	Copyright (C) 2009  Niall Moody
//	
//	This program is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	This program is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program.  If not, see <http://www.gnu.org/licenses/>.
//	----------------------------------------------------------------------------

#ifndef DRAWER_H_
#define DRAWER_H_

#ifdef DEBUG
#pragma warning(disable : 4786) //Stupid MS headers...
#endif

#include <stdint.h>
#include <string>

///	Base class for different drawing backends.
/*!
	Co-ordinates defining where to draw images will be the same for any backend
	and screen/window size.  That is, co-ordinates will always go 0->1024 on the
	x-axis, and 0->768 on the y-axis.  For aspect ratios other than 4:3, a
	4:3 drawing area will be used in the centre of the screen/window, with black
	filling the areas outside.
 */
class Drawer
{
  public:
	///	Constructor.
	Drawer() {};
	///	Destructor.
	virtual ~Drawer() {};

	///	Any initialisation gets done here.
	/*!
		\param width The width of the window/screen to draw to.
		\param height The height of the window/screen to draw to.
		\param fs Whether to go fullscreen or not.
		\param aa How much antialiasing to use (OpenGL only).
		\return True if initialisation was successful, false otherwise.
	 */
	virtual bool initialise(uint16_t width,
							uint16_t height,
							bool fs,
							int aa) = 0;

	///	Loads an image, returns its identifier.
	/*!
		\param data The image data to be loaded.
		\param width The width of the image.
		\param height The height of the image.
		\return The image's identifier if loading was successful, 0 otherwise.

		Images passed in should be in 32-bit RGBA format.  The image data will
		be deleted by the Drawer.  An OpenGL backend will pass the data onto the
		graphics card and delete the pointer passed in, while a 2D SDL backend
		will likely hold onto the pointer until the Drawer has been destroyed
		or the image has been released.
	 */
	virtual uint32_t loadImage(uint8_t *data, uint32_t width, uint32_t height) = 0;
	///	Releases the image associated with the passed-in identifier.
	virtual void releaseImage(uint32_t id) = 0;

	///	Loads a polygon, returns its identifier.
	/*!
		\param points The polygon's points, interlaced (i.e. x1, y1, x2, y2...).
		\param numPoints The number of points that make up this polygon.
		\return The polygon's identifier if loading was successful, 0 otherwise.

		Note that points is assumed to be a series of points around a centre.
		Drawer subclasses will tesselate it like that, so if you don't pass in
		a radial pattern, don't expect the polygon to be rendered the way you
		were expecting.
	 */
	virtual uint32_t loadPoly(float *points, int numPoints) = 0;

	///	Loads a shader, returns its identifier.
	virtual uint32_t loadShader(const std::string& vertex,
								const std::string& fragment) {return 0;};

	///	To be called at the start of a drawing frame.
	virtual void beginDrawing() = 0;
	///	To be called at the end of a drawing frame.
	virtual void endDrawing() = 0;

	///	Returns the contents of the screen as a buffer of pixels.
	/*!
		\return The pixel data.  This must be deleted by the caller.  The size
		of the returned buffer will be
		<width of the screen> x <height of the screen> x 3.

		Make sure you call this after endDrawing().
	 */
	virtual unsigned char *getScreenPixels() = 0;

	///	Activates a shader to be used for the following operations.
	/*!
		\param shader The value returned from loadShader(), or 0 to revert to
		the fixed function.
	 */
	virtual void useShader(uint32_t shader) {};
	///	Draws the passed in image on top of the existing one for any further drawing operations.
	virtual void useSecondImage(uint32_t image) {};

	///	Draws an image at the desired position.
	/*!
		\param id The identifier of the image to draw.
		\param x The x-axis position to draw the image at (0->1024).
		\param y The y-axis position to draw the image at (0->768).
		\param width The width to draw the image (1 == no scaling, &gt;1 larger,
		&lt;1 smaller).
		\param height The height to draw the image (1 == no scaling, &gt;1
		larger, &lt;1 smaller).
		\param r The colour to tint the image, red component.
		\param g The colour to tint the image, green component.
		\param b The colour to tint the image, blue component.
		\param a The colour to tint the image, alpha component.
	 */
	virtual void drawImage(uint32_t id,
						   int16_t x,
						   int16_t y,
						   float width = 1.0f,
						   float height = 1.0f,
						   float r = 1.0f,
						   float g = 1.0f,
						   float b = 1.0f,
						   float a = 1.0f) = 0;
	///	Draws a textured polygon at the desired position.
	/*!
		\param polyId The identifier of the polygon to draw.
		\param textureId The identifier of the texture to draw the polygon with.
		\param id The identifier of the image to draw.
		\param x The x-axis position to draw the image at (0->1024).
		\param y The y-axis position to draw the image at (0->768).
		\param width The width to draw the image (1 == no scaling, &gt;1 larger,
		&lt;1 smaller).
		\param height The height to draw the image (1 == no scaling, &gt;1
		larger, &lt;1 smaller).
		\param r The colour to tint the image, red component.
		\param g The colour to tint the image, green component.
		\param b The colour to tint the image, blue component.
		\param a The colour to tint the image, alpha component.
	 */
	virtual void drawPoly(uint32_t polyId,
						  uint32_t textureId,
						  int16_t x,
						  int16_t y,
						  float width = 1.0f,
						  float height = 1.0f,
						  float r = 1.0f,
						  float g = 1.0f,
						  float b = 1.0f,
						  float a = 1.0f) = 0;
	///	Draws a string at the specified position.
	virtual void drawText(const std::string& text,
						  int16_t x,
						  int16_t y,
						  float height,
						  float r = 1.0f,
						  float g = 1.0f,
						  float b = 1.0f,
						  float a = 1.0f) = 0;
	///	Draws a line between 2 points.
	virtual void drawLine(int16_t x1,
						  int16_t y1,
						  int16_t x2,
						  int16_t y2,
						  float r = 1.0f,
						  float g = 1.0f,
						  float b = 1.0f,
						  float a = 1.0f) = 0;
	///	Fills a rectangle with the specfied colour.
	virtual void fillRect(int16_t x,
						  int16_t y,
						  int16_t w,
						  int16_t h,
						  uint8_t r,
						  uint8_t g,
						  uint8_t b,
						  uint8_t a) = 0;
	///	Fills a rectangle with the specfied gradient.
	virtual void fillGradient(int16_t x,
							  int16_t y,
							  int16_t w,
							  int16_t h,
							  uint8_t r1,
							  uint8_t g1,
							  uint8_t b1,
							  uint8_t a1,
							  uint8_t r2,
							  uint8_t g2,
							  uint8_t b2,
							  uint8_t a2) = 0;

	///	Specifies a viewport to restrict drawing to.
	virtual void setViewport(int16_t x, int16_t y, int16_t w, int16_t h) = 0;
	///	Resets the viewport.
	virtual void resetViewport() = 0;
	///	Returns the width of the available viewport for drawing into.
	virtual int16_t getActualWidth() const = 0;
	///	Returns the height of the available viewport for drawing into.
	virtual int16_t getActualHeight() const = 0;

	///	Enum containing indices for the various possible glyphs.
	enum Glyph
	{
		a = 0,
		b,
		c,
		d,
		e,
		f,
		g,
		h,
		i,
		j,
		k,
		l,
		m,
		n,
		o,
		p,
		q,
		r,
		s,
		t,
		u,
		v,
		w,
		x,
		y,
		z,
		Num0,
		Num1,
		Num2,
		Num3,
		Num4,
		Num5,
		Num6,
		Num7,
		Num8,
		Num9,
		Period,
		Comma,
		Plus,
		Minus,
		Exclaim,
		Question,

		NumGlyphs
	};

	///	Loads a glyph for the text renderer.
	/*!
		\param g The glyph to load.
		\param data The image data to load.
		\param size The size of image.  All glyph images should be square, so
		this would be 32 for a 32x32 image.
	 */
	virtual void loadGlyph(Glyph g, uint8_t *data, uint32_t size) = 0;
  protected:
	///	Helper method to return the index of the desired image.
	/*!
		\return The index of the image.  -1 if it should be a space.
	 */
	inline Glyph getTexture(char character)
	{
		switch(character)
		{
			case '0':
				return Num0;
			case '1':
				return Num1;
			case '2':
				return Num2;
			case '3':
				return Num3;
			case '4':
				return Num4;
			case '5':
				return Num5;
			case '6':
				return Num6;
			case '7':
				return Num7;
			case '8':
				return Num8;
			case '9':
				return Num9;
			case 'a':
				return a;
			case 'b':
				return b;
			case 'c':
				return c;
			case 'd':
				return d;
			case 'e':
				return e;
			case 'f':
				return f;
			case 'g':
				return g;
			case 'h':
				return h;
			case 'i':
				return i;
			case 'j':
				return j;
			case 'k':
				return k;
			case 'l':
				return l;
			case 'm':
				return m;
			case 'n':
				return n;
			case 'o':
				return o;
			case 'p':
				return p;
			case 'q':
				return q;
			case 'r':
				return r;
			case 's':
				return s;
			case 't':
				return t;
			case 'u':
				return u;
			case 'v':
				return v;
			case 'w':
				return w;
			case 'x':
				return x;
			case 'y':
				return y;
			case 'z':
				return z;
			case '.':
				return Period;
			case ',':
				return Comma;
			case '!':
				return Exclaim;
			case '-':
				return Minus;
			case '+':
				return Plus;
			case '?':
				return Question;
			default:
				return NumGlyphs;
		}
	};
};

#endif
