/***************************************************************************

	usrintrf.c

	PSP user interface draw functions.

***************************************************************************/

#include "psp.h"


/***************************************************************************
	Helper macros
 **************************************************************************/

#define vram_pos16(x, y)	video_frame_addr(draw_frame, x, y)
#define vram_pixel16(x, y)	*vram_pos(x, y)

#define vram_pos32(x, y)	video_frame_addr32(draw_frame, x, y)
#define vram_pixel32(x, y)	*vram_pos32(x, y)

#define CMD_RED				(1 << 8)
#define CMD_YELLOW			(2 << 8)
#define CMD_GREEN			(3 << 8)
#define CMD_BLUE			(4 << 8)
#define CMD_MAGENTA			(5 << 8)
#define CMD_PURPLE			(6 << 8)
#define CMD_ORANGE			(7 << 8)
#define CMD_GRAY			(8 << 8)
#define CMD_CYAN			(9 << 8)
#define CMD_PINK			(10 << 8)

#define CODE_HASCOLOR(c)	(c & 0xff00)
#define CODE_NOTFOUND		0xffff

#define isascii(c)	((c) >= 0x20 && (c) <= 0x7e)
#define islatin1(c)	((c) >= 0x80)
#define iskana(c)	((c) >= 0xa0 && (c) <= 0xdf)
#define issjis1(c)	(((c) >= 0x81 && (c) <= 0x9f) | ((c) >= 0xe0 && (c) <= 0xfc))
#define issjis2(c)	((c) >= 0x40 && (c) <= 0xfc && (c) != 0x7f)

enum
{
	FONT_TYPE_CONTROL = 0,
	FONT_TYPE_ASCII,
	FONT_TYPE_LATIN1,
	FONT_TYPE_JPNHAN,
	FONT_TYPE_JPNZEN,
	FONT_TYPE_COMMAND,
	FONT_TYPE_GRAPHIC,
	FONT_TYPE_MAX
};


/***************************************************************************
	Global structures and variables
 **************************************************************************/

UI_PALETTE ui_palette[UI_PAL_MAX];


/***************************************************************************
	Private structures and variables
 **************************************************************************/

static int light_level = 0;

static u32 command_font_color[11] =
{
	MAKECOL32(255,255,255),
	MAKECOL32(255, 32,  0),
	MAKECOL32(255,200,  0),
	MAKECOL32(  0,200, 80),
	MAKECOL32(  0, 64,255),
	MAKECOL32(255,  0,128),
	MAKECOL32(200,  0,200),
	MAKECOL32(255,128,  0),
	MAKECOL32(160,160,160),
	MAKECOL32( 64,200,200),
	MAKECOL32(255, 64,128)
};


/***************************************************************************
	フォントコード取得
 **************************************************************************/

/*------------------------------------------------------
	フォントコード取得 (コマンドリスト用)
 -----------------------------------------------------*/

u16 command_font_get_code(const u8 *s)
{
	u8 c1 = s[0];
	u8 c2 = s[1];

	if (c1 == '_')
	{
		switch (c2)
		{
		case 'A': return 0x00 | CMD_RED;
		case 'B': return 0x01 | CMD_YELLOW;
		case 'C': return 0x02 | CMD_GREEN;
		case 'D': return 0x03 | CMD_BLUE;
		case 'P': return 0x04 | CMD_MAGENTA;
		case 'K': return 0x05 | CMD_PURPLE;
		case 'G': return 0x07 | CMD_BLUE;
		case 'H': return 0x08 | CMD_PINK;
		case 'Z': return 0x09 | CMD_PURPLE;

		case 'S': return 0x14 | CMD_RED;

		case 'a': return 0x16 | CMD_RED;
		case 'b': return 0x17 | CMD_YELLOW;
		case 'c': return 0x18 | CMD_GREEN;
		case 'd': return 0x19 | CMD_BLUE;
		case 'e': return 0x1a | CMD_MAGENTA;
		case 'f': return 0x1b | CMD_PURPLE;
		case 'g': return 0x1c | CMD_CYAN;
		case 'h': return 0x1d | CMD_PINK;
		case 'i': return 0x1e | CMD_ORANGE;
		case 'j': return 0x1f | CMD_GRAY;

		case '1': return 0x20;
		case '2': return 0x21;
		case '3': return 0x22;
		case '4': return 0x23;
		case '5': return 0x24 | CMD_RED;
		case '6': return 0x25;
		case '7': return 0x26;
		case '8': return 0x27;
		case '9': return 0x28;
		case 'N': return 0x29;
		case '+': return 0x2a;
		case '.': return 0x2b;

		case '!': return 0x35;

		case 'k': return 0x36;
		case 'l': return 0x37;
		case 'm': return 0x38;
		case 'n': return 0x39;
		case 'o': return 0x3a;
		case 'p': return 0x3b;
		case 'q': return 0x3c;
		case 'r': return 0x3d;
		case 's': return 0x3e;
		case 't': return 0x3f;
		case 'u': return 0x40;
		case 'v': return 0x41;

		case 'w': return 0x42;
		case 'x': return 0x43;
		case 'y': return 0x44;
		case 'z': return 0x45;
		case 'L': return 0x46;
		case 'M': return 0x47;
		case 'Q': return 0x48;
		case 'R': return 0x49;
		case '^': return 0x4a;
		case '?': return 0x4b;
		case 'X': return 0x4c;

		case 'I': return 0x4e;
		case 'O': return 0x4f;
		case '-': return 0x50;
		case '=': return 0x51;
		case '~': return 0x54;
		case '`': return 0x57;

		case '@': return 0x58;
		case ')': return 0x59;
		case '(': return 0x5a;
		case '*': return 0x5b;
		case '&': return 0x5c;
		case '%': return 0x5d;
		case '$': return 0x5e;
		case '#': return 0x5f;
		case ']': return 0x60;
		case '[': return 0x61;
		case '{': return 0x62;
		case '}': return 0x63;
		case '<': return 0x64;
		case '>': return 0x65;
		}
	}
	else if (c1 == '^')
	{
		switch (c2)
		{
		case 's': return 0x06 | CMD_ORANGE;
		case 'E': return 0x0a | CMD_YELLOW;
		case 'F': return 0x0b | CMD_ORANGE;
		case 'G': return 0x0c | CMD_RED;
		case 'H': return 0x0d | CMD_GRAY;
		case 'I': return 0x0e | CMD_CYAN;
		case 'J': return 0x0f | CMD_BLUE;
		case 'T': return 0x10 | CMD_PURPLE;
		case 'U': return 0x11 | CMD_MAGENTA;
		case 'V': return 0x12 | CMD_PURPLE;
		case 'W': return 0x13 | CMD_MAGENTA;
		case 'S': return 0x15 | CMD_YELLOW;

		case '1': return 0x2c;
		case '2': return 0x2d;
		case '3': return 0x2e;
		case '4': return 0x2f;
		case '6': return 0x30;
		case '7': return 0x31;
		case '8': return 0x32;
		case '9': return 0x33;
		case '!': return 0x34;

		case 'M': return 0x4d;

		case '-': return 0x52;
		case '=': return 0x53;
		case '*': return 0x55;
		case '?': return 0x56;
		}
	}
	return CODE_NOTFOUND;
}


/*------------------------------------------------------
	フォントコード取得 (Latin-1デコード)
 -----------------------------------------------------*/

u16 latin1_get_code(const u8 *s, int *type)
{
	u16 code;

	if ((code = command_font_get_code(s)) != CODE_NOTFOUND)
	{
		*type = FONT_TYPE_COMMAND;
		return code;
	}
	else if (isascii(*s))
	{
		*type = FONT_TYPE_ASCII;
		return *s - 0x20;
	}
	else if (islatin1(*s))
	{
		*type = FONT_TYPE_LATIN1;
		return *s - 0x80;
	}
	*type = FONT_TYPE_CONTROL;
	return *s;
}


/*------------------------------------------------------
	フォントコード取得 (SHIFT-JISデコード)
 -----------------------------------------------------*/

