//	OpenGLDrawer.h - OpenGL drawing backend (using SDL headers).
//  ----------------------------------------------------------------------------
//	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 OPENGLDRAWER_H_
#define OPENGLDRAWER_H_

#include "Drawer.h"

#include "GL/glew.h"
#include <vector>
#include <map>

///	OpenGL drawing backend (using SDL headers).
class OpenGLDrawer : public Drawer
{
  public:
	///	Constructor.
	OpenGLDrawer();
	///	Destructor.
	~OpenGLDrawer();

	///	Initialise the various OpenGL settings.
	bool initialise(uint16_t width,
					uint16_t height,
					bool fs,
					int aa);

	///	Loads an image onto the GPU.
	/*!
		If the image's dimensions are not power-of-two, it will be padded so we
		don't run into problems.  We copy the image's border pixels so the
		texture will tile correctly (if we just blank the extra pixels, it
		creates visible seams when we run at a resolution other than 1024x768).
		The Image structure will then keep track of the actual size of the
		image, and only draw the original rectangle.
	 */
	uint32_t loadImage(uint8_t *data, uint32_t width, uint32_t height);
	///	Loads an image to be used as a glyph.
	void loadGlyph(Glyph g, uint8_t *data, uint32_t size);
	///	Calls glDeleteTextures() on the relevant image.
	void releaseImage(uint32_t id);
	///	Loads a polygon, returns its identifier.
	uint32_t loadPoly(float *points, int numPoints);
	///	Loads a shader, returns its identifier.
	uint32_t loadShader(const std::string& vertex, const std::string& fragment);

	///	Loads the identity matrix etc.
	void beginDrawing();
	///	Swaps buffers.
	void endDrawing();

	///	Returns the contents of the screen as a buffer of pixels.
	unsigned char *getScreenPixels();

	///	Activates a shader to be used for the following operations.
	void useShader(uint32_t shader);
	///	Draws the passed in image on top of the existing one for any further drawing operations.
	void useSecondImage(uint32_t image);

	///	Draws the image as a texture-mapped quad(?).
	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);
	///	Draws a textured polygon at the desired position.
	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);
	///	Draws a string as a serious of texture-mapped quads.
	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);
	///	Draws a line between 2 points.
	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);
	///	Fills a rectangle with the specfied colour.
	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);
	///	Fills a rectangle with the specfied gradient.
	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);

	///	Sets a viewport to restrict drawing to.
	void setViewport(int16_t x, int16_t y, int16_t w, int16_t h);
	///	Resets the viewport.
	void resetViewport();

	///	Returns the width of the available viewport for drawing into.
	int16_t getActualWidth() const {return (int16_t)viewW;};
	///	Returns the height of the available viewport for drawing into.
	int16_t getActualHeight() const {return (int16_t)viewH;};
  private:
	///	Helper method to check whether we're running on a 16-bit display.
	bool is16Bit();

	///	Helper method to initialise the glyphs to blank textures.
	void initFonts();
	///	Helper method to test whether a number is a power-of-two.
	bool isPowerOfTwo(uint32_t val);
	///	Helper method to return the next highest number that is a power-of-two.
	/*!
		\return if val is already power-of-two, it will be returned as-is.
	 */
	uint32_t powerOfTwo(uint32_t val);

	///	Helper method.  Loads a shader file and returns it as a string.
	std::string loadShaderFile(const std::string& path);
	///	Helper method.  Streams the info log to standard out.
	void printInfoLog(GLhandleARB obj);

	///	Structure representing an OpenGL image.
	struct Image
	{
		///	The texture to use.
		GLuint texture;
		///	The width of the image.
		uint16_t width;
		///	The height of the image.
		uint16_t height;
		///	The width of the texture.
		float texWidth;
		///	The height of the texture.
		float texHeight;
	};

	///	Structure representing a polygon.
	struct Polygon
	{
		///	The polygon's points.
		float *xPoints;
		///	The polygon's points.
		float *yPoints;
		///	The polygon's texture coords.
		float *xTex;
		///	The polygon's texture coords.
		float *yTex;
		///	The number of points in the polygon.
		int numPoints;
	};

	///	The texture used to draw lines.
	uint32_t lineImage;

	///	The images currently loaded and ready to be drawn.
	std::map<uint32_t, Image> images;
	///	The polygons currently loaded and ready to be drawn.
	std::vector<Polygon> polys;
	///	The glyphs to draw text with.
	Image glyphs[NumGlyphs];

	///	The second texture if we're doing multitexturing.
	uint32_t secondImage;
	///	The location of the main texture (for shaders).
	/*!
		For this to work, the uniform variable in the fragment shader *must*
		be 'main'.
	 */
	uint32_t tex1Loc;
	///	The location of the second texture (for shaders).
	/*!
		For this to work, the uniform variable in the fragment shader *must*
		be 'second'.
	 */
	uint32_t tex2Loc;

	///	The current max identifier for images.
	uint32_t imagesMaxId;

	///	Whether we're using vertex buffer objects or not.
	bool usingVBO;

	///	The width of our screen.
	int16_t screenWidth;
	///	The height of our screen.
	int16_t screenHeight;
	///	The left side of our viewport.
	float viewX;
	///	The bottom side of our viewport.
	float viewY;
	///	The width of our viewport.
	float viewW;
	///	The height of our viewport.
	float viewH;

	///	Image data used to draw lines.
	static const char* line_png;
	///	Image data used to draw lines.
    const int line_pngSize;// = 144;
};

#endif
