/* グラフィック処理関係 */

#include "bootpack.h"

unsigned short table_8_565[256];

static struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
static unsigned char table_rgb[16 * 3] = {
	0x00, 0x00, 0x00,	/*  0:黒 */
	0xff, 0x00, 0x00,	/*  1:明るい赤 */
	0x00, 0xff, 0x00,	/*  2:明るい緑 */
	0xff, 0xff, 0x00,	/*  3:明るい黄色 */
	0x00, 0x00, 0xff,	/*  4:明るい青 */
	0xff, 0x00, 0xff,	/*  5:明るい紫 */
	0x00, 0xff, 0xff,	/*  6:明るい水色 */
	0xff, 0xff, 0xff,	/*  7:白 */
	0xc6, 0xc6, 0xc6,	/*  8:明るい灰色 */
	0x84, 0x00, 0x00,	/*  9:暗い赤 */
	0x00, 0x84, 0x00,	/* 10:暗い緑 */
	0x84, 0x84, 0x00,	/* 11:暗い黄色 */
	0x00, 0x00, 0x84,	/* 12:暗い青 */
	0x84, 0x00, 0x84,	/* 13:暗い紫 */
	0x00, 0x84, 0x84,	/* 14:暗い水色 */
	0x84, 0x84, 0x84	/* 15:暗い灰色 */
};

void init_palette(void)
{
	int i, r, g, b;
	if (binfo->vmode == 8) {
		for (i = 0; i < 16; i++) {
			table_8_565[i] = i;
		}
		set_palette(0, 15, table_rgb);
		unsigned char table2[216 * 3];
		for (b = 0; b < 6; b++) {
			for (g = 0; g < 6; g++) {
				for (r = 0; r < 6; r++) {
					table2[(r + g * 6 + b * 36) * 3 + 0] = r * 51;
					table2[(r + g * 6 + b * 36) * 3 + 1] = g * 51;
					table2[(r + g * 6 + b * 36) * 3 + 2] = b * 51;
					table_8_565[r + g * 6 + b * 36 + 16] = r + g * 6 + b * 36 + 16;
				}
			}
		}
		set_palette(16, 231, table2);
	} else {
		for (i = 0; i < 16; i++) {
			r = table_rgb[i * 3 + 0];
			g = table_rgb[i * 3 + 1];
			b = table_rgb[i * 3 + 2];
			table_8_565[i] = (unsigned short) (((r << 8) & 0xf800) |
							 ((g << 3) & 0x07e0) | (b >> 3));
		}
		for (b = 0; b < 6; b++) {
			for (g = 0; g < 6; g++) {
				for (r = 0; r < 6; r++) {
					table_8_565[r + g * 6 + b * 36 + 16] =
						(unsigned short) ((((r * 51) << 8) & 0xf800) |
						(((g * 51) << 3) & 0x07e0) | ((b * 51) >> 3));
				}
			}
		}
	}
	return;
}

void set_palette(int start, int end, unsigned char *rgb)
{
	int i, eflags;
	eflags = io_load_eflags();	/* 割り込み許可フラグの値を記録する */
	io_cli(); 					/* 許可フラグを0にして割り込み禁止にする */
	io_out8(0x03c8, start);
	for (i = start; i <= end; i++) {
		io_out8(0x03c9, rgb[0] / 4);
		io_out8(0x03c9, rgb[1] / 4);
		io_out8(0x03c9, rgb[2] / 4);
		rgb += 3;
	}
	io_store_eflags(eflags);	/* 割り込み許可フラグを元に戻す */
	return;
}