u16 sjis_get_code(const u8 *s, int *type)
{
	u8 c1 = s[0];
	u8 c2 = s[1];
	u16 code;

	if ((code = command_font_get_code(s)) != CODE_NOTFOUND)
	{
		*type = FONT_TYPE_COMMAND;
		return code;
	}
	else if (issjis1(c1) && issjis2(c2))
	{
		*type = FONT_TYPE_JPNZEN;
		return sjis_table[(c2 | (c1 << 8)) - 0x8140];
	}
	else if (isascii(c1))
	{
		if (c1 != '\\')
		{
			*type = FONT_TYPE_ASCII;
			return c1 - 0x20;
		}
		else
		{
			*type = FONT_TYPE_JPNHAN;
			return 0;
		}
	}
	else if (iskana(c1))
	{
		*type = FONT_TYPE_JPNHAN;
		return c1 - 0xa0;
	}
	*type = FONT_TYPE_CONTROL;
	return c1;
}


/*------------------------------------------------------
	フォントコード取得 (ユーザインタフェース)
 -----------------------------------------------------*/

#if JAPANESE_UI
INLINE u16 uifont_get_code(const u8 *s, int *type)
{
	u8 c1 = s[0];
	u8 c2 = s[1];
	u16 code;

	if (issjis1(c1) && issjis2(c2))
	{
		*type = FONT_TYPE_JPNZEN;
		return sjis_table[(c2 | (c1 << 8)) - 0x8140];
	}
	else if (c1 == 0x5c)
	{
		*type = FONT_TYPE_JPNHAN;
		return 0;
	}
	else if (iskana(c1))
	{
		*type = FONT_TYPE_JPNHAN;
		return c1 - 0xa0;
	}
	else if (isascii(c1))
	{
		*type = FONT_TYPE_ASCII;
		return c1 - 0x20;
	}
	else if ((c1 >= 0x10 && c1 <= 0x1e) && c1 != 0x1a)
	{
		*type = FONT_TYPE_GRAPHIC;
		if (c1 < 0x1a)
			return c1 - 0x10;
		else
			return c1 - 0x11;
	}
	*type = FONT_TYPE_CONTROL;
	return c1;
}
#else
INLINE u16 uifont_get_code(const u8 *s, int *type)
{
	u8 *p = (u8 *)s;

	if (isascii(*p))
	{
		*type = FONT_TYPE_ASCII;
		return *p - 0x20;
	}
	else if (*p == 0xa5)
	{
		*type = FONT_TYPE_ASCII;
		return 0x7f - 0x20;
	}
	else if ((*p >= 0x10 && *p <= 0x1e) && *p != 0x1a)
	{
		*type = FONT_TYPE_GRAPHIC;
		if (*p < 0x1a)
			return *p - 0x10;
		else
			return *p - 0x11;
	}
	*type = FONT_TYPE_CONTROL;
	return *s;
}
#endif


/***************************************************************************
	フォント文字幅取得
 **************************************************************************/

/*------------------------------------------------------
	フォント描画幅取得 (ユーザインタフェース)
 -----------------------------------------------------*/

int uifont_get_string_width(const char *s)
{
	int width, type;
	u16 code;
	u8 *p = (u8 *)s;

	width = 0;

	while (*p)
	{
		if ((code = uifont_get_code(p, &type)) != CODE_NOTFOUND)
		{
			switch (type)
			{
			case FONT_TYPE_ASCII:
				width += ascii_14p_get_pitch(code);
				p++;
				break;

			case FONT_TYPE_GRAPHIC:
				width += graphic_font_get_pitch(code);
				p++;
				break;

#if JAPANESE_UI
			case FONT_TYPE_JPNHAN:
				width += jpn_h14p_get_pitch(code);
				p += 2;
				break;

			case FONT_TYPE_JPNZEN:
				width += jpn_z14p_get_pitch(code);
				p += 2;
				break;
#endif

			case FONT_TYPE_CONTROL:
				width += ascii_14p_get_pitch(0);
				p++;
				break;

			}
		}
		else break;
	}

	return width;
}


/**************************************************************************************************
	32bit color 描画関数
 *************************************************************************************************/

/*******************************************************
	内部フォント描画関数
 ******************************************************/

/*------------------------------------------------------
	内部フォント描画関数 (32bit)
 -----------------------------------------------------*/

static int internal_font_putc(struct font_t *font, int sx, int sy, int src_r, int src_g, int src_b)
{
	int x, y, p;
	int dst_r, dst_g, dst_b, alpha;
	u32 *dst, *vptr, color;
	u8 data;

	if (sx + font->pitch < 0 || sx >= SCR_WIDTH)
		return 0;

	vptr = vram_pos32(sx, sy);
	dst = &vptr[font->skipx + (font->skipy << 9)];	// font_skipy << 9 = font_skipy * BUF_WIDTH

	sy += font->skipy;

	p = 0;

	for (y = 0; y < font->height; y++)
	{
		if (sy + y >= 0 && sy + y < SCR_HEIGHT)
		{
			for (x = 0; x < font->width;)
			{
				data = font->data[p++];

				alpha = data & 0x0f;
				if (alpha)
				{
					color = dst[x];

					dst_r = GETR32(color);
					dst_g = GETG32(color);
					dst_b = GETB32(color);

					dst_r = alpha_blend[alpha][src_r][dst_r];
					dst_g = alpha_blend[alpha][src_g][dst_g];
					dst_b = alpha_blend[alpha][src_b][dst_b];

					dst[x] = MAKECOL32(dst_r, dst_g, dst_b);
				}
				x++;

				alpha = data >> 4;
				if (alpha)
				{
					color = dst[x];

					dst_r = GETR32(color);
					dst_g = GETG32(color);
					dst_b = GETB32(color);

					dst_r = alpha_blend[alpha][src_r][dst_r];
					dst_g = alpha_blend[alpha][src_g][dst_g];
					dst_b = alpha_blend[alpha][src_b][dst_b];

					dst[x] = MAKECOL32(dst_r, dst_g, dst_b);
				}
				x++;
			}
			dst += BUF_WIDTH;
		}
	}

	return 1;
}


/*------------------------------------------------------
	内部シャドウ描画関数 (32bit)
 -----------------------------------------------------*/

static int internal_shadow_putc(struct font_t *font, int sx, int sy)
{
	int x, y, p;
	int dst_r, dst_g, dst_b, alpha;
	u32 *dst, *vptr;
	u8 data;

	if (sx + font->pitch < 0 || sx >= SCR_WIDTH)
		return 0;

	vptr = vram_pos32(sx, sy);
	dst = &vptr[font->skipx + (font->skipy << 9)];	// font_skipy << 9 = font_skipy * BUF_WIDTH

	sy += font->skipy;

	p = 0;

	for (y = 0; y < font->height; y++)
	{
		if (sy + y >= 0 && sy + y < SCR_HEIGHT)
		{
			for (x = 0; x < font->width;)
			{
				data = font->data[p++];

				alpha = data & 0x0f;
				if (alpha)
				{
					dst_r = GETR32(dst[x]);
					dst_g = GETG32(dst[x]);
					dst_b = GETB32(dst[x]);

					dst_r = alpha_blend[alpha][dst_r >> 1][dst_r];
					dst_g = alpha_blend[alpha][dst_g >> 1][dst_g];
					dst_b = alpha_blend[alpha][dst_b >> 1][dst_b];

					dst[x] = MAKECOL32(dst_r, dst_g, dst_b);
				}
				x++;

				alpha = data >> 4;
				if (alpha)
				{
					dst_r = GETR32(dst[x]);
					dst_g = GETG32(dst[x]);
					dst_b = GETB32(dst[x]);

					dst_r = alpha_blend[alpha][dst_r >> 1][dst_r];
					dst_g = alpha_blend[alpha][dst_g >> 1][dst_g];
					dst_b = alpha_blend[alpha][dst_b >> 1][dst_b];

					dst[x] = MAKECOL32(dst_r, dst_g, dst_b);
				}
				x++;
			}
			dst += BUF_WIDTH;
		}
	}

	return 1;
}


/*------------------------------------------------------
	内部ライト描画関数 (32bit)
 -----------------------------------------------------*/

