diff options
Diffstat (limited to 'src/mame/video/stvvdp1.c')
-rw-r--r-- | src/mame/video/stvvdp1.c | 2147 |
1 files changed, 2147 insertions, 0 deletions
diff --git a/src/mame/video/stvvdp1.c b/src/mame/video/stvvdp1.c new file mode 100644 index 00000000000..9ac5b3b6c29 --- /dev/null +++ b/src/mame/video/stvvdp1.c @@ -0,0 +1,2147 @@ +/* + +STV - VDP1 + +crude drawing code to support some of the basic vdp1 features +based on what hanagumi columns needs +-- to be expanded + +the vdp1 draws to the FRAMEBUFFER which is mapped in memory + +Framebuffer todo: +- finish manual erase +- add proper framebuffer erase +- 8 bpp support - now we always draw as 16 bpp, but this is not a problem since + VDP2 interprets framebuffer as 8 bpp in these cases +*/ + + +#include "driver.h" + +static int vdp1_sprite_log = 0; + +UINT32 *stv_vdp1_vram; +static UINT32 *stv_vdp1_regs; +UINT8* stv_vdp1_gfx_decode; + +extern UINT32 *stv_scu; +extern int stv_vblank; + +static UINT16 *stv_framebuffer[2]; +static UINT16 **stv_framebuffer_draw_lines; +UINT16 **stv_framebuffer_display_lines; +static int stv_framebuffer_width; +static int stv_framebuffer_height; +int stv_framebuffer_mode; +int stv_framebuffer_double_interlace; +static int stv_vdp1_fbcr_accessed; +static int stv_vdp1_current_display_framebuffer; +static int stv_vdp1_current_draw_framebuffer; +static int stv_vdp1_clear_framebuffer_on_next_frame; +static rectangle stv_vdp1_system_cliprect; +static rectangle stv_vdp1_user_cliprect; + +static int stvvdp1_local_x; +static int stvvdp1_local_y; + +struct stv_vdp1_poly_scanline +{ + INT32 x[2]; + INT32 b[2]; + INT32 g[2]; + INT32 r[2]; + INT32 db; + INT32 dg; + INT32 dr; +}; + +struct stv_vdp1_poly_scanline_data +{ + INT32 sy, ey; + struct stv_vdp1_poly_scanline scanline[512]; +}; + +static struct stv_vdp1_poly_scanline_data* stv_vdp1_shading_data; + +enum { FRAC_SHIFT = 16 }; + +struct spoint { + INT32 x, y; + INT32 u, v; +}; + +struct shaded_point +{ + INT32 x,y; + INT32 r,g,b; +}; + +#define RGB_R(_color) (_color & 0x1f) +#define RGB_G(_color) ((_color >> 5) & 0x1f) +#define RGB_B(_color) ((_color >> 10) & 0x1f) + +#define SWAP_INT32(_a,_b) \ + { \ + INT32 t; \ + t = _a; \ + _a = _b; \ + _b = t; \ + } + +#define SWAP_INT32PTR(_p1, _p2) \ + { \ + INT32 *p; \ + p = _p1; \ + _p1 = _p2; \ + _p2 = p; \ + } + +/*TV Mode Selection Register */ +/* + xxxx xxxx xxxx ---- | UNUSED + ---- ---- ---- x--- | VBlank Erase/Write (VBE) + ---- ---- ---- -xxx | TV Mode (TVM) + TV-Mode: + This sets the Frame Buffer size,the rotation of the Frame Buffer & the bit width. + bit 2 HDTV disable(0)/enable(1) + bit 1 non-rotation/rotation(1) + bit 0 16(0)/8(1) bits per pixel + Size of the Frame Buffer: + 7 invalid + 6 invalid + 5 invalid + 4 512x256 + 3 512x512 + 2 512x256 + 1 1024x256 + 0 512x256 +*/ +#define STV_VDP1_TVMR ((stv_vdp1_regs[0x000/4] >> 16)&0x0000ffff) +#define STV_VDP1_VBE ((STV_VDP1_TVMR & 0x0008) >> 3) +#define STV_VDP1_TVM ((STV_VDP1_TVMR & 0x0007) >> 0) + +/*Frame Buffer Change Mode Register*/ +/* + xxxx xxxx xxx- ---- | UNUSED + ---- ---- ---x ---- | Even/Odd Coordinate Select Bit (EOS) + ---- ---- ---- x--- | Double Interlace Mode (DIE) + ---- ---- ---- -x-- | Double Interlace Draw Line (DIL) + ---- ---- ---- --x- | Frame Buffer Change Trigger (FCM) + ---- ---- ---- ---x | Frame Buffer Change Mode (FCT) +*/ +#define STV_VDP1_FBCR ((stv_vdp1_regs[0x000/4] >> 0)&0x0000ffff) +#define STV_VDP1_EOS ((STV_VDP1_FBCR & 0x0010) >> 4) +#define STV_VDP1_DIE ((STV_VDP1_FBCR & 0x0008) >> 3) +#define STV_VDP1_DIL ((STV_VDP1_FBCR & 0x0004) >> 2) +#define STV_VDP1_FCM ((STV_VDP1_FBCR & 0x0002) >> 1) +#define STV_VDP1_FCT ((STV_VDP1_FBCR & 0x0001) >> 0) + +/*Plot Trigger Register*/ +/* + xxxx xxxx xxxx xx-- | UNUSED + ---- ---- ---- --xx | Plot Trigger Mode (PTM) + + Plot Trigger Mode: + 3 Invalid + 2 Automatic draw + 1 VDP1 draw by request + 0 VDP1 Idle (no access) +*/ +#define STV_VDP1_PTMR ((stv_vdp1_regs[0x004/4] >> 16)&0x0000ffff) +#define STV_VDP1_PTM ((STV_VDP1_PTMR & 0x0003) >> 0) +#define SET_PTM_FROM_1_TO_0 if(STV_VDP1_PTM & 1) stv_vdp1_regs[0x004/4]^=0x00010000 +/*Erase/Write Upper-Left register*/ +/* + x--- ---- ---- ---- | UNUSED + -xxx xxx- ---- ---- | X1 register + ---- ---x xxxx xxxx | Y1 register + +*/ +#define STV_VDP1_EWLR ((stv_vdp1_regs[0x008/4] >> 16)&0x0000ffff) +#define STV_VDP1_EWLR_X1 ((STV_VDP1_EWLR & 0x7e00) >> 9) +#define STV_VDP1_EWLR_Y1 ((STV_VDP1_EWLR & 0x01ff) >> 0) +/*Erase/Write Lower-Right register*/ +/* + xxxx xxx- ---- ---- | X3 register + ---- ---x xxxx xxxx | Y3 register + +*/ +#define STV_VDP1_EWRR ((stv_vdp1_regs[0x008/4] >> 0)&0x0000ffff) +#define STV_VDP1_EWRR_X3 ((STV_VDP1_EWRR & 0xfe00) >> 9) +#define STV_VDP1_EWRR_Y3 ((STV_VDP1_EWRR & 0x01ff) >> 0) +/*Transfer End Status Register*/ +/* + xxxx xxxx xxxx xx-- | UNUSED + ---- ---- ---- --x- | CEF + ---- ---- ---- ---x | BEF + +*/ +#define STV_VDP1_EDSR ((stv_vdp1_regs[0x010/4] >> 16)&0x0000ffff) +#define STV_VDP1_CEF (STV_VDP1_EDSR & 2) +#define STV_VDP1_BEF (STV_VDP1_EDSR & 1) +#define SET_CEF_FROM_1_TO_0 if(STV_VDP1_CEF) stv_vdp1_regs[0x010/4]^=0x00020000 +#define SET_CEF_FROM_0_TO_1 if(!(STV_VDP1_CEF)) stv_vdp1_regs[0x010/4]^=0x00020000 +/**/ + + + +static void stv_vdp1_process_list(void); + +READ32_HANDLER( stv_vdp1_regs_r ) +{ +// static int x; + +// x ^= 0x00020000; + + logerror ("cpu #%d (PC=%08X) VDP1: Read from Registers, Offset %04x\n",cpu_getactivecpu(), activecpu_get_pc(), offset); +// if (offset == 0x04) return x; + + return stv_vdp1_regs[offset]; +} + +static void stv_clear_framebuffer( int which_framebuffer ) +{ + if ( vdp1_sprite_log ) logerror( "Clearing %d framebuffer\n", stv_vdp1_current_draw_framebuffer ); + memset( stv_framebuffer[ which_framebuffer ], 0, 1024 * 256 * sizeof(UINT16) * 2 ); +} + + +static void stv_prepare_framebuffers( void ) +{ + int i,rowsize; + + rowsize = stv_framebuffer_width; + if ( stv_vdp1_current_draw_framebuffer == 0 ) + { + for ( i = 0; i < stv_framebuffer_height; i++ ) + { + stv_framebuffer_draw_lines[i] = &stv_framebuffer[0][ i * rowsize ]; + stv_framebuffer_display_lines[i] = &stv_framebuffer[1][ i * rowsize ]; + } + for ( ; i < 512; i++ ) + { + stv_framebuffer_draw_lines[i] = &stv_framebuffer[0][0]; + stv_framebuffer_display_lines[i] = &stv_framebuffer[1][0]; + } + + } + else + { + for ( i = 0; i < stv_framebuffer_height; i++ ) + { + stv_framebuffer_draw_lines[i] = &stv_framebuffer[1][ i * rowsize ]; + stv_framebuffer_display_lines[i] = &stv_framebuffer[0][ i * rowsize ]; + } + for ( ; i < 512; i++ ) + { + stv_framebuffer_draw_lines[i] = &stv_framebuffer[1][0]; + stv_framebuffer_display_lines[i] = &stv_framebuffer[0][0]; + } + + } + + for ( ; i < 512; i++ ) + { + stv_framebuffer_draw_lines[i] = &stv_framebuffer[0][0]; + stv_framebuffer_display_lines[i] = &stv_framebuffer[1][0]; + } + +} + +static void stv_vdp1_change_framebuffers( void ) +{ + stv_vdp1_current_display_framebuffer ^= 1; + stv_vdp1_current_draw_framebuffer ^= 1; + if ( vdp1_sprite_log ) logerror( "Changing framebuffers: %d - draw, %d - display\n", stv_vdp1_current_draw_framebuffer, stv_vdp1_current_display_framebuffer ); + stv_prepare_framebuffers(); +} + +static void stv_set_framebuffer_config( void ) +{ + if ( stv_framebuffer_mode == STV_VDP1_TVM && + stv_framebuffer_double_interlace == STV_VDP1_DIE ) return; + + if ( vdp1_sprite_log ) logerror( "Setting framebuffer config\n" ); + stv_framebuffer_mode = STV_VDP1_TVM; + stv_framebuffer_double_interlace = STV_VDP1_DIE; + switch( stv_framebuffer_mode ) + { + case 0: stv_framebuffer_width = 512; stv_framebuffer_height = 256; break; + case 1: stv_framebuffer_width = 1024; stv_framebuffer_height = 256; break; + case 2: stv_framebuffer_width = 512; stv_framebuffer_height = 256; break; + case 3: stv_framebuffer_width = 512; stv_framebuffer_height = 512; break; + case 4: stv_framebuffer_width = 512; stv_framebuffer_height = 256; break; + default: logerror( "Invalid framebuffer config %x\n", STV_VDP1_TVM ); stv_framebuffer_width = 512; stv_framebuffer_height = 256; break; + } + if ( STV_VDP1_DIE ) stv_framebuffer_height *= 2; /* double interlace */ + + stv_vdp1_current_draw_framebuffer = 0; + stv_vdp1_current_display_framebuffer = 1; + stv_prepare_framebuffers(); +} + +WRITE32_HANDLER( stv_vdp1_regs_w ) +{ + COMBINE_DATA(&stv_vdp1_regs[offset]); + if ( offset == 0 ) + { + stv_set_framebuffer_config(); + if ( ACCESSING_LSW32 ) + { + if ( vdp1_sprite_log ) logerror( "VDP1: Access to register FBCR = %1X\n", STV_VDP1_FBCR ); + stv_vdp1_fbcr_accessed = 1; + } + else + { + if ( vdp1_sprite_log ) logerror( "VDP1: Access to register TVMR = %1X\n", STV_VDP1_TVMR ); + if ( STV_VDP1_VBE && stv_vblank ) + { + stv_vdp1_clear_framebuffer_on_next_frame = 1; + } + + /* needed by pblbeach, it doesn't clear local coordinates in its sprite list...*/ + if ( !strcmp(Machine->gamedrv->name, "pblbeach") ) + { + stvvdp1_local_x = stvvdp1_local_y = 0; + } + } + } + else if ( offset == 1 ) + { + if ( ACCESSING_MSW32 ) + { + if ( STV_VDP1_PTMR == 1 ) + { + if ( vdp1_sprite_log ) logerror( "VDP1: Access to register PTMR = %1X\n", STV_VDP1_PTMR ); + stv_vdp1_process_list( ); + + if(!(stv_scu[40] & 0x2000)) /*Sprite draw end irq*/ + { + logerror( "Interrupt: Sprite draw end, Vector 0x4d, Level 0x02\n" ); + cpunum_set_input_line_and_vector(0, 2, HOLD_LINE , 0x4d); + } + } + } + else if ( ACCESSING_LSW32 ) + { + if ( vdp1_sprite_log ) logerror( "VDP1: Erase data set %08X\n", data ); + } + } + else if ( offset == 2 ) + { + if ( ACCESSING_MSW32 ) + { + if ( vdp1_sprite_log ) logerror( "VDP1: Erase upper-left coord set: %08X\n", data ); + } + else if ( ACCESSING_LSW32 ) + { + if ( vdp1_sprite_log ) logerror( "VDP1: Erase lower-right coord set: %08X\n", data ); + } + } + +} + +READ32_HANDLER ( stv_vdp1_vram_r ) +{ + return stv_vdp1_vram[offset]; +} + + +WRITE32_HANDLER ( stv_vdp1_vram_w ) +{ + UINT8 *vdp1 = stv_vdp1_gfx_decode; + + COMBINE_DATA (&stv_vdp1_vram[offset]); + +// if (((offset * 4) > 0xdf) && ((offset * 4) < 0x140)) +// { +// logerror("cpu #%d (PC=%08X): VRAM dword write to %08X = %08X & %08X\n", cpu_getactivecpu(), activecpu_get_pc(), offset*4, data, mem_mask ^ 0xffffffff); +// } + + data = stv_vdp1_vram[offset]; + /* put in gfx region for easy decoding */ + vdp1[offset*4+0] = (data & 0xff000000) >> 24; + vdp1[offset*4+1] = (data & 0x00ff0000) >> 16; + vdp1[offset*4+2] = (data & 0x0000ff00) >> 8; + vdp1[offset*4+3] = (data & 0x000000ff) >> 0; +} + +WRITE32_HANDLER ( stv_vdp1_framebuffer0_w ) +{ + //popmessage ("STV VDP1 Framebuffer 0 WRITE offset %08x data %08x",offset, data); + if ( STV_VDP1_TVM & 0 ) + { + /* 8-bit mode */ + } + else + { + /* 16-bit mode */ + if ( ACCESSING_MSW32 ) + { + stv_framebuffer[stv_vdp1_current_draw_framebuffer][offset*2] = (data >> 16) & 0xffff; + } + if ( ACCESSING_LSW32 ) + { + stv_framebuffer[stv_vdp1_current_draw_framebuffer][offset*2+1] = data & 0xffff; + } + } +} + +READ32_HANDLER ( stv_vdp1_framebuffer0_r ) +{ + UINT32 result = 0; + //popmessage ("STV VDP1 Framebuffer 0 READ offset %08x",offset); + if ( STV_VDP1_TVM & 0 ) + { + /* 8-bit mode */ + } + else + { + /* 16-bit mode */ + if ( ACCESSING_MSW32 ) + { + result |= (stv_framebuffer[stv_vdp1_current_draw_framebuffer][offset*2] << 16); + } + if ( ACCESSING_LSW32 ) + { + result |= stv_framebuffer[stv_vdp1_current_draw_framebuffer][offset*2+1]; + } + + } + + return result; +} + +#ifdef UNUSED_FUNCTION +WRITE32_HANDLER ( stv_vdp1_framebuffer1_w ) +{ + //popmessage ("STV VDP1 Framebuffer 1 WRITE offset %08x data %08x",offset, data); +} + +READ32_HANDLER ( stv_vdp1_framebuffer1_r ) +{ + //popmessage ("STV VDP1 Framebuffer 1 READ offset %08x",offset); + return 0xffff; +} +#endif + + +/* + +there is a command every 0x20 bytes +the first word is the control word +the rest are data used by it + +--- +00 CMDCTRL + e--- ---- ---- ---- | end bit (15) + -jjj ---- ---- ---- | jump select bits (12-14) + ---- zzzz ---- ---- | zoom point / hotspot (8-11) + ---- ---- 00-- ---- | UNUSED + ---- ---- --dd ---- | character read direction (4,5) + ---- ---- ---- cccc | command bits (0-3) + +02 CMDLINK + llll llll llll ll-- | link + ---- ---- ---- --00 | UNUSED + +04 CMDPMOD + m--- ---- ---- ---- | MON (looks at MSB and apply shadows etc.) + -00- ---- ---- ---- | UNUSED + ---h ---- ---- ---- | HSS (High Speed Shrink) + ---- p--- ---- ---- | PCLIP (Pre Clipping Disable) + ---- -c-- ---- ---- | CLIP (Clipping Mode Bit) + ---- --m- ---- ---- | CMOD (User Clipping Enable Bit) + ---- ---M ---- ---- | MESH (Mesh Enable Bit) + ---- ---- e--- ---- | ECD (End Code Disable) + ---- ---- -S-- ---- | SPD (Transparent Pixel Disable) + ---- ---- --cc c--- | Colour Mode + ---- ---- ---- -CCC | Colour Calculation bits + +06 CMDCOLR + mmmm mmmm mmmm mmmm | Colour Bank, Colour Lookup /8 + +08 CMDSRCA (Character Address) + aaaa aaaa aaaa aa-- | Character Address + ---- ---- ---- --00 | UNUSED + +0a CMDSIZE (Character Size) + 00-- ---- ---- ---- | UNUSED + --xx xxxx ---- ---- | Character Size (X) + ---- ---- yyyy yyyy | Character Size (Y) + +0c CMDXA (used for normal sprite) + eeee ee-- ---- ---- | extension bits + ---- --xx xxxx xxxx | x position + +0e CMDYA (used for normal sprite) + eeee ee-- ---- ---- | extension bits + ---- --yy yyyy yyyy | y position + +10 CMDXB +12 CMDYB +14 CMDXC +16 CMDYC +18 CMDXD +1a CMDYD +1c CMDGRDA (Gouraud Shading Table) +1e UNUSED +--- + + +*/ + +static struct stv_vdp2_sprite_list +{ + + int CMDCTRL, CMDLINK, CMDPMOD, CMDCOLR, CMDSRCA, CMDSIZE, CMDGRDA; + int CMDXA, CMDYA; + int CMDXB, CMDYB; + int CMDXC, CMDYC; + int CMDXD, CMDYD; + + int ispoly; + +} stv2_current_sprite; + +/* Gouraud shading */ + +static struct _stv_gouraud_shading +{ + /* Gouraud shading table */ + UINT16 GA; + UINT16 GB; + UINT16 GC; + UINT16 GD; +} stv_gouraud_shading; + +static void stv_clear_gouraud_shading(void) +{ + memset( &stv_gouraud_shading, 0, sizeof( stv_gouraud_shading ) ); +} + +static UINT8 stv_read_gouraud_table(void) +{ + int gaddr; + + if ( (stv2_current_sprite.CMDPMOD & 0x7) == 4 ) + { + gaddr = stv2_current_sprite.CMDGRDA * 8; + stv_gouraud_shading.GA = (stv_vdp1_vram[gaddr/4] >> 16) & 0xffff; + stv_gouraud_shading.GB = (stv_vdp1_vram[gaddr/4] >> 0) & 0xffff; + stv_gouraud_shading.GC = (stv_vdp1_vram[gaddr/4 + 1] >> 16) & 0xffff; + stv_gouraud_shading.GD = (stv_vdp1_vram[gaddr/4 + 1] >> 0) & 0xffff; + return 1; + } + else + { + return 0; + } +} + +INLINE INT32 _shading( INT32 color, INT32 correction ) +{ + correction = (correction >> 16) & 0x1f; + color += (correction - 16); + + if ( color < 0 ) color = 0; + if ( color > 0x1f ) color = 0x1f; + + return color; +}; + +static UINT16 stv_vdp1_apply_gouraud_shading( int x, int y, UINT16 pix ) +{ + INT32 r,g,b, msb; + + msb = pix & 0x8000; + +#ifdef MAME_DEBUG + if ( (stv_vdp1_shading_data->scanline[y].x[0] >> 16) != x ) + { + logerror( "ERROR in computing x coordinates (line %d, x = %x, %d, xc = %x, %d)\n", y, x, x, stv_vdp1_shading_data->scanline[y].x[0], stv_vdp1_shading_data->scanline[y].x[0] >> 16 ); + }; +#endif + + b = RGB_B(pix); + g = RGB_G(pix); + r = RGB_R(pix); + + b = _shading( b, stv_vdp1_shading_data->scanline[y].b[0] ); + g = _shading( g, stv_vdp1_shading_data->scanline[y].g[0] ); + r = _shading( r, stv_vdp1_shading_data->scanline[y].r[0] ); + + stv_vdp1_shading_data->scanline[y].b[0] += stv_vdp1_shading_data->scanline[y].db; + stv_vdp1_shading_data->scanline[y].g[0] += stv_vdp1_shading_data->scanline[y].dg; + stv_vdp1_shading_data->scanline[y].r[0] += stv_vdp1_shading_data->scanline[y].dr; + + stv_vdp1_shading_data->scanline[y].x[0] += 1 << FRAC_SHIFT; + + return msb | b << 10 | g << 5 | r; +} + +static void stv_vdp1_setup_shading_for_line(INT32 y, INT32 x1, INT32 x2, + INT32 r1, INT32 g1, INT32 b1, + INT32 r2, INT32 g2, INT32 b2) +{ + int xx1 = x1>>FRAC_SHIFT; + int xx2 = x2>>FRAC_SHIFT; + + + if ( xx1 > xx2 ) + { + SWAP_INT32(xx1, xx2); + SWAP_INT32(r1, r2); + SWAP_INT32(g1, g2); + SWAP_INT32(b1, b2); + } + + if ( (y >= 0) && (y < 512) ) + { + INT32 dx; + INT32 gbd, ggd, grd; + + dx = xx2 - xx1; + + if ( dx == 0 ) + { + gbd = ggd = grd = 0; + } + else + { + gbd = abs(b2 - b1) / dx; + if (b2 < b1) gbd = -gbd; + ggd = abs(g2 - g1) / dx; + if (g2 < g1) ggd = -ggd; + grd = abs(r2 - r1) / dx; + if (r2 < r1) grd = -grd; + } + + stv_vdp1_shading_data->scanline[y].x[0] = x1; + stv_vdp1_shading_data->scanline[y].x[1] = x2; + + stv_vdp1_shading_data->scanline[y].b[0] = b1; + stv_vdp1_shading_data->scanline[y].g[0] = g1; + stv_vdp1_shading_data->scanline[y].r[0] = r1; + stv_vdp1_shading_data->scanline[y].b[1] = b2; + stv_vdp1_shading_data->scanline[y].g[1] = g2; + stv_vdp1_shading_data->scanline[y].r[1] = r2; + + stv_vdp1_shading_data->scanline[y].db = gbd; + stv_vdp1_shading_data->scanline[y].dg = ggd; + stv_vdp1_shading_data->scanline[y].dr = grd; + + } +} + +static void stv_vdp1_setup_shading_for_slope( + INT32 x1, INT32 x2, INT32 sl1, INT32 sl2, INT32 *nx1, INT32 *nx2, + INT32 r1, INT32 r2, INT32 slr1, INT32 slr2, INT32 *nr1, INT32 *nr2, + INT32 g1, INT32 g2, INT32 slg1, INT32 slg2, INT32 *ng1, INT32 *ng2, + INT32 b1, INT32 b2, INT32 slb1, INT32 slb2, INT32 *nb1, INT32 *nb2, + INT32 _y1, INT32 y2) +{ + if(x1 > x2 || (x1==x2 && sl1 > sl2)) { + SWAP_INT32(x1,x2); + SWAP_INT32(sl1,sl2); + SWAP_INT32PTR(nx1, nx2); + SWAP_INT32(r1,r2); + SWAP_INT32(slr1, slr2); + SWAP_INT32PTR(nr1, nr2); + SWAP_INT32(g1, g2); + SWAP_INT32(slg1, slg2); + SWAP_INT32PTR(ng1, ng2); + SWAP_INT32(b1, b2); + SWAP_INT32(slb1, slb2); + SWAP_INT32PTR(nb1, nb2); + } + + while(_y1 < y2) + { + stv_vdp1_setup_shading_for_line(_y1, x1, x2, r1, g1, b1, r2, g2, b2); + x1 += sl1; + r1 += slr1; + g1 += slg1; + b1 += slb1; + + x2 += sl2; + r2 += slr2; + g2 += slg2; + b2 += slb2; + _y1++; + } + *nx1 = x1; + *nr1 = r1; + *ng1 = g1; + *nb1 = b1; + + *nx2 = x2; + *nr2 = r2; + *nb2 = b2; + *ng2 = g2; +} + +static void stv_vdp1_setup_shading(const struct spoint* q, const rectangle *cliprect) +{ + INT32 x1, x2, delta, cury, limy; + INT32 r1, g1, b1, r2, g2, b2; + INT32 sl1, slg1, slb1, slr1; + INT32 sl2, slg2, slb2, slr2; + int pmin, pmax, i, ps1, ps2; + struct shaded_point p[8]; + UINT16 gd[4]; + + if ( stv_read_gouraud_table() == 0 ) return; + + gd[0] = stv_gouraud_shading.GA; + gd[1] = stv_gouraud_shading.GB; + gd[2] = stv_gouraud_shading.GC; + gd[3] = stv_gouraud_shading.GD; + + for(i=0; i<4; i++) { + p[i].x = p[i+4].x = q[i].x << FRAC_SHIFT; + p[i].y = p[i+4].y = q[i].y; + p[i].r = p[i+4].r = RGB_R(gd[i]) << FRAC_SHIFT; + p[i].g = p[i+4].g = RGB_G(gd[i]) << FRAC_SHIFT; + p[i].b = p[i+4].b = RGB_B(gd[i]) << FRAC_SHIFT; + } + + pmin = pmax = 0; + for(i=1; i<4; i++) { + if(p[i].y < p[pmin].y) + pmin = i; + if(p[i].y > p[pmax].y) + pmax = i; + } + + cury = p[pmin].y; + limy = p[pmax].y; + + stv_vdp1_shading_data->sy = cury; + stv_vdp1_shading_data->ey = limy; + + if(cury == limy) { + x1 = x2 = p[0].x; + ps1 = ps2 = 0; + for(i=1; i<4; i++) { + if(p[i].x < x1) { + x1 = p[i].x; + ps1 = i; + } + if(p[i].x > x2) { + x2 = p[i].x; + ps2 = i; + } + } + stv_vdp1_setup_shading_for_line(cury, x1, x2, p[ps1].r, p[ps1].g, p[ps1].b, p[ps2].r, p[ps2].g, p[ps2].b); + goto finish; + } + + ps1 = pmin+4; + ps2 = pmin; + + goto startup; + + for(;;) { + if(p[ps1-1].y == p[ps2+1].y) { + stv_vdp1_setup_shading_for_slope( + x1, x2, sl1, sl2, &x1, &x2, + r1, r2, slr1, slr2, &r1, &r2, + g1, g2, slg1, slg2, &g1, &g2, + b1, b2, slb1, slb2, &b1, &b2, + cury, p[ps1-1].y); + cury = p[ps1-1].y; + if(cury >= limy) + break; + ps1--; + ps2++; + + startup: + while(p[ps1-1].y == cury) + ps1--; + while(p[ps2+1].y == cury) + ps2++; + x1 = p[ps1].x; + r1 = p[ps1].r; + g1 = p[ps1].g; + b1 = p[ps1].b; + x2 = p[ps2].x; + r2 = p[ps2].r; + g2 = p[ps2].g; + b2 = p[ps2].b; + + delta = cury-p[ps1-1].y; + sl1 = (x1-p[ps1-1].x)/delta; + slr1 = (r1-p[ps1-1].r)/delta; + slg1 = (g1-p[ps1-1].g)/delta; + slb1 = (b1-p[ps1-1].b)/delta; + + delta = cury-p[ps2+1].y; + sl2 = (x2-p[ps2+1].x)/delta; + slr2 = (r2-p[ps2+1].r)/delta; + slg2 = (g2-p[ps2+1].g)/delta; + slb2 = (b2-p[ps2+1].b)/delta; + } else if(p[ps1-1].y < p[ps2+1].y) { + stv_vdp1_setup_shading_for_slope( + x1, x2, sl1, sl2, &x1, &x2, + r1, r2, slr1, slr2, &r1, &r2, + g1, g2, slg1, slg2, &g1, &g2, + b1, b2, slb1, slb2, &b1, &b2, + cury, p[ps1-1].y); + cury = p[ps1-1].y; + if(cury >= limy) + break; + ps1--; + while(p[ps1-1].y == cury) + ps1--; + x1 = p[ps1].x; + r1 = p[ps1].r; + g1 = p[ps1].g; + b1 = p[ps1].b; + + delta = cury-p[ps1-1].y; + sl1 = (x1-p[ps1-1].x)/delta; + slr1 = (r1-p[ps1-1].r)/delta; + slg1 = (g1-p[ps1-1].g)/delta; + slb1 = (b1-p[ps1-1].b)/delta; + } else { + stv_vdp1_setup_shading_for_slope( + x1, x2, sl1, sl2, &x1, &x2, + r1, r2, slr1, slr2, &r1, &r2, + g1, g2, slg1, slg2, &g1, &g2, + b1, b2, slb1, slb2, &b1, &b2, + cury, p[ps2+1].y); + cury = p[ps2+1].y; + if(cury >= limy) + break; + ps2++; + while(p[ps2+1].y == cury) + ps2++; + x2 = p[ps2].x; + r2 = p[ps2].r; + g2 = p[ps2].g; + b2 = p[ps2].b; + + delta = cury-p[ps2+1].y; + sl2 = (x2-p[ps2+1].x)/delta; + slr2 = (r2-p[ps2+1].r)/delta; + slg2 = (g2-p[ps2+1].g)/delta; + slb2 = (b2-p[ps2+1].b)/delta; + } + } + if(cury == limy) + stv_vdp1_setup_shading_for_line(cury, x1, x2, r1, g1, b1, r2, g2, b2 ); + +finish: + + if ( stv_vdp1_shading_data->sy < 0 ) stv_vdp1_shading_data->sy = 0; + if ( stv_vdp1_shading_data->sy >= 512 ) return; + if ( stv_vdp1_shading_data->ey < 0 ) return; + if ( stv_vdp1_shading_data->ey >= 512 ) stv_vdp1_shading_data->ey = 511; + + for ( cury = stv_vdp1_shading_data->sy; cury <= stv_vdp1_shading_data->ey; cury++ ) + { + while( (stv_vdp1_shading_data->scanline[cury].x[0] >> 16) < cliprect->min_x ) + { + stv_vdp1_shading_data->scanline[cury].x[0] += (1 << FRAC_SHIFT); + stv_vdp1_shading_data->scanline[cury].b[0] += stv_vdp1_shading_data->scanline[cury].db; + stv_vdp1_shading_data->scanline[cury].g[0] += stv_vdp1_shading_data->scanline[cury].dg; + stv_vdp1_shading_data->scanline[cury].r[0] += stv_vdp1_shading_data->scanline[cury].dr; + } + } + +} + +/* note that if we're drawing +to the framebuffer we CAN'T frameskip the vdp1 drawing as the hardware can READ the framebuffer +and if we skip the drawing the content could be incorrect when it reads it, although i have no idea +why they would want to */ + +extern UINT32* stv_vdp2_cram; + +static UINT8* gfxdata; +static UINT16 sprite_colorbank; + + +static void (*drawpixel)(int x, int y, int patterndata, int offsetcnt); + +static void drawpixel_poly(int x, int y, int patterndata, int offsetcnt) +{ + stv_framebuffer_draw_lines[y][x] = stv2_current_sprite.CMDCOLR; +} + +static void drawpixel_8bpp_trans(int x, int y, int patterndata, int offsetcnt) +{ + UINT16 pix; + + pix = gfxdata[patterndata+offsetcnt]; + if ( pix & 0xff ) + { + stv_framebuffer_draw_lines[y][x] = pix | sprite_colorbank; + } +}; + +static void drawpixel_4bpp_notrans(int x, int y, int patterndata, int offsetcnt) +{ + UINT16 pix; + + pix = gfxdata[patterndata+offsetcnt/2]; + pix = offsetcnt&1 ? (pix & 0x0f):((pix & 0xf0)>>4) ; + stv_framebuffer_draw_lines[y][x] = pix | sprite_colorbank; +} + +static void drawpixel_4bpp_trans(int x, int y, int patterndata, int offsetcnt) +{ + UINT16 pix; + + pix = gfxdata[patterndata+offsetcnt/2]; + pix = offsetcnt&1 ? (pix & 0x0f):((pix & 0xf0)>>4) ; + if ( pix ) + stv_framebuffer_draw_lines[y][x] = pix | sprite_colorbank; +} + +static void drawpixel_generic(int x, int y, int patterndata, int offsetcnt) +{ + int pix,mode,transmask, spd = stv2_current_sprite.CMDPMOD & 0x40; + int mesh = stv2_current_sprite.CMDPMOD & 0x100; + int pix2; + + if ( mesh && !((x ^ y) & 1) ) + { + return; + } + + if ( stv2_current_sprite.ispoly ) + { + pix = stv2_current_sprite.CMDCOLR&0xffff; + + transmask = 0xffff; + if ( pix & 0x8000 ) + { + mode = 5; + } + else + { + mode = 1; + } + } + else + { + switch (stv2_current_sprite.CMDPMOD&0x0038) + { + case 0x0000: // mode 0 16 colour bank mode (4bits) (hanagumi blocks) + // most of the shienryu sprites use this mode + pix = gfxdata[patterndata+offsetcnt/2]; + pix = offsetcnt&1 ? (pix & 0x0f):((pix & 0xf0)>>4) ; + pix = pix+((stv2_current_sprite.CMDCOLR&0xfff0)); + mode = 0; + transmask = 0xf; + break; + case 0x0008: // mode 1 16 colour lookup table mode (4bits) + // shienryu explosisons (and some enemies) use this mode + pix2 = gfxdata[patterndata+offsetcnt/2]; + pix2 = offsetcnt&1 ? (pix2 & 0x0f):((pix2 & 0xf0)>>4); + pix = pix2&1 ? + ((((stv_vdp1_vram[(((stv2_current_sprite.CMDCOLR&0xffff)*8)>>2)+((pix2&0xfffe)/2)])) & 0x0000ffff) >> 0): + ((((stv_vdp1_vram[(((stv2_current_sprite.CMDCOLR&0xffff)*8)>>2)+((pix2&0xfffe)/2)])) & 0xffff0000) >> 16); + + mode = 5; + transmask = 0xffff; + + if ( !spd ) + { + if ( (pix2 & 0xf) == 0 ) + { + return; + } + else + { + spd = 1; + } + } + break; + case 0x0010: // mode 2 64 colour bank mode (8bits) (character select portraits on hanagumi) + pix = gfxdata[patterndata+offsetcnt]; + mode = 2; + pix = pix+(stv2_current_sprite.CMDCOLR&0xffc0); + transmask = 0x3f; + break; + case 0x0018: // mode 3 128 colour bank mode (8bits) (little characters on hanagumi use this mode) + pix = gfxdata[patterndata+offsetcnt]; + pix = pix+(stv2_current_sprite.CMDCOLR&0xff80); + transmask = 0x7f; + mode = 3; + // pix = mame_rand(Machine); + break; + case 0x0020: // mode 4 256 colour bank mode (8bits) (hanagumi title) + pix = gfxdata[patterndata+offsetcnt]; + pix = pix+(stv2_current_sprite.CMDCOLR&0xff00); + transmask = 0xff; + mode = 4; + break; + case 0x0028: // mode 5 32,768 colour RGB mode (16bits) + pix = gfxdata[patterndata+offsetcnt*2+1] | (gfxdata[patterndata+offsetcnt*2]<<8) ; + mode = 5; + transmask = 0xffff; + break; + default: // other settings illegal + pix = mame_rand(Machine); + mode = 0; + transmask = 0xff; + } + + + // preliminary end code disable support + if ( ((stv2_current_sprite.CMDPMOD & 0x80) == 0) && + ((pix & transmask) == transmask) ) + { + return; + } + } + + /* MSBON */ + pix |= stv2_current_sprite.CMDPMOD & 0x8000; + if ( mode != 5 ) + { + if ( (pix & transmask) || spd ) + { + stv_framebuffer_draw_lines[y][x] = pix; + } + } + else + { + if ( (pix & transmask) || spd ) + { + switch( stv2_current_sprite.CMDPMOD & 0x7 ) + { + case 0: /* replace */ + stv_framebuffer_draw_lines[y][x] = pix; + break; + case 1: /* shadow */ + if ( stv_framebuffer_draw_lines[y][x] & 0x8000 ) + { + stv_framebuffer_draw_lines[y][x] = ((stv_framebuffer_draw_lines[y][x] & ~0x8421) >> 1) | 0x8000; + } + break; + case 2: /* half luminance */ + stv_framebuffer_draw_lines[y][x] = ((pix & ~0x8421) >> 1) | 0x8000; + break; + case 3: /* half transparent */ + if ( stv_framebuffer_draw_lines[y][x] & 0x8000 ) + { + stv_framebuffer_draw_lines[y][x] = alpha_blend_r16( stv_framebuffer_draw_lines[y][x], pix, 0x80 ) | 0x8000; + } + else + { + stv_framebuffer_draw_lines[y][x] = pix; + } + break; + case 4: /* Gouraud shading */ + stv_framebuffer_draw_lines[y][x] = stv_vdp1_apply_gouraud_shading( x, y, pix ); + break; + default: + stv_framebuffer_draw_lines[y][x] = pix; + break; + } + } + } +} + + +static void stv_vdp1_set_drawpixel(void) +{ + int sprite_type = stv2_current_sprite.CMDCTRL & 0x000f; + int sprite_mode = stv2_current_sprite.CMDPMOD&0x0038; + int spd = stv2_current_sprite.CMDPMOD & 0x40; + int mesh = stv2_current_sprite.CMDPMOD & 0x100; + int ecd = stv2_current_sprite.CMDPMOD & 0x80; + + gfxdata = stv_vdp1_gfx_decode; + + if ( mesh || !ecd || ((stv2_current_sprite.CMDPMOD & 0x7) != 0) ) + { + drawpixel = drawpixel_generic; + return; + } + + if (sprite_type == 4 && ((stv2_current_sprite.CMDPMOD & 0x7) == 0)) + { + drawpixel = drawpixel_poly; + } + else if ( (sprite_mode == 0x20) && !spd ) + { + sprite_colorbank = (stv2_current_sprite.CMDCOLR&0xff00); + drawpixel = drawpixel_8bpp_trans; + } + else if ((sprite_mode == 0x00) && spd) + { + sprite_colorbank = (stv2_current_sprite.CMDCOLR&0xfff0); + drawpixel = drawpixel_4bpp_notrans; + } + else if (sprite_mode == 0x00 && !spd ) + { + sprite_colorbank = (stv2_current_sprite.CMDCOLR&0xfff0); + drawpixel = drawpixel_4bpp_trans; + } + else + { + drawpixel = drawpixel_generic; + } +} + + +static void vdp1_fill_slope(const rectangle *cliprect, int patterndata, int xsize, + INT32 x1, INT32 x2, INT32 sl1, INT32 sl2, INT32 *nx1, INT32 *nx2, + INT32 u1, INT32 u2, INT32 slu1, INT32 slu2, INT32 *nu1, INT32 *nu2, + INT32 v1, INT32 v2, INT32 slv1, INT32 slv2, INT32 *nv1, INT32 *nv2, + INT32 _y1, INT32 y2) +{ + if(_y1 > cliprect->max_y) + return; + + if(y2 <= cliprect->min_y) { + int delta = y2-_y1; + *nx1 = x1+delta*sl1; + *nu1 = u1+delta*slu1; + *nv1 = v1+delta*slv1; + *nx2 = x2+delta*sl2; + *nu2 = u2+delta*slu2; + *nv2 = v2+delta*slv2; + return; + } + + if(y2 > cliprect->max_y) + y2 = cliprect->max_y+1; + + if(_y1 < cliprect->min_y) { + int delta = cliprect->min_y - _y1; + x1 += delta*sl1; + u1 += delta*slu1; + v1 += delta*slv1; + x2 += delta*sl2; + u2 += delta*slu2; + v2 += delta*slv2; + _y1 = cliprect->min_y; + } + + if(x1 > x2 || (x1==x2 && sl1 > sl2)) { + INT32 t, *tp; + t = x1; + x1 = x2; + x2 = t; + t = sl1; + sl1 = sl2; + sl2 = t; + tp = nx1; + nx1 = nx2; + nx2 = tp; + + t = u1; + u1 = u2; + u2 = t; + t = slu1; + slu1 = slu2; + slu2 = t; + tp = nu1; + nu1 = nu2; + nu2 = tp; + + t = v1; + v1 = v2; + v2 = t; + t = slv1; + slv1 = slv2; + slv2 = t; + tp = nv1; + nv1 = nv2; + nv2 = tp; + } + + while(_y1 < y2) { + if(_y1 >= cliprect->min_y) { + INT32 slux = 0, slvx = 0; + int xx1 = x1>>FRAC_SHIFT; + int xx2 = x2>>FRAC_SHIFT; + INT32 u = u1; + INT32 v = v1; + if(xx1 != xx2) { + int delta = xx2-xx1; + slux = (u2-u1)/delta; + slvx = (v2-v1)/delta; + } + if(xx1 <= cliprect->max_x || xx2 >= cliprect->min_x) { + if(xx1 < cliprect->min_x) { + int delta = cliprect->min_x-xx1; + u += slux*delta; + v += slvx*delta; + xx1 = cliprect->min_x; + } + if(xx2 > cliprect->max_x) + xx2 = cliprect->max_x; + + while(xx1 <= xx2) { + drawpixel(xx1,_y1, + patterndata, + (v>>FRAC_SHIFT)*xsize+(u>>FRAC_SHIFT)); + xx1++; + u += slux; + v += slvx; + } + } + } + + x1 += sl1; + u1 += slu1; + v1 += slv1; + x2 += sl2; + u2 += slu2; + v2 += slv2; + _y1++; + } + *nx1 = x1; + *nu1 = u1; + *nv1 = v1; + *nx2 = x2; + *nu2 = u2; + *nv2 = v2; +} + +static void vdp1_fill_line(const rectangle *cliprect, int patterndata, int xsize, INT32 y, + INT32 x1, INT32 x2, INT32 u1, INT32 u2, INT32 v1, INT32 v2) +{ + int xx1 = x1>>FRAC_SHIFT; + int xx2 = x2>>FRAC_SHIFT; + + if(y > cliprect->max_y || y < cliprect->min_y) + return; + + if(xx1 <= cliprect->max_x || xx2 >= cliprect->min_x) { + INT32 slux = 0, slvx = 0; + INT32 u = u1; + INT32 v = v1; + if(xx1 != xx2) { + int delta = xx2-xx1; + slux = (u2-u1)/delta; + slvx = (v2-v1)/delta; + } + if(xx1 < cliprect->min_x) { + int delta = cliprect->min_x-xx1; + u += slux*delta; + v += slvx*delta; + xx1 = cliprect->min_x; + } + if(xx2 > cliprect->max_x) + xx2 = cliprect->max_x; + + while(xx1 <= xx2) { + drawpixel(xx1,y, + patterndata, + (v>>FRAC_SHIFT)*xsize+(u>>FRAC_SHIFT)); + xx1++; + u += slux; + v += slvx; + } + } +} + +static void vdp1_fill_quad(const rectangle *cliprect, int patterndata, int xsize, const struct spoint *q) +{ + INT32 sl1, sl2, slu1, slu2, slv1, slv2, cury, limy, x1, x2, u1, u2, v1, v2, delta; + int pmin, pmax, i, ps1, ps2; + struct spoint p[8]; + + for(i=0; i<4; i++) { + p[i].x = p[i+4].x = q[i].x << FRAC_SHIFT; + p[i].y = p[i+4].y = q[i].y; + p[i].u = p[i+4].u = q[i].u << FRAC_SHIFT; + p[i].v = p[i+4].v = q[i].v << FRAC_SHIFT; + } + + pmin = pmax = 0; + for(i=1; i<4; i++) { + if(p[i].y < p[pmin].y) + pmin = i; + if(p[i].y > p[pmax].y) + pmax = i; + } + + cury = p[pmin].y; + limy = p[pmax].y; + + if(cury == limy) { + x1 = x2 = p[0].x; + u1 = u2 = p[0].u; + v1 = v2 = p[0].v; + for(i=1; i<4; i++) { + if(p[i].x < x1) { + x1 = p[i].x; + u1 = p[i].u; + v1 = p[i].v; + } + if(p[i].x > x2) { + x2 = p[i].x; + u2 = p[i].u; + v2 = p[i].v; + } + } + vdp1_fill_line(cliprect, patterndata, xsize, cury, x1, x2, u1, u2, v1, v2); + return; + } + + if(cury > cliprect->max_y) + return; + if(limy <= cliprect->min_y) + return; + + if(limy > cliprect->max_y) + limy = cliprect->max_y; + + ps1 = pmin+4; + ps2 = pmin; + + goto startup; + + for(;;) { + if(p[ps1-1].y == p[ps2+1].y) { + vdp1_fill_slope(cliprect, patterndata, xsize, + x1, x2, sl1, sl2, &x1, &x2, + u1, u2, slu1, slu2, &u1, &u2, + v1, v2, slv1, slv2, &v1, &v2, + cury, p[ps1-1].y); + cury = p[ps1-1].y; + if(cury >= limy) + break; + ps1--; + ps2++; + + startup: + while(p[ps1-1].y == cury) + ps1--; + while(p[ps2+1].y == cury) + ps2++; + x1 = p[ps1].x; + u1 = p[ps1].u; + v1 = p[ps1].v; + x2 = p[ps2].x; + u2 = p[ps2].u; + v2 = p[ps2].v; + + delta = cury-p[ps1-1].y; + sl1 = (x1-p[ps1-1].x)/delta; + slu1 = (u1-p[ps1-1].u)/delta; + slv1 = (v1-p[ps1-1].v)/delta; + + delta = cury-p[ps2+1].y; + sl2 = (x2-p[ps2+1].x)/delta; + slu2 = (u2-p[ps2+1].u)/delta; + slv2 = (v2-p[ps2+1].v)/delta; + } else if(p[ps1-1].y < p[ps2+1].y) { + vdp1_fill_slope(cliprect, patterndata, xsize, + x1, x2, sl1, sl2, &x1, &x2, + u1, u2, slu1, slu2, &u1, &u2, + v1, v2, slv1, slv2, &v1, &v2, + cury, p[ps1-1].y); + cury = p[ps1-1].y; + if(cury >= limy) + break; + ps1--; + while(p[ps1-1].y == cury) + ps1--; + x1 = p[ps1].x; + u1 = p[ps1].u; + v1 = p[ps1].v; + + delta = cury-p[ps1-1].y; + sl1 = (x1-p[ps1-1].x)/delta; + slu1 = (u1-p[ps1-1].u)/delta; + slv1 = (v1-p[ps1-1].v)/delta; + } else { + vdp1_fill_slope(cliprect, patterndata, xsize, + x1, x2, sl1, sl2, &x1, &x2, + u1, u2, slu1, slu2, &u1, &u2, + v1, v2, slv1, slv2, &v1, &v2, + cury, p[ps2+1].y); + cury = p[ps2+1].y; + if(cury >= limy) + break; + ps2++; + while(p[ps2+1].y == cury) + ps2++; + x2 = p[ps2].x; + u2 = p[ps2].u; + v2 = p[ps2].v; + + delta = cury-p[ps2+1].y; + sl2 = (x2-p[ps2+1].x)/delta; + slu2 = (u2-p[ps2+1].u)/delta; + slv2 = (v2-p[ps2+1].v)/delta; + } + } + if(cury == limy) + vdp1_fill_line(cliprect, patterndata, xsize, cury, x1, x2, u1, u2, v1, v2); +} + +static int x2s(int v) +{ + return (INT32)(INT16)v + stvvdp1_local_x; +} + +static int y2s(int v) +{ + return (INT32)(INT16)v + stvvdp1_local_y; +} + +static void stv_vdp1_draw_line( const rectangle *cliprect) +{ + struct spoint q[4]; + + q[0].x = x2s(stv2_current_sprite.CMDXA); + q[0].y = y2s(stv2_current_sprite.CMDYA); + q[1].x = x2s(stv2_current_sprite.CMDXB); + q[1].y = y2s(stv2_current_sprite.CMDYB); + q[2].x = x2s(stv2_current_sprite.CMDXA); + q[2].y = y2s(stv2_current_sprite.CMDYA); + q[3].x = x2s(stv2_current_sprite.CMDXB); + q[3].y = y2s(stv2_current_sprite.CMDYB); + + q[0].u = q[3].u = q[1].u = q[2].u = 0; + q[0].v = q[1].v = q[2].v = q[3].v = 0; + + vdp1_fill_quad(cliprect, 0, 1, q); +} + +static void stv_vdp1_draw_poly_line( const rectangle *cliprect) +{ + struct spoint q[4]; + + q[0].x = x2s(stv2_current_sprite.CMDXA); + q[0].y = y2s(stv2_current_sprite.CMDYA); + q[1].x = x2s(stv2_current_sprite.CMDXB); + q[1].y = y2s(stv2_current_sprite.CMDYB); + q[2].x = x2s(stv2_current_sprite.CMDXA); + q[2].y = y2s(stv2_current_sprite.CMDYA); + q[3].x = x2s(stv2_current_sprite.CMDXB); + q[3].y = y2s(stv2_current_sprite.CMDYB); + + q[0].u = q[3].u = q[1].u = q[2].u = 0; + q[0].v = q[1].v = q[2].v = q[3].v = 0; + + vdp1_fill_quad(cliprect, 0, 1, q); + + q[0].x = x2s(stv2_current_sprite.CMDXB); + q[0].y = y2s(stv2_current_sprite.CMDYB); + q[1].x = x2s(stv2_current_sprite.CMDXC); + q[1].y = y2s(stv2_current_sprite.CMDYC); + q[2].x = x2s(stv2_current_sprite.CMDXB); + q[2].y = y2s(stv2_current_sprite.CMDYB); + q[3].x = x2s(stv2_current_sprite.CMDXC); + q[3].y = y2s(stv2_current_sprite.CMDYC); + + q[0].u = q[3].u = q[1].u = q[2].u = 0; + q[0].v = q[1].v = q[2].v = q[3].v = 0; + + vdp1_fill_quad(cliprect, 0, 1, q); + + q[0].x = x2s(stv2_current_sprite.CMDXC); + q[0].y = y2s(stv2_current_sprite.CMDYC); + q[1].x = x2s(stv2_current_sprite.CMDXD); + q[1].y = y2s(stv2_current_sprite.CMDYD); + q[2].x = x2s(stv2_current_sprite.CMDXC); + q[2].y = y2s(stv2_current_sprite.CMDYC); + q[3].x = x2s(stv2_current_sprite.CMDXD); + q[3].y = y2s(stv2_current_sprite.CMDYD); + + q[0].u = q[3].u = q[1].u = q[2].u = 0; + q[0].v = q[1].v = q[2].v = q[3].v = 0; + + vdp1_fill_quad(cliprect, 0, 1, q); + + q[0].x = x2s(stv2_current_sprite.CMDXD); + q[0].y = y2s(stv2_current_sprite.CMDYD); + q[1].x = x2s(stv2_current_sprite.CMDXA); + q[1].y = y2s(stv2_current_sprite.CMDYA); + q[2].x = x2s(stv2_current_sprite.CMDXD); + q[2].y = y2s(stv2_current_sprite.CMDYD); + q[3].x = x2s(stv2_current_sprite.CMDXA); + q[3].y = y2s(stv2_current_sprite.CMDYA); + + q[0].u = q[3].u = q[1].u = q[2].u = 0; + q[0].v = q[1].v = q[2].v = q[3].v = 0; + + stv_vdp1_setup_shading(q, cliprect); + vdp1_fill_quad(cliprect, 0, 1, q); + +} + +static void stv_vpd1_draw_distorted_sprite(const rectangle *cliprect) +{ + struct spoint q[4]; + + int xsize, ysize; + int direction; + int patterndata; + + direction = (stv2_current_sprite.CMDCTRL & 0x0030)>>4; + + if ( stv2_current_sprite.ispoly ) + { + xsize = ysize = 1; + patterndata = 0; + } + else + { + xsize = (stv2_current_sprite.CMDSIZE & 0x3f00) >> 8; + xsize = xsize * 8; + if (xsize == 0) return; /* setting prohibited */ + + ysize = (stv2_current_sprite.CMDSIZE & 0x00ff); + if (ysize == 0) return; /* setting prohibited */ + + patterndata = (stv2_current_sprite.CMDSRCA) & 0xffff; + patterndata = patterndata * 0x8; + + } + + + q[0].x = x2s(stv2_current_sprite.CMDXA); + q[0].y = y2s(stv2_current_sprite.CMDYA); + q[1].x = x2s(stv2_current_sprite.CMDXB); + q[1].y = y2s(stv2_current_sprite.CMDYB); + q[2].x = x2s(stv2_current_sprite.CMDXC); + q[2].y = y2s(stv2_current_sprite.CMDYC); + q[3].x = x2s(stv2_current_sprite.CMDXD); + q[3].y = y2s(stv2_current_sprite.CMDYD); + + if(direction & 1) { // xflip + q[0].u = q[3].u = xsize-1; + q[1].u = q[2].u = 0; + } else { + q[0].u = q[3].u = 0; + q[1].u = q[2].u = xsize-1; + } + if(direction & 2) { // yflip + q[0].v = q[1].v = ysize-1; + q[2].v = q[3].v = 0; + } else { + q[0].v = q[1].v = 0; + q[2].v = q[3].v = ysize-1; + } + + stv_vdp1_setup_shading(q, cliprect); + vdp1_fill_quad(cliprect, patterndata, xsize, q); +} + +static void stv_vpd1_draw_scaled_sprite(const rectangle *cliprect) +{ + struct spoint q[4]; + + int xsize, ysize; + int direction; + int patterndata; + int zoompoint; + int x,y; + int x2,y2; + int screen_width,screen_height,screen_height_negative = 0; + + direction = (stv2_current_sprite.CMDCTRL & 0x0030)>>4; + + xsize = (stv2_current_sprite.CMDSIZE & 0x3f00) >> 8; + xsize = xsize * 8; + + ysize = (stv2_current_sprite.CMDSIZE & 0x00ff); + + patterndata = (stv2_current_sprite.CMDSRCA) & 0xffff; + patterndata = patterndata * 0x8; + + zoompoint = (stv2_current_sprite.CMDCTRL & 0x0f00)>>8; + + x = stv2_current_sprite.CMDXA; + y = stv2_current_sprite.CMDYA; + + screen_width = (INT16)stv2_current_sprite.CMDXB; + if ( (screen_width < 0) && zoompoint) + { + screen_width = -screen_width; + direction |= 1; + } + + screen_height = (INT16)stv2_current_sprite.CMDYB; + if ( (screen_height < 0) && zoompoint ) + { + screen_height_negative = 1; + screen_height = -screen_height; + direction |= 2; + } + + x2 = stv2_current_sprite.CMDXC; // second co-ordinate set x + y2 = stv2_current_sprite.CMDYC; // second co-ordinate set y + + switch (zoompoint) + { + case 0x0: // specified co-ordinates + break; + case 0x5: // up left + break; + case 0x6: // up center + x -= screen_width/2 ; + break; + case 0x7: // up right + x -= screen_width; + break; + + case 0x9: // center left + y -= screen_height/2 ; + break; + case 0xa: // center center + y -= screen_height/2 ; + x -= screen_width/2 ; + + break; + + case 0xb: // center right + y -= screen_height/2 ; + x -= screen_width; + break; + + case 0xd: // center left + y -= screen_height; + break; + + case 0xe: // center center + y -= screen_height; + x -= screen_width/2 ; + break; + + case 0xf: // center right + y -= screen_height; + x -= screen_width; + break; + + default: // illegal + break; + + } + + /* 0----1 + | | + | | + 3----2 */ + + if (zoompoint) + { + q[0].x = x2s(x); + q[0].y = y2s(y); + q[1].x = x2s(x)+screen_width; + q[1].y = y2s(y); + q[2].x = x2s(x)+screen_width; + q[2].y = y2s(y)+screen_height; + q[3].x = x2s(x); + q[3].y = y2s(y)+screen_height; + + if ( screen_height_negative ) + { + q[0].y += screen_height; + q[1].y += screen_height; + q[2].y += screen_height; + q[3].y += screen_height; + } + } + else + { + q[0].x = x2s(x); + q[0].y = y2s(y); + q[1].x = x2s(x2); + q[1].y = y2s(y); + q[2].x = x2s(x2); + q[2].y = y2s(y2); + q[3].x = x2s(x); + q[3].y = y2s(y2); + } + + + if(direction & 1) { // xflip + q[0].u = q[3].u = xsize-1; + q[1].u = q[2].u = 0; + } else { + q[0].u = q[3].u = 0; + q[1].u = q[2].u = xsize-1; + } + if(direction & 2) { // yflip + q[0].v = q[1].v = ysize-1; + q[2].v = q[3].v = 0; + } else { + q[0].v = q[1].v = 0; + q[2].v = q[3].v = ysize-1; + } + + stv_vdp1_setup_shading(q, cliprect); + vdp1_fill_quad(cliprect, patterndata, xsize, q); +} + + +static void stv_vpd1_draw_normal_sprite(const rectangle *cliprect, int sprite_type) +{ + UINT16 *destline; + + int y, ysize, drawypos; + int x, xsize, drawxpos; + int direction; + int patterndata; + UINT8 shading; + int su, u, dux, duy; + int maxdrawypos, maxdrawxpos; + + + + shading = stv_read_gouraud_table(); + + x = x2s(stv2_current_sprite.CMDXA); + y = y2s(stv2_current_sprite.CMDYA); + + direction = (stv2_current_sprite.CMDCTRL & 0x0030)>>4; + + xsize = (stv2_current_sprite.CMDSIZE & 0x3f00) >> 8; + xsize = xsize * 8; + + ysize = (stv2_current_sprite.CMDSIZE & 0x00ff); + + patterndata = (stv2_current_sprite.CMDSRCA) & 0xffff; + patterndata = patterndata * 0x8; + + if (vdp1_sprite_log) logerror ("Drawing Normal Sprite x %04x y %04x xsize %04x ysize %04x patterndata %06x\n",x,y,xsize,ysize,patterndata); + + if ( x > cliprect->max_x ) return; + if ( y > cliprect->max_y ) return; + + shading = stv_read_gouraud_table(); + if ( shading ) + { + struct spoint q[4]; + q[0].x = x; q[0].y = y; + q[1].x = x + xsize; q[1].y = y; + q[2].x = x + xsize; q[2].y = y + ysize; + q[3].x = x; q[3].y = y + ysize; + + stv_vdp1_setup_shading( q, cliprect ); + } + + u = 0; + dux = 1; + duy = xsize; + if ( direction & 0x1 ) //xflip + { + dux = -1; + u = xsize - 1; + } + if ( direction & 0x2 ) //yflip + { + duy = -xsize; + u += xsize*(ysize-1); + } + if ( y < cliprect->min_y ) //clip y + { + u += xsize*(cliprect->min_y - y); + ysize -= (cliprect->min_y - y); + y = cliprect->min_y; + } + if ( x < cliprect->min_x ) //clip x + { + u += dux*(cliprect->min_x - x); + xsize -= (cliprect->min_x - x); + x = cliprect->min_x; + } + maxdrawypos = MIN(y+ysize-1,cliprect->max_y); + maxdrawxpos = MIN(x+xsize-1,cliprect->max_x); + for (drawypos = y; drawypos <= maxdrawypos; drawypos++ ) + { + destline = stv_framebuffer_draw_lines[drawypos]; + su = u; + for (drawxpos = x; drawxpos <= maxdrawxpos; drawxpos++ ) + { + drawpixel( drawxpos, drawypos, patterndata, u ); + u += dux; + } + u = su + duy; + } +} + +void stv_vdp1_process_list() +{ + int position; + int spritecount; + int vdp1_nest; + rectangle *cliprect; + + spritecount = 0; + position = 0; + + if (vdp1_sprite_log) logerror ("Sprite List Process START\n"); + + vdp1_nest = -1; + + stv_clear_gouraud_shading(); + + /*Set CEF bit to 0*/ + SET_CEF_FROM_1_TO_0; + + while (spritecount<10000) // if its drawn this many sprites something is probably wrong or sega were crazy ;-) + { + int draw_this_sprite; + + draw_this_sprite = 1; + + // if (position >= ((0x80000/0x20)/4)) // safety check + // { + // if (vdp1_sprite_log) logerror ("Sprite List Position Too High!\n"); + // position = 0; + // } + + stv2_current_sprite.CMDCTRL = (stv_vdp1_vram[position * (0x20/4)+0] & 0xffff0000) >> 16; + + if (stv2_current_sprite.CMDCTRL == 0x8000) + { + if (vdp1_sprite_log) logerror ("List Terminator (0x8000) Encountered, Sprite List Process END\n"); + goto end; // end of list + } + + stv2_current_sprite.CMDLINK = (stv_vdp1_vram[position * (0x20/4)+0] & 0x0000ffff) >> 0; + stv2_current_sprite.CMDPMOD = (stv_vdp1_vram[position * (0x20/4)+1] & 0xffff0000) >> 16; + stv2_current_sprite.CMDCOLR = (stv_vdp1_vram[position * (0x20/4)+1] & 0x0000ffff) >> 0; + stv2_current_sprite.CMDSRCA = (stv_vdp1_vram[position * (0x20/4)+2] & 0xffff0000) >> 16; + stv2_current_sprite.CMDSIZE = (stv_vdp1_vram[position * (0x20/4)+2] & 0x0000ffff) >> 0; + stv2_current_sprite.CMDXA = (stv_vdp1_vram[position * (0x20/4)+3] & 0xffff0000) >> 16; + stv2_current_sprite.CMDYA = (stv_vdp1_vram[position * (0x20/4)+3] & 0x0000ffff) >> 0; + stv2_current_sprite.CMDXB = (stv_vdp1_vram[position * (0x20/4)+4] & 0xffff0000) >> 16; + stv2_current_sprite.CMDYB = (stv_vdp1_vram[position * (0x20/4)+4] & 0x0000ffff) >> 0; + stv2_current_sprite.CMDXC = (stv_vdp1_vram[position * (0x20/4)+5] & 0xffff0000) >> 16; + stv2_current_sprite.CMDYC = (stv_vdp1_vram[position * (0x20/4)+5] & 0x0000ffff) >> 0; + stv2_current_sprite.CMDXD = (stv_vdp1_vram[position * (0x20/4)+6] & 0xffff0000) >> 16; + stv2_current_sprite.CMDYD = (stv_vdp1_vram[position * (0x20/4)+6] & 0x0000ffff) >> 0; + stv2_current_sprite.CMDGRDA = (stv_vdp1_vram[position * (0x20/4)+7] & 0xffff0000) >> 16; +// stv2_current_sprite.UNUSED = (stv_vdp1_vram[position * (0x20/4)+7] & 0x0000ffff) >> 0; + + /* proecess jump / skip commands, set position for next sprite */ + switch (stv2_current_sprite.CMDCTRL & 0x7000) + { + case 0x0000: // jump next + if (vdp1_sprite_log) logerror ("Sprite List Process + Next (Normal)\n"); + position++; + break; + case 0x1000: // jump assign + if (vdp1_sprite_log) logerror ("Sprite List Process + Jump Old %06x New %06x\n", position, (stv2_current_sprite.CMDLINK>>2)); + position= (stv2_current_sprite.CMDLINK>>2); + break; + case 0x2000: // jump call + if (vdp1_nest == -1) + { + if (vdp1_sprite_log) logerror ("Sprite List Process + Call Old %06x New %06x\n",position, (stv2_current_sprite.CMDLINK>>2)); + vdp1_nest = position+1; + position = (stv2_current_sprite.CMDLINK>>2); + } + else + { + if (vdp1_sprite_log) logerror ("Sprite List Nested Call, ignoring\n"); + position++; + } + break; + case 0x3000: + if (vdp1_nest != -1) + { + if (vdp1_sprite_log) logerror ("Sprite List Process + Return\n"); + position = vdp1_nest; + vdp1_nest = -1; + } + else + { + if (vdp1_sprite_log) logerror ("Attempted return from no subroutine, aborting\n"); + position++; + goto end; // end of list + } + break; + case 0x4000: + draw_this_sprite = 0; + position++; + break; + case 0x5000: + if (vdp1_sprite_log) logerror ("Sprite List Skip + Jump Old %06x New %06x\n", position, (stv2_current_sprite.CMDLINK>>2)); + draw_this_sprite = 0; + position= (stv2_current_sprite.CMDLINK>>2); + + break; + case 0x6000: + draw_this_sprite = 0; + if (vdp1_nest == -1) + { + if (vdp1_sprite_log) logerror ("Sprite List Skip + Call To Subroutine Old %06x New %06x\n",position, (stv2_current_sprite.CMDLINK>>2)); + + vdp1_nest = position+1; + position = (stv2_current_sprite.CMDLINK>>2); + } + else + { + if (vdp1_sprite_log) logerror ("Sprite List Nested Call, ignoring\n"); + position++; + } + break; + case 0x7000: + draw_this_sprite = 0; + if (vdp1_nest != -1) + { + if (vdp1_sprite_log) logerror ("Sprite List Skip + Return from Subroutine\n"); + + position = vdp1_nest; + vdp1_nest = -1; + } + else + { + if (vdp1_sprite_log) logerror ("Attempted return from no subroutine, aborting\n"); + position++; + goto end; // end of list + } + break; + } + + /* continue to draw this sprite only if the command wasn't to skip it */ + if (draw_this_sprite ==1) + { + if ( stv2_current_sprite.CMDPMOD & 0x0400 ) + { + cliprect = &stv_vdp1_user_cliprect; + } + else + { + cliprect = &stv_vdp1_system_cliprect; + } + + stv_vdp1_set_drawpixel(); + + switch (stv2_current_sprite.CMDCTRL & 0x000f) + { + case 0x0000: + if (vdp1_sprite_log) logerror ("Sprite List Normal Sprite\n"); + stv2_current_sprite.ispoly = 0; + stv_vpd1_draw_normal_sprite(cliprect, 0); + break; + + case 0x0001: + if (vdp1_sprite_log) logerror ("Sprite List Scaled Sprite\n"); + stv2_current_sprite.ispoly = 0; + stv_vpd1_draw_scaled_sprite(cliprect); + break; + + case 0x0002: + if (vdp1_sprite_log) logerror ("Sprite List Distorted Sprite\n"); + stv2_current_sprite.ispoly = 0; + stv_vpd1_draw_distorted_sprite(cliprect); + break; + + case 0x0004: + if (vdp1_sprite_log) logerror ("Sprite List Polygon\n"); + stv2_current_sprite.ispoly = 1; + stv_vpd1_draw_distorted_sprite(cliprect); + break; + + case 0x0005: + if (vdp1_sprite_log) logerror ("Sprite List Polyline\n"); + stv2_current_sprite.ispoly = 1; + stv_vdp1_draw_poly_line(cliprect); + break; + + case 0x0006: + if (vdp1_sprite_log) logerror ("Sprite List Line\n"); + stv2_current_sprite.ispoly = 1; + stv_vdp1_draw_line(cliprect); + break; + + case 0x0008: + if (vdp1_sprite_log) logerror ("Sprite List Set Command for User Clipping (%d,%d),(%d,%d)\n", stv2_current_sprite.CMDXA, stv2_current_sprite.CMDYA, stv2_current_sprite.CMDXC, stv2_current_sprite.CMDYC); + stv_vdp1_user_cliprect.min_x = stv2_current_sprite.CMDXA; + stv_vdp1_user_cliprect.min_y = stv2_current_sprite.CMDYA; + stv_vdp1_user_cliprect.max_x = stv2_current_sprite.CMDXC; + stv_vdp1_user_cliprect.max_y = stv2_current_sprite.CMDYC; + break; + + case 0x0009: + if (vdp1_sprite_log) logerror ("Sprite List Set Command for System Clipping (0,0),(%d,%d)\n", stv2_current_sprite.CMDXC, stv2_current_sprite.CMDYC); + stv_vdp1_system_cliprect.min_x = 0; + stv_vdp1_system_cliprect.min_y = 0; + stv_vdp1_system_cliprect.max_x = stv2_current_sprite.CMDXC; + stv_vdp1_system_cliprect.max_y = stv2_current_sprite.CMDYC; + break; + + case 0x000a: + if (vdp1_sprite_log) logerror ("Sprite List Local Co-Ordinate Set\n"); + stvvdp1_local_x = (INT16)stv2_current_sprite.CMDXA; + stvvdp1_local_y = (INT16)stv2_current_sprite.CMDYA; + break; + + default: + if (vdp1_sprite_log) logerror ("Sprite List Illegal!\n"); + break; + + + } + + + } + + spritecount++; + + } + + + end: + /*set CEF to 1*/ + SET_CEF_FROM_0_TO_1; + + /* not here! this is done every frame drawn even if the cpu isn't running eg in the debugger */ +// if(!(stv_scu[40] & 0x2000)) /*Sprite draw end irq*/ +// cpunum_set_input_line_and_vector(0, 2, HOLD_LINE , 0x4d); + + if (vdp1_sprite_log) logerror ("End of list processing!\n"); +} + +void video_update_vdp1(running_machine *machine) +{ + int framebufer_changed = 0; + +// int enable; +// if (input_code_pressed (KEYCODE_R)) vdp1_sprite_log = 1; +// if (input_code_pressed (KEYCODE_T)) vdp1_sprite_log = 0; + +// if (input_code_pressed (KEYCODE_Y)) vdp1_sprite_log = 0; +// { +// FILE *fp; +// +// fp=fopen("vdp1_ram.dmp", "w+b"); +// if (fp) +// { +// fwrite(stv_vdp1, 0x00100000, 1, fp); +// fclose(fp); +// } +// } + if (vdp1_sprite_log) logerror("video_update_vdp1 called\n"); + if (vdp1_sprite_log) logerror( "FBCR = %0x, accessed = %d\n", STV_VDP1_FBCR, stv_vdp1_fbcr_accessed ); + + if ( stv_vdp1_clear_framebuffer_on_next_frame ) + { + if ( ((STV_VDP1_FBCR & 0x3) == 3) && + stv_vdp1_fbcr_accessed ) + { + stv_clear_framebuffer(stv_vdp1_current_display_framebuffer); + stv_vdp1_clear_framebuffer_on_next_frame = 0; + } + } + + switch( STV_VDP1_FBCR & 0x3 ) + { + case 0: /* Automatic mode */ + stv_vdp1_change_framebuffers(); + stv_clear_framebuffer(stv_vdp1_current_draw_framebuffer); + framebufer_changed = 1; + break; + case 1: /* Setting prohibited */ + break; + case 2: /* Manual mode - erase */ + if ( stv_vdp1_fbcr_accessed ) + { + stv_vdp1_clear_framebuffer_on_next_frame = 1; + } + break; + case 3: /* Manual mode - change */ + if ( stv_vdp1_fbcr_accessed ) + { + stv_vdp1_change_framebuffers(); + if ( STV_VDP1_VBE ) + { + stv_clear_framebuffer(stv_vdp1_current_draw_framebuffer); + } + framebufer_changed = 1; + } + break; + } + stv_vdp1_fbcr_accessed = 0; + + if (vdp1_sprite_log) logerror( "PTM = %0x, TVM = %x\n", STV_VDP1_PTM, STV_VDP1_TVM ); + switch(STV_VDP1_PTM & 3) + { + case 0:/*Idle Mode*/ + break; + case 1:/*Draw by request*/ + break; + case 2:/*Automatic Draw*/ + if ( framebufer_changed ) + stv_vdp1_process_list(); + break; + case 3: /*<invalid>*/ + logerror("Warning: Invalid PTM mode set for VDP1!\n"); + break; + } + //popmessage("%04x %04x",STV_VDP1_EWRR_X3,STV_VDP1_EWRR_Y3); +} + +static void stv_vdp1_state_save_postload(void) +{ + UINT8 *vdp1 = stv_vdp1_gfx_decode; + int offset; + UINT32 data; + + stv_framebuffer_mode = -1; + stv_framebuffer_double_interlace = -1; + + stv_set_framebuffer_config(); + + for (offset = 0; offset < 0x80000/4; offset++ ) + { + data = stv_vdp1_vram[offset]; + /* put in gfx region for easy decoding */ + vdp1[offset*4+0] = (data & 0xff000000) >> 24; + vdp1[offset*4+1] = (data & 0x00ff0000) >> 16; + vdp1[offset*4+2] = (data & 0x0000ff00) >> 8; + vdp1[offset*4+3] = (data & 0x000000ff) >> 0; + } +} + +int stv_vdp1_start ( void ) +{ + stv_vdp1_regs = auto_malloc ( 0x040000 ); + stv_vdp1_vram = auto_malloc ( 0x100000 ); + stv_vdp1_gfx_decode = auto_malloc( 0x100000 ); + + stv_vdp1_shading_data = auto_malloc( sizeof(struct stv_vdp1_poly_scanline_data) ); + + memset(stv_vdp1_regs, 0, 0x040000); + memset(stv_vdp1_vram, 0, 0x100000); + + stv_framebuffer[0] = auto_malloc( 1024 * 256 * sizeof(UINT16) * 2 ); /* *2 is for double interlace */ + stv_framebuffer[1] = auto_malloc( 1024 * 256 * sizeof(UINT16) * 2 ); + + stv_framebuffer_display_lines = auto_malloc( 512 * sizeof(UINT16*) ); + stv_framebuffer_draw_lines = auto_malloc( 512 * sizeof(UINT16*) ); + + stv_framebuffer_width = stv_framebuffer_height = 0; + stv_framebuffer_mode = -1; + stv_framebuffer_double_interlace = -1; + stv_vdp1_fbcr_accessed = 0; + stv_vdp1_current_display_framebuffer = 0; + stv_vdp1_current_draw_framebuffer = 1; + stv_clear_framebuffer(stv_vdp1_current_draw_framebuffer); + stv_vdp1_clear_framebuffer_on_next_frame = 0; + + stv_vdp1_system_cliprect.min_x = stv_vdp1_system_cliprect.max_x = 0; + stv_vdp1_system_cliprect.min_y = stv_vdp1_system_cliprect.max_y = 0; + stv_vdp1_user_cliprect.min_x = stv_vdp1_user_cliprect.max_x = 0; + stv_vdp1_user_cliprect.min_y = stv_vdp1_user_cliprect.max_y = 0; + + // save state + state_save_register_global_pointer(stv_vdp1_regs, 0x040000/4); + state_save_register_global_pointer(stv_vdp1_vram, 0x100000/4); + state_save_register_global(stv_vdp1_fbcr_accessed); + state_save_register_global(stv_vdp1_current_display_framebuffer); + state_save_register_global(stv_vdp1_current_draw_framebuffer); + state_save_register_global(stv_vdp1_clear_framebuffer_on_next_frame); + state_save_register_global(stvvdp1_local_x); + state_save_register_global(stvvdp1_local_y); + state_save_register_func_postload(stv_vdp1_state_save_postload); + return 0; +} |