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

	usrintrf.c

	PSP user interface draw functions.

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

#include "psp.h"


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

#define FONT_UPARROW		0x01
#define FONT_DOWNARROW		0x02
#define FONT_LEFTARROW		0x03
#define FONT_RIGHTARROW		0x04
#define FONT_CIRCLE			0x05
#define FONT_CROSS			0x06
#define FONT_SQUARE			0x07
#define FONT_TRIANGLE		0x08
#define FONT_UPTRIANGLE		0x09
#define FONT_DOWNTRIANGLE	0x0a
#define FONT_LEFTTRIANGLE	0x0b
#define FONT_RIGHTTRIANGLE	0x0c

#define MAKECOL(r, g, b)	((b << 10) | (g << 5) | r)
#define GETR(color)			((color >>  0) & 0x1f)
#define GETG(color)			((color >>  5) & 0x1f)
#define GETB(color)			((color >> 10) & 0x1f)

#define vram_pos(x, y)		video_frame_addr(draw_frame, x, y)
#define vram_pixel(x, y)	*vram_pos(x, y)


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

int bg_brightness = 100;

UI_PALETTE logo_pal;
UI_PALETTE title_pal;
UI_PALETTE infobar_pal;
UI_PALETTE select_pal;
UI_PALETTE normal_pal;
UI_PALETTE bg1_pal;
UI_PALETTE bg2_pal;
UI_PALETTE bg3_pal;
UI_PALETTE filesel1_pal;
UI_PALETTE filesel2_pal;


/***************************************************************************
	Private variables (font and icon data)
 **************************************************************************/

#include "font.c"


/*------------------------------------------------------
	Get font code
 -----------------------------------------------------*/

INLINE int font_get_code(const unsigned char c)
{
	if (c >= 0x20 && c < 0x80)
	{
		// normal charactor
		return c - 0x20;
	}
	else if (c >= 0x01 && c <= 0x0c)
	{
		// glaphic charactor
		return c + 0x5f;
	}
	else
		return 0;
}


/*------------------------------------------------------
	Get srting width
 -----------------------------------------------------*/

int font_get_string_width(const char *s)
{
	int i, len, width;

	len = strlen(s);
	width = 0;

	for (i = 0; i < len; i++)
		width += font_pitch[font_get_code(s[i])] - 2;

	return width;
}


/*------------------------------------------------------
	Draw font (white)
 -----------------------------------------------------*/

INLINE void font_draw(int sx, int sy, const char *s)
{
	int i;
	int len = strlen(s);
	u16 *vptr = vram_pos(sx, sy);

	for (i = 0; i < len; i++)
	{
		u8 code = font_get_code(s[i]);

		if (code)
		{
			int x, y;
			u16 *dst = vptr;

			for (y = 0; y < 20; y++)
			{
				for (x = 0; x < font_pitch[code]; x++)
				{
					int alpha = font_data[code][y][x];

					if (alpha == 0x1f)
					{
						dst[x] = 0x7fff;
					}
					else if (alpha)
					{
						int r = GETR(dst[x]);
						int g = GETG(dst[x]);
						int b = GETB(dst[x]);

						r = additional_blend_table[r][alpha];
						g = additional_blend_table[g][alpha];
						b = additional_blend_table[b][alpha];

						dst[x] = MAKECOL(r, g, b);
					}
				}
				dst += BUF_WIDTH;
			}
		}
		vptr += font_pitch[code] - 2;
	}
}


/*------------------------------------------------------
	Draw font (specified color)
 -----------------------------------------------------*/

