/**
画像読み込み、pngファイル書き込み
*/
module coneneko.image;
import
	std.string,
	std.c.string,
	std.windows.charset,
	sdl,
	sdl_image;

extern (C)
{
	void readAndDeletePngReader(void* handle, void* buffer);
	void* createAndGetSizePngReader(char* pngFileName, uint* width, uint* height); // TODO const
	bool writePngWriter(char* fileName, void* buffer, uint width, uint height); // TODO const
}

// writePngに対するテスト用、r8g8b8a8だけ対応、PNG_COLOR_TYPE_RGB_ALPHAとPNG_COLOR_TYPE_RGBを読める
private uint[] readPng(string pngFileName, out uint width, out uint height)
{
	void* handle = createAndGetSizePngReader(cast(char*)pngFileName.toStringz(), &width, &height); // d2
	assert(handle);
	uint[] result = new uint[width * height];
	readAndDeletePngReader(handle, result.ptr);
	return result;
}

///
void writePng(string pngFileName, uint[] buffer, uint width, uint height)
{
	auto b = writePngWriter(cast(char*)pngFileName.toStringz(), cast(uint*)buffer.ptr, width, height); // d2
	assert(b);
}

version (PNG_FILE_TEST_MAIN)
{
	import std.stdio;
	
	void main()
	{
		writePngTest();
		readPngTest();
	}
	
	uint toColor(ubyte r, ubyte g, ubyte b, ubyte a)
	{
		ubyte[4] result;
		result[0] = r;
		result[1] = g;
		result[2] = b;
		result[3] = a;
		return *(cast(uint*)&result[0]);
	}
	
	uint[] testData(out uint width, out uint height)
	{
		const uint WIDTH = 256, HEIGHT = 256;
		width = WIDTH;
		height = HEIGHT;
		uint[] result = new uint[WIDTH * HEIGHT];
		for (int y = 0; y < HEIGHT; y++)
		{
			for (int x = 0; x < WIDTH; x++)
			{
				result[y * WIDTH + x] = toColor(cast(ubyte)x, cast(ubyte)y, 255, 255);
			}
		}
		return result;
	}
	
	void writePngTest()
	{
		uint width, height;
		uint[] data = testData(width, height);
		writePng("pngtest2.png", data, width, height);
		writefln("writePngTest end");
	}
	
	void readPngTest()
	{
		uint width, height, width2, height2;
		uint[] buffer = readPng("pngtest2.png", width, height);
		uint[] data = testData(width2, height2);
		assert(width2 == width);
		assert(height2 == height);
		for (int i = 0; i < data.length; i++)
		{
			assert(data[i] == buffer[i]);
		}
		writefln("readPngTest end");
	}
}

uint[] createRgba32Pixels(SDL_Surface* surface)
{
	SDL_PixelFormat format = rgba32PixelFormat;
	surface = SDL_ConvertSurface(surface, &format, SDL_SWSURFACE);
	uint[] result = new uint[surface.w * surface.h];
	memcpy(result.ptr, surface.pixels, uint.sizeof * result.length);
	return result;
}

private SDL_PixelFormat rgba32PixelFormat()
{
	SDL_PixelFormat result;
	with (result)
	{
		palette = null;
		BitsPerPixel = 32;
		BytesPerPixel = 4;
		Rmask = 0xff;
		Gmask = 0xff00;
		Bmask = 0xff0000;
		Amask = 0xff000000;
		Rshift = 0;
		Gshift = 8;
		Bshift = 16;
		Ashift = 24;
		Rloss = Gloss = Bloss = Aloss = 0;
		colorkey = 0;
		alpha = 255;
	}
	return result;
}

private string getSdlError()
{
	return std.string.toString(SDL_GetError());
}

uint[] readImage(string fileName, out uint width, out uint height) ///
{
	SDL_Surface* image = IMG_Load(cast(char*)toMBSz(fileName));
	if (!image) throw new Exception("readImage:\"" ~ fileName ~ "\" " ~ getSdlError());
	width = image.w;
	height = image.h;
	uint[] result = createRgba32Pixels(image);
	SDL_FreeSurface(image);
	return result;
}
