#include "../bootpack.h"

void IDraw::line(int x0, int y0, int x1, int y1, color_16 color) {
	int i, x, y, len, dx, dy;
	dx = x1 - x0;
	dy = y1 - y0;
	x = x0 << 10;
	y = y0 << 10;
	dx = dx < 0 ? - dx : dx;
	dy = dy < 0 ? - dy : dy;
	if (dx >= dy) {
		len = dx + 1;
		dx = x0 > x1 ? -1024 : 1024;
		dy = y0 <= y1 ? ((y1 - y0 + 1) << 10) / len : ((y1 - y0 - 1) << 10) / len;
	} else {
		len = dy + 1;
		dy = y0 > y1 ? -1024 : 1024;
		dx = x0 <= x1 ? ((x1 - x0 + 1) << 10) / len : ((x1 - x0 - 1) << 10) / len;
	}
	
	for (i = 0; i < len; i++) {
		point(x >> 10, y >> 10, color);
		x += dx;
		y += dy;
	}
}

void IDraw::box(int x0, int y0, int x1, int y1, color_16 color) {
	int x_org = x0;
	for (; y0 <= y1; y0++) {
		for (x0 = x_org; x0 <= x1; x0++) {
			point(x0, y0, color);
		}
	}
}

void IDraw::putchar(int x, int y, byte c, color_16 color,
			Font* font) {
	Font& rfont = *font; // 参照型に直す （いちいち->と書くのが面倒なため）
	int x_bytes = ((rfont.getxsize() + 0x07) & 0xf8) >> 3;
	int i, j, cnt;
	const byte* rfont_c = rfont.getptr()
		+ c * (x_bytes) * rfont.getysize();
	byte d = 0;
	/*
	 * 前提となるフォントの構造
	 * 
	 * 横サイズが8の倍数でないとき、8の倍数にそろえられて格納されている
	 * （たとえばOSAKKIEのminirfont）
	 * 
	 * (((横サイズ + 0x07) & 0xf8) * 縦サイズ / 8) で1文字分が何バイトなのかが
	 * 分かる
	 * 
	 * さらに、フォントは右詰である必要がある
	 */
	for (j = 0; j < rfont.getysize(); j++) {
		for (i = rfont.getxsize() - 1, cnt = 0; i >= 0; i--, cnt++) {
			if ((cnt & 0x07) == 0) {
				// cntが0又は8の倍数
				d = rfont_c[(j * x_bytes) + (cnt >> 3)];
			}
			if (d & 0x01) { point(x + i, y + j, color); }
			d = d >> 1;
		}
	}
}

void IDraw::putchar_expand(int x, int y, byte c, color_16 color,
			dword expand, Font* font) {
	// 拡大表示版putchar
	Font& rfont = *font; // 参照型に直す （いちいち->と書くのが面倒なため）
	int x_bytes = ((rfont.getxsize() + 0x07) & 0xf8) >> 3;
	int i, j, cnt, xpos = x, ypos = y, x_next, y_next;
	const byte* rfont_c = rfont.getptr()
		+ c * (x_bytes) * rfont.getysize();
	byte d = 0;
	/*
	 * 前提となるフォントの構造
	 * 
	 * 横サイズが8の倍数でないとき、8の倍数にそろえられて格納されている
	 * （たとえばOSAKKIEのminirfont）
	 * 
	 * (((横サイズ + 0x07) & 0xf8) * 縦サイズ / 8) で1文字分が何バイトなのかが
	 * 分かる
	 * 
	 * さらに、フォントは右詰である必要がある
	 */
	for (j = 0; j < rfont.getysize(); j++) {
		for (i = rfont.getxsize() - 1, cnt = 0; i >= 0; i--, cnt++) {
			if ((cnt & 0x07) == 0) {
				// cntが0又は8の倍数
				d = rfont_c[(j * x_bytes) + (cnt >> 3)];
			}
			if (d & 0x01) {
				x = i * expand >> 20;
				y = j * expand >> 20;
				x_next = (i + 1) * expand >> 20;
				y_next = (j + 1) * expand >> 20;
				box(x + xpos, y + ypos, x_next + xpos - 1, y_next + ypos - 1, color);
			}
			d = d >> 1;
		}
	}
}

void IDraw::putstr(int x, int y, const char* str, color_16 color,
			Font* font) {
	Font& rfont = *font;
	int i;
	for (i = 0; str[i] != '\0'; i++) {
		// rfontは参照で、fontはポインタなので、使い分けがごっちゃにならないように！
		putchar(x + i * rfont.getxsize(), y, str[i], color, font);
	}
}

