1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4 
5     Sega 16-bit sprite hardware
6 
7 ***************************************************************************/
8 
9 #include "emu.h"
10 #include "sega16sp.h"
11 #include "segaic16.h"
12 
13 
14 
15 //****************************************************************************
16 //  CONSTANTS
17 //****************************************************************************
18 
19 // device type definition
20 DEFINE_DEVICE_TYPE(SEGA_HANGON_SPRITES,    sega_hangon_sprite_device,    "sega_hangon_sprite",    "Sega Custom Sprites (Hang On)")
21 DEFINE_DEVICE_TYPE(SEGA_SHARRIER_SPRITES,  sega_sharrier_sprite_device,  "sega_sharrier_sprite",  "Sega Custom Sprites (Space Harrier)")
22 DEFINE_DEVICE_TYPE(SEGA_OUTRUN_SPRITES,    sega_outrun_sprite_device,    "sega_outrun_sprite",    "Sega Custom Sprites (Out Run)")
23 DEFINE_DEVICE_TYPE(SEGA_SYS16A_SPRITES,    sega_sys16a_sprite_device,    "sega_sys16a_sprite",    "Sega System 16A Sprites")
24 DEFINE_DEVICE_TYPE(BOOTLEG_SYS16A_SPRITES, bootleg_sys16a_sprite_device, "bootleg_sys16a_sprite", "Sega System 16A Sprites (bootleg)")
25 DEFINE_DEVICE_TYPE(SEGA_SYS16B_SPRITES,    sega_sys16b_sprite_device,    "sega_sys16b_sprite",    "Sega System 16B Sprites")
26 DEFINE_DEVICE_TYPE(SEGA_XBOARD_SPRITES,    sega_xboard_sprite_device,    "sega_xboard_sprite",    "Sega X-Board Sprites")
27 DEFINE_DEVICE_TYPE(SEGA_YBOARD_SPRITES,    sega_yboard_sprite_device,    "sega_yboard_sprite",    "Sega Y-Board Sprites")
28 
29 
30 
31 //****************************************************************************
32 //  DEVICE INTERFACE
33 //****************************************************************************
34 
35 //-------------------------------------------------
36 //  sega_16bit_sprite_device -- core constructor
37 //-------------------------------------------------
38 
sega_16bit_sprite_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner)39 sega_16bit_sprite_device::sega_16bit_sprite_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner)
40 	: sprite16_device_ind16(mconfig, type, tag, owner)
41 	, m_flip(false)
42 {
43 	// default to 1:1 bank mapping
44 	for (int bank = 0; bank < ARRAY_LENGTH(m_bank); bank++)
45 		m_bank[bank] = bank;
46 }
47 
48 
49 //-------------------------------------------------
50 //  device_start -- device startup
51 //-------------------------------------------------
52 
device_start()53 void sega_16bit_sprite_device::device_start()
54 {
55 	// let the parent do its work
56 	sprite16_device_ind16::device_start();
57 
58 	// save states
59 	save_item(NAME(m_flip));
60 	save_item(NAME(m_bank));
61 }
62 
63 
64 //-------------------------------------------------
65 //  draw_write -- trigger a buffer flip
66 //-------------------------------------------------
67 
draw_write(uint16_t data)68 void sega_16bit_sprite_device::draw_write(uint16_t data)
69 {
70 	uint32_t *src = reinterpret_cast<uint32_t *>(spriteram());
71 	uint32_t *dst = reinterpret_cast<uint32_t *>(buffer());
72 
73 	// swap the halves of the sprite RAM
74 	for (int i = 0; i < spriteram_bytes()/4; i++)
75 	{
76 		uint32_t temp = *src;
77 		*src++ = *dst;
78 		*dst++ = temp;
79 	}
80 
81 	// hack for thunderblade
82 	*spriteram() = 0xffff;
83 
84 	// we will render the sprites when the video update happens
85 }
86 
87 
88 
89 //****************************************************************************
90 //  HANG ON-STYLE SPRITES
91 //****************************************************************************
92 
93 //-------------------------------------------------
94 //  sega_hangon_sprite_device -- constructor
95 //-------------------------------------------------
96 
sega_hangon_sprite_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)97 sega_hangon_sprite_device::sega_hangon_sprite_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
98 	: sega_16bit_sprite_device(mconfig, SEGA_HANGON_SPRITES, tag, owner)
99 	, m_sprite_region_ptr(*this, DEVICE_SELF)
100 {
101 	set_local_origin(189, -1);
102 }
103 
104 
105 //-------------------------------------------------
106 //  draw -- render the sprites within the cliprect
107 //-------------------------------------------------
108 
draw(bitmap_ind16 & bitmap,const rectangle & cliprect)109 void sega_hangon_sprite_device::draw(bitmap_ind16 &bitmap, const rectangle &cliprect)
110 {
111 	//
112 	//  Hang On-style sprites
113 	//
114 	//      Offs  Bits               Usage
115 	//       +0   bbbbbbbb --------  Bottom scanline of sprite - 1
116 	//       +0   -------- tttttttt  Top scanline of sprite - 1
117 	//       +2   bbbb---- --------  Sprite bank
118 	//       +2   -------x xxxxxxxx  X position of sprite (position $BD is screen position 0)
119 	//       +4   pppppppp pppppppp  Signed 16-bit pitch value between scanlines
120 	//       +6   -ooooooo oooooooo  Offset within selected sprite bank
121 	//       +6   f------- --------  Horizontal flip: read the data backwards if set
122 	//       +8   --cccccc --------  Sprite color palette
123 	//       +8   -------- zzzzzz--  Zoom factor
124 	//       +8   -------- ------pp  Sprite priority
125 	//       +E   dddddddd dddddddd  Scratch space for current address
126 	//
127 	//  Final bitmap format:
128 	//
129 	//            ----pp-- --------  Sprite priority
130 	//            ------cc cccc----  Sprite color palette
131 	//            -------- ----llll  4-bit pixel data
132 	//
133 	//  Special notes:
134 	//
135 	//      There is an interaction between the horizonal flip bit and the offset.
136 	//      The offset is maintained as a 16-bit value, even though only the lower
137 	//      15 bits are used for the address. The top bit is used to control flipping.
138 	//      This means that if the low 15 bits overflow during rendering, the sprite
139 	//      data will be read backwards after the overflow. This is important to
140 	//      emulate correctly as many games make use of this feature to render sprites
141 	//      at the beginning of a bank.
142 	//
143 
144 	// render the sprites in order
145 	const uint16_t *spritebase = &m_sprite_region_ptr[0];
146 	uint8_t numbanks = m_sprite_region_ptr.bytes() / 0x10000;
147 	const uint8_t *zoom = memregion("zoom")->base();
148 	uint16_t *ramend = spriteram() + spriteram_elements();
149 	for (uint16_t *data = spriteram(); data < ramend; data += 8)
150 	{
151 		// fetch the bottom; stop when we get something out of range
152 		int bottom  = data[0] >> 8;
153 		if (bottom > 0xf0)
154 			break;
155 
156 		// extract remaining parameters
157 		int top     = data[0] & 0xff;
158 		int bank    = m_bank[(data[1] >> 12) & 0xf];
159 		int xpos    = data[1] & 0x1ff;
160 		int pitch   = int16_t(data[2]);
161 		uint16_t addr = data[3];
162 		int colpri  = (((data[4] >> 8) & 0x3f) << 4) | (((data[4] >> 0) & 0x3) << 10);
163 		int vzoom   = (data[4] >> 2) & 0x3f;
164 		int hzoom   = vzoom << 1;
165 
166 		// initialize the end address to the start address
167 		data[7] = addr;
168 
169 		// if top greater than/equal to bottom, or invalid bank, punt
170 		if (top >= bottom || bank == 255)
171 			continue;
172 
173 		// clamp to within the memory region size
174 		if (numbanks)
175 			bank %= numbanks;
176 		const uint16_t *spritedata = spritebase + 0x8000 * bank;
177 
178 		// determine the starting zoom address and mask
179 		int zaddr = (vzoom & 0x38) << 5;
180 		int zmask = 1 << (vzoom & 7);
181 
182 		// loop from top to bottom
183 		int minx = xpos;
184 		int maxx = cliprect.min_x - 1;
185 		int miny = cliprect.max_y + 1;
186 		int maxy = cliprect.min_y - 1;
187 		for (int y = top; y < bottom; y++)
188 		{
189 			// advance a row
190 			addr += pitch;
191 
192 			// if the zoom bit says so, add pitch a second time
193 			if (zoom[zaddr++] & zmask)
194 				addr += pitch;
195 
196 			// skip drawing if not within the cliprect
197 			if (y >= cliprect.min_y && y <= cliprect.max_y)
198 			{
199 				uint16_t *dest = &bitmap.pix(y);
200 				int xacc = 0x00;
201 				int x;
202 
203 				// note that the System 16A sprites have a design flaw that allows the address
204 				// to carry into the flip flag, which is the topmost bit -- it is very important
205 				// to emulate this as the games compensate for it
206 
207 				// non-flipped case
208 				if (!(addr & 0x8000))
209 				{
210 					// start at the word before because we preincrement below
211 					data[7] = addr - 1;
212 					for (x = xpos; x <= cliprect.max_x; )
213 					{
214 						uint16_t pixels = spritedata[++data[7] & 0x7fff];
215 
216 						// draw four pixels
217 						int pix;
218 						pix = (pixels >> 12) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
219 						pix = (pixels >>  8) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
220 						pix = (pixels >>  4) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
221 						pix = (pixels >>  0) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
222 
223 						// stop if the last pixel in the group was 0xf
224 						if (pix == 15)
225 							break;
226 					}
227 				}
228 
229 				// flipped case
230 				else
231 				{
232 					// start at the word after because we predecrement below
233 					data[7] = addr + 1;
234 					for (x = xpos; x <= cliprect.max_x; )
235 					{
236 						uint16_t pixels = spritedata[--data[7] & 0x7fff];
237 
238 						// draw four pixels
239 						int pix;
240 						pix = (pixels >>  0) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
241 						pix = (pixels >>  4) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
242 						pix = (pixels >>  8) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
243 						pix = (pixels >> 12) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
244 
245 						// stop if the last pixel in the group was 0xf
246 						if (pix == 15)
247 							break;
248 					}
249 				}
250 
251 				// update bounds
252 				if (x > maxx) maxx = x;
253 				if (y < miny) miny = y;
254 				maxy = y;
255 			}
256 		}
257 
258 		// mark dirty
259 		if (minx <= maxx && miny <= maxy)
260 			mark_dirty(minx, maxx, miny, maxy);
261 	}
262 }
263 
264 
265 
266 //****************************************************************************
267 //  SPACE HARRIER-STYLE SPRITES
268 //****************************************************************************
269 
270 //-------------------------------------------------
271 //  sega_sharrier_sprite_device -- constructor
272 //-------------------------------------------------
273 
sega_sharrier_sprite_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)274 sega_sharrier_sprite_device::sega_sharrier_sprite_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
275 	: sega_16bit_sprite_device(mconfig, SEGA_SHARRIER_SPRITES, tag, owner)
276 	, m_sprite_region_ptr(*this, DEVICE_SELF)
277 {
278 	set_local_origin(189, -1);
279 }
280 
281 
282 //-------------------------------------------------
283 //  draw -- render the sprites within the cliprect
284 //-------------------------------------------------
285 
draw(bitmap_ind16 & bitmap,const rectangle & cliprect)286 void sega_sharrier_sprite_device::draw(bitmap_ind16 &bitmap, const rectangle &cliprect)
287 {
288 	//
289 	//  Space Harrier-style sprites
290 	//
291 	//      Offs  Bits               Usage
292 	//       +0   bbbbbbbb --------  Bottom scanline of sprite - 1
293 	//       +0   -------- tttttttt  Top scanline of sprite - 1
294 	//       +2   bbbb---- --------  Sprite bank
295 	//       +2   -------x xxxxxxxx  X position of sprite (position $BD is screen position 0)
296 	//       +4   s------- --------  Sprite shadow disable (0=enable, 1=disable)
297 	//       +4   -p------ --------  Sprite priority
298 	//       +4   --cccccc --------  Sprite color palette
299 	//       +4   -------- -ppppppp  Signed 7-bit pitch value between scanlines
300 	//       +6   f------- --------  Horizontal flip: read the data backwards if set
301 	//       +6   -ooooooo oooooooo  Offset within selected sprite bank
302 	//       +8   --zzzzzz --------  Horizontal zoom factor
303 	//       +8   -------- --zzzzzz  Vertical zoom factor
304 	//       +E   dddddddd dddddddd  Scratch space for current address
305 	//
306 	//  Final bitmap format:
307 	//
308 	//            ----s--- --------  Sprite shadow disable
309 	//            -----p-- --------  Sprite priority
310 	//            ------cc cccc----  Sprite color palette
311 	//            -------- ----llll  4-bit pixel data
312 	//
313 	//  Special notes:
314 	//
315 	//      There is an interaction between the horizonal flip bit and the offset.
316 	//      The offset is maintained as a 16-bit value, even though only the lower
317 	//      15 bits are used for the address. The top bit is used to control flipping.
318 	//      This means that if the low 15 bits overflow during rendering, the sprite
319 	//      data will be read backwards after the overflow. This is important to
320 	//      emulate correctly as many games make use of this feature to render sprites
321 	//      at the beginning of a bank.
322 	//
323 
324 	// render the sprites in order
325 	const uint32_t *spritebase = &m_sprite_region_ptr[0];
326 	uint8_t numbanks = m_sprite_region_ptr.bytes() / 0x20000;
327 	const uint8_t *zoom = memregion("zoom")->base();
328 	uint16_t *ramend = spriteram() + spriteram_elements();
329 	for (uint16_t *data = spriteram(); data < ramend; data += 8)
330 	{
331 		// fetch the bottom; stop when we get something out of range
332 		int bottom  = data[0] >> 8;
333 		if (bottom > 0xf0)
334 			break;
335 
336 		// extract remaining parameters
337 		int top     = data[0] & 0xff;
338 		int bank    = m_bank[(data[1] >> 12) & 0x7];
339 		int xpos    = data[1] & 0x1ff;
340 		int colpri  = ((data[2] >> 8) & 0xff) << 4;
341 		int pitch   = int16_t(data[2] << 9) >> 9;
342 		uint16_t addr = data[3];
343 		int hzoom   = ((data[4] >> 8) & 0x3f) << 1;
344 		int vzoom   = (data[4] >> 0) & 0x3f;
345 
346 		// initialize the end address to the start address
347 		data[7] = addr;
348 
349 		// if top greater than/equal to bottom, or invalid bank, punt
350 		if (top >= bottom || bank == 255)
351 			continue;
352 
353 		// clamp to within the memory region size
354 		if (numbanks)
355 			bank %= numbanks;
356 		const uint32_t *spritedata = spritebase + 0x8000 * bank;
357 
358 		// determine the starting zoom address and mask
359 		int zaddr = (vzoom & 0x38) << 5;
360 		int zmask = 1 << (vzoom & 7);
361 
362 		// loop from top to bottom
363 		int minx = xpos;
364 		int maxx = cliprect.min_x - 1;
365 		int miny = cliprect.max_y + 1;
366 		int maxy = cliprect.min_y - 1;
367 		for (int y = top; y < bottom; y++)
368 		{
369 			// advance a row
370 			addr += pitch;
371 
372 			// if the zoom bit says so, add pitch a second time
373 			if (zoom[zaddr++] & zmask)
374 				addr += pitch;
375 
376 			// skip drawing if not within the cliprect
377 			if (y >= cliprect.min_y && y <= cliprect.max_y)
378 			{
379 				uint16_t *dest = &bitmap.pix(y);
380 				int xacc = 0x00;
381 				int x;
382 
383 				// note that the System 16A sprites have a design flaw that allows the address
384 				// to carry into the flip flag, which is the topmost bit -- it is very important
385 				// to emulate this as the games compensate for it
386 
387 				// non-flipped case
388 				if (!(addr & 0x8000))
389 				{
390 					// start at the word before because we preincrement below
391 					data[7] = addr - 1;
392 					for (x = xpos; x <= cliprect.max_x; )
393 					{
394 						uint32_t pixels = spritedata[++data[7] & 0x7fff];
395 
396 						// draw 8 pixels
397 						int pix;
398 						pix = (pixels >> 28) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
399 						pix = (pixels >> 24) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
400 						pix = (pixels >> 20) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
401 						pix = (pixels >> 16) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
402 						pix = (pixels >> 12) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
403 						pix = (pixels >>  8) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
404 						pix = (pixels >>  4) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
405 						pix = (pixels >>  0) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
406 
407 						// stop if the last pixel in the group was 0xf
408 						if (pix == 15)
409 							break;
410 					}
411 				}
412 
413 				// flipped case
414 				else
415 				{
416 					// start at the word after because we predecrement below
417 					data[7] = addr + 1;
418 					for (x = xpos; x <= cliprect.max_x; )
419 					{
420 						uint32_t pixels = spritedata[--data[7] & 0x7fff];
421 
422 						// draw 8 pixels
423 						int pix;
424 						pix = (pixels >>  0) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
425 						pix = (pixels >>  4) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
426 						pix = (pixels >>  8) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
427 						pix = (pixels >> 12) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
428 						pix = (pixels >> 16) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
429 						pix = (pixels >> 20) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
430 						pix = (pixels >> 24) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
431 						pix = (pixels >> 28) & 0xf; xacc = (xacc & 0xff) + hzoom; if (xacc < 0x100) { if (x >= cliprect.min_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x++; }
432 
433 						// stop if the last pixel in the group was 0xf
434 						if (pix == 15)
435 							break;
436 					}
437 				}
438 
439 				// update bounds
440 				if (x > maxx) maxx = x;
441 				if (y < miny) miny = y;
442 				maxy = y;
443 			}
444 		}
445 
446 		// mark dirty
447 		if (minx <= maxx && miny <= maxy)
448 			mark_dirty(minx, maxx, miny, maxy);
449 	}
450 }
451 
452 
453 
454 //****************************************************************************
455 //  SYSTEM 16A-STYLE SPRITES
456 //****************************************************************************
457 
458 //-------------------------------------------------
459 //  sega_sys16a_sprite_device -- constructor
460 //-------------------------------------------------
461 
sega_sys16a_sprite_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)462 sega_sys16a_sprite_device::sega_sys16a_sprite_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
463 	: sega_16bit_sprite_device(mconfig, SEGA_SYS16A_SPRITES, tag, owner)
464 	, m_sprite_region_ptr(*this, DEVICE_SELF)
465 {
466 	set_local_origin(189, -1, -189, -1);
467 }
468 
469 
470 //-------------------------------------------------
471 //  draw -- render the sprites within the cliprect
472 //-------------------------------------------------
473 
draw(bitmap_ind16 & bitmap,const rectangle & cliprect)474 void sega_sys16a_sprite_device::draw(bitmap_ind16 &bitmap, const rectangle &cliprect)
475 {
476 	//
477 	//  System 16A-style sprites
478 	//
479 	//      Offs  Bits               Usage
480 	//       +0   bbbbbbbb --------  Bottom scanline of sprite - 1
481 	//       +0   -------- tttttttt  Top scanline of sprite - 1
482 	//       +2   -------x xxxxxxxx  X position of sprite (position $BD is screen position 0)
483 	//       +4   pppppppp pppppppp  Signed 16-bit pitch value between scanlines
484 	//       +6   -ooooooo oooooooo  Offset within selected sprite bank
485 	//       +6   f------- --------  Horizontal flip: read the data backwards if set
486 	//       +8   --cccccc --------  Sprite color palette
487 	//       +8   -------- -bbb----  Sprite bank
488 	//       +8   -------- ------pp  Sprite priority
489 	//       +E   dddddddd dddddddd  Scratch space for current address
490 	//
491 	//  Final bitmap format:
492 	//
493 	//            ----pp-- --------  Sprite priority
494 	//            ------cc cccc----  Sprite color palette
495 	//            -------- ----llll  4-bit pixel data
496 	//
497 	//  Special notes:
498 	//
499 	//      There is an interaction between the horizonal flip bit and the offset.
500 	//      The offset is maintained as a 16-bit value, even though only the lower
501 	//      15 bits are used for the address. The top bit is used to control flipping.
502 	//      This means that if the low 15 bits overflow during rendering, the sprite
503 	//      data will be read backwards after the overflow. This is important to
504 	//      emulate correctly as many games make use of this feature to render sprites
505 	//      at the beginning of a bank.
506 	//
507 
508 	// render the sprites in order
509 	const uint16_t *spritebase = &m_sprite_region_ptr[0];
510 	uint8_t numbanks = m_sprite_region_ptr.bytes() / 0x10000;
511 	uint16_t *ramend = spriteram() + spriteram_elements();
512 	for (uint16_t *data = spriteram(); data < ramend; data += 8)
513 	{
514 		// fetch the bottom; stop when we get something out of range
515 		int bottom  = data[0] >> 8;
516 		if (bottom > 0xf0)
517 			break;
518 
519 		// extract remaining parameters
520 		int top     = data[0] & 0xff;
521 		int xpos    = data[1] & 0x1ff;
522 		int pitch   = int16_t(data[2]);
523 		uint16_t addr = data[3];
524 		int colpri  = (((data[4] >> 8) & 0x3f) << 4) | (((data[4] >> 0) & 0x3) << 10);
525 		int bank    = m_bank[(data[4] >> 4) & 0x7];
526 
527 		// initialize the end address to the start address
528 		data[7] = addr;
529 
530 		// if top greater than/equal to bottom, or invalid bank, punt
531 		if (top >= bottom || bank == 255)
532 			continue;
533 
534 		// clamp to within the memory region size
535 		if (numbanks)
536 			bank %= numbanks;
537 		const uint16_t *spritedata = spritebase + 0x8000 * bank;
538 
539 		// adjust positions for screen flipping
540 		int xdelta = 1;
541 		if (m_flip)
542 		{
543 			int temp = top;
544 			top = 224 - bottom;
545 			bottom = 224 - temp;
546 			xpos = 320 - xpos;
547 			xdelta = -1;
548 			set_origin(m_xoffs_flipped, m_yoffs_flipped);
549 		}
550 		else
551 		{
552 			set_origin(m_xoffs, m_yoffs);
553 		}
554 
555 		// loop from top to bottom
556 		int minx = xpos;
557 		int maxx = xpos;
558 		int miny = cliprect.max_y + 1;
559 		int maxy = cliprect.min_y - 1;
560 		for (int y = top; y < bottom; y++)
561 		{
562 			// advance a row
563 			addr += pitch;
564 
565 			// skip drawing if not within the cliprect
566 			if (y >= cliprect.min_y && y <= cliprect.max_y)
567 			{
568 				uint16_t *dest = &bitmap.pix(y);
569 				int x;
570 
571 				// note that the System 16A sprites have a design flaw that allows the address
572 				// to carry into the flip flag, which is the topmost bit -- it is very important
573 				// to emulate this as the games compensate for it
574 
575 				// non-flipped case
576 				if (!(addr & 0x8000))
577 				{
578 					// start at the word before because we preincrement below
579 					data[7] = addr - 1;
580 					for (x = xpos; ((xpos - x) & 0x1ff) != 1; )
581 					{
582 						uint16_t pixels = spritedata[++data[7] & 0x7fff];
583 
584 						// draw four pixels
585 						int pix;
586 						pix = (pixels >> 12) & 0xf; if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta;
587 						pix = (pixels >>  8) & 0xf; if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta;
588 						pix = (pixels >>  4) & 0xf; if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta;
589 						pix = (pixels >>  0) & 0xf; if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta;
590 
591 						// stop if the last pixel in the group was 0xf
592 						if (pix == 15)
593 							break;
594 					}
595 				}
596 
597 				// flipped case
598 				else
599 				{
600 					// start at the word after because we predecrement below
601 					data[7] = addr + 1;
602 					for (x = xpos; ((xpos - x) & 0x1ff) != 1; )
603 					{
604 						uint16_t pixels = spritedata[--data[7] & 0x7fff];
605 
606 						// draw four pixels
607 						int pix;
608 						pix = (pixels >>  0) & 0xf; if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta;
609 						pix = (pixels >>  4) & 0xf; if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta;
610 						pix = (pixels >>  8) & 0xf; if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta;
611 						pix = (pixels >> 12) & 0xf; if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta;
612 
613 						// stop if the last pixel in the group was 0xf
614 						if (pix == 15)
615 							break;
616 					}
617 				}
618 
619 				// update bounds
620 				if (x > maxx) maxx = x;
621 				if (x < minx) minx = x;
622 				if (y < miny) miny = y;
623 				maxy = y;
624 			}
625 		}
626 
627 		// mark dirty
628 		if (minx <= maxx && miny <= maxy)
629 			mark_dirty(minx, maxx, miny, maxy);
630 	}
631 }
632 
633 
634 //****************************************************************************
635 //  BOOTLEG SYSTEM 16A-STYLE SPRITES
636 //****************************************************************************
637 
638 //-------------------------------------------------
639 //  bootleg_sys16a_sprite_device -- constructor
640 //-------------------------------------------------
641 
bootleg_sys16a_sprite_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)642 bootleg_sys16a_sprite_device::bootleg_sys16a_sprite_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
643 	: sega_16bit_sprite_device(mconfig, BOOTLEG_SYS16A_SPRITES, tag, owner)
644 	, m_sprite_region_ptr(*this, DEVICE_SELF)
645 {
646 	m_addrmap[0] = 0;
647 	m_addrmap[1] = 1;
648 	m_addrmap[2] = 2;
649 	m_addrmap[3] = 3;
650 	m_addrmap[4] = 4;
651 	m_addrmap[5] = 5;
652 	m_addrmap[6] = 6;
653 	m_addrmap[7] = 7;
654 	set_local_origin(189, -1);
655 }
656 
657 
658 //-------------------------------------------------
659 //  set_remap -- configure sprite address
660 //  remapping
661 //-------------------------------------------------
662 
set_remap(uint8_t offs0,uint8_t offs1,uint8_t offs2,uint8_t offs3,uint8_t offs4,uint8_t offs5,uint8_t offs6,uint8_t offs7)663 void bootleg_sys16a_sprite_device::set_remap(uint8_t offs0, uint8_t offs1, uint8_t offs2, uint8_t offs3, uint8_t offs4, uint8_t offs5, uint8_t offs6, uint8_t offs7)
664 {
665 	m_addrmap[0] = offs0;
666 	m_addrmap[1] = offs1;
667 	m_addrmap[2] = offs2;
668 	m_addrmap[3] = offs3;
669 	m_addrmap[4] = offs4;
670 	m_addrmap[5] = offs5;
671 	m_addrmap[6] = offs6;
672 	m_addrmap[7] = offs7;
673 }
674 
675 
676 //-------------------------------------------------
677 //  draw -- render the sprites within the cliprect
678 //-------------------------------------------------
679 
draw(bitmap_ind16 & bitmap,const rectangle & cliprect)680 void bootleg_sys16a_sprite_device::draw(bitmap_ind16 &bitmap, const rectangle &cliprect)
681 {
682 	//
683 	//  Bootleg System 16A-style sprites
684 	//
685 	//  These are identical to regular System 16A sprites (see above), with two exceptions:
686 	//
687 	//      1. Addresses within each sprite entry are generally shuffled relative
688 	//          to the original, and
689 	//
690 	//      2. The pitch increment happens at the end, not at the beginning of
691 	//          the loop.
692 	//
693 
694 	// render the sprites in order
695 	const uint16_t *spritebase = &m_sprite_region_ptr[0];
696 	uint8_t numbanks = m_sprite_region_ptr.bytes() / 0x10000;
697 	uint16_t *ramend = spriteram() + spriteram_elements();
698 	for (uint16_t *data = spriteram(); data < ramend; data += 8)
699 	{
700 		// fetch the bottom; stop when we get something out of range
701 		int bottom  = data[m_addrmap[0]] >> 8;
702 		if (bottom > 0xf0)
703 			break;
704 
705 		// extract remaining parameters
706 		int top     = data[m_addrmap[0]] & 0xff;
707 		int xpos    = data[m_addrmap[1]] & 0x1ff;
708 		int pitch   = int16_t(data[m_addrmap[2]]);
709 		uint16_t addr = data[m_addrmap[3]];
710 		int colpri  = (((data[m_addrmap[4]] >> 8) & 0x3f) << 4) | (((data[m_addrmap[4]] >> 0) & 0x3) << 10);
711 		int bank    = m_bank[(data[m_addrmap[4]] >> 4) & 0x7];
712 
713 		// initialize the end address to the start address
714 		uint16_t &data7 = data[m_addrmap[7]];
715 		data7 = addr;
716 
717 		// if top greater than/equal to bottom, or invalid bank, punt
718 		if (top >= bottom || bank == 255)
719 			continue;
720 
721 		// clamp to within the memory region size
722 		if (numbanks)
723 			bank %= numbanks;
724 		const uint16_t *spritedata = spritebase + 0x8000 * bank;
725 
726 		// adjust positions for screen flipping
727 		int xdelta = 1;
728 		if (m_flip)
729 		{
730 			int temp = top;
731 			top = 224 - bottom;
732 			bottom = 224 - temp;
733 			xpos = 320 - xpos;
734 			xdelta = -1;
735 			set_origin(m_xoffs_flipped, m_yoffs_flipped);
736 		}
737 		else
738 		{
739 			set_origin(m_xoffs, m_yoffs);
740 		}
741 
742 		// loop from top to bottom
743 		int minx = xpos;
744 		int maxx = xpos;
745 		int miny = cliprect.max_y + 1;
746 		int maxy = cliprect.min_y - 1;
747 		for (int y = top; y < bottom; y++)
748 		{
749 			// skip drawing if not within the cliprect
750 			if (y >= cliprect.min_y && y <= cliprect.max_y)
751 			{
752 				uint16_t *dest = &bitmap.pix(y);
753 				int x;
754 
755 				// note that the System 16A sprites have a design flaw that allows the address
756 				// to carry into the flip flag, which is the topmost bit -- it is very important
757 				// to emulate this as the games compensate for it
758 
759 				// non-flipped case
760 				if (!(addr & 0x8000))
761 				{
762 					// start at the word before because we preincrement below
763 					data7 = addr - 1;
764 					for (x = xpos; ((xpos - x) & 0x1ff) != 1; )
765 					{
766 						uint16_t pixels = spritedata[++data7 & 0x7fff];
767 
768 						// draw four pixels
769 						int pix;
770 						pix = (pixels >> 12) & 0xf; if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta;
771 						pix = (pixels >>  8) & 0xf; if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta;
772 						pix = (pixels >>  4) & 0xf; if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta;
773 						pix = (pixels >>  0) & 0xf; if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta;
774 
775 						// stop if the last pixel in the group was 0xf
776 						if (pix == 15)
777 							break;
778 					}
779 				}
780 
781 				// flipped case
782 				else
783 				{
784 					// start at the word after because we predecrement below
785 					data7 = addr + 1;
786 					for (x = xpos; ((xpos - x) & 0x1ff) != 1; )
787 					{
788 						uint16_t pixels = spritedata[--data7 & 0x7fff];
789 
790 						// draw four pixels
791 						int pix;
792 						pix = (pixels >>  0) & 0xf; if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta;
793 						pix = (pixels >>  4) & 0xf; if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta;
794 						pix = (pixels >>  8) & 0xf; if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta;
795 						pix = (pixels >> 12) & 0xf; if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta;
796 
797 						// stop if the last pixel in the group was 0xf
798 						if (pix == 15)
799 							break;
800 					}
801 				}
802 
803 				// update bounds
804 				if (x > maxx) maxx = x;
805 				if (x < minx) minx = x;
806 				if (y < miny) miny = y;
807 				maxy = y;
808 			}
809 
810 			// advance a row - must be done at the end on the bootlegs!
811 			addr += pitch;
812 		}
813 
814 		// mark dirty
815 		if (minx <= maxx && miny <= maxy)
816 			mark_dirty(minx, maxx, miny, maxy);
817 	}
818 }
819 
820 
821 
822 //****************************************************************************
823 //  SYSTEM 16B-STYLE SPRITES
824 //****************************************************************************
825 
826 //-------------------------------------------------
827 //  sega_sys16b_sprite_device -- constructor
828 //-------------------------------------------------
829 
sega_sys16b_sprite_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)830 sega_sys16b_sprite_device::sega_sys16b_sprite_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
831 	: sega_16bit_sprite_device(mconfig, SEGA_SYS16B_SPRITES, tag, owner)
832 	, m_sprite_region_ptr(*this, DEVICE_SELF)
833 {
834 	set_local_origin(184, 0x00, -184, 0);
835 }
836 
837 
838 //-------------------------------------------------
839 //  draw -- render the sprites within the cliprect
840 //-------------------------------------------------
841 
draw(bitmap_ind16 & bitmap,const rectangle & cliprect)842 void sega_sys16b_sprite_device::draw(bitmap_ind16 &bitmap, const rectangle &cliprect)
843 {
844 	//
845 	//  System 16B-style sprites
846 	//
847 	//      Offs  Bits               Usage
848 	//       +0   bbbbbbbb --------  Bottom scanline of sprite - 1
849 	//       +0   -------- tttttttt  Top scanline of sprite - 1
850 	//       +2   -------x xxxxxxxx  X position of sprite (position $BD is screen position 0)
851 	//       +2   ---iiii- --------  Sprite/sprite priority for Y-board
852 	//       +4   e------- --------  Signify end of sprite list
853 	//       +4   -h------ --------  Hide this sprite
854 	//       +4   -------f --------  Horizontal flip: read the data backwards if set
855 	//       +4   -------- pppppppp  Signed 8-bit pitch value between scanlines
856 	//       +6   oooooooo oooooooo  Offset within selected sprite bank
857 	//       +8   ----bbbb --------  Sprite bank
858 	//       +8   -------- pp------  Sprite priority, relative to tilemaps
859 	//       +8   -------- --cccccc  Sprite color palette
860 	//       +A   ------vv vvv-----  Vertical zoom factor (0 = full size, 0x10 = half size)
861 	//       +A   -------- ---hhhhh  Horizontal zoom factor (0 = full size, 0x10 = half size)
862 	//       +E   dddddddd dddddddd  Scratch space for current address
863 	//
864 	//  Final bitmap format:
865 	//
866 	//            iiii---- --------  Sprite/sprite priority for Y-board
867 	//            ----pp-- --------  Sprite priority
868 	//            ------cc cccc----  Sprite color palette
869 	//            -------- ----llll  4-bit pixel data
870 	//
871 	//  Note that the zooming described below is 100% accurate to the real board.
872 	//
873 
874 	// render the sprites in order
875 	const uint16_t *spritebase = &m_sprite_region_ptr[0];
876 	uint8_t numbanks = m_sprite_region_ptr.bytes() / 0x20000;
877 	uint16_t *ramend = spriteram() + spriteram_elements();
878 	for (uint16_t *data = spriteram(); data < ramend; data += 8)
879 	{
880 		// stop when we hit the end of sprite list
881 		if (data[2] & 0x8000)
882 			break;
883 
884 		// extract parameters
885 		int bottom  = data[0] >> 8;
886 		int top     = data[0] & 0xff;
887 		int xpos    = data[1] & 0x1ff;
888 		int hide    = data[2] & 0x4000;
889 		int flip    = data[2] & 0x100;
890 		int pitch   = int8_t(data[2] & 0xff);
891 		uint16_t addr = data[3];
892 		int bank    = m_bank[(data[4] >> 8) & 0xf];
893 		int colpri  = ((data[4] & 0xff) << 4) | (((data[1] >> 9) & 0xf) << 12);
894 		int vzoom   = (data[5] >> 5) & 0x1f;
895 		int hzoom   = data[5] & 0x1f;
896 		const uint16_t *spritedata;
897 
898 		xpos &= 0x1ff;
899 
900 		// initialize the end address to the start address
901 		data[7] = addr;
902 
903 		// if hidden, or top greater than/equal to bottom, or invalid bank, punt
904 		if (hide || top >= bottom || bank == 255)
905 			continue;
906 
907 		// clamp to within the memory region size
908 		if (numbanks)
909 			bank %= numbanks;
910 		spritedata = spritebase + 0x10000 * bank;
911 
912 		// reset the yzoom counter
913 		data[5] &= 0x03ff;
914 
915 		// adjust positions for screen flipping
916 		int xdelta = 1;
917 		if (m_flip)
918 		{
919 			int temp = top;
920 			top = 224 - bottom;
921 			bottom = 224 - temp;
922 			xpos = 320 - xpos;
923 			xdelta = -1;
924 			set_origin(m_xoffs_flipped, m_yoffs_flipped);
925 		}
926 		else
927 		{
928 			set_origin(m_xoffs, m_yoffs);
929 		}
930 
931 		// loop from top to bottom
932 		int minx = xpos;
933 		int maxx = xpos;
934 		int miny = cliprect.max_y + 1;
935 		int maxy = cliprect.min_y - 1;
936 		for (int y = top; y < bottom; y++)
937 		{
938 			// advance a row
939 			addr += pitch;
940 
941 			// accumulate zoom factors; if we carry into the high bit, skip an extra row
942 			data[5] += vzoom << 10;
943 			if (data[5] & 0x8000)
944 			{
945 				addr += pitch;
946 				data[5] &= ~0x8000;
947 			}
948 
949 			// skip drawing if not within the cliprect
950 			if (y >= cliprect.min_y && y <= cliprect.max_y)
951 			{
952 				uint16_t *dest = &bitmap.pix(y);
953 				int x;
954 
955 				// compute the initial X zoom accumulator; this is verified on the real PCB
956 				int xacc = 4 * hzoom;
957 
958 				// non-flipped case
959 				if (!flip)
960 				{
961 					// start at the word before because we preincrement below
962 					data[7] = addr - 1;
963 					for (x = xpos; ((xpos - x) & 0x1ff) != 1; )
964 					{
965 						uint16_t pixels = spritedata[++data[7]];
966 
967 						// draw four pixels
968 						int pix;
969 						pix = (pixels >> 12) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; }
970 						pix = (pixels >>  8) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; }
971 						pix = (pixels >>  4) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; }
972 						pix = (pixels >>  0) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; }
973 
974 						// stop if the last pixel in the group was 0xf
975 						if (pix == 15)
976 							break;
977 					}
978 				}
979 
980 				// flipped case
981 				else
982 				{
983 					// start at the word after because we predecrement below
984 					data[7] = addr + 1;
985 					for (x = xpos; ((xpos - x) & 0x1ff) != 1; )
986 					{
987 						uint16_t pixels = spritedata[--data[7]];
988 
989 						// draw four pixels
990 						int pix;
991 						pix = (pixels >>  0) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; }
992 						pix = (pixels >>  4) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; }
993 						pix = (pixels >>  8) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; }
994 						pix = (pixels >> 12) & 0xf; xacc = (xacc & 0x3f) + hzoom; if (xacc < 0x40) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; }
995 
996 						// stop if the last pixel in the group was 0xf
997 						if (pix == 15)
998 							break;
999 					}
1000 				}
1001 
1002 				// update bounds
1003 				if (x > maxx) maxx = x;
1004 				if (x < minx) minx = x;
1005 				if (y < miny) miny = y;
1006 				maxy = y;
1007 			}
1008 		}
1009 
1010 		// mark dirty
1011 		if (minx <= maxx && miny <= maxy)
1012 			mark_dirty(minx, maxx, miny, maxy);
1013 	}
1014 }
1015 
1016 
1017 
1018 //****************************************************************************
1019 //  OUT RUN/X-BOARD-STYLE SPRITES
1020 //****************************************************************************
1021 
1022 //-------------------------------------------------
1023 //  sega_outrun_sprite_device -- constructor
1024 //-------------------------------------------------
1025 
sega_outrun_sprite_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1026 sega_outrun_sprite_device::sega_outrun_sprite_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1027 	: sega_outrun_sprite_device(mconfig, SEGA_OUTRUN_SPRITES, tag, owner, clock, false)
1028 {
1029 }
1030 
sega_outrun_sprite_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock,bool xboard_variant)1031 sega_outrun_sprite_device::sega_outrun_sprite_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, bool xboard_variant)
1032 	: sega_16bit_sprite_device(mconfig, type, tag, owner)
1033 	, m_is_xboard(xboard_variant)
1034 	, m_sprite_region_ptr(*this, DEVICE_SELF)
1035 {
1036 	set_local_origin(xboard_variant ? 190 : 189, 0x00);
1037 }
1038 
1039 
1040 //-------------------------------------------------
1041 //  sega_xboard_sprite_device -- constructor
1042 //-------------------------------------------------
1043 
sega_xboard_sprite_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1044 sega_xboard_sprite_device::sega_xboard_sprite_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1045 	: sega_outrun_sprite_device(mconfig, SEGA_XBOARD_SPRITES, tag, owner, clock, true)
1046 {
1047 }
1048 
1049 
1050 //-------------------------------------------------
1051 //  draw -- render the sprites within the cliprect
1052 //-------------------------------------------------
1053 
draw(bitmap_ind16 & bitmap,const rectangle & cliprect)1054 void sega_outrun_sprite_device::draw(bitmap_ind16 &bitmap, const rectangle &cliprect)
1055 {
1056 	//
1057 	//  Out Run/X-Board-style sprites
1058 	//
1059 	//      Offs  Bits               Usage
1060 	//       +0   e------- --------  Signify end of sprite list
1061 	//       +0   -h-h---- --------  Hide this sprite if either bit is set
1062 	//       +0   ----bbb- --------  Sprite bank
1063 	//       +0   -------t tttttttt  Top scanline of sprite + 256
1064 	//       +2   oooooooo oooooooo  Offset within selected sprite bank
1065 	//       +4   ppppppp- --------  Signed 7-bit pitch value between scanlines
1066 	//       +4   -------x xxxxxxxx  X position of sprite (position $BE is screen position 0)
1067 	//       +6   -s------ --------  Enable shadows
1068 	//       +6   --pp---- --------  Sprite priority, relative to tilemaps
1069 	//       +6   ------vv vvvvvvvv  Vertical zoom factor (0x200 = full size, 0x100 = half size, 0x300 = 2x size)
1070 	//       +8   y------- --------  Render from top-to-bottom (1) or bottom-to-top (0) on screen
1071 	//       +8   -f------ --------  Horizontal flip: read the data backwards if set
1072 	//       +8   --x----- --------  Render from left-to-right (1) or right-to-left (0) on screen
1073 	//       +8   ------hh hhhhhhhh  Horizontal zoom factor (0x200 = full size, 0x100 = half size, 0x300 = 2x size)
1074 	//       +E   dddddddd dddddddd  Scratch space for current address
1075 	//
1076 	//  Out Run only:
1077 	//       +A   hhhhhhhh --------  Height in scanlines - 1
1078 	//       +A   -------- -ccccccc  Sprite color palette
1079 	//
1080 	//  X-Board only:
1081 	//       +A   ----hhhh hhhhhhhh  Height in scanlines - 1
1082 	//       +C   -------- cccccccc  Sprite color palette
1083 	//
1084 	//  Final bitmap format:
1085 	//
1086 	//            -s------ --------  Shadow control
1087 	//            --pp---- --------  Sprite priority
1088 	//            ----cccc cccc----  Sprite color palette
1089 	//            -------- ----llll  4-bit pixel data
1090 	//
1091 
1092 	set_origin(m_xoffs, m_yoffs);
1093 
1094 	// render the sprites in order
1095 	const uint32_t *spritebase = &m_sprite_region_ptr[0];
1096 	uint8_t numbanks = m_sprite_region_ptr.bytes() / 0x40000;
1097 	uint16_t *ramend = buffer() + spriteram_elements();
1098 	for (uint16_t *data = buffer(); data < ramend; data += 8)
1099 	{
1100 		// stop when we hit the end of sprite list
1101 		if (data[0] & 0x8000)
1102 			break;
1103 
1104 		// extract parameters
1105 		int hide    = (data[0] & 0x5000);
1106 		int bank    = (data[0] >> 9) & 7;
1107 		int top     = (data[0] & 0x1ff) - 0x100;
1108 		uint16_t addr = data[1];
1109 		int pitch   = int16_t((data[2] >> 1) | ((data[4] & 0x1000) << 3)) >> 8;
1110 		int xpos    = data[2] & 0x1ff;
1111 		int vzoom   = data[3] & 0x7ff;
1112 		int ydelta  = (data[4] & 0x8000) ? 1 : -1;
1113 		int flip    = (~data[4] >> 14) & 1;
1114 		int xdelta  = (data[4] & 0x2000) ? 1 : -1;
1115 		int hzoom   = data[4] & 0x7ff;
1116 		int height  = (m_is_xboard ? (data[5] & 0xfff) : (data[5] >> 8)) + 1;
1117 		int colpri  = ((m_is_xboard ? (data[6] & 0xff) : (data[5] & 0x7f)) << 4) | (((data[3] >> 12) & 7) << 12);
1118 
1119 		// adjust X coordinate
1120 		// note: the threshhold below is a guess. If it is too high, rachero will draw garbage
1121 		// If it is too low, smgp won't draw the bottom part of the road
1122 		if (xpos < 0x80 && xdelta < 0)
1123 			xpos += 0x200;
1124 
1125 		// initialize the end address to the start address
1126 		data[7] = addr;
1127 
1128 		// if hidden, punt
1129 		if (hide)
1130 			continue;
1131 
1132 		// clamp to within the memory region size
1133 		if (numbanks)
1134 			bank %= numbanks;
1135 		const uint32_t *spritedata = spritebase + 0x10000 * bank;
1136 
1137 		// clamp to a maximum of 8x (not 100% confirmed)
1138 		if (vzoom < 0x40) vzoom = 0x40;
1139 		if (hzoom < 0x40) hzoom = 0x40;
1140 
1141 		// loop from top to bottom
1142 		int minx = xpos;
1143 		int maxx = xpos;
1144 		int miny = cliprect.max_y + 1;
1145 		int maxy = cliprect.min_y - 1;
1146 		int yacc = 0;
1147 		int ytarget = top + ydelta * height;
1148 		for (int y = top; y != ytarget; y += ydelta)
1149 		{
1150 			// skip drawing if not within the cliprect
1151 			if (y >= cliprect.min_y && y <= cliprect.max_y)
1152 			{
1153 				uint16_t *dest = &bitmap.pix(y);
1154 				int xacc = 0;
1155 				int x;
1156 
1157 				// non-flipped case
1158 				if (!flip)
1159 				{
1160 					// start at the word before because we preincrement below
1161 					data[7] = addr - 1;
1162 					for (x = xpos; (xdelta > 0 && x <= cliprect.max_x) || (xdelta < 0 && x >= cliprect.min_x); )
1163 					{
1164 						uint32_t pixels = spritedata[++data[7]];
1165 
1166 						// draw four pixels
1167 						int pix;
1168 						pix = (pixels >> 28) & 0xf; while (xacc < 0x200) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; xacc += hzoom; } xacc -= 0x200;
1169 						pix = (pixels >> 24) & 0xf; while (xacc < 0x200) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; xacc += hzoom; } xacc -= 0x200;
1170 						pix = (pixels >> 20) & 0xf; while (xacc < 0x200) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; xacc += hzoom; } xacc -= 0x200;
1171 						pix = (pixels >> 16) & 0xf; while (xacc < 0x200) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; xacc += hzoom; } xacc -= 0x200;
1172 						pix = (pixels >> 12) & 0xf; while (xacc < 0x200) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; xacc += hzoom; } xacc -= 0x200;
1173 						pix = (pixels >>  8) & 0xf; while (xacc < 0x200) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; xacc += hzoom; } xacc -= 0x200;
1174 						pix = (pixels >>  4) & 0xf; while (xacc < 0x200) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; xacc += hzoom; } xacc -= 0x200;
1175 						pix = (pixels >>  0) & 0xf; while (xacc < 0x200) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; xacc += hzoom; } xacc -= 0x200;
1176 
1177 						// stop if the second-to-last pixel in the group was 0xf
1178 						if ((pixels & 0x000000f0) == 0x000000f0)
1179 							break;
1180 					}
1181 				}
1182 
1183 				// flipped case
1184 				else
1185 				{
1186 					// start at the word after because we predecrement below
1187 					data[7] = addr + 1;
1188 					for (x = xpos; (xdelta > 0 && x <= cliprect.max_x) || (xdelta < 0 && x >= cliprect.min_x); )
1189 					{
1190 						uint32_t pixels = spritedata[--data[7]];
1191 
1192 						// draw four pixels
1193 						int pix;
1194 						pix = (pixels >>  0) & 0xf; while (xacc < 0x200) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; xacc += hzoom; } xacc -= 0x200;
1195 						pix = (pixels >>  4) & 0xf; while (xacc < 0x200) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; xacc += hzoom; } xacc -= 0x200;
1196 						pix = (pixels >>  8) & 0xf; while (xacc < 0x200) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; xacc += hzoom; } xacc -= 0x200;
1197 						pix = (pixels >> 12) & 0xf; while (xacc < 0x200) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; xacc += hzoom; } xacc -= 0x200;
1198 						pix = (pixels >> 16) & 0xf; while (xacc < 0x200) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; xacc += hzoom; } xacc -= 0x200;
1199 						pix = (pixels >> 20) & 0xf; while (xacc < 0x200) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; xacc += hzoom; } xacc -= 0x200;
1200 						pix = (pixels >> 24) & 0xf; while (xacc < 0x200) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; xacc += hzoom; } xacc -= 0x200;
1201 						pix = (pixels >> 28) & 0xf; while (xacc < 0x200) { if (x >= cliprect.min_x && x <= cliprect.max_x && pix != 0 && pix != 15) dest[x] = colpri | pix; x += xdelta; xacc += hzoom; } xacc -= 0x200;
1202 
1203 						// stop if the second-to-last pixel in the group was 0xf
1204 						if ((pixels & 0x0f000000) == 0x0f000000)
1205 							break;
1206 					}
1207 				}
1208 
1209 				// update bounds
1210 				if (x > maxx) maxx = x;
1211 				if (x < minx) minx = x;
1212 				if (y < miny) miny = y;
1213 				if (y > maxy) maxy = y;
1214 			}
1215 
1216 			// accumulate zoom factors; if we carry into the high bit, skip an extra row
1217 			yacc += vzoom;
1218 			addr += pitch * (yacc >> 9);
1219 			yacc &= 0x1ff;
1220 		}
1221 
1222 		// mark dirty
1223 		if (minx <= maxx && miny <= maxy)
1224 			mark_dirty(minx, maxx, miny, maxy);
1225 	}
1226 }
1227 
1228 
1229 
1230 //****************************************************************************
1231 //  Y BOARD-STYLE SPRITES
1232 //****************************************************************************
1233 
1234 //-------------------------------------------------
1235 //  sega_yboard_sprite_device -- constructor
1236 //-------------------------------------------------
1237 
sega_yboard_sprite_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1238 sega_yboard_sprite_device::sega_yboard_sprite_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
1239 	: sega_16bit_sprite_device(mconfig, SEGA_YBOARD_SPRITES, tag, owner)
1240 	, m_sprite_region_ptr(*this, DEVICE_SELF)
1241 {
1242 	set_local_origin(0x600, 0x600);
1243 }
1244 
1245 
1246 //-------------------------------------------------
1247 //  draw -- render the sprites within the cliprect
1248 //-------------------------------------------------
1249 
draw(bitmap_ind16 & bitmap,const rectangle & cliprect)1250 void sega_yboard_sprite_device::draw(bitmap_ind16 &bitmap, const rectangle &cliprect)
1251 {
1252 	//
1253 	//  Y-Board-style sprites
1254 	//
1255 	//      Offs  Bits               Usage
1256 	//       +0   e------- --------  Signify end of sprite list
1257 	//       +0   -----iii iiiiiiii  Address of indirection table (/16)
1258 	//       +2   bbbb---- --------  Upper 4 bits of bank index
1259 	//       +2   ----xxxx xxxxxxxx  X position of sprite (position $600 is screen position 0)
1260 	//       +4   bbbb---- --------  Lower 4 bits of bank index
1261 	//       +4   ----yyyy yyyyyyyy  Y position of sprite (position $600 is screen position 0)
1262 	//       +6   oooooooo oooooooo  Offset within selected sprite bank
1263 	//       +8   hhhhhhhh hhhhhhhh  Height of sprite
1264 	//       +A   -y------ --------  Render from top-to-bottom (1) or bottom-to-top (0) on screen
1265 	//       +A   --f----- --------  Horizontal flip: read the data backwards if set
1266 	//       +A   ---x---- --------  Render from left-to-right (1) or right-to-left (0) on screen
1267 	//       +A   -----zzz zzzzzzzz  Zoom factor
1268 	//       +C   -ccc---- --------  Sprite color
1269 	//       +C   ----rrrr --------  Sprite priority
1270 	//       +C   -------- pppppppp  Signed 8-bit pitch value between scanlines
1271 	//       +E   ----nnnn nnnnnnnn  Index of next sprite
1272 	//
1273 	//  Final bitmap format:
1274 	//
1275 	//            ccc----- --------  Sprite color
1276 	//            ---rrrr- --------  Sprite priority
1277 	//            -------i iiiiiiii  Indirected color data
1278 	//
1279 	//  In addition to these parameters, the sprite area is clipped using scanline extents
1280 	//  stored for every pair of scanlines in the rotation RAM. It's a bit of a cheat for us
1281 	//  to poke our nose into the rotation structure, but there are no known cases of Y-board
1282 	//  sprites without rotation RAM.
1283 	//
1284 
1285 	set_origin(m_xoffs, m_yoffs);
1286 
1287 	// clear out any scanlines we might be using
1288 	const uint16_t *rotatebase = m_segaic16_rotate[0].buffer ? m_segaic16_rotate[0].buffer.get() : m_segaic16_rotate[0].rotateram;
1289 	rotatebase -= yorigin();
1290 	for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
1291 		if (!(rotatebase[y & ~1] & 0xc000))
1292 			memset(&bitmap.pix(y, cliprect.min_x), 0xff, cliprect.width() * sizeof(uint16_t));
1293 
1294 	// reset the visited list
1295 	uint8_t visited[0x1000];
1296 	memset(visited, 0, sizeof(visited));
1297 
1298 	// render the sprites in order
1299 	const uint64_t *spritebase = &m_sprite_region_ptr[0];
1300 	uint8_t numbanks = m_sprite_region_ptr.bytes() / 0x80000;
1301 	int next = 0;
1302 	for (uint16_t *data = spriteram(); !(data[0] & 0x8000) && !visited[next]; data = spriteram() + next * 8)
1303 	{
1304 		int hide    = (data[0] & 0x5000);
1305 		const uint16_t *indirect = spriteram() + ((data[0] & 0x7ff) << 4);
1306 		int bank    = ((data[1] >> 8) & 0x10) | ((data[2] >> 12) & 0x0f);
1307 		int xpos    = data[1] & 0xfff;
1308 		int top     = data[2] & 0xfff;
1309 		uint16_t addr = data[3];
1310 		int height  = data[4];
1311 		int ydelta  = (data[5] & 0x4000) ? 1 : -1;
1312 		int flip    = (~data[5] >> 13) & 1;
1313 		int xdelta  = (data[5] & 0x1000) ? 1 : -1;
1314 		int zoom    = data[5] & 0x7ff;
1315 		int colpri  = (data[6] << 1) & 0xfe00;
1316 		int pitch   = int8_t(data[6]);
1317 
1318 		// note that we've visited this entry and get the offset of the next one
1319 		visited[next] = 1;
1320 		next = data[7] & 0xfff;
1321 
1322 		// if hidden, or invalid height, punt
1323 		if (hide || height == 0)
1324 			continue;
1325 
1326 		// clamp to within the memory region size
1327 		if (numbanks)
1328 			bank %= numbanks;
1329 		const uint64_t *spritedata = spritebase + 0x10000 * bank;
1330 
1331 		// clamp to a maximum of 8x (not 100% confirmed)
1332 		if (zoom == 0) zoom = 1;
1333 
1334 		// loop from top to bottom
1335 		int dminx = xpos;
1336 		int dmaxx = xpos;
1337 		int dminy = cliprect.max_y + 1;
1338 		int dmaxy = cliprect.min_y - 1;
1339 		int ytarget = top + ydelta * height;
1340 		int yacc = 0;
1341 		for (int y = top; y != ytarget; y += ydelta)
1342 		{
1343 			// skip drawing if not within the cliprect
1344 			if (y >= cliprect.min_y && y <= cliprect.max_y)
1345 			{
1346 				uint16_t *dest = &bitmap.pix(y);
1347 				int minx = rotatebase[y & ~1];
1348 				int maxx = rotatebase[y |  1];
1349 				int xacc = 0;
1350 
1351 				// bit 0x8000 from rotate RAM means that Y is above the top of the screen
1352 				if ((minx & 0x8000) && ydelta < 0)
1353 					break;
1354 
1355 				// bit 0x4000 from rotate RAM means that Y is below the bottom of the screen
1356 				if ((minx & 0x4000) && ydelta > 0)
1357 					break;
1358 
1359 				// if either bit is set, skip the rest for this scanline
1360 				if (!(minx & 0xc000))
1361 				{
1362 					// clamp min/max to the cliprect
1363 					if (minx < cliprect.min_x)
1364 						minx = cliprect.min_x;
1365 					if (maxx > cliprect.max_x)
1366 						maxx = cliprect.max_x;
1367 
1368 					// non-flipped case
1369 					int x;
1370 					if (!flip)
1371 					{
1372 						// start at the word before because we preincrement below
1373 						uint16_t offs = addr - 1;
1374 						for (x = xpos; (xdelta > 0 && x <= maxx) || (xdelta < 0 && x >= minx); )
1375 						{
1376 							uint64_t pixels = spritedata[++offs];
1377 
1378 							// draw 16 pixels
1379 							int pix, ind;
1380 							pix = (pixels >> 60) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1381 							pix = (pixels >> 56) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1382 							pix = (pixels >> 52) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1383 							pix = (pixels >> 48) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1384 							pix = (pixels >> 44) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1385 							pix = (pixels >> 40) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1386 							pix = (pixels >> 36) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1387 							pix = (pixels >> 32) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1388 							pix = (pixels >> 28) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1389 							pix = (pixels >> 24) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1390 							pix = (pixels >> 20) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1391 							pix = (pixels >> 16) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1392 							pix = (pixels >> 12) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1393 							pix = (pixels >>  8) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1394 							pix = (pixels >>  4) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1395 							pix = (pixels >>  0) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1396 
1397 							// stop if the last pixel in the group was 0xf
1398 							if (pix == 0x0f)
1399 								break;
1400 						}
1401 					}
1402 
1403 					// flipped case
1404 					else
1405 					{
1406 						// start at the word after because we predecrement below
1407 						uint16_t offs = addr + 1;
1408 						for (x = xpos; (xdelta > 0 && x <= maxx) || (xdelta < 0 && x >= minx); )
1409 						{
1410 							uint64_t pixels = spritedata[--offs];
1411 
1412 							// draw 16 pixels
1413 							int pix, ind;
1414 							pix = (pixels >>  0) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1415 							pix = (pixels >>  4) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1416 							pix = (pixels >>  8) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1417 							pix = (pixels >> 12) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1418 							pix = (pixels >> 16) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1419 							pix = (pixels >> 20) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1420 							pix = (pixels >> 24) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1421 							pix = (pixels >> 28) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1422 							pix = (pixels >> 32) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1423 							pix = (pixels >> 36) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1424 							pix = (pixels >> 40) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1425 							pix = (pixels >> 44) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1426 							pix = (pixels >> 48) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1427 							pix = (pixels >> 52) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1428 							pix = (pixels >> 56) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1429 							pix = (pixels >> 60) & 0xf; ind = indirect[pix]; while (xacc < 0x200) { if (x >= minx && x <= maxx && ind < 0x1fe) dest[x] = colpri | ind; x += xdelta; xacc += zoom; } xacc -= 0x200;
1430 
1431 							// stop if the last pixel in the group was 0xf
1432 							if (pix == 0x0f)
1433 								break;
1434 						}
1435 					}
1436 
1437 					// update bounds
1438 					if (x > dmaxx) dmaxx = x;
1439 					if (x < dminx) dminx = x;
1440 					if (y < dminy) dminy = y;
1441 					if (y > dmaxy) dmaxy = y;
1442 				}
1443 			}
1444 
1445 			// accumulate zoom factors; if we carry into the high bit, skip an extra row
1446 			yacc += zoom;
1447 			addr += pitch * (yacc >> 9);
1448 			yacc &= 0x1ff;
1449 		}
1450 
1451 		// mark dirty
1452 		if (dminx <= dmaxx && dminy <= dmaxy)
1453 			mark_dirty(dminx, dmaxx, dminy, dmaxy);
1454 	}
1455 }
1456