static int internal_light_putc(struct font_t *font, int sx, int sy)
{
	int x, y, p, level;
	int dst_r, dst_g, dst_b, alpha;
	u32 *dst, *vptr;
	u8 data;

	if (sx + font->pitch < 0 || sx >= SCR_WIDTH)
		return 0;

	vptr = vram_pos32(sx, sy);
	dst = &vptr[font->skipx + (font->skipy << 9)];	// font_skipy << 9 = font_skipy * BUF_WIDTH

	sy += font->skipy;
	level = light_level >> 1;

	p = 0;

	for (y = 0; y < font->height; y++)
	{
		if (sy + y >= 0 && sy + y < SCR_HEIGHT)
		{
			for (x = 0; x < font->width;)
			{
				data = font->data[p++];

				alpha = (data & 0x0f) - level;
				if (alpha > 0)
				{
					dst_r = GETR32(dst[x]);
					dst_g = GETG32(dst[x]);
					dst_b = GETB32(dst[x]);

					dst_r = alpha_blend[alpha][255][dst_r];
					dst_g = alpha_blend[alpha][255][dst_g];
					dst_b = alpha_blend[alpha][255][dst_b];

					dst[x] = MAKECOL32(dst_r, dst_g, dst_b);
				}
				x++;

				alpha = (data >> 4) - level;
				if (alpha > 0)
				{
					dst_r = GETR32(dst[x]);
					dst_g = GETG32(dst[x]);
					dst_b = GETB32(dst[x]);

					dst_r = alpha_blend[alpha][255][dst_r];
					dst_g = alpha_blend[alpha][255][dst_g];
					dst_b = alpha_blend[alpha][255][dst_b];

					dst[x] = MAKECOL32(dst_r, dst_g, dst_b);
				}
				x++;
			}
			dst += BUF_WIDTH;
		}
	}

	return 1;
}


/*******************************************************
	ユーザインタフェース用フォント描画
 ******************************************************/

/*------------------------------------------------------
	文字を描画 (ユーザインタフェース用)
 -----------------------------------------------------*/

INLINE void uifont_draw(int sx, int sy, int r, int g, int b, const char *s)
{
	int type, res = 1;
	u16 code;
	u8 *p = (u8 *)s;
	struct font_t font;

	while (*p && res)
	{
		code = uifont_get_code(p, &type);
		res = 1;

		switch (type)
		{
		case FONT_TYPE_ASCII:
			if ((res = ascii_14p_get_gryph(&font, code)) != 0)
			{
				res = internal_font_putc(&font, sx, sy, r, g, b);
				sx += font.pitch;
				p++;
			}
			break;

		case FONT_TYPE_GRAPHIC:
			if ((res = graphic_font_get_gryph(&font, code)) != 0)
			{
				res = internal_font_putc(&font, sx, sy, r, g, b);
				sx += font.pitch;
				p++;
			}
			break;

#if JAPANESE_UI
		case FONT_TYPE_JPNHAN:
			if ((res = jpn_h14p_get_gryph(&font, code)) != 0)
			{
				res = internal_font_putc(&font, sx, sy, r, g, b);
				sx += font.pitch;
				p++;
			}
			break;

		case FONT_TYPE_JPNZEN:
			if ((res = jpn_z14p_get_gryph(&font, code)) != 0)
			{
				res = internal_font_putc(&font, sx, sy, r, g, b);
				sx += font.pitch;
				p += 2;
			}
			break;
#endif

		default:
			res = 0;
			break;
		}
	}
}


/*------------------------------------------------------
	文字の影を描画 (ユーザインタフェース用)
 -----------------------------------------------------*/

INLINE void uifont_draw_shadow(int sx, int sy, const char *s)
{
	int type, res = 1;
	u16 code;
	u8 *p = (u8 *)s;
	struct font_t font;

	while (*p && res)
	{
		code = uifont_get_code(p, &type);

		switch (type)
		{
		case FONT_TYPE_ASCII:
			if ((res = ascii_14p_get_shadow(&font, code)) != 0)
			{
				res = internal_shadow_putc(&font, sx, sy);
				sx += font.pitch;
				p++;
			}
			break;

		case FONT_TYPE_GRAPHIC:
			if ((res = graphic_font_get_shadow(&font, code)) != 0)
			{
				res = internal_shadow_putc(&font, sx, sy);
				sx += font.pitch;
				p++;
			}
			break;


#if JAPANESE_UI
		case FONT_TYPE_JPNHAN:
			if ((res = jpn_h14p_get_shadow(&font, code)) != 0)
			{
				res = internal_shadow_putc(&font, sx, sy);
				sx += font.pitch;
				p++;
			}
			break;

		case FONT_TYPE_JPNZEN:
			if ((res = jpn_z14p_get_shadow(&font, code)) != 0)
			{
				res = internal_shadow_putc(&font, sx, sy);
				sx += font.pitch;
				p += 2;
			}
			break;
#endif

		default:
			res = 0;
			break;
		}
	}
}


/*------------------------------------------------------
	文字列を描画
 -----------------------------------------------------*/

void uifont_print(int sx, int sy, int r, int g, int b, const char *s)
{
	uifont_draw(sx, sy, r, g, b, s);
}


/*------------------------------------------------------
	文字列を描画 / センタリング処理
 -----------------------------------------------------*/

void uifont_print_center(int sy, int r, int g, int b, const char *s)
{
	int width = uifont_get_string_width(s);
	int sx = (SCR_WIDTH - width) / 2;

	uifont_print(sx, sy, r, g, b, s);
}


/*------------------------------------------------------
	文字列を描画 / 影付き
 -----------------------------------------------------*/

void uifont_print_shadow(int sx, int sy, int r, int g, int b, const char *s)
{
	uifont_draw_shadow(sx, sy, s);
	uifont_print(sx, sy, r, g, b, s);
}


/*------------------------------------------------------
	文字列を描画 / 影付き / センタリング処理
 -----------------------------------------------------*/

void uifont_print_shadow_center(int sy, int r, int g, int b, const char *s)
{
	int width = uifont_get_string_width(s);
	int sx = (SCR_WIDTH - width) / 2;

	uifont_print_shadow(sx, sy, r, g, b, s);
}


/*******************************************************
	テキスト用固定ピッチフォント描画
 ******************************************************/

/*------------------------------------------------------
	欧文文字列描画
 -----------------------------------------------------*/

INLINE void latin1_draw(int sx, int sy, int r, int g, int b, const char *s)
{
	int type, res = 1;
	u16 code;
	u8 *p = (u8 *)s;
	struct font_t font;

	while (*p && res)
	{
		code = latin1_get_code(p, &type);

		switch (type)
		{
		case FONT_TYPE_ASCII:
			if ((res = ascii_14_get_gryph(&font, code)) != 0)
			{
				res = internal_font_putc(&font, sx, sy, r, g, b);
				sx += FONTSIZE / 2;
				p++;
			}
			break;

		case FONT_TYPE_LATIN1:
			if ((res = latin1_14_get_gryph(&font, code)) != 0)
			{
				res = internal_font_putc(&font, sx, sy, r, g, b);
				sx += FONTSIZE / 2;
				p++;
			}
			break;

		case FONT_TYPE_COMMAND:
			{
				int r2, g2, b2;

				if (CODE_HASCOLOR(code))
				{
					u32 color = command_font_color[code >> 8];

					r2 = GETR32(color);
					g2 = GETG32(color);
					b2 = GETB32(color);
					code &= 0xff;
				}
				else
				{
					r2 = r;
					g2 = g;
					b2 = b;
				}

				if ((res = command_font_get_gryph(&font, code)) != 0)
				{
					res = internal_font_putc(&font, sx, sy, r2, g2, b2);
					sx += FONTSIZE;
					p += 2;
				}
			}
			break;

		default:
			res = 0;
			break;
		}
	}
}


/*------------------------------------------------------
	日本語フォント描画
 -----------------------------------------------------*/

