// png2gpn.cpp 
//

#include "stdafx.h"

#ifndef MAX_PATH
#define MAX_PATH 260
#endif

struct StImage {
	int signature;
	int version;
	short width;
	short height;
	int size;
	unsigned int data[1];
};

struct StOption {
	bool use_alpha;
	bool verbose;
} g_option;

enum _errors {
	ERROR_NOERROR,
	ERROR_FOPEN,
	ERROR_DECODE,
	ERROR_NOMEMORY,
	ERROR_UNKNOWN_OPTION,
	COUNT_OF_ERROR
};

char g_szErrorBuf[1024] = "";

int processFile(const char *file)
{
	class Finalizer {
	public:
		Finalizer() {
			fp = NULL;
			buf = NULL;
			img = NULL;
		}
		~Finalizer() {
			if (fp) {
				fclose(fp);
			}
			if (fp) {
				fclose(fp);
			}
			if (buf) {
				delete[] buf;
			}
			if (img) {
				gdImageDestroy(img);
			}
		}
		FILE *fp;
		unsigned char *buf;
		gdImagePtr img;
	} obj;

	FILE *fp = fopen(file, "r");
	if (!fp) {
		printf("Filename: %s\n", file);
		return ERROR_FOPEN;
	}
	obj.fp = fp;

	gdImagePtr img = gdImageCreateFromPng(fp);
	if (!img) {
		return ERROR_DECODE;
	}
	obj.img = img;

	fclose(fp);
	obj.fp = NULL;

	int bytes_per_pixel = g_option.use_alpha ? 4 : 2;
	int size = sizeof (StImage) - 4 + bytes_per_pixel * gdImageSX(img) * gdImageSY(img);
	unsigned char *buf = new unsigned char[size];
	if (!buf) {
		return ERROR_NOMEMORY;
	}
	obj.buf = buf;

	StImage *gpn = (StImage *)buf;
	gpn->signature = *(int *)"gpng";
	gpn->version = g_option.use_alpha ? 1 : 0;
	gpn->width = gdImageSX(img);
	gpn->height = gdImageSY(img);
	gpn->size = size;

	unsigned short *p = (unsigned short *)gpn->data;
	unsigned int pixel;

	for (int y = 0; y < gpn->height; y++) {
		for (int x = 0; x < gpn->width; x++) {
			int color = gdImageGetPixel(img, x, y);
			int r = gdTrueColorGetRed(color);
			int g = gdTrueColorGetGreen(color);
			int b = gdTrueColorGetBlue(color);
			int a = 255 - (gdTrueColorGetAlpha(color) << 1);

			if (g_option.use_alpha) {
				pixel = (b>>3<<10) | (g>>3<<21) | (r>>3) | ((a + 1)>>3<<15);
				*(unsigned int *)p = pixel;
				p += 2;
			} else {
				pixel = (b>>3<<10)|(g>>3<<5)|(r>>3)|(1<<15);
				*p = (unsigned short)pixel;
				p++;
			}

			if (g_option.verbose) {
				char bits[33];
				int i = 0;
				unsigned int mask = g_option.use_alpha ? 0x80000000 : 0x8000;
				for (; mask; i++, mask >>= 1) {
					bits[i] = (pixel & mask) ? '1' : '0';
				}
				bits[i] = 0;
				printf("(%3d,%3d) %02X.%02X,%02X/%02X %08X=%s\n", x, y, r, g, b, a, pixel, bits);
			}
		}
	}

	char szOutName[MAX_PATH];
	strcpy(szOutName, file);
	char *dot = strrchr(szOutName, '.');
	if (!dot) {
		dot = szOutName + strlen(szOutName);
	}
	strcpy(dot, ".gpn");

	fp = fopen(szOutName, "w");
	if (!fp) {
		return ERROR_FOPEN;
	}
	obj.fp = fp;

	fwrite(buf, size, 1, fp);

	return 0;
}

int main(int argc, char *argv[])
{
	memset(&g_option, 0, sizeof (g_option));

	int i, ret;

	for (i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			switch (argv[i][1]) {
			case 'a':
				g_option.use_alpha = true;
				continue;
			case 'n':
				g_option.use_alpha = false;
				continue;
			case 'v':
				g_option.verbose = true;
				continue;
			}

			ret = ERROR_UNKNOWN_OPTION;
			strcpy(g_szErrorBuf, "Unknown option");
		} else {
			ret = processFile(argv[i]);
		}

		if (ret != 0) {
			printf("Error(%d) %s: %s\n", ret, g_szErrorBuf, argv[i]);
			return ret;
		}
	}

	return 0;
}





