//	SDL2.0ImageLoader.cpp - Class used to load images from different file
//							formats.
//  ----------------------------------------------------------------------------
//	This file is part of 'NiallsAVLib', base code for any kind of audiovisual
//	apps.
//	Copyright (C) 2012  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/>.
//	----------------------------------------------------------------------------

#include "drawing/ImageLoader.h"
#include "DebugHeaders.h"
#include "UTF8File.h"

#include "SDL_image.h"

using std::string;

//------------------------------------------------------------------------------
ImageLoader::ImageLoader()
{

}

//------------------------------------------------------------------------------
ImageLoader::~ImageLoader()
{

}

//------------------------------------------------------------------------------
ImageData ImageLoader::loadImage(const char *data, uint32_t size)
{
	ImageData retval;
	bool successfulLoad = false;
	SDL_RWops *rw = SDL_RWFromConstMem(data, size);
	SDL_Surface *tempIm = IMG_Load_RW(rw, 1);

	retval.data = 0;
	retval.width = 0;
	retval.height = 0;

	DebugStatement(L"SDL2.0ImageLoader: Loading image from memory.");

	if(tempIm)
	{
		SDL_LockSurface(tempIm);
		{
			if(tempIm->format->BytesPerPixel == 4)
			{
				int i;
				uint8_t *data = (uint8_t *)(tempIm->pixels);
				uint8_t *tempData = new uint8_t[tempIm->w * tempIm->h * 4];

				//For some reason images are loaded BGR on OSX. I really don't
				//know why...
#ifdef OSX
				for(i=0;i<(tempIm->w * tempIm->h);++i)
				{
					tempData[(i*4)+2] = data[(i*4)];
					tempData[(i*4)+1] = data[(i*4)+1];
					tempData[(i*4)] = data[(i*4)+2];
					tempData[(i*4)+3] = data[(i*4)+3];
				}
#else
				for(i=0;i<(tempIm->w * tempIm->h * 4);++i)
					tempData[i] = data[i];
#endif

				//Premultiply the alpha.
				{
					float alpha;
					float tempf;

					for(i=0;i<(tempIm->w * tempIm->h);++i)
					{
						alpha = (float)tempData[(i*4)+3]/255.0f;

						tempf = (float)tempData[(i*4)]/255.0f;
						tempData[(i*4)] = (uint8_t)(tempf * alpha * 255.0f);
						tempf = (float)tempData[(i*4)+1]/255.0f;
						tempData[(i*4)+1] = (uint8_t)(tempf * alpha * 255.0f);
						tempf = (float)tempData[(i*4)+2]/255.0f;
						tempData[(i*4)+2] = (uint8_t)(tempf * alpha * 255.0f);
					}
				}

				retval.data = tempData;
				retval.width = tempIm->w;
				retval.height = tempIm->h;

				successfulLoad = true;
			}
			//Assume 24-bit RGB.
			else if(tempIm->format->BytesPerPixel == 3)
			{
				int i;
				uint8_t *data = (uint8_t *)(tempIm->pixels);
				uint8_t *tempData = new uint8_t[tempIm->w * tempIm->h * 4];

				DebugStatement(L"SDL2.0ImageLoader: Image 24bit.  Assuming 24bit RGB format.");

				for(i=0;i<(tempIm->w * tempIm->h);++i)
				{
#ifdef OSX
					tempData[(i*4)+2] = data[(i*3)];
					tempData[(i*4)+1] = data[(i*3)+1];
					tempData[(i*4)] = data[(i*3)+2];
					tempData[(i*4)+3] = 255;
#else
					tempData[(i*4)] = data[(i*3)];
					tempData[(i*4)+1] = data[(i*3)+1];
					tempData[(i*4)+2] = data[(i*3)+2];
					tempData[(i*4)+3] = 255;
#endif
				}

				retval.data = tempData;
				retval.width = tempIm->w;
				retval.height = tempIm->h;

				successfulLoad = true;
			}
			else
				DebugStatement(L"SDL2.0ImageLoader: Could not load image. Image neither 32- or 24-bits.");
		}

		if(successfulLoad)
		{
			SDL_UnlockSurface(tempIm);
			SDL_FreeSurface(tempIm);

			DebugStatement(L"SDL2.0ImageLoader: Image loaded from memory.");
		}
		else
			DebugStatement(L"SDL2.0ImageLoader: Could not load image from memory.");
	}
	else
		DebugStatement(L"SDL2.0ImageLoader: Could not load image from memory.");

	if((retval.width > 1024) || (retval.height > 1024))
		DebugStatement(L"SDL2.0ImageLoader: Warning: image dimensions greater than 1024 (" << (unsigned int)retval.width << "x" << (unsigned int)retval.height << ")");

	return retval;
}

