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

                        -= Sky Fox / Exerizer =-

                driver by   Luca Elia (l.elia@tin.it)


                            [ 1 Background ]

    The stars in the background are not tile based (I think!) and
    their rendering is entirely guesswork for now..

    I draw a star for each horizontal line using 2 bytes in the
    background rom:

    - the first byte seems a color / shape info
    - the second byte seems a position info

    The rom holds 4 chunks of $2000 bytes. Most of the data does not
    change between chunks, while the remaining part (which is rendered
    to what seems a "milky way") pulsates in color and/or shape
    to simulate the shimmering of stars (?!) if we draw one chunk only
    and cycle through the four. Indeed, there's a register cycling
    through 4 values.

    Since the result kind of matches a screenshot we have, I feel the
    drawn result is not that far from reality. On the other hand we
    have a random arrangement of stars, so it's hard to tell for sure..

                            [ 256 Sprites ]

    Sprites are 8 planes deep and can be 8x8, 16x16 or 32x32 pixels
    in size. They are stored as 32x32x8 tiles in the ROMs.


***************************************************************************/
#include "driver.h"

/* Variables only used here: */

static UINT8 vreg[8];


/* Variables that driver has access to: */

int skyfox_bg_pos, skyfox_bg_ctrl;



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

                            Memory Handlers

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

READ8_HANDLER( skyfox_vregs_r )	// for debug
{
	return vreg[offset];
}

WRITE8_HANDLER( skyfox_vregs_w )
{
	vreg[offset] = data;

	switch (offset)
	{
		case 0:	skyfox_bg_ctrl = data;	break;
		case 1:	soundlatch_w(0,data);	break;
		case 2:	break;
		case 3:	break;
		case 4:	break;
		case 5:	break;
		case 6:	break;
		case 7:	break;
	}
}



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

  Convert the color PROMs into a more useable format.

  There are three 256x4 palette PROMs (one per gun).
  I don't know the exact values of the resistors between the RAM and the
  RGB output. I assumed these values (the same as Commando)

  bit 3 -- 220 ohm resistor  -- RED/GREEN/BLUE
        -- 470 ohm resistor  -- RED/GREEN/BLUE
        -- 1  kohm resistor  -- RED/GREEN/BLUE
  bit 0 -- 2.2kohm resistor  -- RED/GREEN/BLUE

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

PALETTE_INIT( skyfox )
{
	int i;

	for (i = 0;i < 256;i++)
	{
		int bit0,bit1,bit2,bit3,r,g,b;

		/* red component */
		bit0 = (color_prom[i] >> 0) & 0x01;
		bit1 = (color_prom[i] >> 1) & 0x01;
		bit2 = (color_prom[i] >> 2) & 0x01;
		bit3 = (color_prom[i] >> 3) & 0x01;
		r = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
		/* green component */
		bit0 = (color_prom[i + 256] >> 0) & 0x01;
		bit1 = (color_prom[i + 256] >> 1) & 0x01;
		bit2 = (color_prom[i + 256] >> 2) & 0x01;
		bit3 = (color_prom[i + 256] >> 3) & 0x01;
		g = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;
		/* blue component */
		bit0 = (color_prom[i + 2*256] >> 0) & 0x01;
		bit1 = (color_prom[i + 2*256] >> 1) & 0x01;
		bit2 = (color_prom[i + 2*256] >> 2) & 0x01;
		bit3 = (color_prom[i + 2*256] >> 3) & 0x01;
		b = 0x0e * bit0 + 0x1f * bit1 + 0x43 * bit2 + 0x8f * bit3;

		palette_set_color(machine,i,MAKE_RGB(r,g,b));
	}

	/* Grey scale for the background??? */
	for (i = 0; i < 256; i++)
	{
		palette_set_color(machine,i+256,MAKE_RGB(i,i,i));
	}
}



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

                                Sprites Drawing

Offset:         Value:

03              Code: selects one of the 32x32 tiles in the ROMs.
                (Tiles $80-ff are bankswitched to cover $180 tiles)

