summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/video/ninjakd2.cpp
blob: 67f8d5474754310e2736d0df73bab47266382cb1 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                       
                                                                               


                                                                               
 
                                           


                                                                               
                
                              
 
 





                                       
                                                      
 

                                                            



                                                 
                               


                                             

 
                                                               
 

                                                            



                                                 
                               




                                             
                                                             
 

                                                            



                                                                      
                               




                                                
                                                      




                                                                        
                                                     
 



                                                                        
                                                                                                                                                           
 

                                                       


                                                                                           
                                    




                              
                                                               
 
                                                                                        

 
                                                               
 
                                                                                        

 
                                                               
 
                                                                                        



 





                                       
                                                                
 

                            
         


                                                                                       
 


                                                                                  

         
                                                                                                                                                                          

                                               
                                                           










                                                        

 




                                             
 
                                  
 
                             
 
                                                                                                                                                                                     
 
                                                      

 
                                         
 
                             
 
                                                                                                                                                                                   
 
                                                    

 
                                          
 
                             
 
                                                                                                                                                                                   
 
                                                     

 
                                          
 
                                  
                             
                              
 


                                                                                                                                                                                                                                        
 

                                                
 
                                                     

 
                                         
 
                                  
                             
                              
 


                                                                                                                                                                                                                                        
 


                                                
 
                                                    



 





                                       
                                                    
 

                                                   

 
                                                    
 

                                                   

 
 
                                                 
 
                                                     

 
                                                 
 
                                                     

 
                                                 
 
                                                     

 
                                                    
 
                                                                           
 
 
                                                    
 
                                                                           

 
                                                    
 
                                                                           

 
                                                     
 
                                                                 
 

                                                     

 
                                                     
 
                                                                 
 

                                                     

 
                                                     
 
                                                                 
 

                                                     

 
 
                                                                      
 

                                          

                       
         




                                                                           

         

                                         

 
                                                 
 
                                            

 
                                                 
 
                                             
 
 
                                                 
 
                                             

 
                                                 
 
                                             


 
                                                         
 
                                                  


 






                                       
                                                        
 
                                                     

                                                         
 
                                           

                              







                                                                                     



                                     
                 








                                                                                                                                   
 
                                          
                         



                                                       
                         

                                
                         




                                                            
                                                      
                         
                                                              
                                 

                                                                                                      
                                                                                       


                                                                    
                                                                                   



                                                                


                                 







                                                
         

 




                                                                                

                                                  
                                              

                                                    
                                                             


                                                         
                                                                           
 
                                                         

                                                                       
                                            
         
                                           
         
            
         
                                                                   
                 
                                                                          
                         
                                                                                    
                                                                                      

                         
         

 
 
                                     
 




                                                                                              

                                        
 

 
                                                                                                                       
 
                                                                                      
                                                   
                         
                              
 
                                 
 
                                                           
                                                                              
                                                           



                 
                                                                                                                      
 
                         
                              
 
                                 
 

                                                            
                                                                              

                                                            


                 
 
                                                                                                                     
 
                         
                              
 
                                 
 


                                                            
                                                                              
                                                           




                 
                                                         
 
                      
                  
         
                                       
                                         
 
                                      

                                                                                       
         
 
// license:BSD-3-Clause
// copyright-holders:Roberto Ventura, Leandro Dardini, Yochizo, Nicola Salmoria
/******************************************************************************

    UPL "sprite framebuffer" hardware

    Functions to emulate the video hardware

******************************************************************************/

#include "emu.h"
#include "includes/ninjakd2.h"


/*************************************
 *
 *  Callbacks for the TileMap code
 *
 *************************************/

TILE_GET_INFO_MEMBER(ninjakd2_state::get_fg_tile_info)
{
	int const lo = m_fg_videoram[(tile_index << 1)];
	int const hi = m_fg_videoram[(tile_index << 1) | 1];
	int const tile = ((hi & 0xc0) << 2) | lo;
	int const flipyx = (hi & 0x30) >> 4;
	int const color = hi & 0x0f;

	SET_TILE_INFO_MEMBER(0,
			tile,
			color,
			TILE_FLIPYX(flipyx));
}

TILE_GET_INFO_MEMBER(ninjakd2_state::ninjakd2_get_bg_tile_info)
{
	int const lo = m_bg_videoram[(tile_index << 1)];
	int const hi = m_bg_videoram[(tile_index << 1) | 1];
	int const tile = ((hi & 0xc0) << 2) | lo;
	int const flipyx = (hi & 0x30) >> 4;
	int const color = hi & 0x0f;

	SET_TILE_INFO_MEMBER(2,
			tile,
			color,
			TILE_FLIPYX(flipyx));
}

