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

    Atari I, Robot hardware

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

#include "emu.h"
#include "includes/irobot.h"

#define BITMAP_WIDTH	256


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

  Convert the color PROMs into a more useable format.

  5 bits from polygon ram address the palette ram

  Output of color RAM
  bit 8 -- inverter -- 1K ohm resistor  -- RED
  bit 7 -- inverter -- 2.2K ohm resistor  -- RED
        -- inverter -- 1K ohm resistor  -- GREEN
        -- inverter -- 2.2K ohm resistor  -- GREEN
        -- inverter -- 1K ohm resistor  -- BLUE
        -- inverter -- 2.2K ohm resistor  -- BLUE
        -- inverter -- 2.2K ohm resistor  -- INT
        -- inverter -- 4.7K ohm resistor  -- INT
  bit 0 -- inverter -- 9.1K ohm resistor  -- INT

  Alphanumeric colors are generated by ROM .125, it's outputs are connected
  to bits 1..8 as above. The inputs are:

  A0..1 - Character color
  A2    - Character image (1=pixel on/0=off)
  A3..4 - Alphamap 0,1 (appears that only Alphamap1 is used, it is set by
          the processor)

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

PALETTE_INIT( irobot )
{
	int i;

	/* convert the color prom for the text palette */
	for (i = 0; i < 32; i++)
	{
	    int intensity = color_prom[i] & 0x03;

	    int r = 28 * ((color_prom[i] >> 6) & 0x03) * intensity;
	    int g = 28 * ((color_prom[i] >> 4) & 0x03) * intensity;
	    int b = 28 * ((color_prom[i] >> 2) & 0x03) * intensity;

		int swapped_i = BITSWAP8(i,7,6,5,4,3,0,1,2);

		palette_set_color(machine, swapped_i + 64, MAKE_RGB(r, g, b));
	}
}


WRITE8_HANDLER( irobot_paletteram_w )
{
	int r,g,b;
	int bits,intensity;
	UINT32 color;

	color = ((data << 1) | (offset & 0x01)) ^ 0x1ff;
	intensity = color & 0x07;
	bits = (color >> 3) & 0x03;
	b = 12 * bits * intensity;
	bits = (color >> 5) & 0x03;
	g = 12 * bits * intensity;
	bits = (color >> 7) & 0x03;
	r = 12 * bits * intensity;
	palette_set_color(space->machine(),(offset >> 1) & 0x3F,MAKE_RGB(r,g,b));
}


static void _irobot_poly_clear(running_machine &machine, UINT8 *bitmap_base)
{
	memset(bitmap_base, 0, BITMAP_WIDTH * machine.primary_screen->height());
}

void irobot_poly_clear(running_machine &machine)
{
	irobot_state *state = machine.driver_data<irobot_state>();
	UINT8 *bitmap_base = state->m_bufsel ? state->m_polybitmap2 : state->m_polybitmap1;
	_irobot_poly_clear(machine, bitmap_base);
}


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

  Start the video hardware emulation.

***************************************************************************/
VIDEO_START( irobot )
{
	irobot_state *state = machine.driver_data<irobot_state>();
	/* Setup 2 bitmaps for the polygon generator */
	int height = machine.primary_screen->height();
	state->m_polybitmap1 = auto_alloc_array(machine, UINT8, BITMAP_WIDTH * height);
	state->m_polybitmap2 = auto_alloc_array(machine, UINT8, BITMAP_WIDTH * height);

	/* clear the bitmaps so we start with valid palette look-up values for drawing */
	_irobot_poly_clear(machine, state->m_polybitmap1);
	_irobot_poly_clear(machine, state->m_polybitmap2);

	/* Set clipping */
	state->m_ir_xmin = state->m_ir_ymin = 0;
	state->m_ir_xmax = machine.primary_screen->width();
	state->m_ir_ymax = machine.primary_screen->height();
}


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

    Polygon Generator  (Preliminary information)
    The polygon communication ram works as follows (each location is a 16-bit word):

    0000-xxxx: Object pointer table
        bits 00..10: Address of object data
        bits 12..15: Object type
            0x4 = Polygon
            0x8 = Point
            0xC = Vector
        (0xFFFF means end of table)

    Point Object:
        Word 0, bits 0..15: X Position  (0xFFFF = end of point objects)
        Word 1, bits 7..15: Y Position
        bits 0..5: Color

    Vector Object:
        Word 0, bits 7..15: Ending Y   (0xFFFF = end of line objects)
        Word 1, bits 7..15: Starting Y
                bits 0..5: Color
        Word 2: Slope
        Word 3, bits 0..15: Starting X

    Polygon Object:
        Word 0, bits 0..10: Pointer to second slope list
        Word 1, bits 0..15: Starting X first vector
        Word 2, bits 0..15: Starting X second vector
        Word 3, bits 0..5: Color
        bits 7..15: Initial Y value

    Slope Lists: (one starts at Word 4, other starts at pointer in Word 0)
        Word 0, Slope (0xFFFF = side done)
        Word 1, bits 7..15: Ending Y of vector

    Each side is a continuous set of vectors. Both sides are drawn at
    the same time and the space between them is filled in.

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

