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

    Cinematronics vector hardware

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

#include "emu.h"
#include "video/vector.h"
#include "cpu/ccpu/ccpu.h"
#include "includes/cinemat.h"


/*************************************
 *
 *  Constants
 *
 *************************************/

enum
{
	COLOR_BILEVEL,
	COLOR_16LEVEL,
	COLOR_64LEVEL,
	COLOR_RGB,
	COLOR_QB3
};



/*************************************
 *
 *  Vector rendering
 *
 *************************************/

void cinemat_vector_callback(device_t *device, INT16 sx, INT16 sy, INT16 ex, INT16 ey, UINT8 shift)
{
	cinemat_state *state = device->machine().driver_data<cinemat_state>();
	const rectangle &visarea = device->machine().primary_screen->visible_area();
	int intensity = 0xff;

	/* adjust for slop */
	sx = sx - visarea.min_x;
	ex = ex - visarea.min_x;
	sy = sy - visarea.min_y;
	ey = ey - visarea.min_y;

	/* point intensity is determined by the shift value */
	if (sx == ex && sy == ey)
		intensity = 0x1ff * shift / 8;

	/* move to the starting position if we're not there already */
	if (sx != state->m_lastx || sy != state->m_lasty)
		vector_add_point(device->machine(), sx << 16, sy << 16, 0, 0);

	/* draw the vector */
	vector_add_point(device->machine(), ex << 16, ey << 16, state->m_vector_color, intensity);

	/* remember the last point */
	state->m_lastx = ex;
	state->m_lasty = ey;
}



/*************************************
 *
 *  Vector color handling
 *
 *************************************/

WRITE8_HANDLER(cinemat_vector_control_w)
{
	cinemat_state *state = space->machine().driver_data<cinemat_state>();
	int r, g, b, i;
	cpu_device *cpu = space->machine().device<cpu_device>("maincpu");

	switch (state->m_color_mode)
	{
		case COLOR_BILEVEL:
			/* color is either bright or dim, selected by the value sent to the port */
			state->m_vector_color = (data & 1) ? MAKE_RGB(0x80,0x80,0x80) : MAKE_RGB(0xff,0xff,0xff);
			break;

		case COLOR_16LEVEL:
			/* on the rising edge of the data value, latch bits 0-3 of the */
			/* X register as the intensity */
			if (data != state->m_last_control && data)
			{
				int xval = cpu->state(CCPU_X) & 0x0f;
				i = (xval + 1) * 255 / 16;
				state->m_vector_color = MAKE_RGB(i,i,i);
			}
			break;

		case COLOR_64LEVEL:
			/* on the rising edge of the data value, latch bits 2-7 of the */
			/* X register as the intensity */
			if (data != state->m_last_control && data)
			{
				int xval = cpu->state(CCPU_X);
				xval = (~xval >> 2) & 0x3f;
				i = (xval + 1) * 255 / 64;
				state->m_vector_color = MAKE_RGB(i,i,i);
			}
			break;

		case COLOR_RGB:
			/* on the rising edge of the data value, latch the X register */
			/* as 4-4-4 BGR values */
			if (data != state->m_last_control && data)
			{
				int xval = cpu->state(CCPU_X);
				r = (~xval >> 0) & 0x0f;
				r = r * 255 / 15;
				g = (~xval >> 4) & 0x0f;
				g = g * 255 / 15;
				b = (~xval >> 8) & 0x0f;
				b = b * 255 / 15;
				state->m_vector_color = MAKE_RGB(r,g,b);
			}
			break;

		case COLOR_QB3:
			{
				/* on the falling edge of the data value, remember the original X,Y values */
				/* they will be restored on the rising edge; this is to simulate the fact */
				/* that the Rockola color hardware did not overwrite the beam X,Y position */
				/* on an IV instruction if data == 0 here */
				if (data != state->m_last_control && !data)
				{
					state->m_qb3_lastx = cpu->state(CCPU_X);
					state->m_qb3_lasty = cpu->state(CCPU_Y);
				}

				/* on the rising edge of the data value, latch the Y register */
				/* as 2-3-3 BGR values */
				if (data != state->m_last_control && data)
				{
					int yval = cpu->state(CCPU_Y);
					r = (~yval >> 0) & 0x07;
					r = r * 255 / 7;
					g = (~yval >> 3) & 0x07;
					g = g * 255 / 7;
					b = (~yval >> 6) & 0x03;
					b = b * 255 / 3;
					state->m_vector_color = MAKE_RGB(r,g,b);

					/* restore the original X,Y values */
					cpu->set_state(CCPU_X, state->m_qb3_lastx);
					cpu->set_state(CCPU_Y, state->m_qb3_lasty);
				}
			}
			break;
	}

	/* remember the last value */
	state->m_last_control = data;
}



/*************************************
 *
 *  Video startup
 *
 *************************************/

VIDEO_START( cinemat_bilevel )
{
	cinemat_state *state = machine.driver_data<cinemat_state>();
	state->m_color_mode = COLOR_BILEVEL;
	VIDEO_START_CALL(vector);
}


VIDEO_START( cinemat_16level )
{
	cinemat_state *state = machine.driver_data<cinemat_state>();
	state->m_color_mode = COLOR_16LEVEL;
	VIDEO_START_CALL(vector);
}


VIDEO_START( cinemat_64level )
{
	cinemat_state *state = machine.driver_data<cinemat_state>();
	state->m_color_mode = COLOR_64LEVEL;
	VIDEO_START_CALL(vector);
}


VIDEO_START( cinemat_color )
{
	cinemat_state *state = machine.driver_data<cinemat_state>();
	state->m_color_mode = COLOR_RGB;
	VIDEO_START_CALL(vector);
}


VIDEO_START( cinemat_qb3color )
{
	cinemat_state *state = machine.driver_data<cinemat_state>();
	state->m_color_mode = COLOR_QB3;
	VIDEO_START_CALL(vector);
}



/*************************************
 *
 *  End-of-frame
 *
 *************************************/

SCREEN_UPDATE( cinemat )
{
	SCREEN_UPDATE_CALL(vector);
	vector_clear_list();

	ccpu_wdt_timer_trigger(screen->machine().device("maincpu"));

	return 0;
}



/*************************************
 *
 *  Space War update
 *
 *************************************/

SCREEN_UPDATE( spacewar )
{
	int sw_option = input_port_read(screen->machine(), "INPUTS");

	SCREEN_UPDATE_CALL(cinemat);

	/* set the state of the artwork */
	output_set_value("pressed3", (~sw_option >> 0) & 1);
	output_set_value("pressed8", (~sw_option >> 1) & 1);
	output_set_value("pressed4", (~sw_option >> 2) & 1);
	output_set_value("pressed9", (~sw_option >> 3) & 1);
	output_set_value("pressed1", (~sw_option >> 4) & 1);
	output_set_value("pressed6", (~sw_option >> 5) & 1);
	output_set_value("pressed2", (~sw_option >> 6) & 1);
	output_set_value("pressed7", (~sw_option >> 7) & 1);
	output_set_value("pressed5", (~sw_option >> 10) & 1);
	output_set_value("pressed0", (~sw_option >> 11) & 1);
	return 0;
}

