1 // license:LGPL-2.1+
2 // copyright-holders:David Haywood, Angelo Salese, Olivier Galibert, Mariusz Wojcieszek, R. Belmont
3 /*
4 
5 STV - VDP1
6 
7 the vdp1 draws to the FRAMEBUFFER which is mapped in memory
8 
9 -------------------------- WARNING WARNING WARNING --------------------------
10 This is a legacy core, all game based notes are for a future device rewrite.
11 Please don't remove them if for no reason you truly want to mess with this.
12 -------------------------- WARNING WARNING WARNING --------------------------
13 
14 Framebuffer todo:
15 - finish manual erase
16 - add proper framebuffer erase
17 - 8 bpp support - now we always draw as 16 bpp, but this is not a problem since
18   VDP2 interprets framebuffer as 8 bpp in these cases
19 
20 */
21 
22 
23 #include "emu.h"
24 #include "includes/saturn.h" // FIXME: this is a dependency from devices on MAME
25 
26 
27 #define VDP1_LOG 0
28 
29 
30 enum { FRAC_SHIFT = 16 };
31 
32 struct spoint {
33 	int32_t x, y;
34 	int32_t u, v;
35 };
36 
37 struct shaded_point
38 {
39 	int32_t x,y;
40 	int32_t r,g,b;
41 };
42 
43 #define RGB_R(_color)   (_color & 0x1f)
44 #define RGB_G(_color)   ((_color >> 5) & 0x1f)
45 #define RGB_B(_color)   ((_color >> 10) & 0x1f)
46 
47 #define SWAP_INT32(_a,_b) \
48 	{ \
49 		int32_t t; \
50 		t = _a; \
51 		_a = _b; \
52 		_b = t; \
53 	}
54 
55 #define SWAP_INT32PTR(_p1, _p2) \
56 	{ \
57 		int32_t *p; \
58 		p = _p1; \
59 		_p1 = _p2; \
60 		_p2 = p; \
61 	}
62 
63 /*TV Mode Selection Register */
64 /*
65    xxxx xxxx xxxx ---- | UNUSED
66    ---- ---- ---- x--- | VBlank Erase/Write (VBE)
67    ---- ---- ---- -xxx | TV Mode (TVM)
68    TV-Mode:
69    This sets the Frame Buffer size,the rotation of the Frame Buffer & the bit width.
70    bit 2 HDTV disable(0)/enable(1)
71    bit 1 non-rotation/rotation(1)
72    bit 0 16(0)/8(1) bits per pixel
73    Size of the Frame Buffer:
74    7 invalid
75    6 invalid
76    5 invalid
77    4 512x256
78    3 512x512
79    2 512x256
80    1 1024x256
81    0 512x256
82 */
83 
84 /*Frame Buffer Change Mode Register*/
85 /*
86    xxxx xxxx xxx- ---- | UNUSED
87    ---- ---- ---x ---- | Even/Odd Coordinate Select Bit (EOS)
88    ---- ---- ---- x--- | Double Interlace Mode (DIE)
89    ---- ---- ---- -x-- | Double Interlace Draw Line (DIL)
90    ---- ---- ---- --x- | Frame Buffer Change Trigger (FCM)
91    ---- ---- ---- ---x | Frame Buffer Change Mode (FCT)
92 */
93 #define STV_VDP1_FBCR ((m_vdp1_regs[0x002/2] >> 0)&0xffff)
94 #define STV_VDP1_EOS ((STV_VDP1_FBCR & 0x0010) >> 4)
95 #define STV_VDP1_DIE ((STV_VDP1_FBCR & 0x0008) >> 3)
96 #define STV_VDP1_DIL ((STV_VDP1_FBCR & 0x0004) >> 2)
97 #define STV_VDP1_FCM ((STV_VDP1_FBCR & 0x0002) >> 1)
98 #define STV_VDP1_FCT ((STV_VDP1_FBCR & 0x0001) >> 0)
99 
100 /*Plot Trigger Register*/
101 /*
102    xxxx xxxx xxxx xx-- | UNUSED
103    ---- ---- ---- --xx | Plot Trigger Mode (PTM)
104 
105    Plot Trigger Mode:
106    3 Invalid
107    2 Automatic draw
108    1 VDP1 draw by request
109    0 VDP1 Idle (no access)
110 */
111 #define STV_VDP1_PTMR ((m_vdp1_regs[0x004/2])&0xffff)
112 #define STV_VDP1_PTM  ((STV_VDP1_PTMR & 0x0003) >> 0)
113 #define PTM_0         m_vdp1_regs[0x004/2]&=~0x0001
114 
115 /*
116     Erase/Write Data Register
117     16 bpp = data
118     8 bpp = erase/write data for even/odd X coordinates
119 */
120 #define STV_VDP1_EWDR ((m_vdp1_regs[0x006/2])&0xffff)
121 
122 /*Erase/Write Upper-Left register*/
123 /*
124    x--- ---- ---- ---- | UNUSED
125    -xxx xxx- ---- ---- | X1 register
126    ---- ---x xxxx xxxx | Y1 register
127 
128 */
129 #define STV_VDP1_EWLR ((m_vdp1_regs[0x008/2])&0xffff)
130 #define STV_VDP1_EWLR_X1 ((STV_VDP1_EWLR & 0x7e00) >> 9)
131 #define STV_VDP1_EWLR_Y1 ((STV_VDP1_EWLR & 0x01ff) >> 0)
132 /*Erase/Write Lower-Right register*/
133 /*
134    xxxx xxx- ---- ---- | X3 register
135    ---- ---x xxxx xxxx | Y3 register
136 
137 */
138 #define STV_VDP1_EWRR ((m_vdp1_regs[0x00a/2])&0xffff)
139 #define STV_VDP1_EWRR_X3 ((STV_VDP1_EWRR & 0xfe00) >> 9)
140 #define STV_VDP1_EWRR_Y3 ((STV_VDP1_EWRR & 0x01ff) >> 0)
141 /*Transfer End Status Register*/
142 /*
143    xxxx xxxx xxxx xx-- | UNUSED
144    ---- ---- ---- --x- | CEF
145    ---- ---- ---- ---x | BEF
146 
147 */
148 #define STV_VDP1_EDSR ((m_vdp1_regs[0x010/2])&0xffff)
149 #define STV_VDP1_CEF  (STV_VDP1_EDSR & 2)
150 #define STV_VDP1_BEF  (STV_VDP1_EDSR & 1)
151 /**/
152 
153 
154 
saturn_vdp1_regs_r(offs_t offset)155 uint16_t saturn_state::saturn_vdp1_regs_r(offs_t offset)
156 {
157 	//logerror ("%s VDP1: Read from Registers, Offset %04x\n", machine().describe_context(), offset);
158 
159 	switch(offset)
160 	{
161 		case 0x02/2:
162 			return 0;
163 		case 0x10/2:
164 			break;
165 		case 0x12/2: return m_vdp1.lopr;
166 		case 0x14/2: return m_vdp1.copr;
167 		/* MODR register, read register for the other VDP1 regs
168 		   (Shienryu SS version abuses of this during intro) */
169 		case 0x16/2:
170 			uint16_t modr;
171 
172 			modr = 0x1000; //vdp1 VER
173 			modr |= (STV_VDP1_PTM >> 1) << 8; // PTM1
174 			modr |= STV_VDP1_EOS << 7; // EOS
175 			modr |= STV_VDP1_DIE << 6; // DIE
176 			modr |= STV_VDP1_DIL << 5; // DIL
177 			modr |= STV_VDP1_FCM << 4; //FCM
178 			modr |= STV_VDP1_VBE << 3; //VBE
179 			modr |= STV_VDP1_TVM & 7; //TVM
180 
181 			return modr;
182 		default:
183 			if(!machine().side_effects_disabled())
184 				logerror("%s VDP1: Read from Registers, Offset %04x\n", machine().describe_context(), offset*2);
185 			break;
186 	}
187 
188 	return m_vdp1_regs[offset]; //TODO: write-only regs should return open bus or zero
189 }
190 
191 /* TODO: TVM & 1 is just a kludgy work-around, the VDP1 actually needs to be rewritten from scratch. */
192 /* Daisenryaku Strong Style (daisenss) uses it */
stv_clear_framebuffer(int which_framebuffer)193 void saturn_state::stv_clear_framebuffer( int which_framebuffer )
194 {
195 	int start_x, end_x, start_y, end_y;
196 
197 	start_x = STV_VDP1_EWLR_X1 * ((STV_VDP1_TVM & 1) ? 16 : 8);
198 	start_y = STV_VDP1_EWLR_Y1 * (m_vdp1.framebuffer_double_interlace+1);
199 	end_x = STV_VDP1_EWRR_X3 * ((STV_VDP1_TVM & 1) ? 16 : 8);
200 	end_y = (STV_VDP1_EWRR_Y3+1) * (m_vdp1.framebuffer_double_interlace+1);
201 //  popmessage("%d %d %d %d %d",STV_VDP1_EWLR_X1,STV_VDP1_EWLR_Y1,STV_VDP1_EWRR_X3,STV_VDP1_EWRR_Y3,m_vdp1.framebuffer_double_interlace);
202 
203 	if(STV_VDP1_TVM & 1)
204 	{
205 		for(int y=start_y;y<end_y;y++)
206 			for(int x=start_x;x<end_x;x++)
207 				m_vdp1.framebuffer[ which_framebuffer ][((x&1023)+(y&511)*1024)] = m_vdp1.ewdr;
208 	}
209 	else
210 	{
211 		for(int y=start_y;y<end_y;y++)
212 			for(int x=start_x;x<end_x;x++)
213 				m_vdp1.framebuffer[ which_framebuffer ][((x&511)+(y&511)*512)] = m_vdp1.ewdr;
214 	}
215 
216 	if ( VDP1_LOG ) logerror( "Clearing %d framebuffer\n", m_vdp1.framebuffer_current_draw );
217 //  memset( m_vdp1.framebuffer[ which_framebuffer ], m_vdp1.ewdr, 1024 * 256 * sizeof(uint16_t) * 2 );
218 }
219 
220 
stv_prepare_framebuffers(void)221 void saturn_state::stv_prepare_framebuffers( void )
222 {
223 	int i,rowsize;
224 
225 	rowsize = m_vdp1.framebuffer_width;
226 	if ( m_vdp1.framebuffer_current_draw == 0 )
227 	{
228 		for ( i = 0; i < m_vdp1.framebuffer_height; i++ )
229 		{
230 			m_vdp1.framebuffer_draw_lines[i] = &m_vdp1.framebuffer[0][ i * rowsize ];
231 			m_vdp1.framebuffer_display_lines[i] = &m_vdp1.framebuffer[1][ i * rowsize ];
232 		}
233 		for ( ; i < 512; i++ )
234 		{
235 			m_vdp1.framebuffer_draw_lines[i] = &m_vdp1.framebuffer[0][0];
236 			m_vdp1.framebuffer_display_lines[i] = &m_vdp1.framebuffer[1][0];
237 		}
238 	}
239 	else
240 	{
241 		for ( i = 0; i < m_vdp1.framebuffer_height; i++ )
242 		{
243 			m_vdp1.framebuffer_draw_lines[i] = &m_vdp1.framebuffer[1][ i * rowsize ];
244 			m_vdp1.framebuffer_display_lines[i] = &m_vdp1.framebuffer[0][ i * rowsize ];
245 		}
246 		for ( ; i < 512; i++ )
247 		{
248 			m_vdp1.framebuffer_draw_lines[i] = &m_vdp1.framebuffer[1][0];
249 			m_vdp1.framebuffer_display_lines[i] = &m_vdp1.framebuffer[0][0];
250 		}
251 
252 	}
253 
254 	for ( ; i < 512; i++ )
255 	{
256 		m_vdp1.framebuffer_draw_lines[i] = &m_vdp1.framebuffer[0][0];
257 		m_vdp1.framebuffer_display_lines[i] = &m_vdp1.framebuffer[1][0];
258 	}
259 
260 }
261 
stv_vdp1_change_framebuffers(void)262 void saturn_state::stv_vdp1_change_framebuffers( void )
263 {
264 	m_vdp1.framebuffer_current_display ^= 1;
265 	m_vdp1.framebuffer_current_draw ^= 1;
266 	// "this bit is reset to 0 when the frame buffers are changed"
267 	CEF_0;
268 	if ( VDP1_LOG ) logerror( "Changing framebuffers: %d - draw, %d - display\n", m_vdp1.framebuffer_current_draw, m_vdp1.framebuffer_current_display );
269 	stv_prepare_framebuffers();
270 }
271 
stv_set_framebuffer_config(void)272 void saturn_state::stv_set_framebuffer_config( void )
273 {
274 	if ( m_vdp1.framebuffer_mode == STV_VDP1_TVM &&
275 			m_vdp1.framebuffer_double_interlace == STV_VDP1_DIE ) return;
276 
277 	if ( VDP1_LOG ) logerror( "Setting framebuffer config\n" );
278 	m_vdp1.framebuffer_mode = STV_VDP1_TVM;
279 	m_vdp1.framebuffer_double_interlace = STV_VDP1_DIE;
280 	switch( m_vdp1.framebuffer_mode )
281 	{
282 		case 0: m_vdp1.framebuffer_width = 512; m_vdp1.framebuffer_height = 256; break;
283 		case 1: m_vdp1.framebuffer_width = 1024; m_vdp1.framebuffer_height = 256; break;
284 		case 2: m_vdp1.framebuffer_width = 512; m_vdp1.framebuffer_height = 256; break;
285 		case 3: m_vdp1.framebuffer_width = 512; m_vdp1.framebuffer_height = 512; break;
286 		case 4: m_vdp1.framebuffer_width = 512; m_vdp1.framebuffer_height = 256; break;
287 		default: logerror( "Invalid framebuffer config %x\n", STV_VDP1_TVM ); m_vdp1.framebuffer_width = 512; m_vdp1.framebuffer_height = 256; break;
288 	}
289 	if ( STV_VDP1_DIE ) m_vdp1.framebuffer_height *= 2; /* double interlace */
290 
291 	m_vdp1.framebuffer_current_draw = 0;
292 	m_vdp1.framebuffer_current_display = 1;
293 	stv_prepare_framebuffers();
294 }
295 
saturn_vdp1_regs_w(offs_t offset,uint16_t data,uint16_t mem_mask)296 void saturn_state::saturn_vdp1_regs_w(offs_t offset, uint16_t data, uint16_t mem_mask)
297 {
298 	COMBINE_DATA(&m_vdp1_regs[offset]);
299 
300 	switch(offset)
301 	{
302 		case 0x00/2:
303 			stv_set_framebuffer_config();
304 			if ( VDP1_LOG ) logerror( "VDP1: Access to register TVMR = %1X\n", STV_VDP1_TVMR );
305 
306 			break;
307 		case 0x02/2:
308 			stv_set_framebuffer_config();
309 			if ( VDP1_LOG ) logerror( "VDP1: Access to register FBCR = %1X\n", STV_VDP1_FBCR );
310 			m_vdp1.fbcr_accessed = 1;
311 			break;
312 		case 0x04/2:
313 			if ( VDP1_LOG ) logerror( "VDP1: Access to register PTMR = %1X\n", STV_VDP1_PTM );
314 			if ( STV_VDP1_PTMR == 1 )
315 				stv_vdp1_process_list();
316 
317 			break;
318 		case 0x06/2:
319 			if ( VDP1_LOG ) logerror( "VDP1: Erase data set %08X\n", data );
320 
321 			m_vdp1.ewdr = STV_VDP1_EWDR;
322 			break;
323 		case 0x08/2:
324 			if ( VDP1_LOG ) logerror( "VDP1: Erase upper-left coord set: %08X\n", data );
325 			break;
326 		case 0x0a/2:
327 			if ( VDP1_LOG ) logerror( "VDP1: Erase lower-right coord set: %08X\n", data );
328 			break;
329 		case 0x0c/2:
330 		case 0x0e/2: // After Burner 2 / Out Run / Fantasy Zone writes here with a dword ...
331 			if ( VDP1_LOG ) logerror( "VDP1: Draw forced termination register write: %08X %08X\n", offset*2, data );
332 			break;
333 		default:
334 			printf("Warning: write to unknown VDP1 reg %08x %08x\n",offset*2,data);
335 			break;
336 	}
337 
338 }
339 
saturn_vdp1_vram_r(offs_t offset)340 uint32_t saturn_state::saturn_vdp1_vram_r(offs_t offset)
341 {
342 	return m_vdp1_vram[offset];
343 }
344 
345 
saturn_vdp1_vram_w(offs_t offset,uint32_t data,uint32_t mem_mask)346 void saturn_state::saturn_vdp1_vram_w(offs_t offset, uint32_t data, uint32_t mem_mask)
347 {
348 	uint8_t *vdp1 = m_vdp1.gfx_decode.get();
349 
350 	COMBINE_DATA (&m_vdp1_vram[offset]);
351 
352 //  if (((offset * 4) > 0xdf) && ((offset * 4) < 0x140))
353 //  {
354 //      logerror("%s: VRAM dword write to %08X = %08X & %08X\n", machine().describe_context(), offset*4, data, mem_mask);
355 //  }
356 
357 	data = m_vdp1_vram[offset];
358 	/* put in gfx region for easy decoding */
359 	vdp1[offset*4+0] = (data & 0xff000000) >> 24;
360 	vdp1[offset*4+1] = (data & 0x00ff0000) >> 16;
361 	vdp1[offset*4+2] = (data & 0x0000ff00) >> 8;
362 	vdp1[offset*4+3] = (data & 0x000000ff) >> 0;
363 }
364 
saturn_vdp1_framebuffer0_w(offs_t offset,uint32_t data,uint32_t mem_mask)365 void saturn_state::saturn_vdp1_framebuffer0_w(offs_t offset, uint32_t data, uint32_t mem_mask)
366 {
367 	//popmessage ("STV VDP1 Framebuffer 0 WRITE offset %08x data %08x",offset, data);
368 	if ( STV_VDP1_TVM & 1 )
369 	{
370 		/* 8-bit mode */
371 		//printf("VDP1 8-bit mode %08x %02x\n",offset,data);
372 		if ( ACCESSING_BITS_24_31 )
373 		{
374 			m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2] &= 0x00ff;
375 			m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2] |= data & 0xff00;
376 		}
377 		if ( ACCESSING_BITS_16_23 )
378 		{
379 			m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2] &= 0xff00;
380 			m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2] |= data & 0x00ff;
381 		}
382 		if ( ACCESSING_BITS_8_15 )
383 		{
384 			m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2+1] &= 0x00ff;
385 			m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2+1] |= data & 0xff00;
386 		}
387 		if ( ACCESSING_BITS_0_7 )
388 		{
389 			m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2+1] &= 0xff00;
390 			m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2+1] |= data & 0x00ff;
391 		}
392 	}
393 	else
394 	{
395 		/* 16-bit mode */
396 		if ( ACCESSING_BITS_16_31 )
397 		{
398 			m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2] = (data >> 16) & 0xffff;
399 		}
400 		if ( ACCESSING_BITS_0_15 )
401 		{
402 			m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2+1] = data & 0xffff;
403 		}
404 	}
405 }
406 
saturn_vdp1_framebuffer0_r(offs_t offset,uint32_t mem_mask)407 uint32_t saturn_state::saturn_vdp1_framebuffer0_r(offs_t offset, uint32_t mem_mask)
408 {
409 	uint32_t result = 0;
410 	//popmessage ("STV VDP1 Framebuffer 0 READ offset %08x",offset);
411 	if ( STV_VDP1_TVM & 1 )
412 	{
413 		/* 8-bit mode */
414 		//printf("VDP1 8-bit mode %08x\n",offset);
415 		if ( ACCESSING_BITS_24_31 )
416 			result |= ((m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2] & 0xff00) << 16);
417 		if ( ACCESSING_BITS_16_23 )
418 			result |= ((m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2] & 0x00ff) << 16);
419 		if ( ACCESSING_BITS_8_15 )
420 			result |= ((m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2+1] & 0xff00));
421 		if ( ACCESSING_BITS_0_7 )
422 			result |= ((m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2+1] & 0x00ff));
423 	}
424 	else
425 	{
426 		/* 16-bit mode */
427 		if ( ACCESSING_BITS_16_31 )
428 		{
429 			result |= (m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2] << 16);
430 		}
431 		if ( ACCESSING_BITS_0_15 )
432 		{
433 			result |= (m_vdp1.framebuffer[m_vdp1.framebuffer_current_draw][offset*2+1]);
434 		}
435 
436 	}
437 
438 	return result;
439 }
440 
441 #ifdef UNUSED_FUNCTION
saturn_vdp1_framebuffer1_w(offs_t offset,uint32_t data)442 void saturn_state::saturn_vdp1_framebuffer1_w(offs_t offset, uint32_t data)
443 {
444 	//popmessage ("STV VDP1 Framebuffer 1 WRITE offset %08x data %08x",offset, data);
445 }
446 
saturn_vdp1_framebuffer1_r()447 uint32_t saturn_state::saturn_vdp1_framebuffer1_r()
448 {
449 	//popmessage ("STV VDP1 Framebuffer 1 READ offset %08x",offset);
450 	return 0xffff;
451 }
452 #endif
453 
454 
455 /*
456 
457 there is a command every 0x20 bytes
458 the first word is the control word
459 the rest are data used by it
460 
461 ---
462 00 CMDCTRL
463    e--- ---- ---- ---- | end bit (15)
464    -jjj ---- ---- ---- | jump select bits (12-14)
465    ---- zzzz ---- ---- | zoom point / hotspot (8-11)
466    ---- ---- 00-- ---- | UNUSED
467    ---- ---- --dd ---- | character read direction (4,5)
468    ---- ---- ---- cccc | command bits (0-3)
469 
470 02 CMDLINK
471    llll llll llll ll-- | link
472    ---- ---- ---- --00 | UNUSED
473 
474 04 CMDPMOD
475    m--- ---- ---- ---- | MON (looks at MSB and apply shadows etc.)
476    -00- ---- ---- ---- | UNUSED
477    ---h ---- ---- ---- | HSS (High Speed Shrink)
478    ---- p--- ---- ---- | PCLIP (Pre Clipping Disable)
479    ---- -c-- ---- ---- | CLIP (Clipping Mode Bit)
480    ---- --m- ---- ---- | CMOD (User Clipping Enable Bit)
481    ---- ---M ---- ---- | MESH (Mesh Enable Bit)
482    ---- ---- e--- ---- | ECD (End Code Disable)
483    ---- ---- -S-- ---- | SPD (Transparent Pixel Disable)
484    ---- ---- --cc c--- | Colour Mode
485    ---- ---- ---- -CCC | Colour Calculation bits
486    ---- ---- ---- -1-- | Gouraud shading enable
487    ---- ---- ---- --1- | 1/2 original GFX enable
488    ---- ---- ---- ---1 | 1/2 background enable
489 
490 06 CMDCOLR
491    mmmm mmmm mmmm mmmm | Colour Bank, Colour Lookup /8
492 
493 08 CMDSRCA (Character Address)
494    aaaa aaaa aaaa aa-- | Character Address
495    ---- ---- ---- --00 | UNUSED
496 
497 0a CMDSIZE (Character Size)
498    00-- ---- ---- ---- | UNUSED
499    --xx xxxx ---- ---- | Character Size (X)
500    ---- ---- yyyy yyyy | Character Size (Y)
501 
502 0c CMDXA (used for normal sprite)
503    eeee ee-- ---- ---- | extension bits
504    ---- --xx xxxx xxxx | x position
505 
506 0e CMDYA (used for normal sprite)
507    eeee ee-- ---- ---- | extension bits
508    ---- --yy yyyy yyyy | y position
509 
510 10 CMDXB
511 12 CMDYB
512 14 CMDXC
513 16 CMDYC
514 18 CMDXD
515 1a CMDYD
516 1c CMDGRDA (Gouraud Shading Table)
517 1e UNUSED
518 ---
519 
520 
521 */
522 
stv_clear_gouraud_shading(void)523 void saturn_state::stv_clear_gouraud_shading(void)
524 {
525 	memset( &stv_gouraud_shading, 0, sizeof( stv_gouraud_shading ) );
526 }
527 
stv_read_gouraud_table(void)528 uint8_t saturn_state::stv_read_gouraud_table( void )
529 {
530 	int gaddr;
531 
532 	if ( stv2_current_sprite.CMDPMOD & 0x4 )
533 	{
534 		gaddr = stv2_current_sprite.CMDGRDA * 8;
535 		stv_gouraud_shading.GA = (m_vdp1_vram[gaddr/4] >> 16) & 0xffff;
536 		stv_gouraud_shading.GB = (m_vdp1_vram[gaddr/4] >> 0) & 0xffff;
537 		stv_gouraud_shading.GC = (m_vdp1_vram[gaddr/4 + 1] >> 16) & 0xffff;
538 		stv_gouraud_shading.GD = (m_vdp1_vram[gaddr/4 + 1] >> 0) & 0xffff;
539 		return 1;
540 	}
541 	else
542 	{
543 		return 0;
544 	}
545 }
546 
_shading(int32_t color,int32_t correction)547 static inline int32_t _shading( int32_t color, int32_t correction )
548 {
549 	correction = (correction >> 16) & 0x1f;
550 	color += (correction - 16);
551 
552 	if ( color < 0 ) color = 0;
553 	if ( color > 0x1f ) color = 0x1f;
554 
555 	return color;
556 }
557 
stv_vdp1_apply_gouraud_shading(int x,int y,uint16_t pix)558 uint16_t saturn_state::stv_vdp1_apply_gouraud_shading( int x, int y, uint16_t pix )
559 {
560 	int32_t r,g,b, msb;
561 
562 	msb = pix & 0x8000;
563 
564 #ifdef MAME_DEBUG
565 	if ( (stv_vdp1_shading_data->scanline[y].x[0] >> 16) != x )
566 	{
567 		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 );
568 	};
569 #endif
570 
571 	b = RGB_B(pix);
572 	g = RGB_G(pix);
573 	r = RGB_R(pix);
574 
575 	b = _shading( b, stv_vdp1_shading_data->scanline[y].b[0] );
576 	g = _shading( g, stv_vdp1_shading_data->scanline[y].g[0] );
577 	r = _shading( r, stv_vdp1_shading_data->scanline[y].r[0] );
578 
579 	stv_vdp1_shading_data->scanline[y].b[0] += stv_vdp1_shading_data->scanline[y].db;
580 	stv_vdp1_shading_data->scanline[y].g[0] += stv_vdp1_shading_data->scanline[y].dg;
581 	stv_vdp1_shading_data->scanline[y].r[0] += stv_vdp1_shading_data->scanline[y].dr;
582 
583 	stv_vdp1_shading_data->scanline[y].x[0] += 1 << FRAC_SHIFT;
584 
585 	return msb | b << 10 | g << 5 | r;
586 }
587 
stv_vdp1_setup_shading_for_line(int32_t y,int32_t x1,int32_t x2,int32_t r1,int32_t g1,int32_t b1,int32_t r2,int32_t g2,int32_t b2)588 void saturn_state::stv_vdp1_setup_shading_for_line(int32_t y, int32_t x1, int32_t x2,
589 											int32_t r1, int32_t g1, int32_t b1,
590 											int32_t r2, int32_t g2, int32_t b2)
591 {
592 	int xx1 = x1>>FRAC_SHIFT;
593 	int xx2 = x2>>FRAC_SHIFT;
594 
595 
596 	if ( xx1 > xx2 )
597 	{
598 		SWAP_INT32(xx1, xx2);
599 		SWAP_INT32(r1, r2);
600 		SWAP_INT32(g1, g2);
601 		SWAP_INT32(b1, b2);
602 	}
603 
604 	if ( (y >= 0) && (y < 512) )
605 	{
606 		int32_t  dx;
607 		int32_t   gbd, ggd, grd;
608 
609 		dx = xx2 - xx1;
610 
611 		if ( dx == 0 )
612 		{
613 			gbd = ggd = grd = 0;
614 		}
615 		else
616 		{
617 			gbd = abs(b2 - b1) / dx;
618 			if (b2 < b1) gbd = -gbd;
619 			ggd = abs(g2 - g1) / dx;
620 			if (g2 < g1) ggd = -ggd;
621 			grd = abs(r2 - r1) / dx;
622 			if (r2 < r1) grd = -grd;
623 		}
624 
625 		stv_vdp1_shading_data->scanline[y].x[0] = x1;
626 		stv_vdp1_shading_data->scanline[y].x[1] = x2;
627 
628 		stv_vdp1_shading_data->scanline[y].b[0] = b1;
629 		stv_vdp1_shading_data->scanline[y].g[0] = g1;
630 		stv_vdp1_shading_data->scanline[y].r[0] = r1;
631 		stv_vdp1_shading_data->scanline[y].b[1] = b2;
632 		stv_vdp1_shading_data->scanline[y].g[1] = g2;
633 		stv_vdp1_shading_data->scanline[y].r[1] = r2;
634 
635 		stv_vdp1_shading_data->scanline[y].db = gbd;
636 		stv_vdp1_shading_data->scanline[y].dg = ggd;
637 		stv_vdp1_shading_data->scanline[y].dr = grd;
638 
639 	}
640 }
641 
stv_vdp1_setup_shading_for_slope(int32_t x1,int32_t x2,int32_t sl1,int32_t sl2,int32_t * nx1,int32_t * nx2,int32_t r1,int32_t r2,int32_t slr1,int32_t slr2,int32_t * nr1,int32_t * nr2,int32_t g1,int32_t g2,int32_t slg1,int32_t slg2,int32_t * ng1,int32_t * ng2,int32_t b1,int32_t b2,int32_t slb1,int32_t slb2,int32_t * nb1,int32_t * nb2,int32_t _y1,int32_t y2)642 void saturn_state::stv_vdp1_setup_shading_for_slope(
643 							int32_t x1, int32_t x2, int32_t sl1, int32_t sl2, int32_t *nx1, int32_t *nx2,
644 							int32_t r1, int32_t r2, int32_t slr1, int32_t slr2, int32_t *nr1, int32_t *nr2,
645 							int32_t g1, int32_t g2, int32_t slg1, int32_t slg2, int32_t *ng1, int32_t *ng2,
646 							int32_t b1, int32_t b2, int32_t slb1, int32_t slb2, int32_t *nb1, int32_t *nb2,
647 							int32_t _y1, int32_t y2)
648 {
649 	if(x1 > x2 || (x1==x2 && sl1 > sl2)) {
650 		SWAP_INT32(x1,x2);
651 		SWAP_INT32(sl1,sl2);
652 		SWAP_INT32PTR(nx1, nx2);
653 		SWAP_INT32(r1,r2);
654 		SWAP_INT32(slr1, slr2);
655 		SWAP_INT32PTR(nr1, nr2);
656 		SWAP_INT32(g1, g2);
657 		SWAP_INT32(slg1, slg2);
658 		SWAP_INT32PTR(ng1, ng2);
659 		SWAP_INT32(b1, b2);
660 		SWAP_INT32(slb1, slb2);
661 		SWAP_INT32PTR(nb1, nb2);
662 	}
663 
664 	while(_y1 < y2)
665 	{
666 		stv_vdp1_setup_shading_for_line(_y1, x1, x2, r1, g1, b1, r2, g2, b2);
667 		x1 += sl1;
668 		r1 += slr1;
669 		g1 += slg1;
670 		b1 += slb1;
671 
672 		x2 += sl2;
673 		r2 += slr2;
674 		g2 += slg2;
675 		b2 += slb2;
676 		_y1++;
677 	}
678 	*nx1 = x1;
679 	*nr1 = r1;
680 	*ng1 = g1;
681 	*nb1 = b1;
682 
683 	*nx2 = x2;
684 	*nr2 = r2;
685 	*nb2 = b2;
686 	*ng2 = g2;
687 }
688 
stv_vdp1_setup_shading(const struct spoint * q,const rectangle & cliprect)689 void saturn_state::stv_vdp1_setup_shading(const struct spoint* q, const rectangle &cliprect)
690 {
691 	int32_t x1, x2, delta, cury, limy;
692 	int32_t r1, g1, b1, r2, g2, b2;
693 	int32_t sl1, slg1, slb1, slr1;
694 	int32_t sl2, slg2, slb2, slr2;
695 	int pmin, pmax, i, ps1, ps2;
696 	struct shaded_point p[8];
697 	uint16_t gd[4];
698 
699 	if ( stv_read_gouraud_table() == 0 ) return;
700 
701 	gd[0] = stv_gouraud_shading.GA;
702 	gd[1] = stv_gouraud_shading.GB;
703 	gd[2] = stv_gouraud_shading.GC;
704 	gd[3] = stv_gouraud_shading.GD;
705 
706 	for(i=0; i<4; i++) {
707 		p[i].x = p[i+4].x = q[i].x << FRAC_SHIFT;
708 		p[i].y = p[i+4].y = q[i].y;
709 		p[i].r = p[i+4].r = RGB_R(gd[i]) << FRAC_SHIFT;
710 		p[i].g = p[i+4].g = RGB_G(gd[i]) << FRAC_SHIFT;
711 		p[i].b = p[i+4].b = RGB_B(gd[i]) << FRAC_SHIFT;
712 	}
713 
714 	pmin = pmax = 0;
715 	for(i=1; i<4; i++) {
716 		if(p[i].y < p[pmin].y)
717 			pmin = i;
718 		if(p[i].y > p[pmax].y)
719 			pmax = i;
720 	}
721 
722 	cury = p[pmin].y;
723 	limy = p[pmax].y;
724 
725 	stv_vdp1_shading_data->sy = cury;
726 	stv_vdp1_shading_data->ey = limy;
727 
728 	if(cury == limy) {
729 		x1 = x2 = p[0].x;
730 		ps1 = ps2 = 0;
731 		for(i=1; i<4; i++) {
732 			if(p[i].x < x1) {
733 				x1 = p[i].x;
734 				ps1 = i;
735 			}
736 			if(p[i].x > x2) {
737 				x2 = p[i].x;
738 				ps2 = i;
739 			}
740 		}
741 		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);
742 		goto finish;
743 	}
744 
745 	ps1 = pmin+4;
746 	ps2 = pmin;
747 
748 	goto startup;
749 
750 	for(;;) {
751 		if(p[ps1-1].y == p[ps2+1].y) {
752 			stv_vdp1_setup_shading_for_slope(
753 							x1, x2, sl1, sl2, &x1, &x2,
754 							r1, r2, slr1, slr2, &r1, &r2,
755 							g1, g2, slg1, slg2, &g1, &g2,
756 							b1, b2, slb1, slb2, &b1, &b2,
757 							cury, p[ps1-1].y);
758 			cury = p[ps1-1].y;
759 			if(cury >= limy)
760 				break;
761 			ps1--;
762 			ps2++;
763 
764 		startup:
765 			while(p[ps1-1].y == cury)
766 				ps1--;
767 			while(p[ps2+1].y == cury)
768 				ps2++;
769 			x1 = p[ps1].x;
770 			r1 = p[ps1].r;
771 			g1 = p[ps1].g;
772 			b1 = p[ps1].b;
773 			x2 = p[ps2].x;
774 			r2 = p[ps2].r;
775 			g2 = p[ps2].g;
776 			b2 = p[ps2].b;
777 
778 			delta = cury-p[ps1-1].y;
779 			sl1 = (x1-p[ps1-1].x)/delta;
780 			slr1 = (r1-p[ps1-1].r)/delta;
781 			slg1 = (g1-p[ps1-1].g)/delta;
782 			slb1 = (b1-p[ps1-1].b)/delta;
783 
784 			delta = cury-p[ps2+1].y;
785 			sl2 = (x2-p[ps2+1].x)/delta;
786 			slr2 = (r2-p[ps2+1].r)/delta;
787 			slg2 = (g2-p[ps2+1].g)/delta;
788 			slb2 = (b2-p[ps2+1].b)/delta;
789 		} else if(p[ps1-1].y < p[ps2+1].y) {
790 			stv_vdp1_setup_shading_for_slope(
791 							x1, x2, sl1, sl2, &x1, &x2,
792 							r1, r2, slr1, slr2, &r1, &r2,
793 							g1, g2, slg1, slg2, &g1, &g2,
794 							b1, b2, slb1, slb2, &b1, &b2,
795 							cury, p[ps1-1].y);
796 			cury = p[ps1-1].y;
797 			if(cury >= limy)
798 				break;
799 			ps1--;
800 			while(p[ps1-1].y == cury)
801 				ps1--;
802 			x1 = p[ps1].x;
803 			r1 = p[ps1].r;
804 			g1 = p[ps1].g;
805 			b1 = p[ps1].b;
806 
807 			delta = cury-p[ps1-1].y;
808 			sl1 = (x1-p[ps1-1].x)/delta;
809 			slr1 = (r1-p[ps1-1].r)/delta;
810 			slg1 = (g1-p[ps1-1].g)/delta;
811 			slb1 = (b1-p[ps1-1].b)/delta;
812 		} else {
813 			stv_vdp1_setup_shading_for_slope(
814 							x1, x2, sl1, sl2, &x1, &x2,
815 							r1, r2, slr1, slr2, &r1, &r2,
816 							g1, g2, slg1, slg2, &g1, &g2,
817 							b1, b2, slb1, slb2, &b1, &b2,
818 							cury, p[ps2+1].y);
819 			cury = p[ps2+1].y;
820 			if(cury >= limy)
821 				break;
822 			ps2++;
823 			while(p[ps2+1].y == cury)
824 				ps2++;
825 			x2 = p[ps2].x;
826 			r2 = p[ps2].r;
827 			g2 = p[ps2].g;
828 			b2 = p[ps2].b;
829 
830 			delta = cury-p[ps2+1].y;
831 			sl2 = (x2-p[ps2+1].x)/delta;
832 			slr2 = (r2-p[ps2+1].r)/delta;
833 			slg2 = (g2-p[ps2+1].g)/delta;
834 			slb2 = (b2-p[ps2+1].b)/delta;
835 		}
836 	}
837 	if(cury == limy)
838 		stv_vdp1_setup_shading_for_line(cury, x1, x2, r1, g1, b1, r2, g2, b2 );
839 
840 finish:
841 
842 	if ( stv_vdp1_shading_data->sy < 0 ) stv_vdp1_shading_data->sy = 0;
843 	if ( stv_vdp1_shading_data->sy >= 512 ) return;
844 	if ( stv_vdp1_shading_data->ey < 0 ) return;
845 	if ( stv_vdp1_shading_data->ey >= 512 ) stv_vdp1_shading_data->ey = 511;
846 
847 	for ( cury = stv_vdp1_shading_data->sy; cury <= stv_vdp1_shading_data->ey; cury++ )
848 	{
849 		while( (stv_vdp1_shading_data->scanline[cury].x[0] >> 16) < cliprect.min_x )
850 		{
851 			stv_vdp1_shading_data->scanline[cury].x[0] += (1 << FRAC_SHIFT);
852 			stv_vdp1_shading_data->scanline[cury].b[0] += stv_vdp1_shading_data->scanline[cury].db;
853 			stv_vdp1_shading_data->scanline[cury].g[0] += stv_vdp1_shading_data->scanline[cury].dg;
854 			stv_vdp1_shading_data->scanline[cury].r[0] += stv_vdp1_shading_data->scanline[cury].dr;
855 		}
856 	}
857 
858 }
859 
860 /* note that if we're drawing
861 to the framebuffer we CAN'T frameskip the vdp1 drawing as the hardware can READ the framebuffer
862 and if we skip the drawing the content could be incorrect when it reads it, although i have no idea
863 why they would want to */
864 
865 
866 
drawpixel_poly(int x,int y,int patterndata,int offsetcnt)867 void saturn_state::drawpixel_poly(int x, int y, int patterndata, int offsetcnt)
868 {
869 	/* Capcom Collection Dai 4 uses a dummy polygon to clear VDP1 framebuffer that goes over our current max size ... */
870 	if(x >= 1024 || y >= 512)
871 		return;
872 
873 	m_vdp1.framebuffer_draw_lines[y][x] = stv2_current_sprite.CMDCOLR;
874 }
875 
drawpixel_8bpp_trans(int x,int y,int patterndata,int offsetcnt)876 void saturn_state::drawpixel_8bpp_trans(int x, int y, int patterndata, int offsetcnt)
877 {
878 	uint16_t pix;
879 
880 	pix = m_vdp1.gfx_decode[patterndata+offsetcnt] & 0xff;
881 	if ( pix != 0 )
882 	{
883 		m_vdp1.framebuffer_draw_lines[y][x] = pix | m_sprite_colorbank;
884 	}
885 }
886 
drawpixel_4bpp_notrans(int x,int y,int patterndata,int offsetcnt)887 void saturn_state::drawpixel_4bpp_notrans(int x, int y, int patterndata, int offsetcnt)
888 {
889 	uint16_t pix;
890 
891 	pix = m_vdp1.gfx_decode[patterndata+offsetcnt/2];
892 	pix = offsetcnt&1 ? (pix & 0x0f) : ((pix & 0xf0)>>4);
893 	m_vdp1.framebuffer_draw_lines[y][x] = pix | m_sprite_colorbank;
894 }
895 
drawpixel_4bpp_trans(int x,int y,int patterndata,int offsetcnt)896 void saturn_state::drawpixel_4bpp_trans(int x, int y, int patterndata, int offsetcnt)
897 {
898 	uint16_t pix;
899 
900 	pix = m_vdp1.gfx_decode[patterndata+offsetcnt/2];
901 	pix = offsetcnt&1 ? (pix & 0x0f) : ((pix & 0xf0)>>4);
902 	if ( pix != 0 )
903 		m_vdp1.framebuffer_draw_lines[y][x] = pix | m_sprite_colorbank;
904 }
905 
drawpixel_generic(int x,int y,int patterndata,int offsetcnt)906 void saturn_state::drawpixel_generic(int x, int y, int patterndata, int offsetcnt)
907 {
908 	int pix,transpen, spd = stv2_current_sprite.CMDPMOD & 0x40;
909 //  int mode;
910 	int mesh = stv2_current_sprite.CMDPMOD & 0x100;
911 	int raw,endcode;
912 
913 	if ( mesh && !((x ^ y) & 1) )
914 	{
915 		return;
916 	}
917 
918 	if(x >= 1024 || y >= 512)
919 		return;
920 
921 	if ( stv2_current_sprite.ispoly )
922 	{
923 		raw = pix = stv2_current_sprite.CMDCOLR&0xffff;
924 
925 		transpen = 0;
926 		endcode = 0xffff;
927 		#if 0
928 		if ( pix & 0x8000 )
929 		{
930 			mode = 5;
931 		}
932 		else
933 		{
934 			mode = 1;
935 		}
936 		#endif
937 	}
938 	else
939 	{
940 		switch (stv2_current_sprite.CMDPMOD&0x0038)
941 		{
942 			case 0x0000: // mode 0 16 colour bank mode (4bits) (hanagumi blocks)
943 				// most of the shienryu sprites use this mode
944 				raw = m_vdp1.gfx_decode[(patterndata+offsetcnt/2) & 0xfffff];
945 				raw = offsetcnt&1 ? (raw & 0x0f) : ((raw & 0xf0)>>4);
946 				pix = raw+((stv2_current_sprite.CMDCOLR&0xfff0));
947 				//mode = 0;
948 				transpen = 0;
949 				endcode = 0xf;
950 				break;
951 			case 0x0008: // mode 1 16 colour lookup table mode (4bits)
952 				// shienryu explosions (and some enemies) use this mode
953 				raw = m_vdp1.gfx_decode[(patterndata+offsetcnt/2) & 0xfffff];
954 				raw = offsetcnt&1 ? (raw & 0x0f) : ((raw & 0xf0)>>4);
955 				pix = raw&1 ?
956 				((((m_vdp1_vram[(((stv2_current_sprite.CMDCOLR&0xffff)*8)>>2)+((raw&0xfffe)/2)])) & 0x0000ffff) >> 0):
957 				((((m_vdp1_vram[(((stv2_current_sprite.CMDCOLR&0xffff)*8)>>2)+((raw&0xfffe)/2)])) & 0xffff0000) >> 16);
958 				//mode = 5;
959 				transpen = 0;
960 				endcode = 0xf;
961 				break;
962 			case 0x0010: // mode 2 64 colour bank mode (8bits) (character select portraits on hanagumi)
963 				raw = m_vdp1.gfx_decode[(patterndata+offsetcnt) & 0xfffff] & 0xff;
964 				//mode = 2;
965 				pix = raw+(stv2_current_sprite.CMDCOLR&0xffc0);
966 				transpen = 0;
967 				endcode = 0xff;
968 				// Notes of interest:
969 				// Scud: the disposable assassin wants transparent pen on 0
970 				// sasissu: racing stage background clouds
971 				break;
972 			case 0x0018: // mode 3 128 colour bank mode (8bits) (little characters on hanagumi use this mode)
973 				raw = m_vdp1.gfx_decode[(patterndata+offsetcnt) & 0xfffff] & 0xff;
974 				pix = raw+(stv2_current_sprite.CMDCOLR&0xff80);
975 				transpen = 0;
976 				endcode = 0xff;
977 				//mode = 3;
978 				break;
979 			case 0x0020: // mode 4 256 colour bank mode (8bits) (hanagumi title)
980 				raw = m_vdp1.gfx_decode[(patterndata+offsetcnt) & 0xfffff] & 0xff;
981 				pix = raw+(stv2_current_sprite.CMDCOLR&0xff00);
982 				transpen = 0;
983 				endcode = 0xff;
984 				//mode = 4;
985 				break;
986 			case 0x0028: // mode 5 32,768 colour RGB mode (16bits)
987 				raw = m_vdp1.gfx_decode[(patterndata+offsetcnt*2+1) & 0xfffff] | (m_vdp1.gfx_decode[(patterndata+offsetcnt*2) & 0xfffff]<<8);
988 				//mode = 5;
989 				// TODO: 0x1-0x7ffe reserved (color bank)
990 				pix = raw;
991 				transpen = 0;
992 				endcode = 0x7fff;
993 				break;
994 			case 0x0038: // invalid
995 				// game tengoku uses this on hi score screen (tate mode)
996 				// according to Charles, reads from VRAM address 0
997 				raw = pix = m_vdp1.gfx_decode[1] | (m_vdp1.gfx_decode[0]<<8) ;
998 				// TODO: check transpen
999 				transpen = 0;
1000 				endcode = -1;
1001 				break;
1002 			default: // other settings illegal
1003 				pix = machine().rand();
1004 				raw = pix & 0xff; // just mimic old driver behavior
1005 				//mode = 0;
1006 				transpen = 0;
1007 				endcode = 0xff;
1008 				popmessage("Illegal Sprite Mode %02x, contact MAMEdev",stv2_current_sprite.CMDPMOD&0x0038);
1009 		}
1010 
1011 
1012 		// preliminary end code disable support
1013 		if ( ((stv2_current_sprite.CMDPMOD & 0x80) == 0) &&
1014 			(raw == endcode) )
1015 		{
1016 			return;
1017 		}
1018 	}
1019 
1020 	/* MSBON */
1021 	// TODO: does this always applies to the frame buffer regardless of the mode?
1022 	pix |= stv2_current_sprite.CMDPMOD & 0x8000;
1023 	/*
1024 	TODO: from docs:
1025 	"Except for the color calculation of replace and shadow, color calculation can only be performed when the color code of the original picture is RGB code.
1026 	Color calculation can be executed when the color code is color bank code, but the results are not guaranteed."
1027 	Currently no idea about the "result not guaranteed" part, let's disable this branch for the time being ...
1028 	*/
1029 	#if 0
1030 	if ( mode != 5 )
1031 	{
1032 		if ( (raw != transpen) || spd )
1033 		{
1034 			m_vdp1.framebuffer_draw_lines[y][x] = pix;
1035 		}
1036 	}
1037 	else
1038 	#endif
1039 	{
1040 		if ( (raw != transpen) || spd )
1041 		{
1042 			if ( stv2_current_sprite.CMDPMOD & 0x4 ) /* Gouraud shading */
1043 				pix = stv_vdp1_apply_gouraud_shading( x, y, pix );
1044 
1045 			switch( stv2_current_sprite.CMDPMOD & 0x3 )
1046 			{
1047 				case 0: /* replace */
1048 					m_vdp1.framebuffer_draw_lines[y][x] = pix;
1049 					break;
1050 				case 1: /* shadow */
1051 					if ( m_vdp1.framebuffer_draw_lines[y][x] & 0x8000 )
1052 					{
1053 						m_vdp1.framebuffer_draw_lines[y][x] = ((m_vdp1.framebuffer_draw_lines[y][x] & ~0x8421) >> 1) | 0x8000;
1054 					}
1055 					break;
1056 				case 2: /* half luminance */
1057 					m_vdp1.framebuffer_draw_lines[y][x] = ((pix & ~0x8421) >> 1) | 0x8000;
1058 					break;
1059 				case 3: /* half transparent */
1060 					if ( m_vdp1.framebuffer_draw_lines[y][x] & 0x8000 )
1061 					{
1062 						m_vdp1.framebuffer_draw_lines[y][x] = alpha_blend_r16( m_vdp1.framebuffer_draw_lines[y][x], pix, 0x80 ) | 0x8000;
1063 					}
1064 					else
1065 					{
1066 						m_vdp1.framebuffer_draw_lines[y][x] = pix;
1067 					}
1068 					break;
1069 				//case 4: /* Gouraud shading */
1070 				// TODO: Pro Yakyuu Team mo Tsukurou (during team creation, on PR girl select)
1071 				//case 6:
1072 				//  break;
1073 				//case 7: /* Gouraud-shading + half-transparent */
1074 					// Lupin the 3rd Pyramid no Kenja enemy shadows
1075 					// Death Crimson lives indicators
1076 					// TODO: latter looks really bad.
1077 				default:
1078 					// TODO: mode 5: prohibited, mode 6: gouraud shading + half-luminance, mode 7: gouraud-shading + half-transparent
1079 					popmessage("VDP1 PMOD = %02x, contact MAMEdev",stv2_current_sprite.CMDPMOD & 0x7);
1080 					m_vdp1.framebuffer_draw_lines[y][x] = pix;
1081 					break;
1082 			}
1083 		}
1084 	}
1085 }
1086 
1087 
stv_vdp1_set_drawpixel(void)1088 void saturn_state::stv_vdp1_set_drawpixel( void )
1089 {
1090 	int sprite_type = stv2_current_sprite.CMDCTRL & 0x000f;
1091 	int sprite_mode = stv2_current_sprite.CMDPMOD&0x0038;
1092 	int spd = stv2_current_sprite.CMDPMOD & 0x40;
1093 	int mesh = stv2_current_sprite.CMDPMOD & 0x100;
1094 	int ecd = stv2_current_sprite.CMDPMOD & 0x80;
1095 
1096 	if ( mesh || !ecd || ((stv2_current_sprite.CMDPMOD & 0x7) != 0) )
1097 	{
1098 		drawpixel = &saturn_state::drawpixel_generic;
1099 		return;
1100 	}
1101 
1102 	if(stv2_current_sprite.CMDPMOD & 0x8000)
1103 	{
1104 		drawpixel = &saturn_state::drawpixel_generic;
1105 		return;
1106 	}
1107 
1108 	// polygon / polyline / line with replace case
1109 	if (sprite_type & 4 && ((stv2_current_sprite.CMDPMOD & 0x7) == 0))
1110 	{
1111 		drawpixel = &saturn_state::drawpixel_poly;
1112 	}
1113 	else if ( (sprite_mode == 0x20) && !spd )
1114 	{
1115 		m_sprite_colorbank = (stv2_current_sprite.CMDCOLR&0xff00);
1116 		drawpixel = &saturn_state::drawpixel_8bpp_trans;
1117 	}
1118 	else if ((sprite_mode == 0x00) && spd)
1119 	{
1120 		m_sprite_colorbank = (stv2_current_sprite.CMDCOLR&0xfff0);
1121 		drawpixel = &saturn_state::drawpixel_4bpp_notrans;
1122 	}
1123 	else if (sprite_mode == 0x00 && !spd )
1124 	{
1125 		m_sprite_colorbank = (stv2_current_sprite.CMDCOLR&0xfff0);
1126 		drawpixel = &saturn_state::drawpixel_4bpp_trans;
1127 	}
1128 	else
1129 	{
1130 		drawpixel = &saturn_state::drawpixel_generic;
1131 	}
1132 }
1133 
1134 
vdp1_fill_slope(const rectangle & cliprect,int patterndata,int xsize,int32_t x1,int32_t x2,int32_t sl1,int32_t sl2,int32_t * nx1,int32_t * nx2,int32_t u1,int32_t u2,int32_t slu1,int32_t slu2,int32_t * nu1,int32_t * nu2,int32_t v1,int32_t v2,int32_t slv1,int32_t slv2,int32_t * nv1,int32_t * nv2,int32_t _y1,int32_t y2)1135 void saturn_state::vdp1_fill_slope(const rectangle &cliprect, int patterndata, int xsize,
1136 							int32_t x1, int32_t x2, int32_t sl1, int32_t sl2, int32_t *nx1, int32_t *nx2,
1137 							int32_t u1, int32_t u2, int32_t slu1, int32_t slu2, int32_t *nu1, int32_t *nu2,
1138 							int32_t v1, int32_t v2, int32_t slv1, int32_t slv2, int32_t *nv1, int32_t *nv2,
1139 							int32_t _y1, int32_t y2)
1140 {
1141 	if(_y1 > cliprect.max_y)
1142 		return;
1143 
1144 	if(y2 <= cliprect.min_y) {
1145 		int delta = y2-_y1;
1146 		*nx1 = x1+delta*sl1;
1147 		*nu1 = u1+delta*slu1;
1148 		*nv1 = v1+delta*slv1;
1149 		*nx2 = x2+delta*sl2;
1150 		*nu2 = u2+delta*slu2;
1151 		*nv2 = v2+delta*slv2;
1152 		return;
1153 	}
1154 
1155 	if(y2 > cliprect.max_y)
1156 		y2 = cliprect.max_y+1;
1157 
1158 	if(_y1 < cliprect.min_y) {
1159 		int delta = cliprect.min_y - _y1;
1160 		x1 += delta*sl1;
1161 		u1 += delta*slu1;
1162 		v1 += delta*slv1;
1163 		x2 += delta*sl2;
1164 		u2 += delta*slu2;
1165 		v2 += delta*slv2;
1166 		_y1 = cliprect.min_y;
1167 	}
1168 
1169 	if(x1 > x2 || (x1==x2 && sl1 > sl2)) {
1170 		int32_t t, *tp;
1171 		t = x1;
1172 		x1 = x2;
1173 		x2 = t;
1174 		t = sl1;
1175 		sl1 = sl2;
1176 		sl2 = t;
1177 		tp = nx1;
1178 		nx1 = nx2;
1179 		nx2 = tp;
1180 
1181 		t = u1;
1182 		u1 = u2;
1183 		u2 = t;
1184 		t = slu1;
1185 		slu1 = slu2;
1186 		slu2 = t;
1187 		tp = nu1;
1188 		nu1 = nu2;
1189 		nu2 = tp;
1190 
1191 		t = v1;
1192 		v1 = v2;
1193 		v2 = t;
1194 		t = slv1;
1195 		slv1 = slv2;
1196 		slv2 = t;
1197 		tp = nv1;
1198 		nv1 = nv2;
1199 		nv2 = tp;
1200 	}
1201 
1202 	while(_y1 < y2) {
1203 		if(_y1 >= cliprect.min_y) {
1204 			int32_t slux = 0, slvx = 0;
1205 			int xx1 = x1>>FRAC_SHIFT;
1206 			int xx2 = x2>>FRAC_SHIFT;
1207 			int32_t u = u1;
1208 			int32_t v = v1;
1209 			if(xx1 != xx2) {
1210 				int delta = xx2-xx1;
1211 				slux = (u2-u1)/delta;
1212 				slvx = (v2-v1)/delta;
1213 			}
1214 			if(xx1 <= cliprect.max_x || xx2 >= cliprect.min_x) {
1215 				if(xx1 < cliprect.min_x) {
1216 					int delta = cliprect.min_x-xx1;
1217 					u += slux*delta;
1218 					v += slvx*delta;
1219 					xx1 = cliprect.min_x;
1220 				}
1221 				if(xx2 > cliprect.max_x)
1222 					xx2 = cliprect.max_x;
1223 
1224 				while(xx1 <= xx2) {
1225 					(this->*drawpixel)(xx1,_y1, patterndata, (v>>FRAC_SHIFT)*xsize+(u>>FRAC_SHIFT));
1226 					xx1++;
1227 					u += slux;
1228 					v += slvx;
1229 				}
1230 			}
1231 		}
1232 
1233 		x1 += sl1;
1234 		u1 += slu1;
1235 		v1 += slv1;
1236 		x2 += sl2;
1237 		u2 += slu2;
1238 		v2 += slv2;
1239 		_y1++;
1240 	}
1241 	*nx1 = x1;
1242 	*nu1 = u1;
1243 	*nv1 = v1;
1244 	*nx2 = x2;
1245 	*nu2 = u2;
1246 	*nv2 = v2;
1247 }
1248 
vdp1_fill_line(const rectangle & cliprect,int patterndata,int xsize,int32_t y,int32_t x1,int32_t x2,int32_t u1,int32_t u2,int32_t v1,int32_t v2)1249 void saturn_state::vdp1_fill_line(const rectangle &cliprect, int patterndata, int xsize, int32_t y,
1250 							int32_t x1, int32_t x2, int32_t u1, int32_t u2, int32_t v1, int32_t v2)
1251 {
1252 	int xx1 = x1>>FRAC_SHIFT;
1253 	int xx2 = x2>>FRAC_SHIFT;
1254 
1255 	if(y > cliprect.max_y || y < cliprect.min_y)
1256 		return;
1257 
1258 	if(xx1 <= cliprect.max_x || xx2 >= cliprect.min_x) {
1259 		int32_t slux = 0, slvx = 0;
1260 		int32_t u = u1;
1261 		int32_t v = v1;
1262 		if(xx1 != xx2) {
1263 			int delta = xx2-xx1;
1264 			slux = (u2-u1)/delta;
1265 			slvx = (v2-v1)/delta;
1266 		}
1267 		if(xx1 < cliprect.min_x) {
1268 			int delta = cliprect.min_x-xx1;
1269 			u += slux*delta;
1270 			v += slvx*delta;
1271 			xx1 = cliprect.min_x;
1272 		}
1273 		if(xx2 > cliprect.max_x)
1274 			xx2 = cliprect.max_x;
1275 
1276 		while(xx1 <= xx2) {
1277 			(this->*drawpixel)(xx1,y,patterndata,(v>>FRAC_SHIFT)*xsize+(u>>FRAC_SHIFT));
1278 			xx1++;
1279 			u += slux;
1280 			v += slvx;
1281 		}
1282 	}
1283 }
1284 
vdp1_fill_quad(const rectangle & cliprect,int patterndata,int xsize,const struct spoint * q)1285 void saturn_state::vdp1_fill_quad(const rectangle &cliprect, int patterndata, int xsize, const struct spoint *q)
1286 {
1287 	int32_t sl1, sl2, slu1, slu2, slv1, slv2, cury, limy, x1, x2, u1, u2, v1, v2, delta;
1288 	int pmin, pmax, i, ps1, ps2;
1289 	struct spoint p[8];
1290 
1291 	for(i=0; i<4; i++) {
1292 		p[i].x = p[i+4].x = q[i].x << FRAC_SHIFT;
1293 		p[i].y = p[i+4].y = q[i].y;
1294 		p[i].u = p[i+4].u = q[i].u << FRAC_SHIFT;
1295 		p[i].v = p[i+4].v = q[i].v << FRAC_SHIFT;
1296 	}
1297 
1298 	pmin = pmax = 0;
1299 	for(i=1; i<4; i++) {
1300 		if(p[i].y < p[pmin].y)
1301 			pmin = i;
1302 		if(p[i].y > p[pmax].y)
1303 			pmax = i;
1304 	}
1305 
1306 	cury = p[pmin].y;
1307 	limy = p[pmax].y;
1308 
1309 	if(cury == limy) {
1310 		x1 = x2 = p[0].x;
1311 		u1 = u2 = p[0].u;
1312 		v1 = v2 = p[0].v;
1313 		for(i=1; i<4; i++) {
1314 			if(p[i].x < x1) {
1315 				x1 = p[i].x;
1316 				u1 = p[i].u;
1317 				v1 = p[i].v;
1318 			}
1319 			if(p[i].x > x2) {
1320 				x2 = p[i].x;
1321 				u2 = p[i].u;
1322 				v2 = p[i].v;
1323 			}
1324 		}
1325 		vdp1_fill_line(cliprect, patterndata, xsize, cury, x1, x2, u1, u2, v1, v2);
1326 		return;
1327 	}
1328 
1329 	if(cury > cliprect.max_y)
1330 		return;
1331 	if(limy <= cliprect.min_y)
1332 		return;
1333 
1334 	if(limy > cliprect.max_y)
1335 		limy = cliprect.max_y;
1336 
1337 	ps1 = pmin+4;
1338 	ps2 = pmin;
1339 
1340 	goto startup;
1341 
1342 	for(;;) {
1343 		if(p[ps1-1].y == p[ps2+1].y) {
1344 			vdp1_fill_slope(cliprect, patterndata, xsize,
1345 							x1, x2, sl1, sl2, &x1, &x2,
1346 							u1, u2, slu1, slu2, &u1, &u2,
1347 							v1, v2, slv1, slv2, &v1, &v2,
1348 							cury, p[ps1-1].y);
1349 			cury = p[ps1-1].y;
1350 			if(cury >= limy)
1351 				break;
1352 			ps1--;
1353 			ps2++;
1354 
1355 		startup:
1356 			while(p[ps1-1].y == cury)
1357 				ps1--;
1358 			while(p[ps2+1].y == cury)
1359 				ps2++;
1360 			x1 = p[ps1].x;
1361 			u1 = p[ps1].u;
1362 			v1 = p[ps1].v;
1363 			x2 = p[ps2].x;
1364 			u2 = p[ps2].u;
1365 			v2 = p[ps2].v;
1366 
1367 			delta = cury-p[ps1-1].y;
1368 			sl1 = (x1-p[ps1-1].x)/delta;
1369 			slu1 = (u1-p[ps1-1].u)/delta;
1370 			slv1 = (v1-p[ps1-1].v)/delta;
1371 
1372 			delta = cury-p[ps2+1].y;
1373 			sl2 = (x2-p[ps2+1].x)/delta;
1374 			slu2 = (u2-p[ps2+1].u)/delta;
1375 			slv2 = (v2-p[ps2+1].v)/delta;
1376 		} else if(p[ps1-1].y < p[ps2+1].y) {
1377 			vdp1_fill_slope(cliprect, patterndata, xsize,
1378 							x1, x2, sl1, sl2, &x1, &x2,
1379 							u1, u2, slu1, slu2, &u1, &u2,
1380 							v1, v2, slv1, slv2, &v1, &v2,
1381 							cury, p[ps1-1].y);
1382 			cury = p[ps1-1].y;
1383 			if(cury >= limy)
1384 				break;
1385 			ps1--;
1386 			while(p[ps1-1].y == cury)
1387 				ps1--;
1388 			x1 = p[ps1].x;
1389 			u1 = p[ps1].u;
1390 			v1 = p[ps1].v;
1391 
1392 			delta = cury-p[ps1-1].y;
1393 			sl1 = (x1-p[ps1-1].x)/delta;
1394 			slu1 = (u1-p[ps1-1].u)/delta;
1395 			slv1 = (v1-p[ps1-1].v)/delta;
1396 		} else {
1397 			vdp1_fill_slope(cliprect, patterndata, xsize,
1398 							x1, x2, sl1, sl2, &x1, &x2,
1399 							u1, u2, slu1, slu2, &u1, &u2,
1400 							v1, v2, slv1, slv2, &v1, &v2,
1401 							cury, p[ps2+1].y);
1402 			cury = p[ps2+1].y;
1403 			if(cury >= limy)
1404 				break;
1405 			ps2++;
1406 			while(p[ps2+1].y == cury)
1407 				ps2++;
1408 			x2 = p[ps2].x;
1409 			u2 = p[ps2].u;
1410 			v2 = p[ps2].v;
1411 
1412 			delta = cury-p[ps2+1].y;
1413 			sl2 = (x2-p[ps2+1].x)/delta;
1414 			slu2 = (u2-p[ps2+1].u)/delta;
1415 			slv2 = (v2-p[ps2+1].v)/delta;
1416 		}
1417 	}
1418 	if(cury == limy)
1419 		vdp1_fill_line(cliprect, patterndata, xsize, cury, x1, x2, u1, u2, v1, v2);
1420 }
1421 
x2s(int v)1422 int saturn_state::x2s(int v)
1423 {
1424 	return (int32_t)(int16_t)v + m_vdp1.local_x;
1425 }
1426 
y2s(int v)1427 int saturn_state::y2s(int v)
1428 {
1429 	return (int32_t)(int16_t)v + m_vdp1.local_y;
1430 }
1431 
stv_vdp1_draw_line(const rectangle & cliprect)1432 void saturn_state::stv_vdp1_draw_line(const rectangle &cliprect)
1433 {
1434 	struct spoint q[4];
1435 
1436 	q[0].x = x2s(stv2_current_sprite.CMDXA);
1437 	q[0].y = y2s(stv2_current_sprite.CMDYA);
1438 	q[1].x = x2s(stv2_current_sprite.CMDXB);
1439 	q[1].y = y2s(stv2_current_sprite.CMDYB);
1440 	q[2].x = x2s(stv2_current_sprite.CMDXA);
1441 	q[2].y = y2s(stv2_current_sprite.CMDYA);
1442 	q[3].x = x2s(stv2_current_sprite.CMDXB);
1443 	q[3].y = y2s(stv2_current_sprite.CMDYB);
1444 
1445 	q[0].u = q[3].u = q[1].u = q[2].u = 0;
1446 	q[0].v = q[1].v = q[2].v = q[3].v = 0;
1447 
1448 	vdp1_fill_quad(cliprect, 0, 1, q);
1449 }
1450 
stv_vdp1_draw_poly_line(const rectangle & cliprect)1451 void saturn_state::stv_vdp1_draw_poly_line(const rectangle &cliprect)
1452 {
1453 	struct spoint q[4];
1454 
1455 	q[0].x = x2s(stv2_current_sprite.CMDXA);
1456 	q[0].y = y2s(stv2_current_sprite.CMDYA);
1457 	q[1].x = x2s(stv2_current_sprite.CMDXB);
1458 	q[1].y = y2s(stv2_current_sprite.CMDYB);
1459 	q[2].x = x2s(stv2_current_sprite.CMDXA);
1460 	q[2].y = y2s(stv2_current_sprite.CMDYA);
1461 	q[3].x = x2s(stv2_current_sprite.CMDXB);
1462 	q[3].y = y2s(stv2_current_sprite.CMDYB);
1463 
1464 	q[0].u = q[3].u = q[1].u = q[2].u = 0;
1465 	q[0].v = q[1].v = q[2].v = q[3].v = 0;
1466 
1467 	vdp1_fill_quad(cliprect, 0, 1, q);
1468 
1469 	q[0].x = x2s(stv2_current_sprite.CMDXB);
1470 	q[0].y = y2s(stv2_current_sprite.CMDYB);
1471 	q[1].x = x2s(stv2_current_sprite.CMDXC);
1472 	q[1].y = y2s(stv2_current_sprite.CMDYC);
1473 	q[2].x = x2s(stv2_current_sprite.CMDXB);
1474 	q[2].y = y2s(stv2_current_sprite.CMDYB);
1475 	q[3].x = x2s(stv2_current_sprite.CMDXC);
1476 	q[3].y = y2s(stv2_current_sprite.CMDYC);
1477 
1478 	q[0].u = q[3].u = q[1].u = q[2].u = 0;
1479 	q[0].v = q[1].v = q[2].v = q[3].v = 0;
1480 
1481 	vdp1_fill_quad(cliprect, 0, 1, q);
1482 
1483 	q[0].x = x2s(stv2_current_sprite.CMDXC);
1484 	q[0].y = y2s(stv2_current_sprite.CMDYC);
1485 	q[1].x = x2s(stv2_current_sprite.CMDXD);
1486 	q[1].y = y2s(stv2_current_sprite.CMDYD);
1487 	q[2].x = x2s(stv2_current_sprite.CMDXC);
1488 	q[2].y = y2s(stv2_current_sprite.CMDYC);
1489 	q[3].x = x2s(stv2_current_sprite.CMDXD);
1490 	q[3].y = y2s(stv2_current_sprite.CMDYD);
1491 
1492 	q[0].u = q[3].u = q[1].u = q[2].u = 0;
1493 	q[0].v = q[1].v = q[2].v = q[3].v = 0;
1494 
1495 	vdp1_fill_quad(cliprect, 0, 1, q);
1496 
1497 	q[0].x = x2s(stv2_current_sprite.CMDXD);
1498 	q[0].y = y2s(stv2_current_sprite.CMDYD);
1499 	q[1].x = x2s(stv2_current_sprite.CMDXA);
1500 	q[1].y = y2s(stv2_current_sprite.CMDYA);
1501 	q[2].x = x2s(stv2_current_sprite.CMDXD);
1502 	q[2].y = y2s(stv2_current_sprite.CMDYD);
1503 	q[3].x = x2s(stv2_current_sprite.CMDXA);
1504 	q[3].y = y2s(stv2_current_sprite.CMDYA);
1505 
1506 	q[0].u = q[3].u = q[1].u = q[2].u = 0;
1507 	q[0].v = q[1].v = q[2].v = q[3].v = 0;
1508 
1509 	stv_vdp1_setup_shading(q, cliprect);
1510 	vdp1_fill_quad(cliprect, 0, 1, q);
1511 
1512 }
1513 
stv_vdp1_draw_distorted_sprite(const rectangle & cliprect)1514 void saturn_state::stv_vdp1_draw_distorted_sprite(const rectangle &cliprect)
1515 {
1516 	struct spoint q[4];
1517 
1518 	int xsize, ysize;
1519 	int direction;
1520 	int patterndata;
1521 
1522 	direction = (stv2_current_sprite.CMDCTRL & 0x0030)>>4;
1523 
1524 	if ( stv2_current_sprite.ispoly )
1525 	{
1526 		xsize = ysize = 1;
1527 		patterndata = 0;
1528 	}
1529 	else
1530 	{
1531 		xsize = (stv2_current_sprite.CMDSIZE & 0x3f00) >> 8;
1532 		xsize = xsize * 8;
1533 		if (xsize == 0) return; /* setting prohibited */
1534 
1535 		ysize = (stv2_current_sprite.CMDSIZE & 0x00ff);
1536 		if (ysize == 0) return; /* setting prohibited */
1537 
1538 		patterndata = (stv2_current_sprite.CMDSRCA) & 0xffff;
1539 		patterndata = patterndata * 0x8;
1540 
1541 	}
1542 
1543 
1544 	q[0].x = x2s(stv2_current_sprite.CMDXA);
1545 	q[0].y = y2s(stv2_current_sprite.CMDYA);
1546 	q[1].x = x2s(stv2_current_sprite.CMDXB);
1547 	q[1].y = y2s(stv2_current_sprite.CMDYB);
1548 	q[2].x = x2s(stv2_current_sprite.CMDXC);
1549 	q[2].y = y2s(stv2_current_sprite.CMDYC);
1550 	q[3].x = x2s(stv2_current_sprite.CMDXD);
1551 	q[3].y = y2s(stv2_current_sprite.CMDYD);
1552 
1553 	if(direction & 1) { // xflip
1554 		q[0].u = q[3].u = xsize-1;
1555 		q[1].u = q[2].u = 0;
1556 	} else {
1557 		q[0].u = q[3].u = 0;
1558 		q[1].u = q[2].u = xsize-1;
1559 	}
1560 	if(direction & 2) { // yflip
1561 		q[0].v = q[1].v = ysize-1;
1562 		q[2].v = q[3].v = 0;
1563 	} else {
1564 		q[0].v = q[1].v = 0;
1565 		q[2].v = q[3].v = ysize-1;
1566 	}
1567 
1568 	stv_vdp1_setup_shading(q, cliprect);
1569 	vdp1_fill_quad(cliprect, patterndata, xsize, q);
1570 }
1571 
stv_vdp1_draw_scaled_sprite(const rectangle & cliprect)1572 void saturn_state::stv_vdp1_draw_scaled_sprite(const rectangle &cliprect)
1573 {
1574 	struct spoint q[4];
1575 
1576 	int xsize, ysize;
1577 	int direction;
1578 	int patterndata;
1579 	int zoompoint;
1580 	int x,y;
1581 	int x2,y2;
1582 	int screen_width,screen_height,screen_height_negative = 0;
1583 
1584 	direction = (stv2_current_sprite.CMDCTRL & 0x0030)>>4;
1585 
1586 	xsize = (stv2_current_sprite.CMDSIZE & 0x3f00) >> 8;
1587 	xsize = xsize * 8;
1588 
1589 	ysize = (stv2_current_sprite.CMDSIZE & 0x00ff);
1590 
1591 	patterndata = (stv2_current_sprite.CMDSRCA) & 0xffff;
1592 	patterndata = patterndata * 0x8;
1593 
1594 	zoompoint = (stv2_current_sprite.CMDCTRL & 0x0f00)>>8;
1595 
1596 	x = stv2_current_sprite.CMDXA;
1597 	y = stv2_current_sprite.CMDYA;
1598 
1599 	screen_width = (int16_t)stv2_current_sprite.CMDXB;
1600 	if ( (screen_width < 0) && zoompoint)
1601 	{
1602 		screen_width = -screen_width;
1603 		direction |= 1;
1604 	}
1605 
1606 	screen_height = (int16_t)stv2_current_sprite.CMDYB;
1607 	if ( (screen_height < 0) && zoompoint )
1608 	{
1609 		screen_height_negative = 1;
1610 		screen_height = -screen_height;
1611 		direction |= 2;
1612 	}
1613 
1614 	x2 = stv2_current_sprite.CMDXC; // second co-ordinate set x
1615 	y2 = stv2_current_sprite.CMDYC; // second co-ordinate set y
1616 
1617 	switch (zoompoint)
1618 	{
1619 		case 0x0: // specified co-ordinates
1620 			break;
1621 		case 0x5: // up left
1622 			break;
1623 		case 0x6: // up center
1624 			x -= screen_width/2 ;
1625 			break;
1626 		case 0x7: // up right
1627 			x -= screen_width;
1628 			break;
1629 
1630 		case 0x9: // center left
1631 			y -= screen_height/2 ;
1632 			break;
1633 		case 0xa: // center center
1634 			y -= screen_height/2 ;
1635 			x -= screen_width/2 ;
1636 
1637 			break;
1638 
1639 		case 0xb: // center right
1640 			y -= screen_height/2 ;
1641 			x -= screen_width;
1642 			break;
1643 
1644 		case 0xd: // center left
1645 			y -= screen_height;
1646 			break;
1647 
1648 		case 0xe: // center center
1649 			y -= screen_height;
1650 			x -= screen_width/2 ;
1651 			break;
1652 
1653 		case 0xf: // center right
1654 			y -= screen_height;
1655 			x -= screen_width;
1656 			break;
1657 
1658 		default: // illegal
1659 			break;
1660 
1661 	}
1662 
1663 	/*  0----1
1664 	    |    |
1665 	    |    |
1666 	    3----2   */
1667 
1668 	if (zoompoint)
1669 	{
1670 		q[0].x = x2s(x);
1671 		q[0].y = y2s(y);
1672 		q[1].x = x2s(x)+screen_width;
1673 		q[1].y = y2s(y);
1674 		q[2].x = x2s(x)+screen_width;
1675 		q[2].y = y2s(y)+screen_height;
1676 		q[3].x = x2s(x);
1677 		q[3].y = y2s(y)+screen_height;
1678 
1679 		if ( screen_height_negative )
1680 		{
1681 			q[0].y += screen_height;
1682 			q[1].y += screen_height;
1683 			q[2].y += screen_height;
1684 			q[3].y += screen_height;
1685 		}
1686 	}
1687 	else
1688 	{
1689 		q[0].x = x2s(x);
1690 		q[0].y = y2s(y);
1691 		q[1].x = x2s(x2);
1692 		q[1].y = y2s(y);
1693 		q[2].x = x2s(x2);
1694 		q[2].y = y2s(y2);
1695 		q[3].x = x2s(x);
1696 		q[3].y = y2s(y2);
1697 	}
1698 
1699 
1700 	if(direction & 1) { // xflip
1701 		q[0].u = q[3].u = xsize-1;
1702 		q[1].u = q[2].u = 0;
1703 	} else {
1704 		q[0].u = q[3].u = 0;
1705 		q[1].u = q[2].u = xsize-1;
1706 	}
1707 	if(direction & 2) { // yflip
1708 		q[0].v = q[1].v = ysize-1;
1709 		q[2].v = q[3].v = 0;
1710 	} else {
1711 		q[0].v = q[1].v = 0;
1712 		q[2].v = q[3].v = ysize-1;
1713 	}
1714 
1715 	stv_vdp1_setup_shading(q, cliprect);
1716 	vdp1_fill_quad(cliprect, patterndata, xsize, q);
1717 }
1718 
1719 
1720 
1721 
stv_vdp1_draw_normal_sprite(const rectangle & cliprect,int sprite_type)1722 void saturn_state::stv_vdp1_draw_normal_sprite(const rectangle &cliprect, int sprite_type)
1723 {
1724 	int y, ysize, drawypos;
1725 	int x, xsize, drawxpos;
1726 	int direction;
1727 	int patterndata;
1728 	uint8_t shading;
1729 	int su, u, dux, duy;
1730 	int maxdrawypos, maxdrawxpos;
1731 
1732 	x = x2s(stv2_current_sprite.CMDXA);
1733 	y = y2s(stv2_current_sprite.CMDYA);
1734 
1735 	direction = (stv2_current_sprite.CMDCTRL & 0x0030)>>4;
1736 
1737 	xsize = (stv2_current_sprite.CMDSIZE & 0x3f00) >> 8;
1738 	xsize = xsize * 8;
1739 
1740 	ysize = (stv2_current_sprite.CMDSIZE & 0x00ff);
1741 
1742 	patterndata = (stv2_current_sprite.CMDSRCA) & 0xffff;
1743 	patterndata = patterndata * 0x8;
1744 
1745 	if (VDP1_LOG) logerror ("Drawing Normal Sprite x %04x y %04x xsize %04x ysize %04x patterndata %06x\n",x,y,xsize,ysize,patterndata);
1746 
1747 	if ( x > cliprect.max_x ) return;
1748 	if ( y > cliprect.max_y ) return;
1749 
1750 	shading = stv_read_gouraud_table();
1751 	if ( shading )
1752 	{
1753 		struct spoint q[4];
1754 		q[0].x = x; q[0].y = y;
1755 		q[1].x = x + xsize; q[1].y = y;
1756 		q[2].x = x + xsize; q[2].y = y + ysize;
1757 		q[3].x = x; q[3].y = y + ysize;
1758 
1759 		stv_vdp1_setup_shading( q, cliprect );
1760 	}
1761 
1762 	u = 0;
1763 	dux = 1;
1764 	duy = xsize;
1765 	if ( direction & 0x1 ) //xflip
1766 	{
1767 		dux = -1;
1768 		u = xsize - 1;
1769 	}
1770 	if ( direction & 0x2 ) //yflip
1771 	{
1772 		duy = -xsize;
1773 		u += xsize*(ysize-1);
1774 	}
1775 	if ( y < cliprect.min_y ) //clip y
1776 	{
1777 		u += xsize*(cliprect.min_y - y);
1778 		ysize -= (cliprect.min_y - y);
1779 		y = cliprect.min_y;
1780 	}
1781 	if ( x < cliprect.min_x ) //clip x
1782 	{
1783 		u += dux*(cliprect.min_x - x);
1784 		xsize -= (cliprect.min_x - x);
1785 		x = cliprect.min_x;
1786 	}
1787 	maxdrawypos = std::min(y+ysize-1,cliprect.max_y);
1788 	maxdrawxpos = std::min(x+xsize-1,cliprect.max_x);
1789 	for (drawypos = y; drawypos <= maxdrawypos; drawypos++ )
1790 	{
1791 		//destline = m_vdp1.framebuffer_draw_lines[drawypos];
1792 		su = u;
1793 		for (drawxpos = x; drawxpos <= maxdrawxpos; drawxpos++ )
1794 		{
1795 			(this->*drawpixel)( drawxpos, drawypos, patterndata, u );
1796 			u += dux;
1797 		}
1798 		u = su + duy;
1799 	}
1800 }
1801 
TIMER_CALLBACK_MEMBER(saturn_state::vdp1_draw_end)1802 TIMER_CALLBACK_MEMBER(saturn_state::vdp1_draw_end )
1803 {
1804 	/* set CEF to 1*/
1805 	CEF_1;
1806 
1807 	// TODO: temporary for Batman Forever, presumably anonymous timer not behaving well.
1808 	#if 0
1809 	if(!(m_scu.ism & IRQ_VDP1_END))
1810 	{
1811 		m_maincpu->set_input_line_and_vector(0x2, HOLD_LINE, 0x4d); // SH2
1812 		scu_do_transfer(6);
1813 	}
1814 	else
1815 		m_scu.ist |= (IRQ_VDP1_END);
1816 	#endif
1817 }
1818 
1819 
stv_vdp1_process_list(void)1820 void saturn_state::stv_vdp1_process_list( void )
1821 {
1822 	int position;
1823 	int spritecount;
1824 	int vdp1_nest;
1825 	rectangle *cliprect;
1826 
1827 	spritecount = 0;
1828 	position = 0;
1829 
1830 	if (VDP1_LOG) logerror ("Sprite List Process START\n");
1831 
1832 	vdp1_nest = -1;
1833 
1834 	stv_clear_gouraud_shading();
1835 
1836 	/*Set CEF bit to 0*/
1837 	CEF_0;
1838 
1839 	// TODO: is there an actual limit for this?
1840 	while (spritecount<16383) // max 16383 with texture or max 16384 without texture - vitrually unlimited
1841 	{
1842 		int draw_this_sprite;
1843 
1844 		draw_this_sprite = 1;
1845 
1846 	//  if (position >= ((0x80000/0x20)/4)) // safety check
1847 	//  {
1848 	//      if (VDP1_LOG) logerror ("Sprite List Position Too High!\n");
1849 	//      position = 0;
1850 	//  }
1851 
1852 		spritecount++;
1853 
1854 		stv2_current_sprite.CMDCTRL = (m_vdp1_vram[position * (0x20/4)+0] & 0xffff0000) >> 16;
1855 
1856 		if (stv2_current_sprite.CMDCTRL == 0x8000)
1857 		{
1858 			if (VDP1_LOG) logerror ("List Terminator (0x8000) Encountered, Sprite List Process END\n");
1859 			goto end; // end of list
1860 		}
1861 
1862 		stv2_current_sprite.CMDLINK = (m_vdp1_vram[position * (0x20/4)+0] & 0x0000ffff) >> 0;
1863 		stv2_current_sprite.CMDPMOD = (m_vdp1_vram[position * (0x20/4)+1] & 0xffff0000) >> 16;
1864 		stv2_current_sprite.CMDCOLR = (m_vdp1_vram[position * (0x20/4)+1] & 0x0000ffff) >> 0;
1865 		stv2_current_sprite.CMDSRCA = (m_vdp1_vram[position * (0x20/4)+2] & 0xffff0000) >> 16;
1866 		stv2_current_sprite.CMDSIZE = (m_vdp1_vram[position * (0x20/4)+2] & 0x0000ffff) >> 0;
1867 		stv2_current_sprite.CMDXA   = (m_vdp1_vram[position * (0x20/4)+3] & 0xffff0000) >> 16;
1868 		stv2_current_sprite.CMDYA   = (m_vdp1_vram[position * (0x20/4)+3] & 0x0000ffff) >> 0;
1869 		stv2_current_sprite.CMDXB   = (m_vdp1_vram[position * (0x20/4)+4] & 0xffff0000) >> 16;
1870 		stv2_current_sprite.CMDYB   = (m_vdp1_vram[position * (0x20/4)+4] & 0x0000ffff) >> 0;
1871 		stv2_current_sprite.CMDXC   = (m_vdp1_vram[position * (0x20/4)+5] & 0xffff0000) >> 16;
1872 		stv2_current_sprite.CMDYC   = (m_vdp1_vram[position * (0x20/4)+5] & 0x0000ffff) >> 0;
1873 		stv2_current_sprite.CMDXD   = (m_vdp1_vram[position * (0x20/4)+6] & 0xffff0000) >> 16;
1874 		stv2_current_sprite.CMDYD   = (m_vdp1_vram[position * (0x20/4)+6] & 0x0000ffff) >> 0;
1875 		stv2_current_sprite.CMDGRDA = (m_vdp1_vram[position * (0x20/4)+7] & 0xffff0000) >> 16;
1876 //      stv2_current_sprite.UNUSED  = (m_vdp1_vram[position * (0x20/4)+7] & 0x0000ffff) >> 0;
1877 
1878 		/* proecess jump / skip commands, set position for next sprite */
1879 		switch (stv2_current_sprite.CMDCTRL & 0x7000)
1880 		{
1881 			case 0x0000: // jump next
1882 				if (VDP1_LOG) logerror ("Sprite List Process + Next (Normal)\n");
1883 				position++;
1884 				break;
1885 			case 0x1000: // jump assign
1886 				if (VDP1_LOG) logerror ("Sprite List Process + Jump Old %06x New %06x\n", position, (stv2_current_sprite.CMDLINK>>2));
1887 				position= (stv2_current_sprite.CMDLINK>>2);
1888 				break;
1889 			case 0x2000: // jump call
1890 				if (vdp1_nest == -1)
1891 				{
1892 					if (VDP1_LOG) logerror ("Sprite List Process + Call Old %06x New %06x\n",position, (stv2_current_sprite.CMDLINK>>2));
1893 					vdp1_nest = position+1;
1894 					position = (stv2_current_sprite.CMDLINK>>2);
1895 				}
1896 				else
1897 				{
1898 					if (VDP1_LOG) logerror ("Sprite List Nested Call, ignoring\n");
1899 					position++;
1900 				}
1901 				break;
1902 			case 0x3000:
1903 				if (vdp1_nest != -1)
1904 				{
1905 					if (VDP1_LOG) logerror ("Sprite List Process + Return\n");
1906 					position = vdp1_nest;
1907 					vdp1_nest = -1;
1908 				}
1909 				else
1910 				{
1911 					if (VDP1_LOG) logerror ("Attempted return from no subroutine, aborting\n");
1912 					position++;
1913 					goto end; // end of list
1914 				}
1915 				break;
1916 			case 0x4000:
1917 				draw_this_sprite = 0;
1918 				position++;
1919 				break;
1920 			case 0x5000:
1921 				if (VDP1_LOG) logerror ("Sprite List Skip + Jump Old %06x New %06x\n", position, (stv2_current_sprite.CMDLINK>>2));
1922 				draw_this_sprite = 0;
1923 				position= (stv2_current_sprite.CMDLINK>>2);
1924 
1925 				break;
1926 			case 0x6000:
1927 				draw_this_sprite = 0;
1928 				if (vdp1_nest == -1)
1929 				{
1930 					if (VDP1_LOG) logerror ("Sprite List Skip + Call To Subroutine Old %06x New %06x\n",position, (stv2_current_sprite.CMDLINK>>2));
1931 
1932 					vdp1_nest = position+1;
1933 					position = (stv2_current_sprite.CMDLINK>>2);
1934 				}
1935 				else
1936 				{
1937 					if (VDP1_LOG) logerror ("Sprite List Nested Call, ignoring\n");
1938 					position++;
1939 				}
1940 				break;
1941 			case 0x7000:
1942 				draw_this_sprite = 0;
1943 				if (vdp1_nest != -1)
1944 				{
1945 					if (VDP1_LOG) logerror ("Sprite List Skip + Return from Subroutine\n");
1946 
1947 					position = vdp1_nest;
1948 					vdp1_nest = -1;
1949 				}
1950 				else
1951 				{
1952 					if (VDP1_LOG) logerror ("Attempted return from no subroutine, aborting\n");
1953 					position++;
1954 					goto end; // end of list
1955 				}
1956 				break;
1957 		}
1958 
1959 		/* continue to draw this sprite only if the command wasn't to skip it */
1960 		if (draw_this_sprite ==1)
1961 		{
1962 			if ( stv2_current_sprite.CMDPMOD & 0x0400 )
1963 			{
1964 				//if(stv2_current_sprite.CMDPMOD & 0x0200) /* TODO: Bio Hazard inventory screen uses outside cliprect */
1965 				//  cliprect = &m_vdp1.system_cliprect;
1966 				//else
1967 					cliprect = &m_vdp1.user_cliprect;
1968 			}
1969 			else
1970 			{
1971 				cliprect = &m_vdp1.system_cliprect;
1972 			}
1973 
1974 			stv_vdp1_set_drawpixel();
1975 
1976 			switch (stv2_current_sprite.CMDCTRL & 0x000f)
1977 			{
1978 				case 0x0000:
1979 					if (VDP1_LOG) logerror ("Sprite List Normal Sprite (%d %d)\n",stv2_current_sprite.CMDXA,stv2_current_sprite.CMDYA);
1980 					stv2_current_sprite.ispoly = 0;
1981 					stv_vdp1_draw_normal_sprite(*cliprect, 0);
1982 					break;
1983 
1984 				case 0x0001:
1985 					if (VDP1_LOG) logerror ("Sprite List Scaled Sprite (%d %d)\n",stv2_current_sprite.CMDXA,stv2_current_sprite.CMDYA);
1986 					stv2_current_sprite.ispoly = 0;
1987 					stv_vdp1_draw_scaled_sprite(*cliprect);
1988 					break;
1989 
1990 				case 0x0002:
1991 				case 0x0003: // used by Hardcore 4x4
1992 					if (VDP1_LOG) logerror ("Sprite List Distorted Sprite\n");
1993 					if (VDP1_LOG) logerror ("(A: %d %d)\n",stv2_current_sprite.CMDXA,stv2_current_sprite.CMDYA);
1994 					if (VDP1_LOG) logerror ("(B: %d %d)\n",stv2_current_sprite.CMDXB,stv2_current_sprite.CMDYB);
1995 					if (VDP1_LOG) logerror ("(C: %d %d)\n",stv2_current_sprite.CMDXC,stv2_current_sprite.CMDYC);
1996 					if (VDP1_LOG) logerror ("(D: %d %d)\n",stv2_current_sprite.CMDXD,stv2_current_sprite.CMDYD);
1997 					if (VDP1_LOG) logerror ("CMDPMOD = %04x\n",stv2_current_sprite.CMDPMOD);
1998 
1999 					stv2_current_sprite.ispoly = 0;
2000 					stv_vdp1_draw_distorted_sprite(*cliprect);
2001 					break;
2002 
2003 				case 0x0004:
2004 					if (VDP1_LOG) logerror ("Sprite List Polygon\n");
2005 					stv2_current_sprite.ispoly = 1;
2006 					stv_vdp1_draw_distorted_sprite(*cliprect);
2007 					break;
2008 
2009 				case 0x0005:
2010 //              case 0x0007: // mirror? Baroque uses it, crashes for whatever reason
2011 					if (VDP1_LOG) logerror ("Sprite List Polyline\n");
2012 					stv2_current_sprite.ispoly = 1;
2013 					stv_vdp1_draw_poly_line(*cliprect);
2014 					break;
2015 
2016 				case 0x0006:
2017 					if (VDP1_LOG) logerror ("Sprite List Line\n");
2018 					stv2_current_sprite.ispoly = 1;
2019 					stv_vdp1_draw_line(*cliprect);
2020 					break;
2021 
2022 				case 0x0008:
2023 //              case 0x000b: // mirror? Bug 2
2024 					if (VDP1_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);
2025 					m_vdp1.user_cliprect.set(stv2_current_sprite.CMDXA, stv2_current_sprite.CMDXC, stv2_current_sprite.CMDYA, stv2_current_sprite.CMDYC);
2026 					break;
2027 
2028 				case 0x0009:
2029 					if (VDP1_LOG) logerror ("Sprite List Set Command for System Clipping (0,0),(%d,%d)\n", stv2_current_sprite.CMDXC, stv2_current_sprite.CMDYC);
2030 					m_vdp1.system_cliprect.set(0, stv2_current_sprite.CMDXC, 0, stv2_current_sprite.CMDYC);
2031 					break;
2032 
2033 				case 0x000a:
2034 					if (VDP1_LOG) logerror ("Sprite List Local Co-Ordinate Set (%d %d)\n",(int16_t)stv2_current_sprite.CMDXA,(int16_t)stv2_current_sprite.CMDYA);
2035 					m_vdp1.local_x = (int16_t)stv2_current_sprite.CMDXA;
2036 					m_vdp1.local_y = (int16_t)stv2_current_sprite.CMDYA;
2037 					break;
2038 
2039 				default:
2040 					popmessage ("VDP1: Sprite List Illegal %02x (%d), contact MAMEdev",stv2_current_sprite.CMDCTRL & 0xf,spritecount);
2041 					m_vdp1.lopr = (position * 0x20) >> 3;
2042 					//m_vdp1.copr = (position * 0x20) >> 3;
2043 					// prematurely kill the VDP1 process if an illegal opcode is executed
2044 					// Sexy Parodius calls multiple illegals and expects VDP1 irq to be fired anyway!
2045 					goto end;
2046 			}
2047 		}
2048 
2049 	}
2050 
2051 
2052 	end:
2053 	m_vdp1.copr = (position * 0x20) >> 3;
2054 
2055 
2056 	/* TODO: what's the exact formula? Guess it should be a mix between number of pixels written and actual command data fetched. */
2057 	// if spritecount = 10000 don't send a vdp1 draw end
2058 //  if(spritecount < 10000)
2059 	machine().scheduler().timer_set(m_maincpu->cycles_to_attotime(spritecount*16), timer_expired_delegate(FUNC(saturn_state::vdp1_draw_end),this));
2060 
2061 	if (VDP1_LOG) logerror ("End of list processing!\n");
2062 }
2063 
video_update_vdp1(void)2064 void saturn_state::video_update_vdp1( void )
2065 {
2066 	int framebuffer_changed = 0;
2067 
2068 //  int enable;
2069 //  if (machine.input().code_pressed (KEYCODE_R)) VDP1_LOG = 1;
2070 //  if (machine.input().code_pressed (KEYCODE_T)) VDP1_LOG = 0;
2071 
2072 //  if (machine.input().code_pressed (KEYCODE_Y)) VDP1_LOG = 0;
2073 //  {
2074 //      FILE *fp;
2075 //
2076 //      fp=fopen("vdp1_ram.dmp", "w+b");
2077 //      if (fp)
2078 //      {
2079 //          fwrite(stv_vdp1, 0x00100000, 1, fp);
2080 //          fclose(fp);
2081 //      }
2082 //  }
2083 	if (VDP1_LOG) logerror("video_update_vdp1 called\n");
2084 	if (VDP1_LOG) logerror( "FBCR = %0x, accessed = %d\n", STV_VDP1_FBCR, m_vdp1.fbcr_accessed );
2085 
2086 	if(STV_VDP1_CEF)
2087 		BEF_1;
2088 	else
2089 		BEF_0;
2090 
2091 	if ( m_vdp1.framebuffer_clear_on_next_frame )
2092 	{
2093 		if ( ((STV_VDP1_FBCR & 0x3) == 3) &&
2094 			m_vdp1.fbcr_accessed )
2095 		{
2096 			stv_clear_framebuffer(m_vdp1.framebuffer_current_display);
2097 			m_vdp1.framebuffer_clear_on_next_frame = 0;
2098 		}
2099 	}
2100 
2101 	switch( STV_VDP1_FBCR & 0x3 )
2102 	{
2103 		case 0: /* Automatic mode */
2104 			stv_vdp1_change_framebuffers();
2105 			stv_clear_framebuffer(m_vdp1.framebuffer_current_draw);
2106 			framebuffer_changed = 1;
2107 			break;
2108 		case 1: /* Setting prohibited */
2109 			break;
2110 		case 2: /* Manual mode - erase */
2111 			if ( m_vdp1.fbcr_accessed )
2112 			{
2113 				m_vdp1.framebuffer_clear_on_next_frame = 1;
2114 			}
2115 			break;
2116 		case 3: /* Manual mode - change */
2117 			if ( m_vdp1.fbcr_accessed )
2118 			{
2119 				stv_vdp1_change_framebuffers();
2120 				if ( STV_VDP1_VBE )
2121 				{
2122 					stv_clear_framebuffer(m_vdp1.framebuffer_current_draw);
2123 				}
2124 				/* TODO: Slam n Jam 96 & Cross Romance doesn't like this, investigate. */
2125 				framebuffer_changed = 1;
2126 			}
2127 	//      framebuffer_changed = 1;
2128 			break;
2129 	}
2130 	m_vdp1.fbcr_accessed = 0;
2131 
2132 	if (VDP1_LOG) logerror( "PTM = %0x, TVM = %x\n", STV_VDP1_PTM, STV_VDP1_TVM );
2133 	/*Set CEF bit to 0*/
2134 	//CEF_0;
2135 	switch(STV_VDP1_PTM & 3)
2136 	{
2137 		case 0:/*Idle Mode*/
2138 			/*Set CEF bit to 0*/
2139 			//CEF_0;
2140 			break;
2141 		case 1:/*Draw by request*/
2142 			/*Set CEF bit to 0*/
2143 			//CEF_0;
2144 			break;
2145 		case 2:/*Automatic Draw*/
2146 			if ( framebuffer_changed || VDP1_LOG )
2147 			{
2148 				/*set CEF to 1*/
2149 				stv_vdp1_process_list();
2150 			}
2151 			break;
2152 		case 3: /*<invalid>*/
2153 			logerror("Warning: Invalid PTM mode set for VDP1!\n");
2154 			break;
2155 	}
2156 	//popmessage("%04x %04x",STV_VDP1_EWRR_X3,STV_VDP1_EWRR_Y3);
2157 }
2158 
stv_vdp1_state_save_postload(void)2159 void saturn_state::stv_vdp1_state_save_postload( void )
2160 {
2161 	uint8_t *vdp1 = m_vdp1.gfx_decode.get();
2162 	int offset;
2163 	uint32_t data;
2164 
2165 	m_vdp1.framebuffer_mode = -1;
2166 	m_vdp1.framebuffer_double_interlace = -1;
2167 
2168 	stv_set_framebuffer_config();
2169 
2170 	for (offset = 0; offset < 0x80000/4; offset++ )
2171 	{
2172 		data = m_vdp1_vram[offset];
2173 		/* put in gfx region for easy decoding */
2174 		vdp1[offset*4+0] = (data & 0xff000000) >> 24;
2175 		vdp1[offset*4+1] = (data & 0x00ff0000) >> 16;
2176 		vdp1[offset*4+2] = (data & 0x0000ff00) >> 8;
2177 		vdp1[offset*4+3] = (data & 0x000000ff) >> 0;
2178 	}
2179 }
2180 
stv_vdp1_start(void)2181 int saturn_state::stv_vdp1_start ( void )
2182 {
2183 	m_vdp1_regs = make_unique_clear<uint16_t[]>(0x020/2 );
2184 	m_vdp1_vram = make_unique_clear<uint32_t[]>(0x100000/4 );
2185 	m_vdp1.gfx_decode = std::make_unique<uint8_t[]>(0x100000 );
2186 
2187 	stv_vdp1_shading_data = std::make_unique<struct stv_vdp1_poly_scanline_data>();
2188 
2189 	m_vdp1.framebuffer[0] = std::make_unique<uint16_t[]>(1024 * 256 * 2 ); /* *2 is for double interlace */
2190 	m_vdp1.framebuffer[1] = std::make_unique<uint16_t[]>(1024 * 256 * 2 );
2191 
2192 	m_vdp1.framebuffer_display_lines = auto_alloc_array(machine(), uint16_t *, 512);
2193 	m_vdp1.framebuffer_draw_lines = auto_alloc_array(machine(), uint16_t *, 512);
2194 
2195 	m_vdp1.framebuffer_width = m_vdp1.framebuffer_height = 0;
2196 	m_vdp1.framebuffer_mode = -1;
2197 	m_vdp1.framebuffer_double_interlace = -1;
2198 	m_vdp1.fbcr_accessed = 0;
2199 	m_vdp1.framebuffer_current_display = 0;
2200 	m_vdp1.framebuffer_current_draw = 1;
2201 	stv_clear_framebuffer(m_vdp1.framebuffer_current_draw);
2202 	m_vdp1.framebuffer_clear_on_next_frame = 0;
2203 
2204 	m_vdp1.system_cliprect.set(0, 0, 0, 0);
2205 	/* Kidou Senshi Z Gundam - Zenpen Zeta no Kodou loves to use the user cliprect vars in an undefined state ... */
2206 	m_vdp1.user_cliprect.set(0, 512, 0, 256);
2207 
2208 	// save state
2209 	save_pointer(NAME(m_vdp1_regs), 0x020/2);
2210 	save_pointer(NAME(m_vdp1_vram), 0x100000/4);
2211 	save_item(NAME(m_vdp1.fbcr_accessed));
2212 	save_item(NAME(m_vdp1.framebuffer_current_display));
2213 	save_item(NAME(m_vdp1.framebuffer_current_draw));
2214 	save_item(NAME(m_vdp1.framebuffer_clear_on_next_frame));
2215 	save_item(NAME(m_vdp1.local_x));
2216 	save_item(NAME(m_vdp1.local_y));
2217 	machine().save().register_postload(save_prepost_delegate(FUNC(saturn_state::stv_vdp1_state_save_postload), this));
2218 	return 0;
2219 }
2220