TILE_GET_INFO_MEMBER(ninjakd2_state::mnight_get_bg_tile_info)
{
	int const lo = m_bg_videoram[(tile_index << 1)];
	int const hi = m_bg_videoram[(tile_index << 1) | 1];
	int const tile = ((hi & 0x10) << 6) | ((hi & 0xc0) << 2) | lo;
	int const flipy = (hi & 0x20) >> 5;
	int const color = hi & 0x0f;

	SET_TILE_INFO_MEMBER(2,
			tile,
			color,
			flipy ? TILE_FLIPY : 0);
}

TILEMAP_MAPPER_MEMBER(ninjakd2_state::robokid_bg_scan)
{
	/* logical (col,row) -> memory offset */
	return (col & 0x0f) | ((row & 0x1f) << 4) | ((col & 0x10) << 5);
}

TILEMAP_MAPPER_MEMBER(ninjakd2_state::omegaf_bg_scan)
{
	/* logical (col,row) -> memory offset */
	return (col & 0x0f) | ((row & 0x1f) << 4) | ((col & 0x70) << 5);
}

void ninjakd2_state::robokid_get_bg_tile_info( tile_data& tileinfo, tilemap_memory_index const tile_index, int const gfxnum, const uint8_t* const videoram)
{
	int const lo = videoram[(tile_index << 1)];
	int const hi = videoram[(tile_index << 1) | 1];
	int const tile = ((hi & 0x10) << 7) | ((hi & 0x20) << 5) | ((hi & 0xc0) << 2) | lo;
	int const color = hi & 0x0f;

	SET_TILE_INFO_MEMBER(gfxnum,
			tile,
			color,
			0);
}

TILE_GET_INFO_MEMBER(ninjakd2_state::robokid_get_bg0_tile_info)
{
	robokid_get_bg_tile_info(tileinfo, tile_index, 2, m_robokid_bg0_videoram.get());
}

TILE_GET_INFO_MEMBER(ninjakd2_state::robokid_get_bg1_tile_info)
{
	robokid_get_bg_tile_info(tileinfo, tile_index, 3, m_robokid_bg1_videoram.get());
}

TILE_GET_INFO_MEMBER(ninjakd2_state::robokid_get_bg2_tile_info)
{
	robokid_get_bg_tile_info(tileinfo, tile_index, 4, m_robokid_bg2_videoram.get());
}



/*************************************
 *
 *  Video system start
 *
 *************************************/

void ninjakd2_state::video_init_common(uint32_t vram_alloc_size)
{
	// create video ram
	if (vram_alloc_size)
	{
		m_robokid_bg0_videoram = make_unique_clear<uint8_t[]>(vram_alloc_size);
		m_robokid_bg1_videoram = make_unique_clear<uint8_t[]>(vram_alloc_size);
		m_robokid_bg2_videoram = make_unique_clear<uint8_t[]>(vram_alloc_size);

		save_pointer(NAME(m_robokid_bg0_videoram.get()), vram_alloc_size);
		save_pointer(NAME(m_robokid_bg1_videoram.get()), vram_alloc_size);
		save_pointer(NAME(m_robokid_bg2_videoram.get()), vram_alloc_size);
	}

	m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(ninjakd2_state::get_fg_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
	m_fg_tilemap->set_transparent_pen(0xf);

	m_screen->register_screen_bitmap(m_sprites_bitmap);

	m_sprites_updated = 0;
	m_robokid_sprites = 0;
	m_vram_bank_mask = 0;

	// register for save states
	save_item(NAME(m_sprites_updated));
	save_item(NAME(m_next_sprite_overdraw_enabled));
	save_item(NAME(m_robokid_bg0_bank));
	save_item(NAME(m_robokid_bg1_bank));
	save_item(NAME(m_robokid_bg2_bank));
}

static bool stencil_ninjakd2( uint16_t pal );
static bool stencil_mnight(   uint16_t pal );
static bool stencil_arkarea(  uint16_t pal );
static bool stencil_robokid(  uint16_t pal );
static bool stencil_omegaf(   uint16_t pal );

void ninjakd2_state::video_start()
{
	video_init_common(0);

	m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(ninjakd2_state::ninjakd2_get_bg_tile_info),this), TILEMAP_SCAN_ROWS, 16, 16, 32, 32);

	m_stencil_compare_function = stencil_ninjakd2;
}