INLINE void sjis_draw(int sx, int sy, int r, int g, int b, const char *s)
{
	int type, res = 1;
	u16 code;
	u8 *p = (u8 *)s;
	struct font_t font;

	while (*p && res)
	{
		code = sjis_get_code(p, &type);

		switch (type)
		{
		case FONT_TYPE_ASCII:
			if ((res = ascii_14_get_gryph(&font, code)) != 0)
			{
				res = internal_font_putc(&font, sx, sy, r, g, b);
				sx += FONTSIZE / 2;
				p++;
			}
			break;

		case FONT_TYPE_JPNHAN:
			if ((res = jpn_h14_get_gryph(&font, code)) != 0)
			{
				res = internal_font_putc(&font, sx, sy, r, g, b);
				sx += FONTSIZE / 2;
				p++;
			}
			break;

		case FONT_TYPE_JPNZEN:
			if ((res = jpn_z14_get_gryph(&font, code)) != 0)
			{
				res = internal_font_putc(&font, sx, sy, r, g, b);
				sx += FONTSIZE;
				p += 2;
			}
			break;

		case FONT_TYPE_COMMAND:
			{
				int r2, g2, b2;

				if (CODE_HASCOLOR(code))
				{
					u32 color = command_font_color[code >> 8];

					r2 = GETR32(color);
					g2 = GETG32(color);
					b2 = GETB32(color);
					code &= 0xff;
				}
				else
				{
					r2 = r;
					g2 = g;
					b2 = b;
				}

				if ((res = command_font_get_gryph(&font, code)) != 0)
				{
					res = internal_font_putc(&font, sx, sy, r2, g2, b2);
					sx += FONTSIZE;
					p += 2;
				}
			}
			break;

		default:
			res = 0;
			break;
		}
	}
}


/*------------------------------------------------------
	フォント描画
 -----------------------------------------------------*/

void textfont_print(int sx, int sy, int r, int g, int b, const char *s, int flag)
{
	if (flag & CHARSET_SHIFTJIS)
		sjis_draw(sx, sy, r, g, b, s);
	else
		latin1_draw(sx, sy, r, g, b, s);
}


/***************************************************************************
	アイコン描画
 **************************************************************************/

/*------------------------------------------------------
	アイコン(小)を描画
 -----------------------------------------------------*/

void small_icon(int sx, int sy, int r, int g, int b, int no)
{
	struct font_t font;

	if (icon_s_get_gryph(&font, no))
		internal_font_putc(&font, sx, sy, r, g, b);
}


/*------------------------------------------------------
	アイコン(小)を描画  (影エフェクトあり)
 -----------------------------------------------------*/

void small_icon_shadow(int sx, int sy, int r, int g, int b, int no)
{
	struct font_t font;

	if (icon_s_get_shadow(&font, no))
		internal_shadow_putc(&font, sx, sy);

	if (icon_s_get_gryph(&font, no))
		internal_font_putc(&font, sx, sy, r, g, b);
}


/*------------------------------------------------------
	アイコン(小)を描画  (影、光エフェクトあり)
 -----------------------------------------------------*/

void small_icon_light(int sx, int sy, int r, int g, int b, int no)
{
	struct font_t font;

	if (icon_s_get_shadow(&font, no))
		internal_shadow_putc(&font, sx, sy);

	if (icon_s_get_light(&font, no))
		internal_light_putc(&font, sx - 4, sy - 4);

	if (icon_s_get_gryph(&font, no))
		internal_font_putc(&font, sx, sy, r, g, b);
}


/*------------------------------------------------------
	アイコン(大)を描画
 -----------------------------------------------------*/

void large_icon(int sx, int sy, int r, int g, int b, int no)
{
	struct font_t font;

	if (icon_l_get_gryph(&font, no))
		internal_font_putc(&font, sx, sy, r, g, b);
}


/*------------------------------------------------------
	アイコン(大)を描画 (影エフェクトあり)
 -----------------------------------------------------*/

void large_icon_shadow(int sx, int sy, int r, int g, int b, int no)
{
	struct font_t font;

	if (icon_l_get_shadow(&font, no))
		internal_shadow_putc(&font, sx, sy);

	if (icon_l_get_gryph(&font, no))
		internal_font_putc(&font, sx, sy, r, g, b);
}


/*------------------------------------------------------
	アイコン(大)を描画  (影、光エフェクトあり)
 -----------------------------------------------------*/

void large_icon_light(int sx, int sy, int r, int g, int b, int no)
{
	struct font_t font;

	if (icon_l_get_shadow(&font, no))
		internal_shadow_putc(&font, sx, sy);

	if (icon_l_get_light(&font, no))
		internal_light_putc(&font, sx - 4, sy - 4);

	if (icon_l_get_gryph(&font, no))
		internal_font_putc(&font, sx, sy, r, g, b);
}


/*------------------------------------------------------
	"NEO･GEO CDZ Emulator for PSP" ロゴ描画
 -----------------------------------------------------*/

void logo(int sx, int sy, int r, int g, int b)
{
	int x, y, dst_r, dst_g, dst_b, alpha;
	u32 *dst = vram_pos32(sx, sy);

	for (y = 0; y < 14; y++)
	{
		for (x = 0; x < 232; x++)
		{
			if (x & 1)
				alpha = logo_data[y][x >> 1] >> 4;
			else
				alpha = logo_data[y][x >> 1] & 0x0f;

			if (alpha)
			{
				dst_r = GETR32(dst[x]);
				dst_g = GETG32(dst[x]);
				dst_b = GETB32(dst[x]);

				dst_r = alpha_blend[alpha][r][dst_r];
				dst_g = alpha_blend[alpha][g][dst_g];
				dst_b = alpha_blend[alpha][b][dst_b];

				dst[x] = MAKECOL32(dst_r, dst_g, dst_b);
			}
		}
		dst += BUF_WIDTH;
	}
}


/***************************************************************************
	図形描画
 **************************************************************************/

/*------------------------------------------------------
	水平線描画
 -----------------------------------------------------*/

void hline(int sx, int ex, int y, int r, int g, int b)
{
	int x;
	int width  = (ex - sx) + 1;
	u32 *dst = vram_pos32(sx, y);
	u32 color = MAKECOL32(r, g, b);

	for (x = 0; x < width; x++)
		*dst++ = color;
}


/*------------------------------------------------------
	水平線描画 / アルファブレンドあり
 -----------------------------------------------------*/

void hline_alpha(int sx, int ex, int y, int r, int g, int b, int alpha)
{
	int x, dst_r, dst_g, dst_b;
	int width  = (ex - sx) + 1;
	u32 *dst = vram_pos32(sx, y);

	for (x = 0; x < width; x++)
	{
		dst_r = GETR32(dst[x]);
		dst_g = GETG32(dst[x]);
		dst_b = GETB32(dst[x]);

		dst_r = alpha_blend[alpha][r][dst_r];
		dst_g = alpha_blend[alpha][g][dst_g];
		dst_b = alpha_blend[alpha][b][dst_b];

		dst[x] = MAKECOL32(dst_r, dst_g, dst_b);
	}
}


/*------------------------------------------------------
	水平線描画 / アルファブレンド / グラデーションあり
 -----------------------------------------------------*/

void hline_gradation(int sx, int ex, int y, int r1, int g1, int b1, int r2, int g2, int b2, int alpha)
{
	int x;
	int dr, dg, db;
	int ir, ig, ib;
	int cr, cg, cb;
	int width  = (ex - sx) + 1;
	u32 *dst = vram_pos32(sx, y);

	dr = dg = db = 0;
	cr = cg = cb = 0;
	ir = ig = ib = 0;

	if (r1 != r2)
	{
		dr = (r1 < r2) ? width / (r2 - r1) : width / (r1 - r2);
		ir = (r1 < r2) ? 1 : -1;
	}
	if (g1 != g2)
	{
		dg = (g1 < g2) ? width / (g2 - g1) : width / (g1 - g2);
		ig = (g1 < g2) ? 1 : -1;
	}
	if (b1 != b2)
	{
		db = (b1 < b2) ? width / (b2 - b1) : width / (b1 - b2);
		ib = (b1 < b2) ? 1 : -1;
	}

	if (alpha == 10)
	{
		for (x = 0; x < width; x++)
		{
			dst[x] = MAKECOL32(r1, g1, b1);

			if (dr) { if (cr++ == dr) { r1 += ir; cr = 0; } }
			if (dg) { if (cg++ == dg) { g1 += ig; cg = 0; } }
			if (db) { if (cb++ == db) { b1 += ib; cb = 0; } }
		}
	}
	else
	{
		for (x = 0; x < width; x++)
		{
			r2 = GETR32(dst[x]);
			g2 = GETG32(dst[x]);
			b2 = GETB32(dst[x]);

			r2 = alpha_blend[alpha][r1][r2];
			g2 = alpha_blend[alpha][g1][g2];
			b2 = alpha_blend[alpha][b1][b2];

			dst[x] = MAKECOL32(r2, g2, b2);

			if (dr) { if (cr++ == dr) { r1 += ir; cr = 0; } }
			if (dg) { if (cg++ == dg) { g1 += ig; cg = 0; } }
			if (db) { if (cb++ == db) { b1 += ib; cb = 0; } }
		}
	}
}


