Пример #1
0
void bt459_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect, u8 *pixel_data)
{
	// initialise the blink timer
	if (m_blink_start > screen.frame_number())
		m_blink_start = screen.frame_number();

	// compute the blink state according to the programmed duty cycle
	const bool blink_state = ((screen.frame_number() - m_blink_start) & (
		(m_command_0 & CR0302) == CR0302_1616 ? 0x10 :
		(m_command_0 & CR0302) == CR0302_3232 ? 0x20 :
		(m_command_0 & CR0302) == CR0302_6464 ? 0x40 : 0x30)) == 0;

	// compute the pixel mask from the pixel read mask and blink mask/state
	const u8 pixel_mask = m_pixel_read_mask & (blink_state ? 0xffU : ~m_pixel_blink_mask);

	// draw visible pixel data
	switch (m_command_0 & CR0100)
	{
	case CR0100_1BPP:
		for (int y = screen.visible_area().min_y; y <= screen.visible_area().max_y; y++)
			for (int x = screen.visible_area().min_x; x <= screen.visible_area().max_x; x += 8)
			{
				u8 data = *pixel_data++;

				bitmap.pix(y, x + 7) = get_rgb(data & 0x1, pixel_mask); data >>= 1;
				bitmap.pix(y, x + 6) = get_rgb(data & 0x1, pixel_mask); data >>= 1;
				bitmap.pix(y, x + 5) = get_rgb(data & 0x1, pixel_mask); data >>= 1;
				bitmap.pix(y, x + 4) = get_rgb(data & 0x1, pixel_mask); data >>= 1;
				bitmap.pix(y, x + 3) = get_rgb(data & 0x1, pixel_mask); data >>= 1;
				bitmap.pix(y, x + 2) = get_rgb(data & 0x1, pixel_mask); data >>= 1;
				bitmap.pix(y, x + 1) = get_rgb(data & 0x1, pixel_mask); data >>= 1;
				bitmap.pix(y, x + 0) = get_rgb(data & 0x1, pixel_mask);
			}
		break;

	case CR0100_2BPP:
		for (int y = screen.visible_area().min_y; y <= screen.visible_area().max_y; y++)
			for (int x = screen.visible_area().min_x; x <= screen.visible_area().max_x; x += 4)
			{
				u8 data = *pixel_data++;

				bitmap.pix(y, x + 3) = get_rgb(data & 0x3, pixel_mask); data >>= 2;
				bitmap.pix(y, x + 2) = get_rgb(data & 0x3, pixel_mask); data >>= 2;
				bitmap.pix(y, x + 1) = get_rgb(data & 0x3, pixel_mask); data >>= 2;
				bitmap.pix(y, x + 0) = get_rgb(data & 0x3, pixel_mask);
			}
		break;

	case CR0100_4BPP:
		for (int y = screen.visible_area().min_y; y <= screen.visible_area().max_y; y++)
			for (int x = screen.visible_area().min_x; x <= screen.visible_area().max_x; x += 2)
			{
				u8 data = *pixel_data++;

				bitmap.pix(y, x + 1) = get_rgb(data & 0x7, pixel_mask); data >>= 4;
				bitmap.pix(y, x + 0) = get_rgb(data & 0x7, pixel_mask);
			}
		break;

	case CR0100_8BPP:
		for (int y = screen.visible_area().min_y; y <= screen.visible_area().max_y; y++)
			for (int x = screen.visible_area().min_x; x <= screen.visible_area().max_x; x++)
				bitmap.pix(y, x) = get_rgb(*pixel_data++, pixel_mask);
		break;
	}

	// draw cursors when visible and not blinked off
	if ((m_cursor_command & (CR47 | CR46 | CR45 | CR44)) && ((m_cursor_command & CR40) == 0 || blink_state))
	{
		// get 64x64 bitmap and cross hair cursor plane enable
		const u8 bm_cursor_enable = (m_cursor_command & (CR47 | CR46)) >> 6;
		const u8 ch_cursor_enable = (m_cursor_command & (CR45 | CR44)) >> 4;

		// get cross hair cursor half thickness
		const int ch_thickness = (m_cursor_command & CR4241) >> 1;

		/*
		 * The cursor (x) value to be written is calculated as follows:
		 *
		 *   Cx = desired display screen (x) position + H - P
		 *
		 * where
		 *
		 *   P = 37 if 1:1 input multiplexing, 52 if 4:1 input multiplexing,
		 *       57 if 5:1 input multiplexing
		 *   H = number of pixels between the first rising edge of LD*
		 *       following the falling edge of HSYNC* to active video
		 *
		 * The cursor (y) value to be written is calculated as follows:
		 *
		 *   Cy = desired display screen (y) position + V - 32
		 *
		 * where
		 *
		 *   V = number of scan lines from the second sync pulse during
		 *       vertical blanking to active video
		 *
		 * Values from $0FC0 (-64) to $0FBF (+4031) may be loaded into the
		 * cursor (y) register. The negative values ($0FC0 to $0FFF) are used
		 * in situations where V < 32, and the cursor must be moved off the
		 * top of the screen.
		 */
		const int cursor_x = m_cursor_x + (
			(m_command_0 & CR0706) == CR0706_11MPX ? 37 :
			(m_command_0 & CR0706) == CR0706_41MPX ? 52 :
			(m_command_0 & CR0706) == CR0706_51MPX ? 57 : 0);
		const int cursor_y = (m_cursor_y < 0xfc0 ? m_cursor_y : m_cursor_y - 0x1000) + 32;

		// 64x64 bitmap cursor
		if (bm_cursor_enable)
		{
			// compute target 64x64 rectangle
			rectangle cursor(cursor_x - 31, cursor_x + 32, cursor_y - 31, cursor_y + 32);

			// intersect with screen bitmap
			cursor &= bitmap.cliprect();

			// draw if any portion is visible
			if (!cursor.empty())
			{
				for (int y = 0; y < 64; y++)
				{
					// get screen y pixel coordinate
					const int ypos = cursor_y - 31 + y;

					for (int x = 0; x < 64; x++)
					{
						// get screen x pixel coordinate
						const int xpos = cursor_x - 31 + x;

						// check if pixel is visible
						if (cursor.contains(xpos, ypos))
						{
							// retrieve 2 bits of 64x64 bitmap cursor data
							u8 data = (m_cursor_ram[y * 16 + (x >> 2)] >> ((3 - (x & 3)) << 1)) & bm_cursor_enable;

							// check for dual-cursor mode and combine with cross-hair data
							if (ch_cursor_enable)
								if (((x >= 31 - ch_thickness) && (x <= 31 + ch_thickness)) || ((y >= 31 - ch_thickness) && (y <= 31 + ch_thickness)))
									data = (m_cursor_command & CR43) ? data | ch_cursor_enable : data ^ ch_cursor_enable;

							// write cursor data to screen (normal or X Window mode)
							if (data && !((m_command_2 & CR21) && data == 1))
								bitmap.pix(ypos, xpos) = m_cursor_color[data - 1];
						}
					}
				}
			}
		}

		// cross hair cursor
		if (ch_cursor_enable)
		{
			// get the cross hair cursor color
			const rgb_t ch_color = m_cursor_color[ch_cursor_enable - 1];

			/*
			 * The window (x) value to be written is calculated as follows:
			 *
			 *   Wx = desired display screen (x) position + H - P
			 *
			 * where
			 *
			 *   P = 5 if 1:1 input multiplexing, 20 if 4:1 input multiplexing,
			 *       25 if 5:1 input multiplexing
			 *   H = number of pixels between the first rising edge of LD*
			 *       following the falling edge of HSYNC* to active video
			 *
			 * The window (y) value to be written is calculated as follows:
			 *
			 *   Wy = desired display screen (y) position + V
			 *
			 * where
			 *
			 *   V = number of scan lines from the second sync pulse during
			 *       vertical blanking to active video
			 *
			 * Values from $0000 to $0FFF may be written to the window (x) and
			 * (y) registers. A full-screen cross hair is implemented by
			 * loading the window (x,y) registers with $0000, and the window
			 * width and height registers with $0FFF.
			 */
			const bool full_screen = (m_window_x == 0 && m_window_y == 0 && m_window_w == 0x0fff && m_window_h == 0x0fff);
			const int window_x = full_screen ? screen.visible_area().min_x : m_window_x + (
				(m_command_0 & CR0706) == CR0706_11MPX ? 5 :
				(m_command_0 & CR0706) == CR0706_41MPX ? 20 :
				(m_command_0 & CR0706) == CR0706_51MPX ? 25 : 0);
			const int window_y = full_screen ? screen.visible_area().min_y : m_window_y;

			/*
			 * The actual window width is 2, 8 or 10 pixels more than the
			 * value specified by the window width register, depending on
			 * whether 1:1, 4:1 or 5:1 input multiplexing is specified. The
			 * actual window height is 2 pixels more than the value specified
			 * by the window height register. Therefore, the minimum window
			 * width is 2, 8 or 10 pixels for 1:1, 4:1 and 5:1 multiplexing,
			 * respectively. The minimum window height is 2 pixels.
			 *
			 * Values from $0000 to $0FFF may be written to the window width
			 * and height registers.
			 *
			 * Note: testing indicates the cross-hair cursor should be drawn
			 * strictly inside the window, although this is not 100% clear from
			 * the documentation.
			 */
			const int window_w = full_screen ? screen.visible_area().width() : m_window_w + (
				(m_command_0 & CR0706) == CR0706_11MPX ? 2 :
				(m_command_0 & CR0706) == CR0706_41MPX ? 8 :
				(m_command_0 & CR0706) == CR0706_51MPX ? 10 : 0);
			const int window_h = full_screen ? screen.visible_area().height() : m_window_h + 2;

			// check for dual-cursor mode
			if (bm_cursor_enable)
			{
				// draw the cross hair cursor as vertical and horizontal filled rectangles broken by the 64x64 cursor area
				rectangle v1(cursor_x - ch_thickness, cursor_x + ch_thickness, window_y + 1, cursor_y - 32);
				rectangle v2(cursor_x - ch_thickness, cursor_x + ch_thickness, cursor_y + 33, window_y + window_h);
				rectangle h1(window_x + 1, cursor_x - 32, cursor_y - ch_thickness, cursor_y + ch_thickness);
				rectangle h2(cursor_x + 33, window_x + window_w, cursor_y - ch_thickness, cursor_y + ch_thickness);

				v1 &= bitmap.cliprect();
				v2 &= bitmap.cliprect();
				h1 &= bitmap.cliprect();
				h2 &= bitmap.cliprect();

				if (!v1.empty())
					bitmap.fill(ch_color, v1);
				if (!v2.empty())
					bitmap.fill(ch_color, v2);
				if (!h1.empty())
					bitmap.fill(ch_color, h1);
				if (!h2.empty())
					bitmap.fill(ch_color, h2);
			}
			else
			{
				// draw the cross hair cursor as unbroken vertical and horizontal filled rectangles
				rectangle v(cursor_x - ch_thickness, cursor_x + ch_thickness, window_y + 1, window_y + window_h);
				rectangle h(window_x + 1, window_x + window_w, cursor_y - ch_thickness, cursor_y + ch_thickness);

				v &= bitmap.cliprect();
				h &= bitmap.cliprect();

				if (!v.empty())
					bitmap.fill(ch_color, v);
				if (!h.empty())
					bitmap.fill(ch_color, h);
			}
		}
	}