#define draw_pixel(x,y,c)		polybitmap[(y) * BITMAP_WIDTH + (x)] = (c)
#define fill_hline(x1,x2,y,c)	memset(&polybitmap[(y) * BITMAP_WIDTH + (x1)], (c), (x2) - (x1) + 1)


/*
     Line draw routine
     modified from a routine written by Andrew Caldwell
 */

static void draw_line(running_machine &machine, UINT8 *polybitmap, int x1, int y1, int x2, int y2, int col)
{
	irobot_state *state = machine.driver_data<irobot_state>();
    int dx,dy,sx,sy,cx,cy;

    dx = abs(x1-x2);
    dy = abs(y1-y2);
    sx = (x1 <= x2) ? 1: -1;
    sy = (y1 <= y2) ? 1: -1;
    cx = dx/2;
    cy = dy/2;

    if (dx>=dy)
    {
        for (;;)
        {
        	if (x1 >= state->m_ir_xmin && x1 < state->m_ir_xmax && y1 >= state->m_ir_ymin && y1 < state->m_ir_ymax)
	             draw_pixel (x1, y1, col);
             if (x1 == x2) break;
             x1 += sx;
             cx -= dy;
             if (cx < 0)
             {
                  y1 += sy;
                  cx += dx;
             }
        }
    }
    else
    {
        for (;;)
        {
        	if (x1 >= state->m_ir_xmin && x1 < state->m_ir_xmax && y1 >= state->m_ir_ymin && y1 < state->m_ir_ymax)
	            draw_pixel (x1, y1, col);
            if (y1 == y2) break;
            y1 += sy;
            cy -= dx;
            if (cy < 0)
            {
                 x1 += sx;
                 cy += dy;
            }
        }
    }
}


#define ROUND_TO_PIXEL(x)	((x >> 7) - 128)