//------------------------------------------------------------------------------
ImageData ImageLoader::loadImage(const FilePath& path)
{
	string tempstr;
	ImageData retval;
	bool successfulLoad = false;
	UTF8File::wstringToChar(path.getPath().c_str(), tempstr);
	SDL_Surface *tempIm = IMG_Load(tempstr.c_str());

	retval.data = 0;
	retval.width = 0;
	retval.height = 0;

	DebugStatement(L"SDL2.0ImageLoader: Loading image from file: " << path.getPath());

	if(tempIm)
	{
		SDL_LockSurface(tempIm);
		{
			if(tempIm->format->BytesPerPixel == 4)
			{
				int i;
				uint8_t *data = (uint8_t *)(tempIm->pixels);
				uint8_t *tempData = new uint8_t[tempIm->w * tempIm->h * 4];

				//For some reason images are loaded BGR on OSX. I really don't
				//know why...
#ifdef OSX
				for(i=0;i<(tempIm->w * tempIm->h);++i)
				{
					tempData[(i*4)+2] = data[(i*4)];
					tempData[(i*4)+1] = data[(i*4)+1];
					tempData[(i*4)] = data[(i*4)+2];
					tempData[(i*4)+3] = data[(i*4)+3];
				}
#else
				for(i=0;i<(tempIm->w * tempIm->h * 4);++i)
					tempData[i] = data[i];
#endif

				//Premultiply the alpha.
				{
					float alpha;
					float tempf;

					for(i=0;i<(tempIm->w * tempIm->h);++i)
					{
						alpha = (float)tempData[(i*4)+3]/255.0f;

						tempf = (float)tempData[(i*4)]/255.0f;
						tempData[(i*4)] = (uint8_t)(tempf * alpha * 255.0f);
						tempf = (float)tempData[(i*4)+1]/255.0f;
						tempData[(i*4)+1] = (uint8_t)(tempf * alpha * 255.0f);
						tempf = (float)tempData[(i*4)+2]/255.0f;
						tempData[(i*4)+2] = (uint8_t)(tempf * alpha * 255.0f);
					}
				}

				retval.data = tempData;
				retval.width = tempIm->w;
				retval.height = tempIm->h;

				successfulLoad = true;
			}
			else if(tempIm->format->BytesPerPixel == 3)
			{
				int i;
				uint8_t *data = (uint8_t *)(tempIm->pixels);
				uint8_t *tempData = new uint8_t[tempIm->w * tempIm->h * 4];

				DebugStatement(L"SDL2.0ImageLoader: Image 24bit.  Assuming 24bit RGB format.");

				for(i=0;i<(tempIm->w * tempIm->h);++i)
				{
#ifdef OSX
					tempData[(i*4)+2] = data[(i*3)];
					tempData[(i*4)+1] = data[(i*3)+1];
					tempData[(i*4)] = data[(i*3)+2];
					tempData[(i*4)+3] = 255;
#else
					tempData[(i*4)] = data[(i*3)];
					tempData[(i*4)+1] = data[(i*3)+1];
					tempData[(i*4)+2] = data[(i*3)+2];
					tempData[(i*4)+3] = 255;
#endif
				}

				retval.data = tempData;
				retval.width = tempIm->w;
				retval.height = tempIm->h;

				successfulLoad = true;
			}
			else
				DebugStatement(L"SDL2.0ImageLoader: Could not load image. Image neither 32- or 24-bits.");
		}

		if(successfulLoad)
		{
			SDL_UnlockSurface(tempIm);
			SDL_FreeSurface(tempIm);

			DebugStatement(L"SDL2.0ImageLoader: Image loaded from file.");
		}
		else
			DebugStatement(L"SDL2.0ImageLoader: Could not load image from file.");
	}
	else
		DebugStatement(L"SDL2.0ImageLoader: Could not load image from file.");

	if((retval.width > 1024) || (retval.height > 1024))
		DebugStatement(L"SDL2.0ImageLoader: Warning: image (" << path.getPath().c_str() << ") dimensions greater than 1024 (" << (unsigned int)retval.width << "x" << (unsigned int)retval.height << ")");

	return retval;
}