void IDraw::putstr_expand(int x, int y, const char* str, color_16 color,
			dword expand, Font* font) {
	Font& rfont = *font;
	int i;
	for (i = 0; str[i] != '\0'; i++) {
		// rfontは参照で、fontはポインタなので、使い分けがごっちゃにならないように！
		putchar_expand(x + ((i * rfont.getxsize() * expand) >> 20), y, str[i], color, expand, font);
	}
}

void IDraw::putpict(int xpos, int ypos, const IDraw& pict,
			int x0, int y0, int x1, int y1) {
	int x, y;
	if (x1 == -1) { x1 = pict.get_xsize(); }
	if (y1 == -1) { x1 = pict.get_ysize(); }
	for (y = y0; y < y1; y++) {
		for (x = x0; x < x1; x++) {
			point(xpos + x, ypos + y,
				pict.get_color(x, y)
				);
		}
	}
}




Screen::Screen(IVideo* video_driver, int xsize, int ysize)
{
	xsize_ = xsize;
	ysize_ = ysize;
	vdrv_ = video_driver;
}

inline void Screen::point(int x, int y, color_16 color) {
	vdrv_->WritePoint(x, y, color);
}

inline color_16 Screen::get_color(int x, int y) const {
	return vdrv_->GetPoint(x, y);
}


Picture::Picture()
{
	xsize_ = 0;
	ysize_ = 0;
	buffer_ = NULL;
}

Picture::Picture(int xsize, int ysize)
{
	xsize_ = xsize;
	ysize_ = ysize;
	buffer_ = NULL;
	init(xsize_, ysize_);
}

Picture::Picture(const Picture& pict)
{
	dword i;
	xsize_ = pict.get_xsize();
	ysize_ = pict.get_ysize();
	buffer_ = new color_16[xsize_ * ysize_];
	if (buffer_ != NULL) {
		for (i = 0; i < (dword) xsize_ * ysize_; i++) {
			buffer_[i] = pict.buffer_[i];
		}
	}
}

Picture::~Picture()
{
	if (buffer_ != NULL) {
		delete[] buffer_;
	}
}

void Picture::init(int xsize, int ysize)
{
	dword i;
	if (buffer_ != NULL) {
		delete[] buffer_;
		buffer_ = NULL;
	}
	xsize_ = xsize;
	ysize_ = ysize;
	buffer_ = new color_16[xsize_ * ysize_];
	if (buffer_ != NULL) {
		for (i = 0; i < (dword) xsize_ * ysize_; i++) {
			// 黒で初期化
			buffer_[i] = 0x0000;
		}
	}
}

inline void Picture::point(int x, int y, color_16 color) {
	buffer_[y * xsize_ + x] = color;
}

inline color_16 Picture::get_color(int x, int y) const {
	return buffer_[y * xsize_ + x];
}




void system::init_palette()
{
	byte* table2 = new byte[216 * 3];
	int r, g, b;
	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;
			}
		}
	}
	set_palette(0, 215, table2);
	delete[] table2;
	return;
}

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


color_16 system::mixC(color_32 color1, color_32 color2, int color1_ratio, int color2_ratio)
{
	// 色を合成する
	byte r, g, b;
	byte r1, g1, b1;
	byte r2, g2, b2;
/*	r1 = (color1 & 0xf800) >> 8;
	g1 = (color1 & 0x07e0) >> 3;
	b1 = (color1 & 0x001f) << 3;
	r2 = (color2 & 0xf800) >> 8;
	g2 = (color2 & 0x07e0) >> 3;
	b2 = (color2 & 0x001f) << 3;
*/
	r1 = (color1 & 0xff0000) >> 16;
	g1 = (color1 & 0x00ff00) >> 8;
	b1 = (color1 & 0x0000ff);
	r2 = (color2 & 0xff0000) >> 16;
	g2 = (color2 & 0x00ff00) >> 8;
	b2 = (color2 & 0x0000ff);
	r = (r1 * color1_ratio + r2 * color2_ratio) / (color1_ratio + color2_ratio);
	g = (g1 * color1_ratio + g2 * color2_ratio) / (color1_ratio + color2_ratio);
	b = (b1 * color1_ratio + b2 * color2_ratio) / (color1_ratio + color2_ratio);
	return convC(r << 16 | g << 8 | b);
}