INLINE void font_draw_color(int sx, int sy, u16 color, const char *s)
{
	int i, fr, fg, fb;
	int len = strlen(s);
	u16 *vptr = vram_pos(sx, sy);

	fr = GETR(color);
	fg = GETG(color);
	fb = GETB(color);

	for (i = 0; i < len; i++)
	{
		u8 code = font_get_code(s[i]);

		if (code)
		{
			int x, y;
			u16 *dst = vptr;

			for (y = 0; y < 20; y++)
			{
				for (x = 0; x < font_pitch[code]; x++)
				{
					int alpha = font_data[code][y][x];

					if (alpha == 0x1f)
					{
						dst[x] = color;
					}
					else if (alpha)
					{
						int r = GETR(dst[x]);
						int g = GETG(dst[x]);
						int b = GETB(dst[x]);

						r = multiple_blend_table[r][31 - alpha];
						g = multiple_blend_table[g][31 - alpha];
						b = multiple_blend_table[b][31 - alpha];

						r += multiple_blend_table[fr][alpha];
						g += multiple_blend_table[fg][alpha];
						b += multiple_blend_table[fb][alpha];

						dst[x] = MAKECOL(r, g, b);
					}
				}
				dst += BUF_WIDTH;
			}
		}
		vptr += font_pitch[code] - 2;
	}
}


/*------------------------------------------------------
	Draw font (shadow effect)
 -----------------------------------------------------*/

INLINE void font_draw_shadow(int sx, int sy, const char *s, int level)
{
	int i, len = strlen(s);
	u16 *vptr = vram_pos(sx, sy);

	for (i = 0; i < len; i++)
	{
		u8 code = font_get_code(s[i]);

		if (code)
		{
			int x, y;
			u16 *dst = vptr;

			for (y = 0; y < 20; y++)
			{
				for (x = 0; x < font_pitch[code]; x++)
				{
					int alpha = font_shadow[code][y][x];
					int r = GETR(dst[x]);
					int g = GETG(dst[x]);
					int b = GETB(dst[x]);

					alpha = level + alpha;
					if (alpha > 0x1f) alpha = 0x1f;

					r = multiple_blend_table[r][alpha];
					g = multiple_blend_table[g][alpha];
					b = multiple_blend_table[b][alpha];

					dst[x] = MAKECOL(r, g, b);
				}
				dst += BUF_WIDTH;
			}
		}
		vptr += font_pitch[code] - 2;
	}
}


/*------------------------------------------------------
	Print string
 -----------------------------------------------------*/

void font_print(int sx, int sy, u16 color, const char *s)
{
	if ((color & 0x7fff) == 0x7fff)
		font_draw(sx, sy, s);
	else
		font_draw_color(sx, sy, color, s);
}


/*------------------------------------------------------
	Print string with centering
 -----------------------------------------------------*/

void font_print_center(int sy, u16 color, const char *s)
{
	int width = font_get_string_width(s);
	int sx = (SCR_WIDTH - width) / 2;

	font_print(sx, sy, color, s);
}


/*------------------------------------------------------
	Print string with shadow effect
 -----------------------------------------------------*/

void font_print_shadow(int sx, int sy, u16 color, const char *s, int level)
{
	font_draw_shadow(sx + 1, sy + 1, s, level);

	if ((color & 0x7fff) == 0x7fff)
		font_draw(sx, sy, s);
	else
		font_draw_color(sx, sy, color, s);
}


/*------------------------------------------------------
	Print string with centering and shadow effect
 -----------------------------------------------------*/

void font_print_shadow_center(int sy, u16 color, const char *s, int level)
{
	int width = font_get_string_width(s);
	int sx = (SCR_WIDTH - width) / 2;

	font_print_shadow(sx, sy, color, s, level);
}



/*------------------------------------------------------
	Draw small font
 -----------------------------------------------------*/

