1 // license:BSD-3-Clause
2 // copyright-holders:Bryan McPhail,Ernesto Corvi,Andrew Prime,Zsolt Vasvari
3 // thanks-to:Fuzz
4 /* NeoGeo sprites (and fixed text layer) */
5 
6 #include "emu.h"
7 #include "neogeo_spr.h"
8 #include "screen.h"
9 
10 
11 // pure virtual functions
12 //const device_type NEOGEO_SPRITE_BASE = device_creator<neosprite_base_device>;
13 
neosprite_base_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)14 neosprite_base_device::neosprite_base_device(
15 		const machine_config &mconfig,
16 		device_type type,
17 		const char *tag,
18 		device_t *owner,
19 		uint32_t clock)
20 	: device_t(mconfig, type, tag, owner, clock)
21 	, device_video_interface(mconfig, *this)
22 	, m_bppshift(4)
23 	, m_region_zoomy(*this, "zoomy")
24 {
25 }
26 
device_start()27 void neosprite_base_device::device_start()
28 {
29 	m_videoram = std::make_unique<uint16_t[]>(0x8000 + 0x800);
30 	m_videoram_drawsource = m_videoram.get();
31 
32 	/* clear allocated memory */
33 	memset(m_videoram.get(), 0x00, (0x8000 + 0x800) * sizeof(uint16_t));
34 
35 	create_sprite_line_timer();
36 	create_auto_animation_timer();
37 
38 	/* initialize values that are not modified on a reset */
39 	m_vram_offset = 0;
40 	m_vram_read_buffer = 0;
41 	m_vram_modulo = 0;
42 	m_auto_animation_speed = 0;
43 	m_auto_animation_disabled = 0;
44 	m_auto_animation_counter = 0;
45 	m_auto_animation_frame_counter = 0;
46 
47 	/* register for state saving */
48 	save_pointer(NAME(m_videoram), 0x8000 + 0x800);
49 	save_item(NAME(m_vram_offset));
50 	save_item(NAME(m_vram_read_buffer));
51 	save_item(NAME(m_vram_modulo));
52 	save_item(NAME(m_fixed_layer_source));
53 
54 	save_item(NAME(m_auto_animation_speed));
55 	save_item(NAME(m_auto_animation_disabled));
56 	save_item(NAME(m_auto_animation_counter));
57 	save_item(NAME(m_auto_animation_frame_counter));
58 }
59 
device_reset()60 void neosprite_base_device::device_reset()
61 {
62 	//m_sprite_gfx_address_mask = 0;
63 	optimize_sprite_data();
64 
65 	start_sprite_line_timer();
66 	start_auto_animation_timer();
67 }
68 
69 
70 
71 /*************************************
72  *
73  *  Video RAM access
74  *
75  *************************************/
76 
set_videoram_offset(uint16_t data)77 void neosprite_base_device::set_videoram_offset(uint16_t data)
78 {
79 	m_vram_offset = (data & 0x8000 ? data & 0x87ff : data);
80 
81 	/* the read happens right away */
82 	m_vram_read_buffer = m_videoram[m_vram_offset];
83 }
84 
85 
get_videoram_data()86 uint16_t neosprite_base_device::get_videoram_data()
87 {
88 	return m_vram_read_buffer;
89 }
90 
91 
set_videoram_data(uint16_t data)92 void neosprite_base_device::set_videoram_data(uint16_t data)
93 {
94 	m_videoram[m_vram_offset] = data;
95 
96 	/* auto increment/decrement the current offset - A15 is NOT affected */
97 	set_videoram_offset((m_vram_offset & 0x8000) | ((m_vram_offset + m_vram_modulo) & 0x7fff));
98 }
99 
100 
set_videoram_modulo(uint16_t data)101 void neosprite_base_device::set_videoram_modulo(uint16_t data)
102 {
103 	m_vram_modulo = data;
104 }
105 
106 
get_videoram_modulo()107 uint16_t neosprite_base_device::get_videoram_modulo()
108 {
109 	return m_vram_modulo;
110 }
111 
112 
113 
114 /*************************************
115  *
116  *  Auto animation
117  *
118  *************************************/
119 
set_auto_animation_speed(uint8_t data)120 void neosprite_base_device::set_auto_animation_speed(uint8_t data)
121 {
122 	m_auto_animation_speed = data;
123 }
124 
125 
set_auto_animation_disabled(uint8_t data)126 void neosprite_base_device::set_auto_animation_disabled(uint8_t data)
127 {
128 	m_auto_animation_disabled = data;
129 }
130 
131 
neogeo_get_auto_animation_counter()132 uint8_t neosprite_base_device::neogeo_get_auto_animation_counter()
133 {
134 	return m_auto_animation_counter;
135 }
136 
137 
TIMER_CALLBACK_MEMBER(neosprite_base_device::auto_animation_timer_callback)138 TIMER_CALLBACK_MEMBER(neosprite_base_device::auto_animation_timer_callback)
139 {
140 	if (m_auto_animation_frame_counter == 0)
141 	{
142 		m_auto_animation_frame_counter = m_auto_animation_speed;
143 		m_auto_animation_counter += 1;
144 	}
145 	else
146 		m_auto_animation_frame_counter = m_auto_animation_frame_counter - 1;
147 
148 	m_auto_animation_timer->adjust(screen().time_until_pos(NEOGEO_VSSTART));
149 }
150 
151 
create_auto_animation_timer()152 void neosprite_base_device::create_auto_animation_timer()
153 {
154 	m_auto_animation_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(neosprite_base_device::auto_animation_timer_callback),this));
155 }
156 
157 
start_auto_animation_timer()158 void neosprite_base_device::start_auto_animation_timer()
159 {
160 	m_auto_animation_timer->adjust(screen().time_until_pos(NEOGEO_VSSTART));
161 }
162 
163 
164 
165 /*************************************
166  *
167  *  Fixed layer
168  *
169  *************************************/
170 
neogeo_set_fixed_layer_source(uint8_t data)171 void neosprite_base_device::neogeo_set_fixed_layer_source(uint8_t data)
172 {
173 	m_fixed_layer_source = data;
174 }
175 
176 
draw_fixed_layer(bitmap_rgb32 & bitmap,int scanline)177 void neosprite_base_device::draw_fixed_layer(bitmap_rgb32 &bitmap, int scanline)
178 {
179 	assert((m_fixed_layer_source && m_region_fixed != nullptr) || (m_region_fixedbios != nullptr));
180 
181 	uint8_t* gfx_base = m_fixed_layer_source ? m_region_fixed : m_region_fixedbios->base();
182 	uint32_t addr_mask = ( m_fixed_layer_source ? m_region_fixed_size : m_region_fixedbios->bytes() ) - 1;
183 	uint16_t *video_data = &m_videoram_drawsource[0x7000 | (scanline >> 3)];
184 	uint32_t *pixel_addr = &bitmap.pix(scanline, NEOGEO_HBEND);
185 
186 	int garouoffsets[32];
187 	int banked = m_fixed_layer_source && (addr_mask > 0x1ffff);
188 
189 	/* thanks to Mr K for the garou & kof2000 banking info */
190 	/* Build line banking table for Garou & MS3 before starting render */
191 	if (banked && m_fixed_layer_bank_type == 1)
192 	{
193 		int garoubank = 0;
194 		int k = 0;
195 		int y = 0;
196 		while (y < 32)
197 		{
198 			if (m_videoram_drawsource[0x7500 + k] == 0x0200 && (m_videoram_drawsource[0x7580 + k] & 0xff00) == 0xff00)
199 			{
200 				garoubank = m_videoram_drawsource[0x7580 + k] & 3;
201 				garouoffsets[y++] = garoubank;
202 			}
203 			garouoffsets[y++] = garoubank;
204 			k += 2;
205 		}
206 	}
207 
208 	for (int x = 0; x < 40; x++)
209 	{
210 		uint16_t code_and_palette = *video_data;
211 		uint16_t code = code_and_palette & 0x0fff;
212 
213 		if (banked)
214 		{
215 			int y = scanline >> 3;
216 			switch (m_fixed_layer_bank_type)
217 			{
218 			case 1:
219 				/* Garou, MSlug 3 */
220 				code += 0x1000 * (garouoffsets[(y - 2) & 31] ^ 3);
221 				break;
222 			case 2:
223 				code += 0x1000 * (((m_videoram_drawsource[0x7500 + ((y - 1) & 31) + 32 * (x / 6)] >> (5 - (x % 6)) * 2) & 3) ^ 3);
224 				break;
225 			}
226 		}
227 
228 		{
229 			int gfx_offset = ((code << 5) | (scanline & 0x07)) & addr_mask;
230 
231 			const pen_t *char_pens;
232 
233 			char_pens = &m_pens[code_and_palette >> 12 << m_bppshift];
234 
235 			static const uint32_t pix_offsets[] = { 0x10, 0x18, 0x00, 0x08 };
236 
237 			for (int i = 0; i < 4; i++)
238 			{
239 				draw_fixed_layer_2pixels(pixel_addr, gfx_offset + pix_offsets[i], gfx_base, char_pens);
240 			}
241 		}
242 		video_data = video_data + 0x20;
243 	}
244 }
245 
246 
draw_fixed_layer_2pixels(uint32_t * & pixel_addr,int offset,uint8_t * gfx_base,const pen_t * char_pens)247 inline void neosprite_base_device::draw_fixed_layer_2pixels(uint32_t*&pixel_addr, int offset, uint8_t* gfx_base, const pen_t* char_pens)
248 {
249 	uint8_t data = gfx_base[offset];
250 
251 	if (data & 0x0f)
252 		*pixel_addr = char_pens[data & 0x0f];
253 	pixel_addr++;
254 
255 	if (data & 0xf0)
256 		*pixel_addr = char_pens[(data & 0xf0) >> 4];
257 	pixel_addr++;
258 
259 }
260 
261 /*************************************
262  *
263  *  Sprite hardware
264  *
265  *************************************/
266 
267 #define MAX_SPRITES_PER_SCREEN    (381)
268 #define MAX_SPRITES_PER_LINE      (96)
269 
270 
271 /* horizontal zoom table - verified on real hardware */
272 static const u16 zoom_x_tables[16] =
273 { 0x0080, 0x0880, 0x0888, 0x2888, 0x288a, 0x2a8a, 0x2aaa, 0xaaaa, 0xaaea, 0xbaea, 0xbaeb, 0xbbeb, 0xbbef, 0xfbef, 0xfbff, 0xffff };
274 
275 
sprite_on_scanline(int scanline,int y,int rows)276 inline bool neosprite_base_device::sprite_on_scanline(int scanline, int y, int rows)
277 {
278 	return (rows == 0) || (rows >= 0x20) || ((scanline - y) & 0x1ff) < (rows * 0x10);
279 }
280 
281 
draw_sprites(bitmap_rgb32 & bitmap,int scanline)282 void neosprite_base_device::draw_sprites(bitmap_rgb32 &bitmap, int scanline)
283 {
284 	int max_sprite_index;
285 	int y = 0;
286 	int x = 0;
287 	int rows = 0;
288 	int zoom_y = 0;
289 	int zoom_x = 0;
290 	uint16_t *sprite_list;
291 
292 	/* select the active list */
293 	if (scanline & 0x01)
294 		sprite_list = &m_videoram_drawsource[0x8680];
295 	else
296 		sprite_list = &m_videoram_drawsource[0x8600];
297 
298 	/* optimization -- find last non-zero entry and only draw that many +1
299 	   sprite.  This is not 100% correct as the hardware will keep drawing
300 	   the #0 sprite over and over, but we need the speed */
301 	for (max_sprite_index = (MAX_SPRITES_PER_LINE - 1); max_sprite_index >= 0; max_sprite_index--)
302 	{
303 		if (sprite_list[max_sprite_index] != 0)
304 			break;
305 	}
306 
307 	/* add the +1 now, just in case the 0 at the end is real sprite */
308 	if (max_sprite_index != (MAX_SPRITES_PER_LINE - 1))
309 		max_sprite_index = max_sprite_index + 1;
310 
311 	for (int sprite_index = 0; sprite_index <= max_sprite_index; sprite_index++)
312 	{
313 		uint16_t sprite_number = sprite_list[sprite_index] & 0x01ff;
314 		uint16_t y_control = m_videoram_drawsource[0x8200 | sprite_number];
315 		uint16_t zoom_control = m_videoram_drawsource[0x8000 | sprite_number];
316 
317 		/* if chained, go to next X coordinate and get new X zoom */
318 		if (y_control & 0x40)
319 		{
320 			x = (x + zoom_x + 1) & 0x01ff;
321 			zoom_x = (zoom_control >> 8) & 0x0f;
322 		}
323 		/* new block */
324 		else
325 		{
326 			y = 0x200 - (y_control >> 7);
327 			x = m_videoram_drawsource[0x8400 | sprite_number] >> 7;
328 
329 			zoom_y = (zoom_control & 0xff);
330 
331 			zoom_x = (zoom_control >> 8) & 0x0f;
332 			rows = y_control & 0x3f;
333 		}
334 
335 		/* skip if falls completely outside the screen */
336 		if ((x >= 0x140) && (x <= 0x1f0))
337 			continue;
338 
339 		/* double check the Y coordinate, in case somebody modified the sprite coordinate
340 		   since we buffered it */
341 		if (sprite_on_scanline(scanline, y, rows))
342 		{
343 			int sprite_y;
344 			int tile;
345 			uint8_t sprite_y_and_tile;
346 			offs_t attr_and_code_offs;
347 			uint16_t attr;
348 			uint32_t code;
349 			const pen_t *line_pens;
350 			int x_inc;
351 
352 			int sprite_line = (scanline - y) & 0x1ff;
353 			int zoom_line = sprite_line & 0xff;
354 			int invert = sprite_line & 0x100;
355 
356 			if (invert)
357 				zoom_line ^= 0xff;
358 
359 			if (rows > 0x20)
360 			{
361 				zoom_line = zoom_line % ((zoom_y + 1) << 1);
362 
363 				if (zoom_line > zoom_y)
364 				{
365 					zoom_line = ((zoom_y + 1) << 1) - 1 - zoom_line;
366 					invert = !invert;
367 				}
368 			}
369 
370 			sprite_y_and_tile = m_region_zoomy[(zoom_y << 8) | zoom_line];
371 
372 			sprite_y = sprite_y_and_tile & 0x0f;
373 			tile = sprite_y_and_tile >> 4;
374 
375 			if (invert)
376 			{
377 				sprite_y ^= 0x0f;
378 				tile ^= 0x1f;
379 			}
380 
381 			attr_and_code_offs = (sprite_number << 6) | (tile << 1);
382 			attr = m_videoram_drawsource[attr_and_code_offs + 1];
383 			code = ((attr << 12) & 0xf0000) | m_videoram_drawsource[attr_and_code_offs];
384 
385 			/* substitute auto animation bits */
386 			if (!m_auto_animation_disabled)
387 			{
388 				if (attr & 0x0008)
389 					code = (code & ~0x07) | (m_auto_animation_counter & 0x07);
390 				else if (attr & 0x0004)
391 					code = (code & ~0x03) | (m_auto_animation_counter & 0x03);
392 			}
393 
394 			/* vertical flip? */
395 			if (attr & 0x0002)
396 				sprite_y ^= 0x0f;
397 
398 			u16 zoom_x_table = zoom_x_tables[zoom_x];
399 
400 			/* compute offset in gfx ROM and mask it to the number of bits available */
401 			int gfx_base = ((code << 8) | (sprite_y << 4)) & m_sprite_gfx_address_mask;
402 
403 			line_pens = &m_pens[attr >> 8 << m_bppshift];
404 
405 			/* horizontal flip? */
406 			if (attr & 0x0001)
407 			{
408 				gfx_base = gfx_base + 0x0f;
409 				x_inc = -1;
410 			}
411 			else
412 				x_inc = 1;
413 
414 			/* draw the line - no wrap-around */
415 			if (x <= 0x01f0)
416 			{
417 				uint32_t *pixel_addr = &bitmap.pix(scanline, x + NEOGEO_HBEND);
418 
419 				for (int i = 0; i < 0x10; i++)
420 				{
421 					if (zoom_x_table & 0x8000)
422 					{
423 						draw_pixel(gfx_base, pixel_addr, line_pens);
424 
425 						pixel_addr++;
426 					}
427 
428 					zoom_x_table <<= 1;
429 					if (zoom_x_table == 0)
430 						break;
431 
432 					gfx_base += x_inc;
433 				}
434 			}
435 			/* wrap-around */
436 			else
437 			{
438 				int x_save = x;
439 				uint32_t *pixel_addr = &bitmap.pix(scanline, NEOGEO_HBEND);
440 
441 				for (int i = 0; i < 0x10; i++)
442 				{
443 					if (zoom_x_table & 0x8000)
444 					{
445 						if (x >= 0x200)
446 						{
447 							draw_pixel(gfx_base, pixel_addr, line_pens);
448 
449 							pixel_addr++;
450 						}
451 
452 						x++;
453 					}
454 
455 					zoom_x_table <<= 1;
456 					if (zoom_x_table == 0)
457 						break;
458 
459 					gfx_base += x_inc;
460 				}
461 				x = x_save;
462 			}
463 		}
464 	}
465 }
466 
467 
parse_sprites(int scanline)468 void neosprite_base_device::parse_sprites(int scanline)
469 {
470 	uint16_t sprite_number;
471 	int y = 0;
472 	int rows = 0;
473 	uint16_t *sprite_list;
474 
475 	int active_sprite_count = 0;
476 
477 	/* select the active list */
478 	if (scanline & 0x01)
479 		sprite_list = &m_videoram_drawsource[0x8680];
480 	else
481 		sprite_list = &m_videoram_drawsource[0x8600];
482 
483 	/* scan all sprites */
484 	for (sprite_number = 0; sprite_number < MAX_SPRITES_PER_SCREEN; sprite_number++)
485 	{
486 		uint16_t y_control = m_videoram_drawsource[0x8200 | sprite_number];
487 
488 		/* if not chained, get Y position and height, otherwise use previous values */
489 		if (~y_control & 0x40)
490 		{
491 			y = 0x200 - (y_control >> 7);
492 			rows = y_control & 0x3f;
493 		}
494 
495 		/* skip sprites with 0 rows */
496 		if (rows == 0)
497 			continue;
498 
499 		if (!sprite_on_scanline(scanline, y, rows))
500 			continue;
501 
502 		/* sprite is on this scanline, add it to active list */
503 		*sprite_list = sprite_number;
504 
505 		sprite_list++;
506 
507 		/* increment sprite count, and if we reached the max, bail out */
508 		active_sprite_count++;
509 
510 		if (active_sprite_count == MAX_SPRITES_PER_LINE)
511 			break;
512 	}
513 
514 	/* fill the rest of the sprite list with 0, including one extra entry */
515 	memset(sprite_list, 0, sizeof(sprite_list[0]) * (MAX_SPRITES_PER_LINE - active_sprite_count + 1));
516 }
517 
518 
TIMER_CALLBACK_MEMBER(neosprite_base_device::sprite_line_timer_callback)519 TIMER_CALLBACK_MEMBER(neosprite_base_device::sprite_line_timer_callback)
520 {
521 	int scanline = param;
522 
523 	/* we are at the beginning of a scanline -
524 	   we need to draw the previous scanline and parse the sprites on the current one */
525 	if (scanline != 0)
526 		screen().update_partial(scanline - 1);
527 
528 	parse_sprites(scanline);
529 
530 	/* let's come back at the beginning of the next line */
531 	scanline = (scanline + 1) % NEOGEO_VTOTAL;
532 
533 	m_sprite_line_timer->adjust(screen().time_until_pos(scanline), scanline);
534 }
535 
536 
create_sprite_line_timer()537 void neosprite_base_device::create_sprite_line_timer()
538 {
539 	m_sprite_line_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(neosprite_base_device::sprite_line_timer_callback),this));
540 }
541 
542 
start_sprite_line_timer()543 void neosprite_base_device::start_sprite_line_timer()
544 {
545 	m_sprite_line_timer->adjust(screen().time_until_pos(0));
546 }
547 
548 
get_region_mask(uint8_t * rgn,uint32_t rgn_size)549 uint32_t neosprite_base_device::get_region_mask(uint8_t* rgn, uint32_t rgn_size)
550 {
551 	/* convert the sprite graphics data into a format that
552 	   allows faster blitting */
553 	uint32_t mask;
554 	uint32_t len;
555 	uint32_t bit;
556 
557 	/* get mask based on the length rounded up to the nearest
558 	   power of 2 */
559 	mask = 0xffffffff;
560 
561 	len = rgn_size;
562 
563 	for (bit = 0x80000000; bit != 0; bit >>= 1)
564 	{
565 		if ((len * 2 - 1) & bit)
566 			break;
567 
568 		mask >>= 1;
569 	}
570 
571 	return mask;
572 }
573 
optimize_sprite_data()574 void neosprite_base_device::optimize_sprite_data()
575 {
576 	// this does nothing in this implementation, it's used by neosprite_optimized_device
577 	// m_sprite_gfx_address_mask gets set when the GFX region is assigned
578 	return;
579 }
580 
set_optimized_sprite_data(uint8_t * sprdata,uint32_t mask)581 void neosprite_base_device::set_optimized_sprite_data(uint8_t* sprdata, uint32_t mask)
582 {
583 	return;
584 }
585 
586 // these are for passing in pointers from the main system
set_sprite_region(uint8_t * region_sprites,uint32_t region_sprites_size)587 void neosprite_base_device::set_sprite_region(uint8_t* region_sprites, uint32_t region_sprites_size)
588 {
589 	m_region_sprites = region_sprites;
590 	m_region_sprites_size = region_sprites_size;
591 }
592 
set_fixed_regions(uint8_t * fix_cart,uint32_t fix_cart_size,memory_region * fix_bios)593 void neosprite_base_device::set_fixed_regions(uint8_t* fix_cart, uint32_t fix_cart_size, memory_region* fix_bios)
594 {
595 	m_region_fixed = fix_cart;
596 	m_region_fixed_size = fix_cart_size;
597 	m_region_fixedbios = fix_bios;
598 }
599 
set_pens(const pen_t * pens)600 void neosprite_base_device::set_pens(const pen_t* pens)
601 {
602 	m_pens = pens;
603 }
604 
605 
606 
607 /*********************************************************************************************************************************/
608 /* Regular NeoGeo sprite handling - drawing directly from ROM (or RAM on NeoCD)                                                  */
609 /*                                                                                                                               */
610 /* note, we don't currently use this implementation, reference only                                                              */
611 /* if we do it will be important to ensure that all sprite regions are ^2 sizes - the optimized routine automatically allocates  */
612 /* ^2 sized regions when pre-decoding, but obviously we don't here, so if we want to be safe we'll have to adjust the actual     */
613 /* regions          (alternatively I could add an additional size check in the draw routine, but that would be slower)           */
614 /*********************************************************************************************************************************/
615 
616 DEFINE_DEVICE_TYPE(NEOGEO_SPRITE_REGULAR, neosprite_regular_device, "neosprite_reg", "Neo-Geo Sprites (regular)")
617 
neosprite_regular_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)618 neosprite_regular_device::neosprite_regular_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
619 	: neosprite_base_device(mconfig, NEOGEO_SPRITE_REGULAR, tag, owner, clock)
620 {
621 }
622 
set_sprite_region(uint8_t * region_sprites,uint32_t region_sprites_size)623 void neosprite_regular_device::set_sprite_region(uint8_t* region_sprites, uint32_t region_sprites_size)
624 {
625 	m_region_sprites = region_sprites;
626 	m_region_sprites_size = region_sprites_size;
627 
628 	uint32_t mask = get_region_mask(m_region_sprites, m_region_sprites_size);
629 	uint32_t proper_size = (mask + 1) >>1;
630 
631 	printf("lengths %08x %08x m_region_sprites", region_sprites_size, proper_size);
632 
633 	if (m_region_sprites_size != proper_size)
634 	{
635 		fatalerror("please use power of 2 region sizes with neosprite_base_device to ensure masking works correctly");
636 	}
637 
638 	m_sprite_gfx_address_mask = mask;
639 }
640 
draw_pixel(int romaddr,uint32_t * dst,const pen_t * line_pens)641 inline void neosprite_regular_device::draw_pixel(int romaddr, uint32_t* dst, const pen_t *line_pens)
642 {
643 	const uint8_t* src = m_region_sprites + (((romaddr &~0xff)>>1) | (((romaddr&0x8)^0x8)<<3) | ((romaddr & 0xf0)  >> 2));
644 	const int x = romaddr & 0x7;
645 
646 	const uint8_t gfx = (((src[0x3] >> x) & 0x01) << 3) |
647 						(((src[0x1] >> x) & 0x01) << 2) |
648 						(((src[0x2] >> x) & 0x01) << 1) |
649 						(((src[0x0] >> x) & 0x01) << 0);
650 
651 	if (gfx)
652 		*dst = line_pens[gfx];
653 }
654 
655 
656 
657 /*********************************************************************************************************************************/
658 /* Regular NeoGeo sprite handling with pre-decode optimization                                                                   */
659 /*                                                                                                                               */
660 /* this is closer to the old MAME implementation where the 4bpp graphics have been expanded to an easier to draw 8bpp format     */
661 /* for additional speed                                                                                                          */
662 /*********************************************************************************************************************************/
663 
664 DEFINE_DEVICE_TYPE(NEOGEO_SPRITE_OPTIMZIED, neosprite_optimized_device, "neosprite_opt", "Neo-Geo Sprites (optimized)")
665 
neosprite_optimized_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)666 neosprite_optimized_device::neosprite_optimized_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
667 	: neosprite_base_device(mconfig, NEOGEO_SPRITE_OPTIMZIED, tag, owner, clock)
668 	, m_spritegfx8(nullptr)
669 {
670 }
671 
optimize_helper(std::vector<uint8_t> & spritegfx,uint8_t * region_sprites,uint32_t region_sprites_size)672 uint32_t neosprite_optimized_device::optimize_helper(std::vector<uint8_t> &spritegfx, uint8_t* region_sprites, uint32_t region_sprites_size)
673 {
674 	// convert the sprite graphics data into a format that allows faster blitting
675 	uint8_t *src;
676 	uint8_t *dest;
677 
678 	uint32_t mask = get_region_mask(region_sprites, region_sprites_size);
679 
680 	spritegfx.resize(mask + 1);
681 	uint32_t spritegfx_address_mask = mask;
682 
683 	src = region_sprites;
684 	dest = &spritegfx[0];
685 
686 	for (unsigned i = 0; i < region_sprites_size; i += 0x80, src += 0x80)
687 	{
688 		for (unsigned y = 0; y < 0x10; y++)
689 		{
690 			for (unsigned x = 0; x < 8; x++)
691 			{
692 				*(dest++) = (((src[0x43 | (y << 2)] >> x) & 0x01) << 3) |
693 				(((src[0x41 | (y << 2)] >> x) & 0x01) << 2) |
694 				(((src[0x42 | (y << 2)] >> x) & 0x01) << 1) |
695 				(((src[0x40 | (y << 2)] >> x) & 0x01) << 0);
696 			}
697 
698 			for (unsigned x = 0; x < 8; x++)
699 			{
700 				*(dest++) = (((src[0x03 | (y << 2)] >> x) & 0x01) << 3) |
701 				(((src[0x01 | (y << 2)] >> x) & 0x01) << 2) |
702 				(((src[0x02 | (y << 2)] >> x) & 0x01) << 1) |
703 				(((src[0x00 | (y << 2)] >> x) & 0x01) << 0);
704 			}
705 		}
706 	}
707 
708 	return spritegfx_address_mask;
709 }
710 
711 
optimize_sprite_data()712 void neosprite_optimized_device::optimize_sprite_data()
713 {
714 	m_sprite_gfx_address_mask = optimize_helper(m_sprite_gfx, m_region_sprites, m_region_sprites_size);
715 	m_spritegfx8 = &m_sprite_gfx[0];
716 }
717 
set_optimized_sprite_data(uint8_t * sprdata,uint32_t mask)718 void neosprite_optimized_device::set_optimized_sprite_data(uint8_t* sprdata, uint32_t mask)
719 {
720 	m_sprite_gfx_address_mask = mask;
721 	m_spritegfx8 = &sprdata[0];
722 }
723 
draw_pixel(int romaddr,uint32_t * dst,const pen_t * line_pens)724 inline void neosprite_optimized_device::draw_pixel(int romaddr, uint32_t* dst, const pen_t *line_pens)
725 {
726 	const uint8_t gfx = m_spritegfx8[romaddr];
727 
728 	if (gfx)
729 		*dst = line_pens[gfx];
730 }
731 
732 
733 /*********************************************************************************************************************************/
734 /* MIDAS specific sprite handling                                                                                                */
735 /*                                                                                                                               */
736 /* this is used by the midas.c hardware which is a reengineered NeoGeo, it has 8bbp tiles instead of 4bpp tiles                  */
737 /* and uploads the zoom table.  The additional videoram buffering is a guess because 'hammer' is very glitchy without it         */
738 /*********************************************************************************************************************************/
739 
740 DEFINE_DEVICE_TYPE(NEOGEO_SPRITE_MIDAS, neosprite_midas_device, "midassprite", "MIDAS Sprites")
741 
742 
neosprite_midas_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)743 neosprite_midas_device::neosprite_midas_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
744 	: neosprite_base_device(mconfig, NEOGEO_SPRITE_MIDAS, tag, owner, clock)
745 {
746 	m_bppshift = 8;
747 }
748 
749 
draw_pixel(int romaddr,uint32_t * dst,const pen_t * line_pens)750 inline void neosprite_midas_device::draw_pixel(int romaddr, uint32_t* dst, const pen_t *line_pens)
751 {
752 	const uint8_t* src = m_region_sprites + (((romaddr &~0xff)) | (((romaddr&0x8)^0x8)<<4) | ((romaddr & 0xf0)  >> 1));
753 	const int x = romaddr & 0x7;
754 
755 	const uint8_t gfx =   (((src[0x7] >> x) & 0x01) << 7) |
756 						(((src[0x6] >> x) & 0x01) << 6) |
757 						(((src[0x5] >> x) & 0x01) << 5) |
758 						(((src[0x4] >> x) & 0x01) << 4) |
759 						(((src[0x3] >> x) & 0x01) << 3) |
760 						(((src[0x2] >> x) & 0x01) << 2) |
761 						(((src[0x1] >> x) & 0x01) << 1) |
762 						(((src[0x0] >> x) & 0x01) << 0);
763 
764 	if (gfx)
765 		*dst = line_pens[gfx];
766 }
767 
768 
device_start()769 void neosprite_midas_device::device_start()
770 {
771 	neosprite_base_device::device_start();
772 
773 	m_videoram_buffer = std::make_unique<uint16_t[]>(0x8000 + 0x800);
774 	m_videoram_drawsource = m_videoram_buffer.get();
775 
776 	memset(m_videoram_buffer.get(), 0x00, (0x8000 + 0x800) * sizeof(uint16_t));
777 
778 }
779 
buffer_vram()780 void neosprite_midas_device::buffer_vram()
781 {
782 	memcpy(m_videoram_buffer.get(), m_videoram.get(), (0x8000 + 0x800) * sizeof(uint16_t));
783 }
784 
draw_fixed_layer_2pixels(uint32_t * & pixel_addr,int offset,uint8_t * gfx_base,const pen_t * char_pens)785 inline void neosprite_midas_device::draw_fixed_layer_2pixels(uint32_t*&pixel_addr, int offset, uint8_t* gfx_base, const pen_t* char_pens)
786 {
787 	uint8_t data;
788 
789 	data = ((gfx_base[(offset * 2)+0] & 0x0f)<<0) | ((gfx_base[(offset * 2)+1] & 0x0f)<<4);
790 	if (data)
791 		*pixel_addr = char_pens[data];
792 	pixel_addr++;
793 
794 	data = ((gfx_base[(offset * 2)+0] & 0xf0)>>4) | ((gfx_base[(offset * 2)+1] & 0xf0)<<0);
795 	if (data)
796 		*pixel_addr = char_pens[data];
797 	pixel_addr++;
798 }
799 
set_sprite_region(uint8_t * region_sprites,uint32_t region_sprites_size)800 void neosprite_midas_device::set_sprite_region(uint8_t* region_sprites, uint32_t region_sprites_size)
801 {
802 	m_region_sprites = region_sprites;
803 	m_region_sprites_size = region_sprites_size;
804 	uint32_t mask = get_region_mask(m_region_sprites, m_region_sprites_size);
805 	m_sprite_gfx_address_mask = mask;
806 }
807