//	SDLDrawer.h - SDL (2d/software) drawing backend.
//  ----------------------------------------------------------------------------
//	This file is part of 'Die, you Stupid Hurdlers!', a game for Ludum Dare 14.
//	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 SDLDRAWER_H_
#define SDLDRAWER_H_

#include "Drawer.h"

#include "Float2Int.h"

#include "SDL.h"
#include <map>

///	SDL (2d/software) drawing backend.
class SDLDrawer : public Drawer
{
  public:
	///	Constructor.
	SDLDrawer();
	///	Destructor.
	~SDLDrawer();

	///	Initialise the main drawing surface etc.
	bool initialise(uint16_t width,
					uint16_t height,
					bool fs,
					int aa);

	///	Loads an image onto an SDL surface.
	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);
	///	Frees the SDL surface.
	void releaseImage(uint32_t id);

	///	???
	void beginDrawing();
	///	Swaps buffers.
	void endDrawing();

	///	Blits the image on screen.
	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 string as a series of images.
	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);
	///	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);
  private:
	///	Helper method to setup some blank images for the font glyphs.
	void initGlyphs();
	///	Helper method to scale a surface.
	/*!
		\param input The surface to scale.
		\param width The x-axis amount to scale input to.
		\param height The y-axis amount to scale input to
		\return The scaled surface (do not delete/free).
	 */
	inline SDL_Surface *scaleImage(SDL_Surface *input,
								   uint16_t width,
								   uint16_t height,
								   uint8_t a)
	{
		uint32_t y;
		uint32_t x2, y2;
		uint32_t x3, y3;
		uint8_t *dataIn;
		uint8_t *dataOut;
		double floatX, floatY;

		//Obviously there's no point doing anything if there's no scaling
		//required.
		if((input->w == width) && (input->h == height))
			return input;

		const double xInc = (double)input->w/(double)width;
		const double yInc = (double)input->h/(double)height;

		const double floatWidth = (double)input->w;
		const double floatHeight = (double)input->h;

		SDL_LockSurface(scaleSurface);
		SDL_LockSurface(input);
		{
			dataIn = (uint8_t *)(input->pixels);
			dataOut = (uint8_t *)(scaleSurface->pixels);
			y2 = 0;
			floatY = 0.0f;
			while(floatY < floatHeight)
			{
				x2 = 0;
				floatX = 0.0f;
				y = float2Int(floatY);
				while(floatX < floatWidth)
				{
					x3 = float2Int(floatX)+(y*input->w);
					x3 *= 4;
					y3 = x2+(y2*scaleSurface->w);
					y3 *= 4;

					/*dataOut[y3] = dataIn[x3];
					dataOut[++y3] = dataIn[++x3];
					dataOut[++y3] = dataIn[++x3];
					dataOut[++y3] = dataIn[++x3];*/

					memcpy((void *)(dataOut+y3), (void *)(dataIn+x3), 4);

					//Copy across as a 32-bit integer.
					//*((uint32_t *)(dataOut+y3)) = *((uint32_t *)(dataIn+x3));

					++x2;
					floatX += xInc;
				}
				++y2;
				floatY += yInc;
			}
		}
		SDL_UnlockSurface(input);
		SDL_UnlockSurface(scaleSurface);

		return scaleSurface;
	};

	///	Structure representing an SDL image.
	struct Image
	{
		///	The image to use.
		SDL_Surface *surface;
		///	The pixel data of the image (all images are 32bit RGBA).
		uint8_t *data;
		///	The width of the image.
		uint16_t width;
		///	The height of the image.
		uint16_t height;
	};

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

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

	///	The surface of the screen/window to blit onto.
	SDL_Surface *screen;

	///	Temporary surface used to scale other surfaces.
	SDL_Surface *scaleSurface;
};

#endif
