Пример #1
0
/* basically an add/subtract function with clamping */
static rgb_t jal_blend_func(rgb_t dest, rgb_t addMe, UINT8 alpha)
{
	int r  = (float)RGB_RED  (addMe) ;
	int g  = (float)RGB_GREEN(addMe) ;
	int b  = (float)RGB_BLUE (addMe) ;

	int rd = (float)RGB_RED  (dest) ;
	int gd = (float)RGB_GREEN(dest) ;
	int bd = (float)RGB_BLUE (dest) ;

	int finalR, finalG, finalB ;

	int subR = (alpha & 0x04) >> 2 ;
	int subG = (alpha & 0x02) >> 1 ;
	int subB = (alpha & 0x01) ;

	if (subR) finalR = rd - r ;
	else      finalR = rd + r ;
	if (finalR < 0) finalR = 0 ;
	else if (finalR > 255) finalR = 255 ;


	if (subG) finalG = gd - g ;
	else      finalG = gd + g ;
	if (finalG < 0) finalG = 0 ;
	else if (finalG > 255) finalG = 255 ;


	if (subB) finalB = bd - b ;
	else      finalB = bd + b ;
	if (finalB < 0) finalB = 0 ;
	else if (finalB > 255) finalB = 255 ;

	return MAKE_RGB((UINT8)finalR,(UINT8)finalG,(UINT8)finalB) ;
}
Пример #2
0
void palette_normalize_range(palette_t *palette, UINT32 start, UINT32 end, int lum_min, int lum_max)
{
	UINT32 ymin = 1000 * 255, ymax = 0;
	UINT32 tmin, tmax;
	UINT32 index;

	/* clamp within range */
	start = MAX(start, 0);
	end = MIN(end, palette->numcolors - 1);

	/* find the minimum and maximum brightness of all the colors in the range */
	for (index = start; index <= end; index++)
	{
		rgb_t rgb = palette->entry_color[index];
		UINT32 y = 299 * RGB_RED(rgb) + 587 * RGB_GREEN(rgb) + 114 * RGB_BLUE(rgb);
		ymin = MIN(ymin, y);
		ymax = MAX(ymax, y);
	}

	/* determine target minimum/maximum */
	tmin = (lum_min < 0) ? ((ymin + 500) / 1000) : lum_min;
	tmax = (lum_max < 0) ? ((ymax + 500) / 1000) : lum_max;

	/* now normalize the palette */
	for (index = start; index <= end; index++)
	{
		rgb_t rgb = palette->entry_color[index];
		UINT32 y = 299 * RGB_RED(rgb) + 587 * RGB_GREEN(rgb) + 114 * RGB_BLUE(rgb);
		UINT32 target = tmin + ((y - ymin) * (tmax - tmin + 1)) / (ymax - ymin);
		UINT8 r = (y == 0) ? 0 : rgb_clamp(RGB_RED(rgb) * 1000 * target / y);
		UINT8 g = (y == 0) ? 0 : rgb_clamp(RGB_GREEN(rgb) * 1000 * target / y);
		UINT8 b = (y == 0) ? 0 : rgb_clamp(RGB_BLUE(rgb) * 1000 * target / y);
		palette_entry_set_color(palette, index, MAKE_RGB(r, g, b));
	}
}
Пример #3
0
INLINE void map_attr_to_fg_bg(unsigned char attr, rgb_t *fg, rgb_t *bg)
{

	*bg = MAKE_ARGB(0xff,0xff,0xff,0xff);
	*fg = MAKE_ARGB(0xff,0x00,0x00,0x00);

	if(attr & DCA_ANCILLARY)
		*bg = MAKE_ARGB(0xff,0xe0,0xe0,0xe0);
	if(attr & DCA_SELECTED) {
		*bg = MAKE_ARGB(0xff,0xff,0x80,0x80);
	}
	if(attr & DCA_CURRENT) {
		*bg = MAKE_ARGB(0xff,0xff,0xff,0x00);
	}
	if(attr & DCA_CHANGED) {
		*fg = MAKE_ARGB(0xff,0xff,0x00,0x00);
	}
	if(attr & DCA_INVALID) {
		*fg = MAKE_ARGB(0xff,0x00,0x00,0xff);
	}
	if(attr & DCA_DISABLED) {
		*fg = MAKE_ARGB(RGB_ALPHA(*fg),
				(RGB_RED(*fg)+RGB_RED(*bg)) >> 1,
				(RGB_GREEN(*fg)+RGB_GREEN(*bg)) >> 1,
				(RGB_BLUE(*fg)+RGB_BLUE(*bg)) >> 1);
	}
Пример #4
0
static PALETTE_INIT( wolfpack )
{
	int i;

	palette_set_color(machine, 0, MAKE_RGB(0x00, 0x00, 0x00));
	palette_set_color(machine, 1, MAKE_RGB(0xc1, 0xc1, 0xc1));
	palette_set_color(machine, 2, MAKE_RGB(0x81, 0x81, 0x81));
	palette_set_color(machine, 3, MAKE_RGB(0x48, 0x48, 0x48));

	for (i = 0; i < 4; i++)
	{
		rgb_t color = palette_get_color(machine, i);

		palette_set_color_rgb(machine, 4 + i,
			RGB_RED(color) < 0xb8   ? RGB_RED(color)   + 0x48 : 0xff,
			RGB_GREEN(color) < 0xb8 ? RGB_GREEN(color) + 0x48 : 0xff,
			RGB_BLUE(color) < 0xb8  ? RGB_BLUE(color)  + 0x48 : 0xff);
	}

	colortable[0] = 0;
	colortable[1] = 1;
	colortable[2] = 1;
	colortable[3] = 0;
	colortable[4] = 0;
	colortable[5] = 2;
	colortable[6] = 0;
	colortable[7] = 3;
}
Пример #5
0
/* basically an add/subtract function with clamping */
rgb_t jal_blend_func(rgb_t dest, rgb_t addMe, UINT8 alpha)
{
	int r, g, b;
	int ir, ig, ib;

	r = (int)RGB_RED  (dest);
	g = (int)RGB_GREEN(dest);
	b = (int)RGB_BLUE (dest);

	ir = (int)RGB_RED  (addMe);
	ig = (int)RGB_GREEN(addMe);
	ib = (int)RGB_BLUE (addMe);

	if (alpha & 4)
		{ r -= ir; if (r < 0) r = 0; }
	else
		{ r += ir; if (r > 255) r = 255; }
	if (alpha & 2)
		{ g -= ig; if (g < 0) g = 0; }
	else
		{ g += ig; if (g > 255) g = 255; }
	if (alpha & 1)
		{ b -= ib; if (b < 0) b = 0; }
	else
		{ b += ib; if (b > 255) b = 255; }

	return MAKE_RGB(r,g,b);
}
Пример #6
0
UINT32 speglsht_state::screen_update_speglsht(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
{
	int x,y,dy;

	dy=(m_videoreg&0x20)?(256*512):0; //visible frame

	for(y=0;y<256;y++)
	{
		for(x=0;x<512;x++)
		{
			int tmp=dy+y*512+x;
			PLOT_PIXEL_RGB(x-67,y-5,(m_framebuffer[tmp]>>0)&0xff,(m_framebuffer[tmp]>>8)&0xff,(m_framebuffer[tmp]>>16)&0xff);
		}
	}

	//draw st0016 gfx to temporary bitmap (indexed 16)
	m_bitmap->fill(0);
	st0016_draw_screen(screen, *m_bitmap, cliprect);

	//copy temporary bitmap to rgb 32 bit bitmap
	for(y=cliprect.min_y; y<cliprect.max_y;y++)
	{
		UINT16 *srcline = &m_bitmap->pix16(y);
		for(x=cliprect.min_x; x<cliprect.max_x;x++)
		{
			if(srcline[x])
			{
				rgb_t color=palette_get_color(machine(), srcline[x]);
				PLOT_PIXEL_RGB(x,y,RGB_RED(color),RGB_GREEN(color),RGB_BLUE(color));
			}
		}
	}

	return 0;
}
Пример #7
0
INLINE rgb_t adjust_palette_entry(rgb_t entry, float brightness, float contrast, const UINT8 *gamma_map)
{
	int r = rgb_clamp((float)gamma_map[RGB_RED(entry)] * contrast + brightness);
	int g = rgb_clamp((float)gamma_map[RGB_GREEN(entry)] * contrast + brightness);
	int b = rgb_clamp((float)gamma_map[RGB_BLUE(entry)] * contrast + brightness);
	int a = RGB_ALPHA(entry);
	return MAKE_ARGB(a,r,g,b);
}
Пример #8
0
void GradientFillH(HDC hdc, long x1, long y1, long x2, long y2, COLORREF c1, COLORREF c2)
{
	TRIVERTEX        vert[3] ;
	GRADIENT_RECT    gRect;
	vert [0] .x      = x1;
	vert [0] .y      = y1;
	vert [0] .Red    = RGB_RED(c1) << 8;
	vert [0] .Green  = RGB_GREEN(c1) << 8;
	vert [0] .Blue   = RGB_BLUE(c1) << 8;
	vert [0] .Alpha  = 0x0000;

	vert [1] .x      = x2;
	vert [1] .y      = y2;
	vert [1] .Red    = RGB_RED(c2) << 8;
	vert [1] .Green  = RGB_GREEN(c2) << 8;
	vert [1] .Blue   = RGB_BLUE(c2) << 8;
	vert [1] .Alpha  = 0x0000;

	gRect.UpperLeft  = 0;
	gRect.LowerRight = 1;
	GradientFill(hdc, vert, 2, &gRect, 1, GRADIENT_FILL_RECT_H);
}
Пример #9
0
void m62_state::m62_amplify_contrast(palette_t *palette, UINT32 numcolors)
{
	// m62 palette is very dark, so amplify default contrast
	UINT32 i, ymax=1;
	if (!numcolors) numcolors = palette_get_num_colors(palette);

	// find maximum brightness
	for (i=0;i < numcolors;i++)
	{
		rgb_t rgb = palette_entry_get_color(palette,i);
		UINT32 y = 299 * RGB_RED(rgb) + 587 * RGB_GREEN(rgb) + 114 * RGB_BLUE(rgb);
		ymax = MAX(ymax, y);
	}

	palette_set_contrast(palette, 255000.0/ymax);
}
Пример #10
0
static SCREEN_UPDATE(speglsht)
{
	speglsht_state *state = screen->machine().driver_data<speglsht_state>();
	int x,y,dy;

	dy=(state->m_videoreg&0x20)?(256*512):0; //visible frame

	for(y=0;y<256;y++)
	{
		for(x=0;x<512;x++)
		{
			int tmp=dy+y*512+x;
			PLOT_PIXEL_RGB(x-67,y-5,(state->m_framebuffer[tmp]>>0)&0xff,(state->m_framebuffer[tmp]>>8)&0xff,(state->m_framebuffer[tmp]>>16)&0xff);
		}
	}

	//draw st0016 gfx to temporary bitmap (indexed 16)
	bitmap_fill(state->m_bitmap,NULL,0);
	st0016_draw_screen(screen, state->m_bitmap, cliprect);

	//copy temporary bitmap to rgb 32 bit bitmap
	for(y=cliprect->min_y; y<cliprect->max_y;y++)
	{
		UINT16 *srcline = BITMAP_ADDR16(state->m_bitmap, y, 0);
		for(x=cliprect->min_x; x<cliprect->max_x;x++)
		{
			if(srcline[x])
			{
				rgb_t color=palette_get_color(screen->machine(), srcline[x]);
				PLOT_PIXEL_RGB(x,y,RGB_RED(color),RGB_GREEN(color),RGB_BLUE(color));
			}
		}
	}

	return 0;
}
Пример #11
0
static void
lcd_test(cyg_addrword_t p)
{
    int i, pix, row, col;
    int on;

    diag_printf("LCD test here\n");

    lcd_init(16);
#if 0
    for (i = 0;  i < 16;  i++) {
        on = true;
        diag_printf("Fill with 0x%x\n", i);
        for (row = 0;  row < 240;  row++) {            
            for (col = 0;  col < 320/2;  col++) {
                if (on) {
                    fp->pixels[row][col] = RGB_RED(i)|RGB_GREEN(i)|RGB_BLUE(i);
                } else {
                    fp->pixels[row][col] = 0xFFFF;
                }
            }
            for (col = 320/2;  col < 320;  col++) {
                if (!on) {
                    fp->pixels[row][col] = RGB_RED(i)|RGB_GREEN(i)|RGB_BLUE(i);
                } else {
                    fp->pixels[row][col] = 0xFFFF;
                }
            }
            if ((row & 0x0F) == 0x0F) {
                if (on) {
                    on = false;
                } else {
                    on = true;
                }
            }
        }
        cyg_thread_delay(100);
    }
#endif
#if 0
    for (i = 0;  i < 4;  i++) {
        for (row = 0;  row < 240;  row++) {            
            for (col = 0;  col < 320;  col++) {
                switch (row/40) {
                case 0:
                    pix = col / 20;  // 0..15
                    fp->pixels[row][col] = RGB_RED(pix);
                    break;
                case 1:
                    pix = col / 10;  // 0..31
                    fp->pixels[row][col] = RGB_GREEN(pix);
                    break;
                case 2:
                    pix = col / 20;  // 0..15
                    fp->pixels[row][col] = RGB_BLUE(pix);
                    break;
                case 3:
                    pix = col / 20;  // 0..15
                    fp->pixels[row][col] = RGB_BLUE(pix) | RGB_GREEN(pix);
                    break;
                case 4:
                    pix = col / 20;  // 0..15
                    fp->pixels[row][col] = RGB_BLUE(15) | RGB_GREEN(pix);
                    break;
                case 5:
                    fp->pixels[row][col] = 0xFFFF;
                    break;
                }
            }
        }
        cyg_thread_delay(100);
#if 0
        for (row = 0;  row < 240;  row++) {            
            for (col = 0;  col < 320;  col++) {
                pix = col / 20;  // 0..15
                switch (row/60) {
                case 0:
                    fp->pixels[row][col] = RGB_RED(pix);
                    break;
                case 1:
                    fp->pixels[row][col] = RGB_GREEN(pix);
                    break;
                case 2:
                    fp->pixels[row][col] = RGB_BLUE(pix);
                    break;
                case 3:
                    fp->pixels[row][col] = 0xFFFF;
                    break;
                }
            }
        }
        cyg_thread_delay(100);
#endif
#if 0
        on = true;
        for (row = 0;  row < 240;  row++) {            
            for (col = 0;  col < 320/2;  col++) {
                if (on) {
                    fp->pixels[row][col] = RGB_GREEN(15);
                } else {
                    fp->pixels[row][col] = RGB_BLUE(8);
                }
            }
            for (col = 320/2;  col < 320;  col++) {
                if (!on) {
                    fp->pixels[row][col] = RGB_GREEN(15);
                } else {
                    fp->pixels[row][col] = RGB_BLUE(8);
                }
            }
            if ((row & 0x0F) == 0x0F) {
                if (on) {
                    on = false;
                } else {
                    on = true;
                }
            }
        }
#endif
    }
#endif
#if 0
    for (row = 0;  row < 240;  row++) {            
        for (col = 0;  col < 320;  col++) {
            if (col == 59) {
                fp->pixels[row][col] = 0x0000;
            } else {
                fp->pixels[row][col] = 0xFFFF;
            }
        }
    }
    cyg_thread_delay(100);
#endif
#if 0
    for (i = 0;  i < 16;  i++) {
        diag_printf("Value 0x%04x\n", (1<<i));
        for (row = 0;  row < 240;  row++) {            
            for (col = 0;  col < 320;  col++) {
                fp->pixels[row][col] = (1<<i);
            }
        }
        cyg_thread_delay(500);
    }
#endif
#if 0
    for (i = 0;  i < 32;  i++) {
        diag_printf("Red at %d\n", i);
        for (row = 0;  row < 240;  row++) {            
            for (col = 0;  col < 320;  col++) {
                fp->pixels[row][col] = RGB_RED(i);
            }
        }
        cyg_thread_delay(100);
    }
#endif
#if 0
    for (i = 0;  i < 64;  i++) {
        diag_printf("Green at %d\n", i);
        for (row = 0;  row < 240;  row++) {            
            for (col = 0;  col < 320;  col++) {
                fp->pixels[row][col] = RGB_GREEN(i);
            }
        }
        cyg_thread_delay(100);
    }
#endif
#if 0
    for (i = 0;  i < 32;  i++) {
        diag_printf("BLUE at %d\n", i);
        for (row = 0;  row < 240;  row++) {            
            for (col = 0;  col < 320;  col++) {
                fp->pixels[row][col] = RGB_BLUE(i);
            }
        }
        cyg_thread_delay(100);
    }
#endif

    while (true) {
    for (i = 0;  i < 1;  i++) {
        show_xpm(redboot_xpm);
	cyg_thread_delay(15);
        show_xpm(eCos_xpm);
	cyg_thread_delay(25);
        show_xpm(redboot_xpm);
	cyg_thread_delay(15);
        show_xpm(redhat_xpm);
	cyg_thread_delay(25);
        show_xpm(redboot_xpm);
	cyg_thread_delay(25);
        show_xpm(redboot_xpm);
	cyg_thread_delay(15);
        show_xpm(escw_xpm);
	cyg_thread_delay(25);
        show_xpm(redboot_xpm);
	cyg_thread_delay(15);
        show_xpm(eCos2_xpm);
	cyg_thread_delay(25);
        show_xpm(redboot_xpm);
	cyg_thread_delay(15);
        show_xpm(redhat2_xpm);
	cyg_thread_delay(25);
        show_xpm(logo_xpm);
	cyg_thread_delay(25);
        show_xpm(redboot_xpm);
	cyg_thread_delay(50);
    }

#if 0
    // This doesn't seem to do anything on my unit
    assabet_BCR(SA1110_BCR_MOTOR, SA1110_BCR_MOTOR_ON);
    cyg_thread_delay(2*100);
    assabet_BCR(SA1110_BCR_MOTOR, SA1110_BCR_MOTOR_OFF);
#endif

        show_xpm(redboot_xpm);
	cyg_thread_delay(15);
    lcd_clear();
    lcd_printf("\n\n**** Hello world!\n");
    cyg_thread_delay(5);
    for (i = 0;  i < 64;  i++) {
        lcd_printf("... testing line #%d\n", i);
    }
    cyg_thread_delay(50);

        show_xpm(redboot_xpm);
	cyg_thread_delay(15);
    set_bg(0,0,0);
    set_fg(31,63,0);
    lcd_clear();
    for (i = 0;  i < 32;  i++) {
        lcd_printf("... testing line #%d\n", i);
    }
    cyg_thread_delay(50);
    }  // while

    lcd_clear();
    lcd_printf("*****");    
    cyg_thread_delay(200);

    cyg_test_exit();
}
Пример #12
0
void ui_menu::draw(bool customonly)
{
	float line_height = ui_get_line_height(machine());
	float lr_arrow_width = 0.4f * line_height * machine().render().ui_aspect();
	float ud_arrow_width = line_height * machine().render().ui_aspect();
	float gutter_width = lr_arrow_width * 1.3f;
	float x1, y1, x2, y2;

	float effective_width, effective_left;
	float visible_width, visible_main_menu_height;
	float visible_extra_menu_height = 0;
	float visible_top, visible_left;
	int selected_subitem_too_big = FALSE;
	int visible_lines;
	int top_line;
	int itemnum, linenum;
	int mouse_hit, mouse_button;
	render_target *mouse_target;
	INT32 mouse_target_x, mouse_target_y;
	float mouse_x = -1, mouse_y = -1;

	/* compute the width and height of the full menu */
	visible_width = 0;
	visible_main_menu_height = 0;
	for (itemnum = 0; itemnum < numitems; itemnum++)
	{
		const ui_menu_item &pitem = item[itemnum];
		float total_width;

		/* compute width of left hand side */
		total_width = gutter_width + ui_get_string_width(machine(), pitem.text) + gutter_width;

		/* add in width of right hand side */
		if (pitem.subtext)
			total_width += 2.0f * gutter_width + ui_get_string_width(machine(), pitem.subtext);

		/* track the maximum */
		if (total_width > visible_width)
			visible_width = total_width;

		/* track the height as well */
		visible_main_menu_height += line_height;
	}

	/* account for extra space at the top and bottom */
	visible_extra_menu_height = customtop + custombottom;

	/* add a little bit of slop for rounding */
	visible_width += 0.01f;
	visible_main_menu_height += 0.01f;

	/* if we are too wide or too tall, clamp it down */
	if (visible_width + 2.0f * UI_BOX_LR_BORDER > 1.0f)
		visible_width = 1.0f - 2.0f * UI_BOX_LR_BORDER;

	/* if the menu and extra menu won't fit, take away part of the regular menu, it will scroll */
	if (visible_main_menu_height + visible_extra_menu_height + 2.0f * UI_BOX_TB_BORDER > 1.0f)
		visible_main_menu_height = 1.0f - 2.0f * UI_BOX_TB_BORDER - visible_extra_menu_height;

	visible_lines = floor(visible_main_menu_height / line_height);
	visible_main_menu_height = (float)visible_lines * line_height;

	/* compute top/left of inner menu area by centering */
	visible_left = (1.0f - visible_width) * 0.5f;
	visible_top = (1.0f - (visible_main_menu_height + visible_extra_menu_height)) * 0.5f;

	/* if the menu is at the bottom of the extra, adjust */
	visible_top += customtop;

	/* first add us a box */
	x1 = visible_left - UI_BOX_LR_BORDER;
	y1 = visible_top - UI_BOX_TB_BORDER;
	x2 = visible_left + visible_width + UI_BOX_LR_BORDER;
	y2 = visible_top + visible_main_menu_height + UI_BOX_TB_BORDER;
	if (!customonly)
		ui_draw_outlined_box(container, x1, y1, x2, y2, UI_BACKGROUND_COLOR);

	/* determine the first visible line based on the current selection */
	top_line = selected - visible_lines / 2;
	if (top_line < 0)
		top_line = 0;
	if (top_line + visible_lines >= numitems)
		top_line = numitems - visible_lines;

	/* determine effective positions taking into account the hilighting arrows */
	effective_width = visible_width - 2.0f * gutter_width;
	effective_left = visible_left + gutter_width;

	/* locate mouse */
	mouse_hit = FALSE;
	mouse_button = FALSE;
	if (!customonly)
	{
		mouse_target = ui_input_find_mouse(machine(), &mouse_target_x, &mouse_target_y, &mouse_button);
		if (mouse_target != NULL)
			if (mouse_target->map_point_container(mouse_target_x, mouse_target_y, *container, mouse_x, mouse_y))
				mouse_hit = TRUE;
	}

	/* loop over visible lines */
	hover = numitems + 1;
	if (!customonly)
		for (linenum = 0; linenum < visible_lines; linenum++)
		{
			float line_y = visible_top + (float)linenum * line_height;
			itemnum = top_line + linenum;
			const ui_menu_item &pitem = item[itemnum];
			const char *itemtext = pitem.text;
			rgb_t fgcolor = UI_TEXT_COLOR;
			rgb_t bgcolor = UI_TEXT_BG_COLOR;
			rgb_t fgcolor2 = UI_SUBITEM_COLOR;
			rgb_t fgcolor3 = UI_CLONE_COLOR;
			float line_x0 = x1 + 0.5f * UI_LINE_WIDTH;
			float line_y0 = line_y;
			float line_x1 = x2 - 0.5f * UI_LINE_WIDTH;
			float line_y1 = line_y + line_height;

			/* set the hover if this is our item */
			if (mouse_hit && line_x0 <= mouse_x && line_x1 > mouse_x && line_y0 <= mouse_y && line_y1 > mouse_y && pitem.is_selectable())
				hover = itemnum;

			/* if we're selected, draw with a different background */
			if (itemnum == selected)
			{
#ifdef UI_COLOR_DISPLAY
				rgb_t fgcolor0 = ui_get_rgb_color(CURSOR_SELECTED_TEXT);
				rgb_t bgcolor0 = ui_get_rgb_color(CURSOR_SELECTED_BG);
				fgcolor = MAKE_ARGB(0xe0, RGB_RED(fgcolor0), RGB_GREEN(fgcolor0), RGB_BLUE(fgcolor0));
				bgcolor = MAKE_ARGB(0xe0, RGB_RED(bgcolor0), RGB_GREEN(bgcolor0), RGB_BLUE(bgcolor0));
#else /* UI_COLOR_DISPLAY */
				fgcolor = UI_SELECTED_COLOR;
				bgcolor = UI_SELECTED_BG_COLOR;
#endif /* UI_COLOR_DISPLAY */
				fgcolor2 = UI_SELECTED_COLOR;
				fgcolor3 = UI_SELECTED_COLOR;
			}

			/* else if the mouse is over this item, draw with a different background */
			else if (itemnum == hover)
			{
#ifdef UI_COLOR_DISPLAY
				rgb_t fgcolor0 = ui_get_rgb_color(CURSOR_HOVER_TEXT);
				rgb_t bgcolor0 = ui_get_rgb_color(CURSOR_HOVER_BG);
				fgcolor = MAKE_ARGB(0xe0, RGB_RED(fgcolor0), RGB_GREEN(fgcolor0), RGB_BLUE(fgcolor0));
				bgcolor = MAKE_ARGB(0xe0, RGB_RED(bgcolor0), RGB_GREEN(bgcolor0), RGB_BLUE(bgcolor0));
#else /* UI_COLOR_DISPLAY */
				fgcolor = UI_MOUSEOVER_COLOR;
				bgcolor = UI_MOUSEOVER_BG_COLOR;
#endif /* UI_COLOR_DISPLAY */
				fgcolor2 = UI_MOUSEOVER_COLOR;
				fgcolor3 = UI_MOUSEOVER_COLOR;
			}

			/* if we have some background hilighting to do, add a quad behind everything else */
			if (bgcolor != UI_TEXT_BG_COLOR)
				container->add_quad(line_x0, line_y0, line_x1, line_y1, bgcolor, hilight_texture,
									PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXWRAP(TRUE));

			/* if we're on the top line, display the up arrow */
			if (linenum == 0 && top_line != 0)
			{
				container->add_quad(
									0.5f * (x1 + x2) - 0.5f * ud_arrow_width,
									line_y + 0.25f * line_height,
									0.5f * (x1 + x2) + 0.5f * ud_arrow_width,
									line_y + 0.75f * line_height,
									fgcolor,
									arrow_texture,
									PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT0));
				if (hover == itemnum)
					hover = -2;
			}

			/* if we're on the bottom line, display the down arrow */
			else if (linenum == visible_lines - 1 && itemnum != numitems - 1)
			{
				container->add_quad(
									0.5f * (x1 + x2) - 0.5f * ud_arrow_width,
									line_y + 0.25f * line_height,
									0.5f * (x1 + x2) + 0.5f * ud_arrow_width,
									line_y + 0.75f * line_height,
									fgcolor,
									arrow_texture,
									PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT0 ^ ORIENTATION_FLIP_Y));
				if (hover == itemnum)
					hover = -1;
			}

			/* if we're just a divider, draw a line */
			else if (strcmp(itemtext, MENU_SEPARATOR_ITEM) == 0)
				container->add_line(visible_left, line_y + 0.5f * line_height, visible_left + visible_width, line_y + 0.5f * line_height, UI_LINE_WIDTH, UI_BORDER_COLOR, PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));

			/* if we don't have a subitem, just draw the string centered */
			else if (pitem.subtext == NULL)
				ui_draw_text_full(container, itemtext, effective_left, line_y, effective_width,
							JUSTIFY_CENTER, WRAP_TRUNCATE, DRAW_NORMAL, fgcolor, bgcolor, NULL, NULL);

			/* otherwise, draw the item on the left and the subitem text on the right */
			else
			{
				int subitem_invert = pitem.flags & MENU_FLAG_INVERT;
				const char *subitem_text = pitem.subtext;
				float item_width, subitem_width;

				/* draw the left-side text */
				ui_draw_text_full(container, itemtext, effective_left, line_y, effective_width,
							JUSTIFY_LEFT, WRAP_TRUNCATE, DRAW_NORMAL, fgcolor, bgcolor, &item_width, NULL);

				/* give 2 spaces worth of padding */
				item_width += 2.0f * gutter_width;

				/* if the subitem doesn't fit here, display dots */
				if (ui_get_string_width(machine(), subitem_text) > effective_width - item_width)
				{
					subitem_text = "...";
					if (itemnum == selected)
						selected_subitem_too_big = TRUE;
				}

				/* draw the subitem right-justified */
				ui_draw_text_full(container, subitem_text, effective_left + item_width, line_y, effective_width - item_width,
							JUSTIFY_RIGHT, WRAP_TRUNCATE, DRAW_NORMAL, subitem_invert ? fgcolor3 : fgcolor2, bgcolor, &subitem_width, NULL);

				/* apply arrows */
				if (itemnum == selected && (pitem.flags & MENU_FLAG_LEFT_ARROW))
				{
					container->add_quad(
										effective_left + effective_width - subitem_width - gutter_width,
										line_y + 0.1f * line_height,
										effective_left + effective_width - subitem_width - gutter_width + lr_arrow_width,
										line_y + 0.9f * line_height,
										fgcolor,
										arrow_texture,
										PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT90 ^ ORIENTATION_FLIP_X));
				}
				if (itemnum == selected && (pitem.flags & MENU_FLAG_RIGHT_ARROW))
				{
					container->add_quad(
										effective_left + effective_width + gutter_width - lr_arrow_width,
										line_y + 0.1f * line_height,
										effective_left + effective_width + gutter_width,
										line_y + 0.9f * line_height,
										fgcolor,
										arrow_texture,
										PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA) | PRIMFLAG_TEXORIENT(ROT90));
				}
			}
		}

	/* if the selected subitem is too big, display it in a separate offset box */
	if (selected_subitem_too_big)
	{
		const ui_menu_item &pitem = item[selected];
		int subitem_invert = pitem.flags & MENU_FLAG_INVERT;
		linenum = selected - top_line;
		float line_y = visible_top + (float)linenum * line_height;
		float target_width, target_height;
		float target_x, target_y;

		/* compute the multi-line target width/height */
		ui_draw_text_full(container, pitem.subtext, 0, 0, visible_width * 0.75f,
					JUSTIFY_RIGHT, WRAP_WORD, DRAW_NONE, ARGB_WHITE, ARGB_BLACK, &target_width, &target_height);

		/* determine the target location */
		target_x = visible_left + visible_width - target_width - UI_BOX_LR_BORDER;
		target_y = line_y + line_height + UI_BOX_TB_BORDER;
		if (target_y + target_height + UI_BOX_TB_BORDER > visible_main_menu_height)
			target_y = line_y - target_height - UI_BOX_TB_BORDER;

		/* add a box around that */
		ui_draw_outlined_box(container, target_x - UI_BOX_LR_BORDER,
							target_y - UI_BOX_TB_BORDER,
							target_x + target_width + UI_BOX_LR_BORDER,
							target_y + target_height + UI_BOX_TB_BORDER, subitem_invert ? UI_SELECTED_BG_COLOR : UI_BACKGROUND_COLOR);
		ui_draw_text_full(container, pitem.subtext, target_x, target_y, target_width,
					JUSTIFY_RIGHT, WRAP_WORD, DRAW_NORMAL, UI_SELECTED_COLOR, UI_SELECTED_BG_COLOR, NULL, NULL);
	}

	/* if there is something special to add, do it by calling the virtual method */
	custom_render((selected >= 0 && selected < numitems) ? item[selected].ref : NULL, customtop, custombottom, x1, y1, x2, y2);

	/* return the number of visible lines, minus 1 for top arrow and 1 for bottom arrow */
	visitems = visible_lines - (top_line != 0) - (top_line + visible_lines != numitems);
}