// license:BSD-3-Clause // copyright-holders:David Haywood, Phil Stroffolino /* Namco System 2 Sprites - found on Namco System 2 video board (standard type) based on namcoic.txt this probably consists of the following C106 - Generates memory output clocks to generate X-Axis Zoom for Line Buffer Writes C134 - Object Memory Address Generator. Sequences the sprite memory contents to the hardware. C135 - Checks is object is displayed on Current output line. C146 - Steers the Decode Object Pixel data to the correct line buffer A or B Metal Hawk requires a different draw function, so might use a different chip unless the hookup is just scrambled (needs checking) used by the following drivers namcos2.cpp (all games EXCEPT Steel Gunner, Steel Gunner 2, Lucky & Wild, Suzuka 8 Hours, Suzuka 8 Hours 2 which use the newer Namco NB1 style sprites, see namco_c355spr.cpp) */ #include "emu.h" #include "namcos2_sprite.h" DEFINE_DEVICE_TYPE(NAMCOS2_SPRITE, namcos2_sprite_device, "namcos2_sprite", "Namco System 2 Sprites (C106,C134,C135,C146)") namcos2_sprite_device::namcos2_sprite_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : device_t(mconfig, NAMCOS2_SPRITE, tag, owner, clock), m_gfxdecode(*this, finder_base::DUMMY_TAG), m_spriteram(*this, finder_base::DUMMY_TAG) { } void namcos2_sprite_device::device_start() { } /**************************************************************************************/ /**************************************************************************************/ void namcos2_sprite_device::zdrawgfxzoom( screen_device &screen, bitmap_ind16 &dest_bmp,const rectangle &clip,gfx_element *gfx, u32 code,u32 color,bool flipx,bool flipy,int sx,int sy, int scalex, int scaley, int zpos) { if (!scalex || !scaley) return; if (dest_bmp.bpp() == 16) { if (gfx) { device_palette_interface &palette = gfx->palette(); const int shadow_offset = (palette.shadows_enabled()) ? palette.entries() : 0; const pen_t *pal = &palette.pen(gfx->colorbase() + gfx->granularity() * (color % gfx->colors())); const u8 *source_base = gfx->get_data(code % gfx->elements()); const int sprite_screen_height = (scaley * gfx->height() + 0x8000) >> 16; const int sprite_screen_width = (scalex * gfx->width() + 0x8000) >> 16; if (sprite_screen_width && sprite_screen_height) { /* compute sprite increment per screen pixel */ int dx = (gfx->width() << 16) / sprite_screen_width; int dy = (gfx->height() << 16) / sprite_screen_height; int ex = sx + sprite_screen_width; int ey = sy + sprite_screen_height; int x_index_base; int y_index; if (flipx) { x_index_base = (sprite_screen_width - 1) * dx; dx = -dx; } else { x_index_base = 0; } if (flipy) { y_index = (sprite_screen_height - 1) * dy; dy = -dy; } else { y_index = 0; } if (sx < clip.min_x) { /* clip left */ int pixels = clip.min_x - sx; sx += pixels; x_index_base += pixels * dx; } if (sy < clip.min_y) { /* clip top */ int pixels = clip.min_y - sy; sy += pixels; y_index += pixels * dy; } if (ex > clip.max_x + 1) { /* clip right */ int pixels = ex - clip.max_x - 1; ex -= pixels; } if (ey > clip.max_y + 1) { /* clip bottom */ int pixels = ey - clip.max_y - 1; ey -= pixels; } if (ex > sx) { /* skip if inner loop doesn't draw anything */ bitmap_ind8 &priority_bitmap = screen.priority(); if (priority_bitmap.valid()) { for (int y = sy; y < ey; y++) { const u8 *source = source_base + (y_index>>16) * gfx->rowbytes(); u16 *dest = &dest_bmp.pix16(y); u8 *pri = &priority_bitmap.pix8(y); int x_index = x_index_base; /* this code was previously shared with the c355 where this was needed if (m_palxor) { for (int x = sx; x < ex; x++) { const u8 c = source[x_index >> 16]; if (c != 0xff) { if (pri[x] <= zpos) { switch(c) { case 0: dest[x] = 0x4000 | (dest[x] & 0x1fff); break; case 1: dest[x] = 0x6000 | (dest[x] & 0x1fff); break; default: dest[x] = pal[c]; break; } pri[x] = zpos; } } x_index += dx; } y_index += dy; } else */ { for (int x = sx; x < ex; x++) { const u8 c = source[x_index >> 16]; if (c != 0xff) { if (pri[x] <= zpos) { if (color == 0xf && c==0xfe && shadow_offset) { dest[x] |= shadow_offset; } else { dest[x] = pal[c]; } pri[x] = zpos; } } x_index += dx; } y_index += dy; } } } } } } } } /* zdrawgfxzoom */ void namcos2_sprite_device::zdrawgfxzoom( screen_device &screen, bitmap_rgb32 &dest_bmp,const rectangle &clip,gfx_element *gfx, u32 code,u32 color,bool flipx,bool flipy,int sx,int sy, int scalex, int scaley, int zpos) { /* nop */ } void namcos2_sprite_device::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int pri, int control) { int offset = (control & 0x000f) * (128 * 4); if (pri == 0) { screen.priority().fill(0, cliprect); } for (int loop = 0; loop < 128; loop++) { /**************************************** * word#0 * Sprite Y position D00-D08 * Sprite Size 16/32 D09 * Sprite Size Y D10-D15 * * word#1 * Sprite Quadrant D00-D01 * Sprite Number D02-D13 * Sprite flip X D14 * Sprite flip Y D15 * * word#2 * Sprite X position D00-D10 * * word#3 * Sprite priority D00-D02 * Sprite colour index D04-D07 * Sprite Size X D10-D15 */ const u16 word3 = m_spriteram[offset + (loop * 4) + 3]; if ((word3 & 0xf) == pri) { const u16 word0 = m_spriteram[offset + (loop * 4) + 0]; const u16 word1 = m_spriteram[offset + (loop * 4) + 1]; const u16 offset4 = m_spriteram[offset + (loop * 4) + 2]; const int sizey = ((word0 >> 10) & 0x003f) + 1; int sizex = (word3 >> 10) & 0x003f; if ((word0 & 0x0200) == 0) sizex >>= 1; if ((sizey - 1) && sizex) { const u32 color = (word3 >> 4) & 0x000f; const u32 sprn = (word1 >> 2) & 0x0fff; const int ypos = (0x1ff - (word0 & 0x01ff)) - 0x50 + 0x02; const int xpos = (offset4 & 0x03ff) - 0x50 + 0x07; const bool flipy = word1 & 0x8000; const bool flipx = word1 & 0x4000; const int scalex = (sizex << 16) / ((word0 & 0x0200) ? 0x20 : 0x10); const int scaley = (sizey << 16) / ((word0 & 0x0200) ? 0x20 : 0x10); if (scalex && scaley) { gfx_element *gfx = m_gfxdecode->gfx(0); if ((word0 & 0x0200) == 0) gfx->set_source_clip((word1 & 0x0001) ? 16 : 0, 16, (word1 & 0x0002) ? 16 : 0, 16); else gfx->set_source_clip(0, 32, 0, 32); zdrawgfxzoom( screen, bitmap, cliprect, gfx, sprn, color, flipx,flipy, xpos,ypos, scalex,scaley, loop); } } } } } /* draw_sprites */ void namcos2_sprite_device::draw_sprites_metalhawk(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int pri) { /** * word#0 * xxxxxx---------- ysize * ------x--------- sprite tile size * -------xxxxxxxxx screeny * * word#1 * --xxxxxxxxxxxxxx tile * * word#2 (unused) * * word#3 * xxxxxx---------- xsize * ------xxxxxxxxxx screenx * * word#4 (unused) * word#5 (unused) * * word#6 (orientation) * ---------------x rot90 * --------------x- flipx * -------------x-- flipy * ------------x--- tile size * * word#7 * ------------xxxx priority * --------xxxx---- color * x--------------- unknown */ const u16 *pSource = m_spriteram; if (pri == 0) { screen.priority().fill(0, cliprect); } for (int loop=0; loop < 128; loop++) { const u16 ypos = pSource[0]; const u16 tile = pSource[1]; const u16 xpos = pSource[3]; const u16 flags = pSource[6]; const u16 attrs = pSource[7]; const int sizey = ((ypos >> 10) & 0x003f) + 1; const int sizex = (xpos >> 10) & 0x003f; const u32 sprn = (tile >> 2) & 0x0fff; if ((sizey - 1) && sizex && (attrs & 0xf) == pri) { const bool bBigSprite = flags & 0x0008; const u32 color = (attrs >> 4) & 0x000f; int sx = (xpos & 0x03ff) - 0x50 + 0x07; int sy = (0x1ff - (ypos & 0x01ff)) - 0x50 + 0x02; const bool flipx = flags & 0x0002; const bool flipy = flags & 0x0004; const int scalex = (sizex << 16) / (0x20);//(sizex << 16) / (bBigSprite ? 0x20 : 0x10); correct formula? const int scaley = (sizey << 16) / (bBigSprite ? 0x20 : 0x10); /* swap xy */ const int rgn = (flags & 0x0001); gfx_element *gfx = m_gfxdecode->gfx(rgn); if (bBigSprite) { if (sizex < 0x20) { sx -= (0x20 - sizex) / 0x8; } if (sizey < 0x20) { sy += (0x20 - sizey) / 0xC; } gfx->set_source_clip(0, 32, 0, 32); } else gfx->set_source_clip((tile & 0x0001) ? 16 : 0, 16, (tile & 0x0002) ? 16 : 0, 16); zdrawgfxzoom( screen, bitmap, cliprect, gfx, sprn, color, flipx,flipy, sx,sy, scalex, scaley, loop); } pSource += 8; } } /* draw_sprites_metalhawk */