VIDEO_START_MEMBER(ninjakd2_state,mnight)
{
	video_init_common(0);

	m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(ninjakd2_state::mnight_get_bg_tile_info),this), TILEMAP_SCAN_ROWS, 16, 16, 32, 32);

	m_stencil_compare_function = stencil_mnight;
}

VIDEO_START_MEMBER(ninjakd2_state,arkarea)
{
	video_init_common(0);

	m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(ninjakd2_state::mnight_get_bg_tile_info),this), TILEMAP_SCAN_ROWS, 16, 16, 32, 32);

	m_stencil_compare_function = stencil_arkarea;
}

VIDEO_START_MEMBER(ninjakd2_state,robokid)
{
	video_init_common(0x0800);
	m_vram_bank_mask = 1;
	m_robokid_sprites = 1;

	m_bg0_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(ninjakd2_state::robokid_get_bg0_tile_info),this), tilemap_mapper_delegate(FUNC(ninjakd2_state::robokid_bg_scan),this), 16, 16, 32, 32);
	m_bg1_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(ninjakd2_state::robokid_get_bg1_tile_info),this), tilemap_mapper_delegate(FUNC(ninjakd2_state::robokid_bg_scan),this), 16, 16, 32, 32);
	m_bg2_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(ninjakd2_state::robokid_get_bg2_tile_info),this), tilemap_mapper_delegate(FUNC(ninjakd2_state::robokid_bg_scan),this), 16, 16, 32, 32);

	m_bg1_tilemap->set_transparent_pen(0xf);
	m_bg2_tilemap->set_transparent_pen(0xf);

	m_stencil_compare_function = stencil_robokid;
}

VIDEO_START_MEMBER(ninjakd2_state,omegaf)
{
	video_init_common(0x2000);
	m_vram_bank_mask = 7;
	m_robokid_sprites = 1;

	m_bg0_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(ninjakd2_state::robokid_get_bg0_tile_info),this), tilemap_mapper_delegate(FUNC(ninjakd2_state::omegaf_bg_scan),this), 16, 16, 128, 32);
	m_bg1_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(ninjakd2_state::robokid_get_bg1_tile_info),this), tilemap_mapper_delegate(FUNC(ninjakd2_state::omegaf_bg_scan),this), 16, 16, 128, 32);
	m_bg2_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(ninjakd2_state::robokid_get_bg2_tile_info),this), tilemap_mapper_delegate(FUNC(ninjakd2_state::omegaf_bg_scan),this), 16, 16, 128, 32);

	m_bg0_tilemap->set_transparent_pen(0xf);
	m_bg1_tilemap->set_transparent_pen(0xf);
	m_bg2_tilemap->set_transparent_pen(0xf);

	m_stencil_compare_function = stencil_omegaf;
}



/*************************************
 *
 *  Memory handlers
 *
 *************************************/

WRITE8_MEMBER(ninjakd2_state::ninjakd2_bgvideoram_w)
{
	m_bg_videoram[offset] = data;
	m_bg_tilemap->mark_tile_dirty(offset >> 1);
}

WRITE8_MEMBER(ninjakd2_state::ninjakd2_fgvideoram_w)
{
	m_fg_videoram[offset] = data;
	m_fg_tilemap->mark_tile_dirty(offset >> 1);
}


WRITE8_MEMBER(ninjakd2_state::robokid_bg0_bank_w)
{
	m_robokid_bg0_bank = data & m_vram_bank_mask;
}

WRITE8_MEMBER(ninjakd2_state::robokid_bg1_bank_w)
{
	m_robokid_bg1_bank = data & m_vram_bank_mask;
}

WRITE8_MEMBER(ninjakd2_state::robokid_bg2_bank_w)
{
	m_robokid_bg2_bank = data & m_vram_bank_mask;
}

READ8_MEMBER(ninjakd2_state::robokid_bg0_videoram_r)
{
	return m_robokid_bg0_videoram[(m_robokid_bg0_bank << 10) | offset];
}

READ8_MEMBER(ninjakd2_state::robokid_bg1_videoram_r)
{
	return m_robokid_bg1_videoram[(m_robokid_bg1_bank << 10) | offset];
}

READ8_MEMBER(ninjakd2_state::robokid_bg2_videoram_r)
{
	return m_robokid_bg2_videoram[(m_robokid_bg2_bank << 10) | offset];
}