void boxfill8(unsigned short *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{
	int x, y;
	for (y = y0; y <= y1; y++) {
		for (x = x0; x <= x1; x++)
			vram[y * xsize + x] = table_8_565[c];
	}
	return;
}


/***** 雑用 *****/
struct RGB getRGB8(unsigned char c)
{
	char base;
	struct RGB rgb;

	if (c <= 15) {
		rgb.r = table_rgb[c * 16 + 0];
		rgb.g = table_rgb[c * 16 + 1];
		rgb.b = table_rgb[c * 16 + 2];
		return rgb;
	}

	base = c - 16;
	rgb.r = base % 6;
	rgb.g = ((base % 36) - rgb.r) / 6;
	rgb.b = (base - rgb.g * 6 - rgb.r) / 36;

	rgb.r *= 51;
	rgb.g *= 51;
	rgb.b *= 51;

	return rgb;
}

struct RGB getRGB16(unsigned short c)
{
	struct RGB rgb;

	rgb.r = (c & 0xf800) >> 8;
	rgb.g = (c & 0x07e0) >> 3;
	rgb.b = (c & 0x001f) << 3;

	return rgb;
}

struct RGB getRGBA(unsigned int c)
{
	if (binfo->vmode == 8)
		return getRGB8((unsigned char) c);
	return getRGB16((unsigned short) c);
}


/***** Auto色調節描画関数 *****/

struct RGB getpixelA(void *vram, int xsize, int x, int y)
{
	struct RGB rgb;
	if (binfo->vmode == 8) {
		char *buf;
		buf = vram;
		rgb = getRGB8(buf[y * xsize + x]);
	} else {
		short *buf;
		buf = vram;
		rgb = getRGB16(buf[y * xsize + x]);
	}
	return rgb;
}

void setpixelA(void *vram, int xsize, int r, int g, int b, int x, int y)
{
	if (binfo->vmode == 8) {
		char c, *buf;
		c = 16 + (r / 51) + (g / 51) * 6 + (b / 51) * 36;
		buf = vram;
		buf[y * xsize + x] = c;
	} else {
		short c, *buf;
		c = (((r << 8) & 0xf800) | ((g << 3) & 0x07e0) | (b >> 3));
		buf = vram;
		buf[y * xsize + x] = c;
	}
}

void boxfillA(void *vram, int xsize, int r, int g, int b, int x0, int y0, int x1, int y1)
{
	int x, y;
	for (y = y0; y <= y1; y++) {
		for (x = x0; x <= x1; x++) {
			setpixelA(vram, xsize, r, g, b, x, y);
		}
	}
	return;
}

int loadimageA(void *vram, char *filename, int x, int y, int bufx, int *fat)
{
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
	unsigned char *filebuf, r, g, b;
	struct DLL_STRPICENV env;
	struct RGB *picbuf;
	int info[8], fsize, xx, yy;
	struct FILEINFO *finfo = file_search(filename, (struct FILEINFO *) (ADR_DISKIMG + 0x002600), 224);

	if (finfo != 0) {
		fsize   = finfo->size;
		filebuf = (unsigned char *) memman_alloc_4k(memman, fsize);
		filebuf = file_loadfile2(finfo->clustno, &fsize, fat);
		if (info_JPEG(&env, info, fsize, filebuf) == 0) {
			return 0;
		}
		picbuf = (struct RGB *) memman_alloc_4k(memman, info[2] * info[3] * sizeof(struct RGB));
		decode0_JPEG(&env, fsize, filebuf, 4, (unsigned char *) picbuf, 0);
		for (yy = 0; yy < info[3]; yy++) {
			for (xx = 0; xx < info[2]; xx++) {
				r = picbuf[yy * info[2] + xx].r;
				g = picbuf[yy * info[2] + xx].g;
				b = picbuf[yy * info[2] + xx].b;
				setpixelA(vram, bufx, r, g, b, x + xx, y + yy);
			}
		}
	} else {
		return 0;
	}
	return 1;
}

void putfontA(void *vram, int xsize, int x, int y, int r, int g, int b, char *font)
{
	int i;
	char d;
	for (i = 0; i < 16; i++) {
		d = font[i];
		if ((d & 0x80) != 0) setpixelA(vram, xsize, r, g, b, x+0, y + i);
		if ((d & 0x40) != 0) setpixelA(vram, xsize, r, g, b, x+1, y + i);
		if ((d & 0x20) != 0) setpixelA(vram, xsize, r, g, b, x+2, y + i);
		if ((d & 0x10) != 0) setpixelA(vram, xsize, r, g, b, x+3, y + i);
		if ((d & 0x08) != 0) setpixelA(vram, xsize, r, g, b, x+4, y + i);
		if ((d & 0x04) != 0) setpixelA(vram, xsize, r, g, b, x+5, y + i);
		if ((d & 0x02) != 0) setpixelA(vram, xsize, r, g, b, x+6, y + i);
		if ((d & 0x01) != 0) setpixelA(vram, xsize, r, g, b, x+7, y + i);
	}
	return;
}

void putstringA(void *vram, int xsize, int x, int y, int r, int g, int b, unsigned char *s)
{
	extern char hankaku[4096];
	struct TASK *task = task_now();
	char *nihongo = (char *) *((int *) 0x0fe8), *font;
	int k, t;

	if (task->langmode == 0) {
		for (; *s != 0x00; s++) {
			putfontA(vram, xsize, x, y, r, g, b, hankaku + *s * 16);
			x += 8;
		}
	}
	if (task->langmode == 1) {
		for (; *s != 0x00; s++) {
			if (task->langbyte1 == 0) {
				if ((0x81 <= *s && *s <= 0x9f) || (0xe0 <= *s && *s <= 0xfc)) {
					task->langbyte1 = *s;
				} else {
					putfontA(vram, xsize, x, y, r, g, b, nihongo + *s * 16);
				}
			} else {
				if (0x81 <= task->langbyte1 && task->langbyte1 <= 0x9f) {
					k = (task->langbyte1 - 0x81) * 2;
				} else {
					k = (task->langbyte1 - 0xe0) * 2 + 62;
				}
				if (0x40 <= *s && *s <= 0x7e) {
					t = *s - 0x40;
				} else if (0x80 <= *s && *s <= 0x9e) {
					t = *s - 0x80 + 63;
				} else {
					t = *s - 0x9f;
					k++;
				}
				task->langbyte1 = 0;
				font = nihongo + 256 * 16 + (k * 94 + t) * 32;
				putfontA(vram, xsize, x - 8, y, r, g, b, font     );	/* 左半分 */
				putfontA(vram, xsize, x    , y, r, g, b, font + 16);	/* 右半分 */
			}
			x += 8;
		}
	}
	return;
}

void putblockA(void *vram, int vxsize, int pxsize, int pysize, int px0, int py0,
			   void *buf, int bxsize)
{
	int x, y;
	for (y = 0; y < pysize; y++) {
		for (x = 0; x < pxsize; x++) {
			if (binfo->vmode == 8) {
				char *p, *q;
				p = vram;
				q = buf;
				p[(py0 + y) * vxsize + (px0 + x)] = q[y * bxsize + x];
			} else {
				short *p, *q;
				p = vram;
				q = buf;
				p[(py0 + y) * vxsize + (px0 + x)] = q[y * bxsize + x];
			}
		}
	}
	return;
}

void init_mouse_cursor(short *mouse, char bc)
/* マウスカーソルを準備（16x16） */
{
	static char cursor[16][16] = {
		"**..............",
		"*O*.............",
		"*OO*............",
		"*OOO*...........",
		"*OOOO*..........",
		"*OOOOO*.........",
		"*OOOOOO*........",
		"*OOOOOOO*.......",
		"*OOOOOOOO*......",
		"*OOOOO*****.....",
		"*OO*OO*.........",
		"*O*.*OO*........",
		"**..*OO*........",
		"*....*OO*.......",
		".....*OO*.......",
		"......**........"
	};
	int x, y;

	for (y = 0; y < 16; y++) {
		for (x = 0; x < 16; x++) {
			if (cursor[y][x] == '*') {
				setpixelA(mouse, 16, COLA_000000, x, y);
			}
			if (cursor[y][x] == 'O') {
				setpixelA(mouse, 16, COLA_FFFFFF, x, y);
			}
			if (cursor[y][x] == '.') {
				struct RGB rgb;
				rgb = getRGB8(bc);
				setpixelA(mouse, 16, COLA_RGB(rgb), x, y);
			}
		}
	}
	return;
}

void init_mouse_cursor_hide(short *mouse, char bc)
/* マウスカーソルを消す（16x16） */
{
	int x, y;

	for (y = 0; y < 16; y++) {
		for (x = 0; x < 16; x++) {
			struct RGB rgb;
			rgb = getRGB8(bc);
			setpixelA(mouse, 16, COLA_RGB(rgb), x, y);
		}
	}
	return;
}