INLINE void small_font_draw(int sx, int sy, u16 color, const char *s, int bg)
{
	int i, len = strlen(s);
	u16 *vptr = vram_pos(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 = small_font[(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;
	}
}


/*------------------------------------------------------
	Print small font
 -----------------------------------------------------*/

void small_font_print(int sx, int sy, u16 color, const char *s, int bg)
{
	small_font_draw(sx, sy, color, s, bg);
}


/*------------------------------------------------------
	Print small font with centering
 -----------------------------------------------------*/

void small_font_print_center(int sy, u16 color, const char *s, int bg)
{
	int width = strlen(s) << 3;

	small_font_draw((SCR_WIDTH - width) >> 1, sy, color, s, bg);
}


/*------------------------------------------------------
	Draw large icon (white color)
 -----------------------------------------------------*/

INLINE void large_icon_draw(int sx, int sy, int no)
{
	int x, y;
	u16 *dst = vram_pos(sx, sy);

	for (y = 0; y < 24; y++)
	{
		for (x = 0; x < 32; x++)
		{
			int alpha = icon_l[no][y][x];

			if (alpha == 0x1f)
			{
				dst[x] = 0x7fff;
			}
			else if (alpha)
			{
				int r = GETR(dst[x]);
				int g = GETG(dst[x]);
				int b = GETB(dst[x]);

				r = additional_blend_table[r][alpha];
				g = additional_blend_table[g][alpha];
				b = additional_blend_table[b][alpha];

				dst[x] = MAKECOL(r, g, b);
			}
		}
		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	Draw large icon (specified color)
 -----------------------------------------------------*/

INLINE void large_icon_draw_color(int sx, int sy, int no, u16 color)
{
	int x, y, ir, ig, ib;
	u16 *dst = vram_pos(sx, sy);

	ir = GETR(color);
	ig = GETG(color);
	ib = GETB(color);

	for (y = 0; y < 24; y++)
	{
		for (x = 0; x < 32; x++)
		{
			int alpha = icon_l[no][y][x];

			if (alpha == 0x1f)
			{
				dst[x] = color;
			}
			else if (alpha)
			{
				int r = GETR(dst[x]);
				int g = GETG(dst[x]);
				int b = GETB(dst[x]);

				r = multiple_blend_table[r][31 - alpha];
				g = multiple_blend_table[g][31 - alpha];
				b = multiple_blend_table[b][31 - alpha];

				r += multiple_blend_table[ir][alpha];
				g += multiple_blend_table[ig][alpha];
				b += multiple_blend_table[ib][alpha];

				dst[x] = MAKECOL(r, g, b);
			}
		}
		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	Draw large icon
 -----------------------------------------------------*/

void large_icon(int sx, int sy, u16 color, int no)
{
	if ((color & 0x7fff) == 0x7fff)
		large_icon_draw(sx, sy, no);
	else
		large_icon_draw_color(sx, sy, no, color);
}


/*------------------------------------------------------
	Draw large icon (shadow effect)
 -----------------------------------------------------*/

void large_icon_shadow(int sx, int sy, int no, int level)
{
	int x, y;
	u16 *dst = vram_pos(sx, sy);

	for (y = 0; y < 24; y++)
	{
		for (x = 0; x < 32; x++)
		{
			int alpha = icon_l_shadow[no][y][x];
			int r = GETR(dst[x]);
			int g = GETG(dst[x]);
			int b = GETB(dst[x]);

			alpha = level + alpha;
			if (alpha > 0x1f) alpha = 0x1f;

			r = multiple_blend_table[r][alpha];
			g = multiple_blend_table[g][alpha];
			b = multiple_blend_table[b][alpha];

			dst[x] = MAKECOL(r, g, b);
		}
		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	Draw large icon (light shadow effect)
 -----------------------------------------------------*/

void large_icon_lightshadow(int sx, int sy, int no, int level)
{
	int x, y;
	u16 *dst = vram_pos(sx, sy);

	for (y = 0; y < 24; y++)
	{
		for (x = 0; x < 32; x++)
		{
			int alpha = icon_l_shadow[no][y][x];
			int r = GETR(dst[x]);
			int g = GETG(dst[x]);
			int b = GETB(dst[x]);

			alpha = level - alpha;
			if (alpha < 0) alpha = 0;

			r = additional_blend_table[r][alpha];
			g = additional_blend_table[g][alpha];
			b = additional_blend_table[b][alpha];

			dst[x] = MAKECOL(r, g, b);
		}
		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	Draw small icon (white color)
 -----------------------------------------------------*/

INLINE void small_icon_draw(int sx, int sy, int no)
{
	int x, y;
	u16 *dst = vram_pos(sx, sy);

	for (y = 0; y < 20; y++)
	{
		for (x = 0; x < 24; x++)
		{
			int alpha = icon_s[no][y][x];

			if (alpha == 0x1f)
			{
				dst[x] = 0x7fff;
			}
			else if (alpha)
			{
				int r = GETR(dst[x]);
				int g = GETG(dst[x]);
				int b = GETB(dst[x]);

				r = additional_blend_table[r][alpha];
				g = additional_blend_table[g][alpha];
				b = additional_blend_table[b][alpha];

				dst[x] = MAKECOL(r, g, b);
			}
		}
		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	Draw small icon (specified color)
 -----------------------------------------------------*/

INLINE void small_icon_draw_color(int sx, int sy, int no, u16 color)
{
	int x, y, ir, ig, ib;
	u16 *dst = vram_pos(sx, sy);

	ir = GETR(color);
	ig = GETG(color);
	ib = GETB(color);

	for (y = 0; y < 20; y++)
	{
		for (x = 0; x < 24; x++)
		{
			int alpha = icon_s[no][y][x];

			if (alpha == 0x1f)
			{
				dst[x] = color;
			}
			else if (alpha)
			{
				int r = GETR(dst[x]);
				int g = GETG(dst[x]);
				int b = GETB(dst[x]);

				r = multiple_blend_table[r][31 - alpha];
				g = multiple_blend_table[g][31 - alpha];
				b = multiple_blend_table[b][31 - alpha];

				r += multiple_blend_table[ir][alpha];
				g += multiple_blend_table[ig][alpha];
				b += multiple_blend_table[ib][alpha];

				dst[x] = MAKECOL(r, g, b);
			}
		}
		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	Draw small icon
 -----------------------------------------------------*/

void small_icon(int sx, int sy, u16 color, int no)
{
	if ((color & 0x7fff) == 0x7fff)
		small_icon_draw(sx, sy, no);
	else
		small_icon_draw_color(sx, sy, no, color);
}


/*------------------------------------------------------
	Draw small icon (shadow effect)
 -----------------------------------------------------*/

void small_icon_shadow(int sx, int sy, int no, int level)
{
	int x, y;
	u16 *dst = vram_pos(sx, sy);

	for (y = 0; y < 20; y++)
	{
		for (x = 0; x < 24; x++)
		{
			int alpha = icon_s_shadow[no][y][x];
			int r = GETR(dst[x]);
			int g = GETG(dst[x]);
			int b = GETB(dst[x]);

			alpha = level + alpha;
			if (alpha > 0x1f) alpha = 0x1f;

			r = multiple_blend_table[r][alpha];
			g = multiple_blend_table[g][alpha];
			b = multiple_blend_table[b][alpha];

			dst[x] = MAKECOL(r, g, b);
		}
		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	Draw small icon (light shadow effect)
 -----------------------------------------------------*/

void small_icon_lightshadow(int sx, int sy, int no, int level)
{
	int x, y;
	u16 *dst = vram_pos(sx, sy);

	for (y = 0; y < 20; y++)
	{
		for (x = 0; x < 24; x++)
		{
			int alpha = icon_s_shadow[no][y][x];
			int r = GETR(dst[x]);
			int g = GETG(dst[x]);
			int b = GETB(dst[x]);

			alpha = level - alpha;
			if (alpha < 0) alpha = 0;

			r = additional_blend_table[r][alpha];
			g = additional_blend_table[g][alpha];
			b = additional_blend_table[b][alpha];

			dst[x] = MAKECOL(r, g, b);
		}
		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	Draw horizontal line
 -----------------------------------------------------*/

void hline(int sx, int ex, int y, u16 color)
{
	int x;
	int width  = (ex - sx) + 1;
	u16 *dst = vram_pos(sx, y);

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


/*------------------------------------------------------
	Draw horizontal line (change brightness)
 -----------------------------------------------------*/

void hline_brightness(int sx, int ex, int y, int brightness)
{
	int x, r, g, b;
	int width  = (ex - sx) + 1;
	u16 *dst = vram_pos(sx, y);

	for (x = 0; x < width; x++)
	{
		r = GETR(*dst);
		g = GETG(*dst);
		b = GETB(*dst);

		r = r * brightness / 100;
		g = g * brightness / 100;
		b = b * brightness / 100;

		*dst++ = MAKECOL(r, g, b);
	}
}


/*------------------------------------------------------
	Draw horizontal line (alpha blend)
 -----------------------------------------------------*/

void hline_alpha(int sx, int ex, int y, u16 color, int alpha)
{
	int x, r, g, b;
	int r2, g2, b2;
	int width  = (ex - sx) + 1;
	u16 *dst = vram_pos(sx, y);

	r = GETR(color);
	g = GETG(color);
	b = GETB(color);

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

		r2 = GETR(color);
		g2 = GETG(color);
		b2 = GETB(color);

		r2 = multiple_blend_table[r2][31 - alpha];
		g2 = multiple_blend_table[g2][31 - alpha];
		b2 = multiple_blend_table[b2][31 - alpha];

		r2 += multiple_blend_table[r][alpha];
		g2 += multiple_blend_table[g][alpha];
		b2 += multiple_blend_table[b][alpha];

		*dst++ = MAKECOL(r2, g2, b2);
	}
}


/*------------------------------------------------------
	Draw horizontal line (with gradation)
 -----------------------------------------------------*/

void hline_gradation(int sx, int ex, int y, u16 scolor, u16 ecolor, int alpha)
{
	int x, r, g, b;
	int r2, g2, b2;
	int dr, dg, db;
	int ir, ig, ib;
	int cr, cg, cb;
	int width  = (ex - sx) + 1;
	u16 *dst = vram_pos(sx, y);

	r = GETR(scolor);
	g = GETG(scolor);
	b = GETB(scolor);

	r2 = GETR(ecolor);
	g2 = GETG(ecolor);
	b2 = GETB(ecolor);

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

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

	if (alpha == 0x1f)
	{
		for (x = 0; x < width; x++)
		{
			dst[x] = MAKECOL(r, g, b);

			if (dr)
			{
				if (cr++ == dr)
				{
					r += ir;
					cr = 0;
				}
			}
			if (dg)
			{
				if (cg++ == dg)
				{
					g += ig;
					cg = 0;
				}
			}
			if (db)
			{
				if (cb++ == db)
				{
					b += ib;
					cb = 0;
				}
			}
		}
	}
	else
	{
		for (x = 0; x < width; x++)
		{
			int color = dst[x];

			r2 = GETR(color);
			g2 = GETG(color);
			b2 = GETB(color);

			r2 = multiple_blend_table[r2][31 - alpha];
			g2 = multiple_blend_table[g2][31 - alpha];
			b2 = multiple_blend_table[b2][31 - alpha];

			r2 += multiple_blend_table[r][alpha];
			g2 += multiple_blend_table[g][alpha];
			b2 += multiple_blend_table[b][alpha];

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

			if (dr)
			{
				if (cr++ == dr)
				{
					r += ir;
					cr = 0;
				}
			}
			if (dg)
			{
				if (cg++ == dg)
				{
					g += ig;
					cg = 0;
				}
			}
			if (db)
			{
				if (cb++ == db)
				{
					b += ib;
					cb = 0;
				}
			}
		}
	}
}


/*------------------------------------------------------
	Draw virtical line
 -----------------------------------------------------*/

void vline(int x, int sy, int ey, u16 color)
{
	int y;
	int height = (ey - sy) + 1;
	u16 *dst = vram_pos(x, sy);

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


/*------------------------------------------------------
	Draw virtical line (change brightness)
 -----------------------------------------------------*/

void vline_brightness(int x, int sy, int ey, int brightness)
{
	int y, r, g, b;
	int height = (ey - sy) + 1;
	u16 *dst = vram_pos(x, sy);

	for (y = 0; y < height; y++)
	{
		r = GETR(*dst);
		g = GETG(*dst);
		b = GETB(*dst);

		r = r * brightness / 100;
		g = g * brightness / 100;
		b = b * brightness / 100;

		*dst = MAKECOL(r, g, b);
		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	Draw virtical line (alpha blend)
 -----------------------------------------------------*/

void vline_alpha(int x, int sy, int ey, u16 color, int alpha)
{
	int y, r, g, b;
	int r2, g2, b2;
	int height = (ey - sy) + 1;
	u16 *dst = vram_pos(x, sy);

	r = GETR(color);
	g = GETG(color);
	b = GETB(color);

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

		r2 = GETR(color);
		g2 = GETG(color);
		b2 = GETB(color);

		r2 = multiple_blend_table[r2][31 - alpha];
		g2 = multiple_blend_table[g2][31 - alpha];
		b2 = multiple_blend_table[b2][31 - alpha];

		r2 += multiple_blend_table[r][alpha];
		g2 += multiple_blend_table[g][alpha];
		b2 += multiple_blend_table[b][alpha];

		*dst = MAKECOL(r2, g2, b2);
		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	Draw virtical line (with gradation)
 -----------------------------------------------------*/

void vline_gradation(int x, int sy, int ey, u16 scolor, u16 ecolor, int alpha)
{
	int y, r, g, b;
	int r2, g2, b2;
	int dr, dg, db;
	int ir, ig, ib;
	int cr, cg, cb;
	int height  = (ey - sy) + 1;
	u16 *dst = vram_pos(x, sy);

	r = GETR(scolor);
	g = GETG(scolor);
	b = GETB(scolor);

	r2 = GETR(ecolor);
	g2 = GETG(ecolor);
	b2 = GETB(ecolor);

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

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

	if (alpha == 0x1f)
	{
		for (y = 0; y < height; y++)
		{
			*dst = MAKECOL(r, g, b);
			dst += BUF_WIDTH;

			if (dr)
			{
				if (cr++ == dr)
				{
					r += ir;
					cr = 0;
				}
			}
			if (dg)
			{
				if (cg++ == dg)
				{
					g += ig;
					cg = 0;
				}
			}
			if (db)
			{
				if (cb++ == db)
				{
					b += ib;
					cb = 0;
				}
			}
		}
	}
	else
	{
		for (y = 0; y < height; y++)
		{
			int color = *dst;

			r2 = GETR(color);
			g2 = GETG(color);
			b2 = GETB(color);

			r2 = multiple_blend_table[r2][31 - alpha];
			g2 = multiple_blend_table[g2][31 - alpha];
			b2 = multiple_blend_table[b2][31 - alpha];

			r2 += multiple_blend_table[r][alpha];
			g2 += multiple_blend_table[g][alpha];
			b2 += multiple_blend_table[b][alpha];

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

			dst += BUF_WIDTH;

			if (dr)
			{
				if (cr++ == dr)
				{
					r += ir;
					cr = 0;
				}
			}
			if (dg)
			{
				if (cg++ == dg)
				{
					g += ig;
					cg = 0;
				}
			}
			if (db)
			{
				if (cb++ == db)
				{
					b += ib;
					cb = 0;
				}
			}
		}
	}
}


/*------------------------------------------------------
	Draw filled box
 -----------------------------------------------------*/

void box(int sx, int sy, int ex, int ey, u16 color)
{
	hline(sx, ex, sy, color);
	hline(sx, ex, ey, color);
	vline(sx, sy, ey, color);
	vline(ex, sy, ey, color);
}


/*------------------------------------------------------
	Draw filled box
 -----------------------------------------------------*/

void boxfill(int sx, int sy, int ex, int ey, u16 color)
{
	int x, y;
	int width  = (ex - sx) + 1;
	int height = (ey - sy) + 1;
	u16 *dst = vram_pos(sx, sy);

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

		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	Draw filled box (alpha blend)
 -----------------------------------------------------*/

void boxfill_alpha(int sx, int sy, int ex, int ey, u16 color, int alpha)
{
	int x, y;
	int r, g, b;
	int r2, g2, b2;
	int width  = (ex - sx) + 1;
	int height = (ey - sy) + 1;
	u16 *dst = vram_pos(sx, sy);

	r = GETR(color);
	g = GETG(color);
	b = GETB(color);

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

			r2 = GETR(color);
			g2 = GETG(color);
			b2 = GETB(color);

			r2 = multiple_blend_table[r2][31 - alpha];
			g2 = multiple_blend_table[g2][31 - alpha];
			b2 = multiple_blend_table[b2][31 - alpha];

			r2 += multiple_blend_table[r][alpha];
			g2 += multiple_blend_table[g][alpha];
			b2 += multiple_blend_table[b][alpha];

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

		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	Draw filled box (with horizontal gradation)
 -----------------------------------------------------*/

void boxfill_gradation(int sx, int sy, int ex, int ey, u16 scolor, u16 ecolor, int alpha)
{
	int x, y, r, g, b;
	int r2, g2, b2;
	int dr, dg, db;
	int ir, ig, ib;
	int cr, cg, cb;
	int width  = (ex - sx) + 1;
	int height = (ey - sy) + 1;
	u16 *dst = vram_pos(sx, sy);

	r = GETR(scolor);
	g = GETG(scolor);
	b = GETB(scolor);

	r2 = GETR(ecolor);
	g2 = GETG(ecolor);
	b2 = GETB(ecolor);

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

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

	if (alpha == 0x1f)
	{
		for (x = 0; x < width; x++)
		{
			for (y = 0; y < height; y++)
			{
				dst[y * BUF_WIDTH + x] = MAKECOL(r, g, b);
			}

			if (dr)
			{
				if (cr++ == dr)
				{
					r += ir;
					cr = 0;
				}
			}
			if (dg)
			{
				if (cg++ == dg)
				{
					g += ig;
					cg = 0;
				}
			}
			if (db)
			{
				if (cb++ == db)
				{
					b += ib;
					cb = 0;
				}
			}
		}
	}
	else
	{
		for (x = 0; x < width; x++)
		{
			for (y = 0; y < height; y++)
			{
				int color = dst[y * BUF_WIDTH + x];

				r2 = GETR(color);
				g2 = GETG(color);
				b2 = GETB(color);

				r2 = multiple_blend_table[r2][31 - alpha];
				g2 = multiple_blend_table[g2][31 - alpha];
				b2 = multiple_blend_table[b2][31 - alpha];

				r2 += multiple_blend_table[r][alpha];
				g2 += multiple_blend_table[g][alpha];
				b2 += multiple_blend_table[b][alpha];

				dst[y * BUF_WIDTH + x] = MAKECOL(r2, g2, b2);
			}

			if (dr)
			{
				if (cr++ == dr)
				{
					r += ir;
					cr = 0;
				}
			}
			if (dg)
			{
				if (cg++ == dg)
				{
					g += ig;
					cg = 0;
				}
			}
			if (db)
			{
				if (cb++ == db)
				{
					b += ib;
					cb = 0;
				}
			}
		}
	}
}


/*------------------------------------------------------
	Draw dialog box
 -----------------------------------------------------*/

void draw_dialog(int sx, int sy, int ex, int ey)
{
	boxfill_alpha(sx+1, sy+1, ex-1, ey-1, 0, 16);

	hline_gradation(sx, ex, sy, MAKECOL15(255,255,255), MAKECOL15(200,200,200), 28);
	vline_gradation(sx, sy, ey, MAKECOL15(255,255,255), MAKECOL15(200,200,200), 28);
	vline_gradation(ex, sy, ey, MAKECOL15(200,200,200), MAKECOL15(145,145,145), 28);
	hline_gradation(sx, ex, ey, MAKECOL15(200,200,200), MAKECOL15(145,145,145), 28);

	hline_gradation(sx-1, ex+1, sy-1, MAKECOL15(255,255,255), MAKECOL15(200,200,200), 24);
	vline_gradation(sx-1, sy-1, ey+1, MAKECOL15(255,255,255), MAKECOL15(200,200,200), 24);
	vline_gradation(ex+1, sy-1, ey+1, MAKECOL15(200,200,200), MAKECOL15(145,145,145), 24);
	hline_gradation(sx-1, ex+1, ey+1, MAKECOL15(200,200,200), MAKECOL15(145,145,145), 24);
}


/*------------------------------------------------------
	Draw scroll bar
 -----------------------------------------------------*/

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

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

		height -= 2;
		bar_size = (int)((float)height / (float)total_lines * (float)disp_lines);
		bar_blank = height - bar_size;

		bar_top = (int)((float)bar_blank / (float)total_lines * (float)total_lines);
		if (bar_top != bar_size) bar_size++;
		if (bar_top != bar_size) bar_size++;

		bar_top = (int)((float)bar_blank / (float)total_lines * (float)current_line);

		boxfill(sx, sy, ex, ey, BG1_COL);

		sx++;
		ex--;
		sy = sy + 1 + bar_top;
		ey = sy + bar_size;

		boxfill(sx+1, sy+1, ex-1, ey-1, BG2_COL);

		r = bg2_pal.r + 2; if (r > 31) r = 31;
		g = bg2_pal.g + 2; if (g > 31) g = 31;
		b = bg2_pal.b + 2; if (b > 31) b = 31;
		hline(sx, ex, sy, MAKECOL(r,g,b));
		vline(sx, sy, ey, MAKECOL(r,g,b));

		r = bg2_pal.r - 2; if (r < 0) r = 0;
		g = bg2_pal.g - 2; if (g < 0) g = 0;
		b = bg2_pal.b - 2; if (b < 0) b = 0;
		vline(ex, sy, ey, MAKECOL(r,g,b));
		hline(sx, ex, ey, MAKECOL(r,g,b));
	}
}


/*------------------------------------------------------
	Draw "NEOGEO CDZ Emulator for PSP" logo
 -----------------------------------------------------*/

void draw_logo(int sx, int sy, u16 color)
{
	int x, y, lr, lg, lb;
	u16 *dst = vram_pos(sx, sy);

	lr = GETR(color);
	lg = GETG(color);
	lb = GETB(color);

	for (y = 0; y < 16; y++)
	{
		for (x = 0; x < 256; x++)
		{
			int alpha = logo[y][x];

			if (alpha)
			{
				int r = GETR(dst[x]);
				int g = GETG(dst[x]);
				int b = GETB(dst[x]);

				r = multiple_blend_table[r][31 - alpha];
				g = multiple_blend_table[g][31 - alpha];
				b = multiple_blend_table[b][31 - alpha];

				r += multiple_blend_table[lr][alpha];
				g += multiple_blend_table[lg][alpha];
				b += multiple_blend_table[lb][alpha];

				dst[x] = MAKECOL(r, g, b);
			}
		}
		dst += BUF_WIDTH;
	}
}


/*------------------------------------------------------
	Get UI_PALETTE
 -----------------------------------------------------*/

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


/*------------------------------------------------------
	Set UI_PALETTE
 -----------------------------------------------------*/

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