void irobot_run_video(running_machine &machine)
{
	irobot_state *state = machine.driver_data<irobot_state>();
	UINT8 *polybitmap;
	UINT16 *combase16 = (UINT16 *)state->m_combase;
	int sx,sy,ex,ey,sx2,ey2;
	int color;
	UINT32 d1;
	int lpnt,spnt,spnt2;
	int shp;
	INT32 word1,word2;

	logerror("Starting Polygon Generator, Clear=%d\n",state->m_vg_clear);

	if (state->m_bufsel)
		polybitmap = state->m_polybitmap2;
	else
		polybitmap = state->m_polybitmap1;

	lpnt=0;
	while (lpnt < 0x7ff)
	{
		d1 = combase16[lpnt++];
		if (d1 == 0xffff) break;
		spnt = d1 & 0x07ff;
		shp = (d1 & 0xf000) >> 12;

		/* pixel */
		if (shp == 0x8)
		{
			while (spnt < 0x7ff)
			{
				sx = combase16[spnt];
				if (sx == 0xffff) break;
				sy = combase16[spnt+1];
				color = sy & 0x3f;
				sx = ROUND_TO_PIXEL(sx);
				sy = ROUND_TO_PIXEL(sy);
	        	if (sx >= state->m_ir_xmin && sx < state->m_ir_xmax && sy >= state->m_ir_ymin && sy < state->m_ir_ymax)
					draw_pixel(sx,sy,color);
				spnt+=2;
			}//while object
		}//if point

		/* line */
		if (shp == 0xc)
		{
			while (spnt < 0x7ff)
			{
				ey = combase16[spnt];
				if (ey == 0xffff) break;
				ey = ROUND_TO_PIXEL(ey);
				sy = combase16[spnt+1];
				color = sy & 0x3f;
				sy = ROUND_TO_PIXEL(sy);
				sx = combase16[spnt+3];
				word1 = (INT16)combase16[spnt+2];
				ex = sx + word1 * (ey - sy + 1);
				draw_line(machine, polybitmap, ROUND_TO_PIXEL(sx),sy,ROUND_TO_PIXEL(ex),ey,color);
				spnt+=4;
			}//while object
		}//if line

		/* polygon */
		if (shp == 0x4)
		{
			spnt2 = combase16[spnt] & 0x7ff;

			sx = combase16[spnt+1];
			sx2 = combase16[spnt+2];
			sy = combase16[spnt+3];
			color = sy & 0x3f;
			sy = ROUND_TO_PIXEL(sy);
			spnt+=4;

			word1 = (INT16)combase16[spnt];
			ey = combase16[spnt+1];
			if (word1 != -1 || ey != 0xffff)
			{
				ey = ROUND_TO_PIXEL(ey);
				spnt+=2;

			//  sx += word1;

				word2 = (INT16)combase16[spnt2];
				ey2 = ROUND_TO_PIXEL(combase16[spnt2+1]);
				spnt2+=2;

			//  sx2 += word2;

				while(1)
				{
					if (sy >= state->m_ir_ymin && sy < state->m_ir_ymax)
					{
						int x1 = ROUND_TO_PIXEL(sx);
						int x2 = ROUND_TO_PIXEL(sx2);
						int temp;

						if (x1 > x2) temp = x1, x1 = x2, x2 = temp;
						if (x1 < state->m_ir_xmin) x1 = state->m_ir_xmin;
						if (x2 >= state->m_ir_xmax) x2 = state->m_ir_xmax - 1;
						if (x1 < x2)
							fill_hline(x1 + 1, x2, sy, color);
					}
					sy++;

					if (sy > ey)
					{
						word1 = (INT16)combase16[spnt];
						ey = combase16[spnt+1];
						if (word1 == -1 && ey == 0xffff)
							break;
						ey = ROUND_TO_PIXEL(ey);
						spnt+=2;
					}
					else
						sx += word1;

					if (sy > ey2)
					{
						word2 = (INT16)combase16[spnt2];
						ey2 = ROUND_TO_PIXEL(combase16[spnt2+1]);
						spnt2+=2;
					}
					else
						sx2 += word2;

				} //while polygon
			}//if at least 2 sides
		} //if polygon
	} //while object
}



SCREEN_UPDATE( irobot )
{
	irobot_state *state = screen->machine().driver_data<irobot_state>();
	UINT8 *videoram = state->m_videoram;
	UINT8 *bitmap_base = state->m_bufsel ? state->m_polybitmap1 : state->m_polybitmap2;
	int x, y, offs;

	/* copy the polygon bitmap */
	for (y = cliprect->min_y; y <= cliprect->max_y; y++)
		draw_scanline8(bitmap, 0, y, BITMAP_WIDTH, &bitmap_base[y * BITMAP_WIDTH], NULL);

	/* redraw the non-zero characters in the alpha layer */
	for (y = offs = 0; y < 32; y++)
		for (x = 0; x < 32; x++, offs++)
		{
			int code = videoram[offs] & 0x3f;
			int color = ((videoram[offs] & 0xc0) >> 6) | (state->m_alphamap >> 3);

			drawgfx_transpen(bitmap,cliprect,screen->machine().gfx[0],
					code, color,
					0,0,
					8*x,8*y,0);
		}

	return 0;
}