WRITE8_MEMBER(ninjakd2_state::robokid_bg0_videoram_w)
{
	int const address = (m_robokid_bg0_bank << 10 ) | offset;

	m_robokid_bg0_videoram[address] = data;
	m_bg0_tilemap->mark_tile_dirty(address >> 1);
}

WRITE8_MEMBER(ninjakd2_state::robokid_bg1_videoram_w)
{
	int const address = (m_robokid_bg1_bank << 10 ) | offset;

	m_robokid_bg1_videoram[address] = data;
	m_bg1_tilemap->mark_tile_dirty(address >> 1);
}

WRITE8_MEMBER(ninjakd2_state::robokid_bg2_videoram_w)
{
	int const address = (m_robokid_bg2_bank << 10 ) | offset;

	m_robokid_bg2_videoram[address] = data;
	m_bg2_tilemap->mark_tile_dirty(address >> 1);
}


void ninjakd2_state::bg_ctrl(int offset, int data, tilemap_t* tilemap)
{
	int scrollx = tilemap->scrollx(0);
	int scrolly = tilemap->scrolly(0);

	switch (offset)
	{
		case 0: scrollx = ((scrollx & 0x100) | data);        break;
		case 1: scrollx = ((scrollx & 0x0ff) | (data << 8)); break;
		case 2: scrolly = ((scrolly & 0x100) | data);        break;
		case 3: scrolly = ((scrolly & 0x0ff) | (data << 8)); break;
		case 4: tilemap->enable(data & 1); break;
	}

	tilemap->set_scrollx(0, scrollx);
	tilemap->set_scrolly(0, scrolly);
}

WRITE8_MEMBER(ninjakd2_state::ninjakd2_bg_ctrl_w)
{
	bg_ctrl(offset, data, m_bg_tilemap);
}

WRITE8_MEMBER(ninjakd2_state::robokid_bg0_ctrl_w)
{
	bg_ctrl(offset, data, m_bg0_tilemap);
}

WRITE8_MEMBER(ninjakd2_state::robokid_bg1_ctrl_w)
{
	bg_ctrl(offset, data, m_bg1_tilemap);
}

WRITE8_MEMBER(ninjakd2_state::robokid_bg2_ctrl_w)
{
	bg_ctrl(offset, data, m_bg2_tilemap);
}


WRITE8_MEMBER(ninjakd2_state::ninjakd2_sprite_overdraw_w)
{
	m_next_sprite_overdraw_enabled = data & 1;
}



/*************************************
 *
 *  Video update
 *
 *************************************/

void ninjakd2_state::draw_sprites( bitmap_ind16 &bitmap)
{
	gfx_element* const gfx = m_gfxdecode->gfx(1);
	int const big_xshift = m_robokid_sprites ? 1 : 0;
	int const big_yshift = m_robokid_sprites ? 0 : 1;

	uint8_t* sprptr = &m_spriteram[11];
	int sprites_drawn = 0;

	/* The sprite generator draws exactly 96 16x16 sprites per frame. When big
	   (32x32) sprites are drawn, this counts for 4 sprites drawn, so the sprite
	   list is reduced accordingly (i.e. three slots at the end of the list will
	   be ignored). Note that a disabled sprite, even if it is not drawn, still
	   counts as one sprite drawn.
	   This is proven by Mutant Night, which doesn't work correctly (leaves shots
	   on screen) if we don't take big sprites into account.
	*/

	for (;;)
	{
		if (sprptr[2] & 0x02)
		{
			int sx = sprptr[1] - ((sprptr[2] & 0x01) << 8);
			int sy = sprptr[0];
			// Ninja Kid II doesn't use the topmost bit (it has smaller ROMs) so it might not be connected on the board
			int code = sprptr[3] + ((sprptr[2] & 0xc0) << 2) + ((sprptr[2] & 0x08) << 7);
			int flipx = (sprptr[2] & 0x10) >> 4;
			int flipy = (sprptr[2] & 0x20) >> 5;
			int const color = sprptr[4] & 0x0f;
			// Ninja Kid II doesn't use the 'big' feature so it might not be available on the board
			int const big = (sprptr[2] & 0x04) >> 2;

			if (flip_screen())
			{
				sx = 240 - 16*big - sx;
				sy = 240 - 16*big - sy;
				flipx ^= 1;
				flipy ^= 1;
			}

			if (big)
			{
				code &= ~3;
				code ^= flipx << big_xshift;
				code ^= flipy << big_yshift;
			}

			for (int y = 0; y <= big; ++y)
			{
				for (int x = 0; x <= big; ++x)
				{
					int const tile = code ^ (x << big_xshift) ^ (y << big_yshift);

						gfx->transpen(bitmap,bitmap.cliprect(),
							tile,
							color,
							flipx,flipy,
							sx + 16*x, sy + 16*y, 0xf);

					++sprites_drawn;
					if (sprites_drawn >= 96)
						return;
				}
			}
		}
		else
		{
			++sprites_drawn;
			if (sprites_drawn >= 96)
				return;
		}

		sprptr += 16;
	}
}