/*------------------------------------------------------
	垂直線描画
 -----------------------------------------------------*/

void vline(int x, int sy, int ey, int r, int g, int b)
{
	int y;
	int height = (ey - sy) + 1;
	u32 *dst = vram_pos32(x, sy);
	u32 color = MAKECOL32(r, g, b);

	for (y = 0; y < height; y++)
	{
		*dst = color;
		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	垂直線描画 / アルファブレンドあり
 -----------------------------------------------------*/

void vline_alpha(int x, int sy, int ey, int r, int g, int b, int alpha)
{
	int y, dst_r, dst_g, dst_b;
	int height = (ey - sy) + 1;
	u32 *dst = vram_pos32(x, sy);

	for (y = 0; y < height; y++)
	{
		dst_r = GETR32(*dst);
		dst_g = GETG32(*dst);
		dst_b = GETB32(*dst);

		dst_r = alpha_blend[alpha][r][dst_r];
		dst_g = alpha_blend[alpha][g][dst_g];
		dst_b = alpha_blend[alpha][b][dst_b];

		*dst = MAKECOL32(dst_r, dst_g, dst_b);

		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	垂直線描画 / アルファブレンド / グラデーションあり
 -----------------------------------------------------*/

void vline_gradation(int x, int sy, int ey, int r1, int g1, int b1, int r2, int g2, int b2, int alpha)
{
	int y;
	int dr, dg, db;
	int ir, ig, ib;
	int cr, cg, cb;
	int height  = (ey - sy) + 1;
	u32 *dst = vram_pos32(x, sy);

	dr = dg = db = 0;
	cr = cg = cb = 0;
	ir = ig = ib = 0;

	if (r1 != r2)
	{
		dr = (r1 < r2) ? height / (r2 - r1) : height / (r1 - r2);
		ir = (r1 < r2) ? 1 : -1;
	}
	if (g1 != g2)
	{
		dg = (g1 < g2) ? height / (g2 - g1) : height / (g1 - g2);
		ig = (g1 < g2) ? 1 : -1;
	}
	if (b1 != b2)
	{
		db = (b1 < b2) ? height / (b2 - b1) : height / (b1 - b2);
		ib = (b1 < b2) ? 1 : -1;
	}

	if (alpha == 10)
	{
		for (y = 0; y < height; y++)
		{
			*dst = MAKECOL32(r1, g1, b1);
			dst += BUF_WIDTH;

			if (dr) { if (cr++ == dr) { r1 += ir; cr = 0; } }
			if (dg) { if (cg++ == dg) { g1 += ig; cg = 0; } }
			if (db) { if (cb++ == db) { b1 += ib; cb = 0; } }
		}
	}
	else
	{
		for (y = 0; y < height; y++)
		{
			r2 = GETR32(*dst);
			g2 = GETG32(*dst);
			b2 = GETB32(*dst);

			r2 = alpha_blend[alpha][r1][r2];
			g2 = alpha_blend[alpha][g1][g2];
			b2 = alpha_blend[alpha][b1][b2];

			*dst = MAKECOL32(r2, g2, b2);

			dst += BUF_WIDTH;

			if (dr) { if (cr++ == dr) { r1 += ir; cr = 0; } }
			if (dg) { if (cg++ == dg) { g1 += ig; cg = 0; } }
			if (db) { if (cb++ == db) { b1 += ib; cb = 0; } }
		}
	}
}


/*------------------------------------------------------
	四角形描画
 -----------------------------------------------------*/

void box(int sx, int sy, int ex, int ey, int r, int g, int b)
{
	hline(sx, ex - 1, sy, r, g, b);
	vline(ex, sy, ey - 1, r, g, b);
	hline(sx + 1, ex, ey, r, g, b);
	vline(sx, sy + 1, ey, r, g, b);
}

/*------------------------------------------------------
	四角形塗りつぶし
 -----------------------------------------------------*/

void boxfill(int sx, int sy, int ex, int ey, int r, int g, int b)
{
	int x, y;
	int width  = (ex - sx) + 1;
	int height = (ey - sy) + 1;
	u32 color, *dst = vram_pos32(sx, sy);

	color = MAKECOL32(r, g, b);

	for (y = 0; y < height; y++)
	{
		for (x = 0; x < width; x++)
		{
			dst[x] = color;
		}
		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	四角形塗りつぶし / アルファブレンドあり
 -----------------------------------------------------*/

void boxfill_alpha(int sx, int sy, int ex, int ey, int r, int g, int b, int alpha)
{
	int x, y;
	int dst_r, dst_g, dst_b;
	int width  = (ex - sx) + 1;
	int height = (ey - sy) + 1;
	u32 color, *dst = vram_pos32(sx, sy);

	for (y = 0; y < height; y++)
	{
		for (x = 0; x < width; x++)
		{
			color = dst[x];

			dst_r = GETR32(color);
			dst_g = GETG32(color);
			dst_b = GETB32(color);

			dst_r = alpha_blend[alpha][r][dst_r];
			dst_g = alpha_blend[alpha][g][dst_g];
			dst_b = alpha_blend[alpha][b][dst_b];

			dst[x] = MAKECOL32(dst_r, dst_g, dst_b);
		}
		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	四角形塗りつぶし
	アルファブレンド / グラデーションあり
 -----------------------------------------------------*/

void boxfill_gradation(int sx, int sy, int ex, int ey, int r1, int g1, int b1, int r2, int g2, int b2, int alpha, int dir)
{
	int x, y;
	int width  = (ex - sx) + 1;
	int height = (ey - sy) + 1;

	if (dir)
	{
		// 縦方向
		for (x = 0; x < width; x++)
			vline_gradation(sx + x, sy, ey, r1, g1, b1, r2, g2, b2, alpha);
	}
	else
	{
		// 横方向
		for (y = 0; y < height; y++)
			hline_gradation(sx, ex, sy + y, r1, g1, b1, r2, g2, b2, alpha);
	}
}


/***************************************************************************
	ユーザインタフェースのパーツを描画
 **************************************************************************/

/*------------------------------------------------------
	四角形の影を描画 (ダイアログボックス等)
 -----------------------------------------------------*/

static void draw_boxshadow(u32 *vptr, int w, int h, int no)
{
	int x, y;
	int dst_r, dst_g, dst_b, a;
	u32 *dst = vptr;

	for (y = 0; y < h; y++)
	{
		for (x = 0; x < w; x++)
		{
			if (x & 1)
				a = shadow[no][y][x >> 1] >> 4;
			else
				a = shadow[no][y][x >> 1] & 0x0f;

			if (a)
			{
				dst_r = GETR32(dst[x]);
				dst_g = GETG32(dst[x]);
				dst_b = GETB32(dst[x]);

				dst_r = alpha_blend[a][dst_r >> 2][dst_r];
				dst_g = alpha_blend[a][dst_g >> 2][dst_g];
				dst_b = alpha_blend[a][dst_b >> 2][dst_b];

				dst[x] = MAKECOL32(dst_r, dst_g, dst_b);
			}
		}
		dst += BUF_WIDTH;
	}
}


static void fill_boxshadow(u32 *vptr, int w, int h)
{
	int x, y;
	int dst_r, dst_g, dst_b;
	u32 *dst = vptr;

	for (y = 0; y < h; y++)
	{
		for (x = 0; x < w; x++)
		{
			dst_r = GETR32(dst[x]);
			dst_g = GETG32(dst[x]);
			dst_b = GETB32(dst[x]);

			dst_r = alpha_blend[15][dst_r >> 2][dst_r];
			dst_g = alpha_blend[15][dst_g >> 2][dst_g];
			dst_b = alpha_blend[15][dst_b >> 2][dst_b];

			dst[x] = MAKECOL32(dst_r, dst_g, dst_b);
		}
		dst += BUF_WIDTH;
	}
}


void draw_box_shadow(int sx, int sy, int ex, int ey)
{
	int i, width, height;
	int w, h, nw, nh, sx2, sy2;
	u32 *vptr;

	width = (ex - sx) + 1;
	height = (ey - sy) + 1;

	width  -= 14;
	height -= 14;

	nw = width / 8;
	nh = height / 8;

	w = width % 8;
	h = height % 8;

	/*----------------------------------*/
	// top
	/*----------------------------------*/
	sx2 = sx + 2;
	sy2 = sy + 2;
	vptr = vram_pos32(sx2, sy2);

	// left top
	draw_boxshadow(vptr, 8, 8, 0);
	vptr += 8;

	// top
	for (i = 0; i < nw; i++)
	{
		draw_boxshadow(vptr, 8, 8, 1);
		vptr += 8;
	}
	draw_boxshadow(vptr, w, 8, 1);
	vptr += w;

	// right top
	draw_boxshadow(vptr, 8, 8, 2);

	/*----------------------------------*/
	// left
	/*----------------------------------*/
	sx2 = sx + 2;
	sy2 = sy + 10;
	vptr = vram_pos32(sx2, sy2);

	for (i = 0; i < nh; i++)
	{
		draw_boxshadow(vptr, 8, 8, 3);
		vptr += 8 * BUF_WIDTH;
	}
	draw_boxshadow(vptr, 8, h, 3);

	/*----------------------------------*/
	// right
	/*----------------------------------*/
	sx2 = sx + 10 + width;
	sy2 = sy + 10;
	vptr = vram_pos32(sx2, sy2);

	for (i = 0; i < nh; i++)
	{
		draw_boxshadow(vptr, 8, 8, 5);
		vptr += 8 * BUF_WIDTH;
	}
	draw_boxshadow(vptr, 8, h, 5);

	/*----------------------------------*/
	// bottom
	/*----------------------------------*/
	sx2 = sx + 2;
	sy2 = sy + 10 + height;
	vptr = vram_pos32(sx2, sy2);

	// left bottom
	draw_boxshadow(vptr, 8, 8, 6);
	vptr += 8;

	// bottom
	for (i = 0; i < nw; i++)
	{
		draw_boxshadow(vptr, 8, 8, 7);
		vptr += 8;
	}
	draw_boxshadow(vptr, w, 8, 7);
	vptr += w;

	// right bottom
	draw_boxshadow(vptr, 8, 8, 8);

	vptr = vram_pos32(sx + 10, sy + 10);
	fill_boxshadow(vptr, width, height);
}


/*------------------------------------------------------
	上部バーの影を描画
 -----------------------------------------------------*/

void draw_bar_shadow(void)
{
	int i;
	u32 *vptr = vram_pos32(0, 20);

	for (i = 0; i < SCR_WIDTH / 8; i++)
	{
		draw_boxshadow(vptr, 8, 8, 7);
		vptr += 8;
	}

	vptr = vram_pos32(0, 0);
	fill_boxshadow(vptr, SCR_WIDTH, 20);
}


/*------------------------------------------------------
	ダイアログボックス描画
 -----------------------------------------------------*/

void draw_dialog(int sx, int sy, int ex, int ey)
{
	draw_box_shadow(sx, sy, ex, ey);

	hline_alpha(sx, ex - 1, sy, UI_COLOR(UI_PAL_FRAME), 10);
	vline_alpha(ex, sy, ey - 1, UI_COLOR(UI_PAL_FRAME), 10);
	hline_alpha(sx + 1, ex, ey, UI_COLOR(UI_PAL_FRAME), 10);
	vline_alpha(sx, sy + 1, ey, UI_COLOR(UI_PAL_FRAME), 10);

	sx++;
	ex--;
	sy++;
	ey--;

	hline_alpha(sx, ex - 1, sy, UI_COLOR(UI_PAL_FRAME), 12);
	vline_alpha(ex, sy, ey - 1, UI_COLOR(UI_PAL_FRAME), 12);
	hline_alpha(sx + 1, ex, ey, UI_COLOR(UI_PAL_FRAME), 12);
	vline_alpha(sx, sy + 1, ey, UI_COLOR(UI_PAL_FRAME), 12);

	sx++;
	ex--;
	sy++;
	ey--;

	boxfill_alpha(sx, sy, ex, ey, UI_COLOR(UI_PAL_BG1), 10);
}


/*------------------------------------------------------
	スクロールバー描画
 -----------------------------------------------------*/

void draw_scrollbar(int sx, int sy, int ex, int ey, int disp_lines, int total_lines, int current_line)
{
	int height = (ey - sy) + 1;

	if (total_lines > disp_lines)
	{
		int line_height;
		int bar_size, bar_blank, bar_top;

		boxfill_alpha(sx, sy, ex, sy + 9, UI_COLOR(UI_PAL_FRAME), 14);
		boxfill_alpha(sx, sy + 10, ex, ey - 10, UI_COLOR(UI_PAL_FRAME), 6);
		boxfill_alpha(sx, ey - 9, ex, ey, UI_COLOR(UI_PAL_FRAME), 14);

		uifont_print(sx - 2, sy - 2, UI_COLOR(UI_PAL_SELECT), FONT_UPTRIANGLE);
		uifont_print(sx - 2, ey - 11, UI_COLOR(UI_PAL_SELECT), FONT_DOWNTRIANGLE);

		height -= 23;
		sy += 11;

		bar_size = height >> 2;	// 最低限必要なサイズ
		line_height = (height - bar_size) / (total_lines - 1);
		bar_blank = (total_lines - 1) * line_height;
		bar_size  = height - bar_blank;
		bar_top = line_height * current_line;

		sy = sy + bar_top;
		ey = sy + bar_size;

		hline_alpha(sx, ex - 1, sy, UI_COLOR(UI_PAL_FRAME), 12);
		vline_alpha(ex, sy, ey - 1, UI_COLOR(UI_PAL_FRAME), 12);
		hline_alpha(sx + 1, ex, ey, UI_COLOR(UI_PAL_FRAME), 12);
		vline_alpha(sx, sy + 1, ey, UI_COLOR(UI_PAL_FRAME), 12);

		sx++;
		ex--;
		sy++;
		ey--;

		boxfill_alpha(sx, sy, ex, ey, UI_COLOR(UI_PAL_BG1), 12);
	}
}


/**************************************************************************************************
	16bit color 描画関数
 *************************************************************************************************/

/*------------------------------------------------------
	内部フォント描画関数 (16bit color)
 -----------------------------------------------------*/

static int internal_font_putc16(struct font_t *font, int sx, int sy, int src_r, int src_g, int src_b)
{
	int x, y, p;
	int dst_r, dst_g, dst_b, alpha;
	u16 *dst, *vptr;
	u8 data;

	if (sx + font->pitch < 0 || sx >= SCR_WIDTH)
		return 0;

	vptr = vram_pos16(sx, sy);
	dst = &vptr[font->skipx + (font->skipy << 9)];	// font_skipy << 9 = font_skipy * BUF_WIDTH

	sy += font->skipy;
	p = 0;

	for (y = 0; y < font->height; y++)
	{
		if (sy + y >= 0 && sy + y < SCR_HEIGHT)
		{
			for (x = 0; x < font->width;)
			{
				data = font->data[p++];

				alpha = data & 0x0f;
				if (alpha)
				{
					dst_r = GETR15(dst[x]);
					dst_g = GETG15(dst[x]);
					dst_b = GETB15(dst[x]);

					dst_r = alpha_blend[alpha][src_r][dst_r];
					dst_g = alpha_blend[alpha][src_g][dst_g];
					dst_b = alpha_blend[alpha][src_b][dst_b];

					dst[x] = MAKECOL15(dst_r, dst_g, dst_b);
				}
				x++;

				alpha = data >> 4;
				if (alpha)
				{
					dst_r = GETR15(dst[x]);
					dst_g = GETG15(dst[x]);
					dst_b = GETB15(dst[x]);

					dst_r = alpha_blend[alpha][src_r][dst_r];
					dst_g = alpha_blend[alpha][src_g][dst_g];
					dst_b = alpha_blend[alpha][src_b][dst_b];

					dst[x] = MAKECOL15(dst_r, dst_g, dst_b);
				}
				x++;
			}
			dst += BUF_WIDTH;
		}
	}

	return 1;
}


/*------------------------------------------------------
	内部シャドウ描画関数 (16bit color)
 -----------------------------------------------------*/

static int internal_shadow_putc16(struct font_t *font, int sx, int sy)
{
	int x, y, p;
	int dst_r, dst_g, dst_b, alpha;
	u16 *dst, *vptr;
	u8 data;

	if (sx + font->pitch < 0 || sx >= SCR_WIDTH)
		return 0;

	vptr = vram_pos16(sx, sy);
	dst = &vptr[font->skipx + (font->skipy << 9)];	// font_skipy << 9 = font_skipy * BUF_WIDTH

	sy += font->skipy;
	p = 0;

	for (y = 0; y < font->height; y++)
	{
		if (sy + y >= 0 && sy + y < SCR_HEIGHT)
		{
			for (x = 0; x < font->width;)
			{
				data = font->data[p++];

				alpha = data & 0x0f;
				if (alpha)
				{
					dst_r = GETR15(dst[x]);
					dst_g = GETG15(dst[x]);
					dst_b = GETB15(dst[x]);

					dst_r = alpha_blend[alpha][dst_r >> 1][dst_r];
					dst_g = alpha_blend[alpha][dst_g >> 1][dst_g];
					dst_b = alpha_blend[alpha][dst_b >> 1][dst_b];

					dst[x] = MAKECOL15(dst_r, dst_g, dst_b);
				}
				x++;

				alpha = data >> 4;
				if (alpha)
				{
					dst_r = GETR15(dst[x]);
					dst_g = GETG15(dst[x]);
					dst_b = GETB15(dst[x]);

					dst_r = alpha_blend[alpha][dst_r >> 1][dst_r];
					dst_g = alpha_blend[alpha][dst_g >> 1][dst_g];
					dst_b = alpha_blend[alpha][dst_b >> 1][dst_b];

					dst[x] = MAKECOL15(dst_r, dst_g, dst_b);
				}
				x++;
			}
			dst += BUF_WIDTH;
		}
	}

	return 1;
}


/***************************************************************************
	ユーザインタフェース用フォント描画 (16bit color)
 **************************************************************************/

/*------------------------------------------------------
	文字を描画 (ユーザインタフェース用)
 -----------------------------------------------------*/

INLINE void uifont_draw16(int sx, int sy, int r, int g, int b, const char *s)
{
	int type, res = 1;
	u16 code;
	u8 *p = (u8 *)s;
	struct font_t font;

	while (*p && res)
	{
		code = uifont_get_code(p, &type);

		switch (type)
		{
		case FONT_TYPE_ASCII:
			if (ascii_14p_get_gryph(&font, code))
			{
				res = internal_font_putc16(&font, sx, sy, r, g, b);
				sx += font.pitch;
			}
			p++;
			break;

		case FONT_TYPE_GRAPHIC:
			if (graphic_font_get_gryph(&font, code))
			{
				res = internal_font_putc16(&font, sx, sy, r, g, b);
				sx += font.pitch;
			}
			p++;
			break;

#if JAPANESE_UI
		case FONT_TYPE_JPNHAN:
			if (jpn_h14p_get_gryph(&font, code))
			{
				res = internal_font_putc16(&font, sx, sy, r, g, b);
				sx += font.pitch;
			}
			p++;
			break;

		case FONT_TYPE_JPNZEN:
			if (jpn_z14p_get_gryph(&font, code))
			{
				res = internal_font_putc16(&font, sx, sy, r, g, b);
				sx += font.pitch;
			}
			p += 2;
			break;
#endif

		default:
			p++;
			break;
		}
	}
}


/*------------------------------------------------------
	文字の影を描画 (ユーザインタフェース用)
 -----------------------------------------------------*/

INLINE void uifont_draw_shadow16(int sx, int sy, const char *s)
{
	int type, res = 1;
	u16 code;
	u8 *p = (u8 *)s;
	struct font_t font;

	while (*p && res)
	{
		code = uifont_get_code(p, &type);

		switch (type)
		{
		case FONT_TYPE_ASCII:
			if (ascii_14p_get_shadow(&font, code))
			{
				res = internal_shadow_putc16(&font, sx, sy);
				sx += font.pitch;
			}
			p++;
			break;

		case FONT_TYPE_GRAPHIC:
			if (graphic_font_get_shadow(&font, code))
			{
				res = internal_shadow_putc16(&font, sx, sy);
				sx += font.pitch;
			}
			p++;
			break;


#if JAPANESE_UI
		case FONT_TYPE_JPNHAN:
			if (jpn_h14p_get_shadow(&font, code))
			{
				res = internal_shadow_putc16(&font, sx, sy);
				sx += font.pitch;
			}
			p++;
			break;

		case FONT_TYPE_JPNZEN:
			if (jpn_z14p_get_shadow(&font, code))
			{
				res = internal_shadow_putc16(&font, sx, sy);
				sx += font.pitch;
			}
			p += 2;
			break;
#endif

		default:
			p++;
			break;
		}
	}
}


/*------------------------------------------------------
	文字列を描画
 -----------------------------------------------------*/

void uifont_print16(int sx, int sy, int r, int g, int b, const char *s)
{
	uifont_draw16(sx, sy, r, g, b, s);
}


/*------------------------------------------------------
	文字列を描画 / センタリング処理
 -----------------------------------------------------*/

void uifont_print_center16(int sy, int r, int g, int b, const char *s)
{
	int width = uifont_get_string_width(s);
	int sx = (SCR_WIDTH - width) / 2;

	uifont_print16(sx, sy, r, g, b, s);
}


/*------------------------------------------------------
	文字列を描画 / 影付き
 -----------------------------------------------------*/

void uifont_print_shadow16(int sx, int sy, int r, int g, int b, const char *s)
{
	uifont_draw_shadow16(sx, sy, s);
	uifont_print16(sx, sy, r, g, b, s);
}


/*------------------------------------------------------
	文字列を描画 / 影付き / センタリング処理
 -----------------------------------------------------*/

void uifont_print_shadow_center16(int sy, int r, int g, int b, const char *s)
{
	int width = uifont_get_string_width(s);
	int sx = (SCR_WIDTH - width) / 2;

	uifont_print_shadow16(sx, sy, r, g, b, s);
}


/***************************************************************************
	ゲーム画面用フォント描画 (16bit colorのみ)
 **************************************************************************/

/*------------------------------------------------------
	文字列描画
 -----------------------------------------------------*/

void small_font_print(int sx, int sy, int r, int g, int b, const char *s, int bg)
{
	int i, len = strlen(s);
	int color = MAKECOL15(r, g, b);
	u16 *vptr = vram_pos16(sx, sy);

	for (i = 0; i < len; i++)
	{
		u8 code = ((u8)s[i] >= 0x20 && (u8)s[i] <= 0x7f) ? (u8)s[i] - 0x20 : 0x20;
		int x, y;
		u16 *dst = vptr;

		for (y = 0; y < 8; y++)
		{
			u8 data = font_s[(code << 3) + y];
			u8 mask = 0x80;

			for (x = 0; x < 8; x++)
			{
				if (data & mask)
				{
					dst[x] = color;
				}
				else if (bg)
				{
					dst[x] = 0;
				}
				mask >>= 1;
			}
			dst += BUF_WIDTH;
		}

		vptr += 8;
	}
}


/*------------------------------------------------------
	文字列描画 (センタリング処理)
 -----------------------------------------------------*/

void small_font_print_center(int sy, int r, int g, int b, const char *s, int bg)
{
	int width = strlen(s) << 3;

	small_font_print((SCR_WIDTH - width) >> 1, sy, r, g, b, s, bg);
}


/***************************************************************************
	図形描画
 **************************************************************************/

/*------------------------------------------------------
	水平線描画 (アルファブレンドあり)
 -----------------------------------------------------*/

void hline_alpha16(int sx, int ex, int y, int r, int g, int b, int alpha)
{
	int x, dst_r, dst_g, dst_b;
	int width  = (ex - sx) + 1;
	u16 *dst = vram_pos16(sx, y);

	for (x = 0; x < width; x++)
	{
		dst_r = GETR15(dst[x]);
		dst_g = GETG15(dst[x]);
		dst_b = GETB15(dst[x]);

		dst_r = alpha_blend[alpha][r][dst_r];
		dst_g = alpha_blend[alpha][g][dst_g];
		dst_b = alpha_blend[alpha][b][dst_b];

		dst[x] = MAKECOL15(dst_r, dst_g, dst_b);
	}
}


/*------------------------------------------------------
	垂直線描画 (アルファブレンドあり)
 -----------------------------------------------------*/

void vline_alpha16(int x, int sy, int ey, int r, int g, int b, int alpha)
{
	int y, dst_r, dst_g, dst_b;
	int height = (ey - sy) + 1;
	u16 *dst = vram_pos16(x, sy);

	for (y = 0; y < height; y++)
	{
		dst_r = GETR15(*dst);
		dst_g = GETG15(*dst);
		dst_b = GETB15(*dst);

		dst_r = alpha_blend[alpha][r][dst_r];
		dst_g = alpha_blend[alpha][g][dst_g];
		dst_b = alpha_blend[alpha][b][dst_b];

		*dst = MAKECOL15(dst_r, dst_g, dst_b);

		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	四角形塗りつぶし (アルファブレンドあり)
 -----------------------------------------------------*/

void boxfill_alpha16(int sx, int sy, int ex, int ey, int r, int g, int b, int alpha)
{
	int x, y;
	int dst_r, dst_g, dst_b;
	int width  = (ex - sx) + 1;
	int height = (ey - sy) + 1;
	u16 *dst = vram_pos16(sx, sy);

	for (y = 0; y < height; y++)
	{
		for (x = 0; x < width; x++)
		{
			dst_r = GETR15(dst[x]);
			dst_g = GETG15(dst[x]);
			dst_b = GETB15(dst[x]);

			dst_r = alpha_blend[alpha][r][dst_r];
			dst_g = alpha_blend[alpha][g][dst_g];
			dst_b = alpha_blend[alpha][b][dst_b];

			dst[x] = MAKECOL15(dst_r, dst_g, dst_b);
		}

		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	ダイアログボックス描画
 -----------------------------------------------------*/

void draw_dialog16(int sx, int sy, int ex, int ey)
{
	hline_alpha16(sx, ex - 1, sy, UI_COLOR(UI_PAL_FRAME), 12);
	vline_alpha16(ex, sy, ey - 1, UI_COLOR(UI_PAL_FRAME), 12);
	hline_alpha16(sx + 1, ex, ey, UI_COLOR(UI_PAL_FRAME), 12);
	vline_alpha16(sx, sy + 1, ey, UI_COLOR(UI_PAL_FRAME), 12);

	sx++;
	ex--;
	sy++;
	ey--;

	hline_alpha16(sx, ex - 1, sy, UI_COLOR(UI_PAL_FRAME), 14);
	vline_alpha16(ex, sy, ey - 1, UI_COLOR(UI_PAL_FRAME), 14);
	hline_alpha16(sx + 1, ex, ey, UI_COLOR(UI_PAL_FRAME), 14);
	vline_alpha16(sx, sy + 1, ey, UI_COLOR(UI_PAL_FRAME), 14);

	sx++;
	ex--;
	sy++;
	ey--;

	boxfill_alpha16(sx, sy, ex, ey, UI_COLOR(UI_PAL_BG1), 12);
}


/**************************************************************************************************
	その他描画関数
 *************************************************************************************************/

/*******************************************************
	アイコンの光
 ******************************************************/

int ui_light_update(void)
{
	static int light_dir = 1;
	int prev_level;

	prev_level = light_level >> 1;

	light_level += light_dir;
	if (light_level > 31)
	{
		light_level = 31;
		light_dir = -1;
	}
	else if (light_level < 0)
	{
		light_level = 0;
		light_dir = 1;
	}

	return (prev_level != (light_level >> 1)) << 1;
}


/*******************************************************
	ポップアップメッセージ
 ******************************************************/

/*--------------------------------------------------------
	ポップアップメッセージをリセット
 -------------------------------------------------------*/

static int ui_popup_counter = 0;
static int ui_popup_prev_counter = 0;
static char ui_popup_message[256];

void ui_popup_reset(void)
{
	memset(ui_popup_message, 0, sizeof(ui_popup_message));
	ui_popup_counter = 0;
	ui_popup_prev_counter = 0;
}

/*--------------------------------------------------------
	ポップアップメッセージを登録
 -------------------------------------------------------*/

void ui_popup(const char *text, ...)
{
	va_list arg;

	va_start(arg, text);
	vsprintf(ui_popup_message, text, arg);
	va_end(arg);

	ui_popup_counter = 2 * 60;
}


/*--------------------------------------------------------
	ポップアップメッセージを表示
 -------------------------------------------------------*/

int ui_show_popup(int draw)
{
	int update = 0;

	if (ui_popup_counter > 0)
	{
		if (ui_popup_prev_counter == 0)
			update = 1;

		if (draw)
		{
			int sx, sy, ex, ey;
			int width = uifont_get_string_width(ui_popup_message);

			sx = (SCR_WIDTH - width) >> 1;
			sy = (SCR_HEIGHT - FONTSIZE) >> 1;
			ex = sx + width;
			ey = sy + (FONTSIZE - 1);

			if (video_mode == 32)
			{
				draw_dialog(sx - FONTSIZE/2, sy - FONTSIZE/2, ex + FONTSIZE/2, ey + FONTSIZE/2);
				uifont_print_shadow_center(sy, 255, 255, 255, ui_popup_message);
			}
			else
			{
				draw_dialog16(sx - FONTSIZE/2, sy - FONTSIZE/2, ex + FONTSIZE/2, ey + FONTSIZE/2);
				uifont_print_shadow_center16(sy, COLOR_WHITE, ui_popup_message);
			}
		}

		ui_popup_counter--;
		ui_popup_prev_counter = ui_popup_counter;

		if (update || !ui_popup_counter) return 1;
	}
	return 0;
}


/*******************************************************
	ユーザインタフェース色設定
 ******************************************************/

/*------------------------------------------------------
	UI_PALETTE取得
 -----------------------------------------------------*/

void get_ui_color(UI_PALETTE *pal, int *r, int *g, int *b)
{
	*r = pal->r;
	*g = pal->g;
	*b = pal->b;
}


/*------------------------------------------------------
	UI_PALETTE設定
 -----------------------------------------------------*/

void set_ui_color(UI_PALETTE *pal, int r, int g, int b)
{
	pal->r = r;
	pal->g = g;
	pal->b = b;
}


/*******************************************************
	ユーザインタフェース画面退避/復帰
 ******************************************************/

static u32 *screen_backup = NULL;

/*------------------------------------------------------
	スクリーン退避
 -----------------------------------------------------*/

void ui_screen_backup(int frame)
{
	int x, y;
	u32 *p, *vptr = video_frame_addr32(frame, 0, 0);

	p = screen_backup = (u32 *)malloc(SCR_WIDTH * SCR_HEIGHT * sizeof(u32));

	for (y = 0; y < SCR_HEIGHT; y++)
	{
		for (x = 0; x < SCR_WIDTH; x++)
		{
			*p++ = vptr[x];
		}
		vptr += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	スクリーン復帰
 -----------------------------------------------------*/

void ui_screen_restore(int frame)
{
	int x, y;
	u32 *p, *vptr = video_frame_addr32(frame, 0, 0);

	p = screen_backup;

	for (y = 0; y < SCR_HEIGHT; y++)
	{
		for (x = 0; x < SCR_WIDTH; x++)
		{
			vptr[x] = *p++;
		}
		vptr += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	スクリーン解放
 -----------------------------------------------------*/

void ui_screen_free(void)
{
	if (screen_backup)
	{
		free(screen_backup);
		screen_backup = NULL;
	}
}


/*******************************************************
	ユーザインタフェーススクリーンショット保存
 ******************************************************/

void ui_save_screenshot(const char *name)
{
	char path[MAX_PATH];

	sprintf(path, "%ssnap/%s.png", launchDir, name);
	save_png(path);

#if JAPANESE_UI
	ui_popup("スクリーンショットを\"%s.png\"に保存しました。", name);
#else
	ui_popup("snapshot saved as \"%s.png\".", name);
#endif
}
