#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];
}