02              Code + Attr

                    7654 ----   Code (low 4 bits)
                                8x8   sprites use bits 7654 (since there are 16 8x8  tiles in the 32x32 one)
                                16x16 sprites use bits --54 (since there are 4 16x16 tiles in the 32x32 one)
                                32x32 sprites use no bits   (since the 32x32 tile is already selected)

                    7--- 3---   Size
                                1--- 1--- : 32x32 sprites
                                0--- 1--- : 16x16 sprites
                                8x8 sprites otherwise

                    ---- -2--   Flip Y
                    ---- --1-   Flip X
                    ---- ---0   X Low Bit

00              Y

01              X (High 8 Bits)

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

static void draw_sprites(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
{
	int offs;

	int width	=	machine->screen[0].width;
	int height	=	machine->screen[0].height;

	/* The 32x32 tiles in the 80-ff range are bankswitched */
	int shift	=	(skyfox_bg_ctrl & 0x80) ? (4-1) : 4;

	for (offs = 0; offs < spriteram_size; offs += 4)
	{
		int xstart, ystart, xend, yend;
		int xinc, yinc, dx, dy;
		int low_code, high_code, n;

		int y		=		spriteram[offs+0];
		int x		=		spriteram[offs+1];
		int code	=		spriteram[offs+2] + spriteram[offs+3] * 256;
		int flipx	=		code & 0x2;
		int flipy	=		code & 0x4;

		x = x * 2 + (code & 1);	// add the least significant bit

		high_code = ((code >> 4) & 0x7f0) +
					((code & 0x8000) >> shift);

		switch( code & 0x88 )
		{
			case 0x88:	n = 4;	low_code = 0;										break;
			case 0x08:	n = 2;	low_code = ((code&0x20)?8:0) + ((code&0x10)?2:0);	break;
			default:	n = 1;	low_code = (code >> 4) & 0xf;
		}

#define DRAW_SPRITE(DX,DY,CODE) \
		drawgfx(bitmap,machine->gfx[0], \
				(CODE), \
				0, \
				flipx,flipy, \
				x + (DX),y + (DY), \
				cliprect,TRANSPARENCY_PEN, 0xff); \

		if (skyfox_bg_ctrl & 1)	// flipscreen
		{
			x = width  - x - (n-1)*8;
			y = height - y - (n-1)*8;
			flipx = !flipx;
			flipy = !flipy;
		}

		if (flipx)	{ xstart = n-1;  xend = -1;  xinc = -1; }
		else		{ xstart = 0;    xend = n;   xinc = +1; }

		if (flipy)	{ ystart = n-1;  yend = -1;  yinc = -1; }
		else		{ ystart = 0;    yend = n;   yinc = +1; }


		code = low_code + high_code;

		for (dy = ystart; dy != yend; dy += yinc)
		{
			for (dx = xstart; dx != xend; dx += xinc)
				DRAW_SPRITE( dx*8, dy*8, code++);

			if (n==2)	code+=2;
		}
	}
}





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

                            Background Rendering

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

static void draw_background(running_machine *machine, mame_bitmap *bitmap, const rectangle *cliprect)
{
	UINT8 *RAM	=	memory_region(REGION_GFX2);
	int x,y,i;

	/* The foreground stars (sprites) move at twice this speed when
       the bg scroll rate [e.g. (skyfox_bg_reg >> 1) & 7] is 4 */
	int pos = (skyfox_bg_pos >> 4) & (512*2-1);

	for (i = 0 ; i < 0x1000; i++)
	{
		int pen,offs,j;

		offs	=	(i*2+((skyfox_bg_ctrl>>4)&0x3)*0x2000) % 0x8000;

		pen		=	RAM[offs];
		x		=	RAM[offs+1]*2 + (i&1) + pos + ((i & 8)?512:0);
		y		=	((i/8)/2)*8 + (i%8);

		if (skyfox_bg_ctrl & 1)	// flipscreen
		{
			x = 512 * 2 - (x%(512*2));
			y = 256     - (y%256);
		}

		for (j = 0 ; j <= ((pen&0x80)?0:3); j++)
			*BITMAP_ADDR16(bitmap,
						   ( ((j/2)&1) + y ) % 256,
						   ( (j&1)     + x ) % 512) = machine->pens[256+(pen&0x7f)];
	}
}


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


                                Screen Drawing


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


VIDEO_UPDATE( skyfox )
{
	fillbitmap(bitmap,machine->pens[255],cliprect);	// the bg is black
	draw_background(machine, bitmap, cliprect);
	draw_sprites(machine, bitmap, cliprect);
	return 0;
}
