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