static bool stencil_ninjakd2( uint16_t pal ) { return( (pal & 0xf0) == 0xf0 ); }
static bool stencil_mnight(   uint16_t pal ) { return( (pal & 0xf0) == 0xf0 ); }
static bool stencil_arkarea(  uint16_t pal ) { return( (pal & 0xf0) == 0xf0 ); }
static bool stencil_robokid(  uint16_t pal ) { return( (pal & 0xf0) <  0xe0 ); }
static bool stencil_omegaf(   uint16_t pal ) { return( true ); }
//////            OVERDRAW     STENCIL     UNKNOWN
//////  NINJAKD2  023459ABCDE  F           1678
//////    MNIGHT  0134568ABCDE F           279
//////   ARKAREA  012345679BDE             8ACF
//////   ROBOKID  EF           01236       45789ABCD
//////    OMEGAF  -            -           -         (unused)
// I could not find a port to select overdraw or stencil.
// Temporarily, I compare with constant number.
// This is very hackish.
// (Is there a possibility that software can't select it but hardware can?)

void ninjakd2_state::erase_sprites( bitmap_ind16 &bitmap)
{
	// if sprite overdraw is disabled, clear the sprite framebuffer
	if (!m_next_sprite_overdraw_enabled)
	{
		m_sprites_bitmap.fill(0xf);
	}
	else
	{
		for (int y = 0; y < m_sprites_bitmap.height(); ++y)
		{
			for (int x = 0; x < m_sprites_bitmap.width(); ++x)
			{
				uint16_t* const ptr = &m_sprites_bitmap.pix16(y, x);
				if ( (*m_stencil_compare_function)(*ptr) ) *ptr = 0xf;
			}
		}
	}
}


void ninjakd2_state::update_sprites()
{
	////// Before modified, this was written.
		// we want to erase the sprites with the old setting and draw them with the
		// new one. Not doing this causes a glitch in Ninja Kid II when taking the top
		// exit from stage 3.
	////// The glitch is correct behavior.
	erase_sprites(m_sprites_bitmap);
	draw_sprites(m_sprites_bitmap);
}


uint32_t ninjakd2_state::screen_update_ninjakd2(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
	// updating sprites here instead than in screen_vblank avoids a palette glitch
	// at the end of the "rainbow sky" screens.
	update_sprites();
	m_sprites_updated = 1;

	bitmap.fill(0, cliprect);

	m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
	copybitmap_trans(bitmap, m_sprites_bitmap, 0, 0, 0, 0, cliprect, 0xf);
	m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);

	return 0;
}

uint32_t ninjakd2_state::screen_update_robokid(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
	update_sprites();
	m_sprites_updated = 1;

	bitmap.fill(0, cliprect);

	m_bg0_tilemap->draw(screen, bitmap, cliprect, 0, 0);
	m_bg1_tilemap->draw(screen, bitmap, cliprect, 0, 0);
	copybitmap_trans(bitmap, m_sprites_bitmap, 0, 0, 0, 0, cliprect, 0xf);
	m_bg2_tilemap->draw(screen, bitmap, cliprect, 0, 0);
	m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);

	return 0;
}

uint32_t ninjakd2_state::screen_update_omegaf(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
	update_sprites();
	m_sprites_updated = 1;

	bitmap.fill(0, cliprect);

	m_bg0_tilemap->draw(screen, bitmap, cliprect, 0, 0);
	m_bg1_tilemap->draw(screen, bitmap, cliprect, 0, 0);
	m_bg2_tilemap->draw(screen, bitmap, cliprect, 0, 0);
	copybitmap_trans(bitmap, m_sprites_bitmap, 0, 0, 0, 0, cliprect, 0xf);
	m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);

	return 0;
}


WRITE_LINE_MEMBER(ninjakd2_state::screen_vblank_ninjakd2)
{
	// rising edge
	if (state)
	{
		if (!m_sprites_updated)
			update_sprites();

		m_sprites_updated = 0;

		m_maincpu->set_input_line_and_vector(0, HOLD_LINE, 0xd7); /* RST 10h */
	}
}