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

                                
                                                                            




                                                                     

                                                                            










                                                                                                                                                                                                                                                       


                                                                                                                                                                                                                                     



                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                     










                                                                                                                                                                                                                                                       
                                                                                                                                                                                                                                     
















                                                                                                                                                                                                                                     


                                                                                                                                                                                                                                     


                                                                                                                                                                                                                                     
                                                                            
 
                
                    
                   

 


                                                                            
 
                                                   

                                                   

                                                   
 
                                                              












                                   
                                                   


                                                

                                                   
 
                                                                    










                                  
 


                                                                            
 
                         
                                                                                                        
 


                                                   
 
                                                                                                                                         
                                                                          























                                                    
 

 
                                                   


                                                   
 
                                                                                       
 






                                                                                                     
 









                                                                                                           
 



                                                                                                            
 

                                                                                 
 


                                                   
 

                                                                                      
 






                                                 
                                               
                                       



                                                 
                                            




                                             
                                                

                                 
 
                                 
                                                                  
                 
                                                                 


                                            
         


 
                                                   

                                                  

                                                   
 
                                                                                                             
 

                                                                  
                             
 
                                        
         
                               
                                                                                             
                              
                                                                                    



         









                                                   
                                                        
                           

                                                                       


















                                                 
 




                                                              
 






























                                                                          
                                                                 








                                                   

                                           













                                                   
            




                                                                                                          
         

                                      
                                                                   
                                    
                                                                   
                                          
                                                                            
                              



         
                                                   

                                             
                                                   
 
                                                             
 

                                                                       
 
                                                                                 
                                            
                                                                
         
                                                       
                                           
                             
                 
                                                                



                                                
                 

                    




                                                                         

                 



                                                          
                    
                                                              

         





                                                   

                                               


                                                   
                                                                                                                       


                                                              
                                                                       























                                                                           
         

                                  

         

                                       
 



                                    
 

                                               
         

                                                         
                    
                                                         
         











                                                                                        
         






                                                            
 


                                        
                 


                                                             
 




                                                                               
                         



                                                                        
                                                 


                                                             
 





                                                                                                       
 
                                                          
                                                                                                                          

                                                                                                        

                         
 

                                               
                 

                                                                              
                         



                                                                       
                                                 


                                                             
 





                                                                                                        
 
                                                          
                                                                                                                          

                                                                                                        



                         



                                               


 
 


                                                                            
 


                                                   
 
                                                                 
                    

                   
 


 


                                                   
 
                                                                                
 









                                                       
 

                                  
         

                                              
         
 

                                             
                                      
                           
         

                           
         

                      


 


                                                   
 
                                                                           
                         
 
 

 


                                                   
 
                                                                                                                  
 




                                            
 
                                           
                                       

                         
         

                               
         
                    
 
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************

    atarimo.c

    Common motion object management functions for Atari raster games.

****************************************************************************

            gfx bks lnk spl rev swp nei pps sof max basepal maxcols trn link        code        upper       color       xpos        ypos        width       height      hflip       vflip       priority    neighbor    absolute    special
arcadecl    0   1   1   0   0   0   0   0   0   0   0x100   0x100   0   00ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0           0           0           0           0           0
atarisy1    0   8   1   1   0   0   0   0   0   x38 0x100   0x100   0   0,0,0,003f  0,ffff,0,0  0           0,ff00,0,0  0,0,3fe0,0  3fe0,0,0,0  0           000f,0,0,0  8000,0,0,0  0           0,0,8000,0  0           0           0,ffff,0,0  == ffff
atarisy2    1   1   1   0   0   0   0   0   0   0   0x000   0x040   15  0,0,0,07f8  0,07ff,0,0  0007,0,0,0  0,0,0,3000  0,0,ffc0,0  7fc0,0,0,0  0           0,3800,0,0  0,4000,0,0  0           0,0,0,c000  0,8000,0,0  0           0
badlands    1   1   0   1   0   0   0   0   0   0   0x080   0x080   0   003f,0,0,0  0fff,0,0,0  0           0,0,0,0007  0,0,0,ff80  0,ff80,0,0  0           0,000f,0,0  0           0           0,0,0,0008  0           0           0
batman      1   1   1   0   1   0   0   8   0   0   0x100   0x100   0   03ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0,8000,0,0  0           0,0,0070,0  0           0           0
blstroid    1   1   1   0   0   0   0   0   0   0   0x000   0x100   0   0,0,0ff8,0  0,3fff,0,0  0           0,0,0,000f  0,0,0,ffc0  ff80,0,0,0  0           000f,0,0,0  0,8000,0,0  0,4000,0,0  0           0           0           0
cyberbal    1   1   1   0   0   0   1   1k  0   0   0x600   0x100   0   0,0,07f8,0  7fff,0,0,0  0           0,0,0,000f  0,0,0,ffc0  0,ff80,0,0  0           0,000f,0,0  8000,0,0,0  0           0           0,0,0,0010  0           0
eprom       0   1   1   0   1   0   0   8   0   0   0x100   0x100   0   03ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0,0,0,0008  0           0,0,0070,0  0           0           0
guts        0   1   1   0   0   0   0   8   0   0   0x100   0x100   0   03ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,000f  0,8000,0,0  0           0,0,0070,0  0           0           0
gauntlet    0   1   1   1   0   0   0   8   1   0   0x100   0x100   0   0,0,0,03ff  7fff,0,0,0  0           0,000f,0,0  0,ff80,0,0  0,0,ff80,0  0,0,0038,0  0,0,0007,0  0,0,0040,0  0           0           0           0           0
klax        1   1   1   0   0   0   0   8   0   0   0x000   0x100   0   00ff,0,0,0  0,0fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0,0,0,0008  0           0           0           0           0
offtwall    0   1   1   0   0   0   0   8   0   0   0x100   0x100   0   00ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0,8000,0,0  0           0           0           0           0
rampart     0   1   1   0   0   0   0   8   0   0   0x100   0x100   0   00ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0,8000,0,0  0           0           0           0           0
relief      1   1   1   0   0   0   0   8   0   0   0x100   0x100   0   00ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0,8000,0,0  0           0           0           0           0
shuuz       1   1   1   0   0   0   0   8   0   0   0x000   0x100   0   00ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0,8000,0,0  0           0           0           0           0
skullxbo    0   2   1   0   0   0   0   8   0   0   0x000   0x200   0   00ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ffc0,0  0,0,0,ff80  0,0,0,0070  0,0,0,000f  0,8000,0,0  0           0,0,0030,0  0           0           0
thunderj    1   1   1   0   1   0   0   8   0   0   0x100   0x100   0   03ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0,8000,0,0  0           0,0,0070,0  0           0           0
toobin      1   1   1   0   0   1   0   1k  0   0   0x100   0x100   0   0,0,00ff,0  0,3fff,0,0  0           0,0,0,000f  0,0,0,ffc0  7fc0,0,0,0  0007,0,0,0  0038,0,0,0  0,4000,0,0  0,8000,0,0  0           0           8000,0,0,0  0
vindictr    0   1   1   0   0   0   0   8   0   0   0x100   0x100   0   0,0,0,03ff  7fff,0,0,0  0           0,000f,0,0  0,ff80,0,0  0,0,ff80,0  0,0,0038,0  0,0,0007,0  0,0,0040,0  0           0,0070,0,0  0           0           0
xybots      1   1   0   0   0   0   0   0   0   0   0x100   0x300   0   003f,0,0,0  3fff,0,0,0  0           0,0,0,000f  0,0,0,ff80  0,0,ff80,0  0           0,0,0007,0  8000,0,0,0  0           0,000f,0,0  0           0           0



Sorted

atarisy1    0   8   1   1   0   0   0   0   0   x38 0x100   0x100   0   0,0,0,003f  0,ffff,0,0  0           0,ff00,0,0  0,0,3fe0,0  3fe0,0,0,0  0           000f,0,0,0  8000,0,0,0  0           0,0,8000,0  0           0           0,ffff,0,0  == ffff

atarisy2    1   1   1   0   0   0   0   0   0   0   0x000   0x040   15  0,0,0,07f8  0,07ff,0,0  0007,0,0,0  0,0,0,3000  0,0,ffc0,0  7fc0,0,0,0  0           0,3800,0,0  0,4000,0,0  0           0,0,0,c000  0,8000,0,0  0           0

toobin      1   1   1   0   0   1   0   1k  0   0   0x100   0x100   0   0,0,00ff,0  0,3fff,0,0  0           0,0,0,000f  0,0,0,ffc0  7fc0,0,0,0  0007,0,0,0  0038,0,0,0  0,4000,0,0  0,8000,0,0  0           0           8000,0,0,0  0

gauntlet    0   1   1   1   0   0   0   8   1   0   0x100   0x100   0   0,0,0,03ff  7fff,0,0,0  0           0,000f,0,0  0,ff80,0,0  0,0,ff80,0  0,0,0038,0  0,0,0007,0  0,0,0040,0  0           0           0           0           0
vindictr    0   1   1   0   0   0   0   8   0   0   0x100   0x100   0   0,0,0,03ff  7fff,0,0,0  0           0,000f,0,0  0,ff80,0,0  0,0,ff80,0  0,0,0038,0  0,0,0007,0  0,0,0040,0  0           0,0070,0,0  0           0           0

xybots      1   1   0   0   0   0   0   0   0   0   0x100   0x300   0   003f,0,0,0  3fff,0,0,0  0           0,0,0,000f  0,0,0,ff80  0,0,ff80,0  0           0,0,0007,0  8000,0,0,0  0           0,000f,0,0  0           0           0

blstroid    1   1   1   0   0   0   0   0   0   0   0x000   0x100   0   0,0,0ff8,0  0,3fff,0,0  0           0,0,0,000f  0,0,0,ffc0  ff80,0,0,0  0           000f,0,0,0  0,8000,0,0  0,4000,0,0  0           0           0           0

badlands    1   1   0   1   0   0   0   0   0   0   0x080   0x080   0   003f,0,0,0  0fff,0,0,0  0           0,0,0,0007  0,0,0,ff80  0,ff80,0,0  0           0,000f,0,0  0           0           0,0,0,0008  0           0           0
cyberbal    1   1   1   0   0   0   1   1k  0   0   0x600   0x100   0   0,0,07f8,0  7fff,0,0,0  0           0,0,0,000f  0,0,0,ffc0  0,ff80,0,0  0           0,000f,0,0  8000,0,0,0  0           0           0,0,0,0010  0           0

batman      1   1   1   0   1   0   0   8   0   0   0x100   0x100   0   03ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0,8000,0,0  0           0,0,0070,0  0           0           0
eprom       0   1   1   0   1   0   0   8   0   0   0x100   0x100   0   03ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0,0,0,0008  0           0,0,0070,0  0           0           0
guts        0   1   1   0   0   0   0   8   0   0   0x100   0x100   0   03ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,000f  0,8000,0,0  0           0,0,0070,0  0           0           0
skullxbo    0   2   1   0   0   0   0   8   0   0   0x000   0x200   0   00ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ffc0,0  0,0,0,ff80  0,0,0,0070  0,0,0,000f  0,8000,0,0  0           0,0,0030,0  0           0           0
thunderj    1   1   1   0   1   0   0   8   0   0   0x100   0x100   0   03ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0,8000,0,0  0           0,0,0070,0  0           0           0
arcadecl    0   1   1   0   0   0   0   0   0   0   0x100   0x100   0   00ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0           0           0           0           0           0
klax        1   1   1   0   0   0   0   8   0   0   0x000   0x100   0   00ff,0,0,0  0,0fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0,0,0,0008  0           0           0           0           0
offtwall    0   1   1   0   0   0   0   8   0   0   0x100   0x100   0   00ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0,8000,0,0  0           0           0           0           0
rampart     0   1   1   0   0   0   0   8   0   0   0x100   0x100   0   00ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0,8000,0,0  0           0           0           0           0
relief      1   1   1   0   0   0   0   8   0   0   0x100   0x100   0   00ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0,8000,0,0  0           0           0           0           0
shuuz       1   1   1   0   0   0   0   8   0   0   0x000   0x100   0   00ff,0,0,0  0,7fff,0,0  0           0,0,000f,0  0,0,ff80,0  0,0,0,ff80  0,0,0,0070  0,0,0,0007  0,8000,0,0  0           0           0           0           0

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

#include "emu.h"
#include "atarimo.h"
#include "screen.h"


//**************************************************************************
//  INLINE FUNCTIONS
//**************************************************************************

//-------------------------------------------------
//  compute_log: Computes the number of bits
//  necessary to hold a given value. The input must
//  be an even power of two.
//-------------------------------------------------

inline int atari_motion_objects_device::compute_log(int value)
{
	int log = 0;

	if (value == 0)
		return -1;
	while (!(value & 1))
		log++, value >>= 1;
	if (value != 1)
		return -1;
	return log;
}


//-------------------------------------------------
//  round_to_powerof2: Rounds a number up to the
//  nearest power of 2. Even powers of 2 are
//  rounded up to the next greatest power
//  (e.g., 4 returns 8).
//-------------------------------------------------

inline int atari_motion_objects_device::round_to_powerof2(int value)
{
	int log = 0;

	if (value == 0)
		return 1;
	while ((value >>= 1) != 0)
		log++;
	return 1 << (log + 1);
}



//**************************************************************************
//  CORE IMPLEMENTATION
//**************************************************************************

// device type definition
DEFINE_DEVICE_TYPE(ATARI_MOTION_OBJECTS, atari_motion_objects_device, "atarimo", "Atari Motion Objects")

//-------------------------------------------------
//  atari_motion_objects_device - constructor
//-------------------------------------------------

atari_motion_objects_device::atari_motion_objects_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: sprite16_device_ind16(mconfig, ATARI_MOTION_OBJECTS, tag, owner)
	, device_video_interface(mconfig, *this)
	, m_tilewidth(0)
	, m_tileheight(0)
	, m_tilexshift(0)
	, m_tileyshift(0)
	, m_bitmapwidth(0)
	, m_bitmapheight(0)
	, m_bitmapxmask(0)
	, m_bitmapymask(0)
	, m_entrycount(0)
	, m_entrybits(0)
	, m_spriterammask(0)
	, m_spriteramsize(0)
	, m_slipshift(0)
	, m_sliprammask(0)
	, m_slipramsize(0)
	, m_bank(0)
	, m_xscroll(0)
	, m_yscroll(0)
	, m_slipram(*this, "slip")
	, m_activelast(nullptr)
	, m_last_xpos(0)
	, m_next_xpos(0)
	, m_gfxdecode(*this, finder_base::DUMMY_TAG)
{
}

//-------------------------------------------------
//  draw: Render the motion objects to the
//  destination bitmap.
//-------------------------------------------------

void atari_motion_objects_device::draw(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
	// compute start/stop bands
	int startband = ((cliprect.min_y + m_yscroll - m_slipoffset) & m_bitmapymask) >> m_slipshift;
	int stopband = ((cliprect.max_y + m_yscroll - m_slipoffset) & m_bitmapymask) >> m_slipshift;
	if (startband > stopband)
		startband -= m_bitmapheight >> m_slipshift;
	if (m_slipshift == 0)
		stopband = startband;

	// loop over SLIP bands
	for (int band = startband; band <= stopband; band++)
	{
		// compute the starting link and clip for the current band
		rectangle bandclip = cliprect;
		int link = 0;
		if (m_slipshift != 0)
		{
			// extract the link from the SLIP RAM
			link = (m_slipram[band & m_sliprammask] >> m_linkmask.shift()) & m_linkmask.mask();

			// compute minimum Y and wrap around if necessary
			bandclip.min_y = ((band << m_slipshift) - m_yscroll + m_slipoffset) & m_bitmapymask;
			if (bandclip.min_y >= bitmap.height())
				bandclip.min_y -= m_bitmapheight;

			// maximum Y is based on the minimum
			bandclip.max_y = bandclip.min_y + (1 << m_slipshift) - 1;

			// keep within the cliprect
			bandclip &= cliprect;
		}

		// if this matches the last link, we don't need to re-process the list
		build_active_list(link);

		// initialize the parameters
		m_next_xpos = 123456;

		// safety check
		if (m_activelist == m_activelast)
			continue;

		// set the start and end points
		uint16_t *first, *last;
		int step;
		if (m_reverse)
		{
			first = m_activelast - 4;
			last = m_activelist;
			step = -4;
		}
		else
		{
			first = m_activelist;
			last = m_activelast - 4;
			step = 4;
		}

		// render the mos
		for (uint16_t *current = first; ; current += step)
		{
			render_object(bitmap, bandclip, current);
			if (current == last)
				break;
		}
	}
}


//-------------------------------------------------
//  apply_stain: Mark high palette bits
//  starting at the given X,Y and continuing until
//  a stop or the end of line.
//-------------------------------------------------

void atari_motion_objects_device::apply_stain(bitmap_ind16 &bitmap, uint16_t *pf, uint16_t *mo, int x, int y)
{
	const uint16_t START_MARKER = ((4 << PRIORITY_SHIFT) | 2);
	const uint16_t END_MARKER =   ((4 << PRIORITY_SHIFT) | 4);
	bool offnext = false;

	for ( ; x < bitmap.width(); x++)
	{
		pf[x] |= 0x400;
		if (offnext && ((mo[x] == 0xffff) || (mo[x] & START_MARKER) != START_MARKER))
			break;
		offnext = (mo[x] != 0xffff) && ((mo[x] & END_MARKER) == END_MARKER);
	}
}


//-------------------------------------------------
//  device_start: Start up the device
//-------------------------------------------------

void atari_motion_objects_device::device_start()
{
	// call parent
	sprite16_device_ind16::device_start();

	// verify configuration
	gfx_element *gfx = m_gfxdecode->gfx(m_gfxindex);
	if (gfx == nullptr)
		throw emu_fatalerror("No gfxelement #%d!", m_gfxindex);

	// determine the masks
	m_linkmask.set(m_link_entry);
	m_codemask.set(m_code_entry);
	m_colormask.set(m_color_entry);
	m_xposmask.set(m_xpos_entry);
	m_yposmask.set(m_ypos_entry);
	m_widthmask.set(m_width_entry);
	m_heightmask.set(m_height_entry);
	m_hflipmask.set(m_hflip_entry);
	m_vflipmask.set(m_vflip_entry);
	m_prioritymask.set(m_priority_entry);
	m_neighbormask.set(m_neighbor_entry);
	m_absolutemask.set(m_absolute_entry);

	// derive tile information
	m_tilewidth = gfx->width();
	m_tileheight = gfx->height();
	m_tilexshift = compute_log(m_tilewidth);
	m_tileyshift = compute_log(m_tileheight);

	// derive bitmap information
	m_bitmapwidth = round_to_powerof2(m_xposmask.mask());
	m_bitmapheight = round_to_powerof2(m_yposmask.mask());
	m_bitmapxmask = m_bitmapwidth - 1;
	m_bitmapymask = m_bitmapheight - 1;

	// derive sprite information
	m_entrycount = round_to_powerof2(m_linkmask.mask());
	m_entrybits = compute_log(m_entrycount);
	m_spriteramsize = m_bankcount * m_entrycount;
	m_spriterammask = m_spriteramsize - 1;
	m_slipshift = (m_slipheight != 0) ? compute_log(m_slipheight) : 0;
	m_slipramsize = m_bitmapheight >> m_slipshift;
	m_sliprammask = m_slipramsize - 1;
	if (m_maxperline == 0)
		m_maxperline = MAX_PER_BANK;

	// allocate and initialize the code lookup
	int codesize = round_to_powerof2(m_codemask.mask());
	m_codelookup.resize(codesize);
	for (int i = 0; i < codesize; i++)
		m_codelookup[i] = i;

	// allocate and initialize the color lookup
	int colorsize = round_to_powerof2(m_colormask.mask());
	m_colorlookup.resize(colorsize);
	for (int i = 0; i < colorsize; i++)
		m_colorlookup[i] = i;

	// allocate and the gfx lookup
	int gfxsize = codesize / 256;
	m_gfxlookup.resize(gfxsize);
	for (int i = 0; i < gfxsize; i++)
		m_gfxlookup[i] = m_gfxindex;

	// allocate a timer to periodically force update
	m_force_update_timer = timer_alloc(TID_FORCE_UPDATE);
	m_force_update_timer->adjust(screen().time_until_pos(0));

	// register for save states
	save_item(NAME(m_bank));
	save_item(NAME(m_xscroll));
	save_item(NAME(m_yscroll));
}


//-------------------------------------------------
//  device_reset: Handle a device reset by
//  clearing the interrupt lines and states
//-------------------------------------------------

void atari_motion_objects_device::device_reset()
{
	// call parent
	sprite16_device_ind16::device_reset();

	// reset the live state
	m_bank = 0;
}


//-------------------------------------------------
//  device_timer: Handle device-specific timer
//  calbacks
//-------------------------------------------------

void atari_motion_objects_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
	switch (id)
	{
		case TID_FORCE_UPDATE:
			if (param > 0)
				screen().update_partial(param - 1);
			param += 64;
			if (param >= screen().visible_area().max_y)
				param = 0;
			timer.adjust(screen().time_until_pos(param), param);
			break;
	}
}


//-------------------------------------------------
//  build_active_list: Build a list of active
//  objects.
//-------------------------------------------------

void atari_motion_objects_device::build_active_list(int link)
{
	uint16_t *bankbase = &spriteram()[m_bank << (m_entrybits + 2)];
	uint16_t *current = &m_activelist[0];

	// visit all the motion objects and copy their data into the display list
	uint8_t visited[MAX_PER_BANK] = {0};
	for (int i = 0; i < m_maxperline && !visited[link]; i++)
	{
		// copy the current entry into the list
		uint16_t *modata = current;
		if (!m_split)
		{
			uint16_t *srcdata = &bankbase[link * 4];
			*current++ = srcdata[0];
			*current++ = srcdata[1];
			*current++ = srcdata[2];
			*current++ = srcdata[3];
		}
		else
		{
			uint16_t *srcdata = &bankbase[link];
			*current++ = srcdata[uint32_t(0 << m_entrybits)];
			*current++ = srcdata[uint32_t(1 << m_entrybits)];
			*current++ = srcdata[uint32_t(2 << m_entrybits)];
			*current++ = srcdata[uint32_t(3 << m_entrybits)];
		}

		// link to the next object
		visited[link] = 1;
		if (m_linked)
			link = m_linkmask.extract(modata);
		else
			link = (link + 1) & m_linkmask.mask();
	}

	// note the last entry
	m_activelast = current;
}


//-------------------------------------------------
//  render_object: Internal processing callback
//  that renders to the backing bitmap and then
//  copies the result  to the destination.
//-------------------------------------------------

void atari_motion_objects_device::render_object(bitmap_ind16 &bitmap, const rectangle &cliprect, const uint16_t *entry)
{
	// select the gfx element and save off key information
	int rawcode = m_codemask.extract(entry);
	gfx_element *gfx = m_gfxdecode->gfx(m_gfxlookup[rawcode >> 8]);
	int save_granularity = gfx->granularity();
	int save_colorbase = gfx->colorbase();
	int save_colors = gfx->colors();
	gfx->set_granularity(1);
	gfx->set_colorbase(0);
	gfx->set_colors(65536);

	// extract data from the various words
	int code = m_codelookup[rawcode];
	int color = m_colorlookup[m_colormask.extract(entry)];
	int xpos = m_xposmask.extract(entry);
	int ypos = -m_yposmask.extract(entry);
	int hflip = m_hflipmask.extract(entry);
	int vflip = m_vflipmask.extract(entry);
	int width = m_widthmask.extract(entry) + 1;
	int height = m_heightmask.extract(entry) + 1;
	int priority = m_prioritymask.extract(entry);

	// compute the effective color, merging in priority
	color = (color * save_granularity) | (priority << PRIORITY_SHIFT);
	color += m_palettebase;

	// add in the scroll positions if we're not in absolute coordinates
	if (!m_absolutemask.extract(entry))
	{
		xpos -= m_xscroll;
		ypos -= m_yscroll;
	}

	// adjust for height
	ypos -= height << m_tileyshift;

	// handle previous hold bits
	if (m_next_xpos != 123456)
		xpos = m_next_xpos;
	m_next_xpos = 123456;

	// check for the hold bit
	if (m_neighbormask.extract(entry) != 0)
	{
		if (!m_nextneighbor)
			xpos = m_last_xpos + m_tilewidth;
		else
			m_next_xpos = xpos + m_tilewidth;
	}
	m_last_xpos = xpos;

	// adjust the final coordinates
	xpos &= m_bitmapxmask;
	ypos &= m_bitmapymask;
	if (xpos >= bitmap.width())
		xpos -= m_bitmapwidth;
	if (ypos >= bitmap.height())
		ypos -= m_bitmapheight;

	// is this one special?
	if (m_specialmask.mask() == 0 || m_specialmask.extract(entry) != m_specialvalue)
	{
		// adjust for h flip
		int xadv = m_tilewidth;
		if (hflip)
		{
			xpos += (width - 1) << m_tilexshift;
			xadv = -xadv;
		}

		// adjust for v flip
		int yadv = m_tileheight;
		if (vflip)
		{
			ypos += (height - 1) << m_tileyshift;
			yadv = -yadv;
		}

		// standard order is: loop over Y first, then X
		if (!m_swapxy)
		{
			// loop over the height
			for (int y = 0, sy = ypos; y < height; y++, sy += yadv)
			{
				// clip the Y coordinate
				if (sy <= cliprect.min_y - m_tileheight)
				{
					code += width;
					continue;
				}
				else if (sy > cliprect.max_y)
					break;

				// loop over the width
				for (int x = 0, sx = xpos; x < width; x++, sx += xadv, code++)
				{
					// clip the X coordinate
					if (sx <= -cliprect.min_x - m_tilewidth || sx > cliprect.max_x)
						continue;

					// draw the sprite
					gfx->transpen_raw(bitmap,cliprect, code, color, hflip, vflip, sx, sy, m_transpen);
					mark_dirty(sx, sx + m_tilewidth - 1, sy, sy + m_tileheight - 1);
				}
			}
		}

		// alternative order is swapped
		else
		{
			// loop over the width
			for (int x = 0, sx = xpos; x < width; x++, sx += xadv)
			{
				// clip the X coordinate
				if (sx <= cliprect.min_x - m_tilewidth)
				{
					code += height;
					continue;
				}
				else if (sx > cliprect.max_x)
					break;

				// loop over the height
				for (int y = 0, sy = ypos; y < height; y++, sy += yadv, code++)
				{
					// clip the X coordinate
					if (sy <= -cliprect.min_y - m_tileheight || sy > cliprect.max_y)
						continue;

					// draw the sprite
					gfx->transpen_raw(bitmap,cliprect, code, color, hflip, vflip, sx, sy, m_transpen);
					mark_dirty(sx, sx + m_tilewidth - 1, sy, sy + m_tileheight - 1);
				}
			}
		}
	}

	// restore original gfx information
	gfx->set_granularity(save_granularity);
	gfx->set_colorbase(save_colorbase);
	gfx->set_colors(save_colors);
}



//**************************************************************************
//  SPRITE PARAMETER
//**************************************************************************

//-------------------------------------------------
//  sprite_parameter: Constructor
//-------------------------------------------------

atari_motion_objects_device::sprite_parameter::sprite_parameter()
	: m_word(0),
	m_shift(0),
	m_mask(0)
{
}


//-------------------------------------------------
//  set: Sets the mask via an input 4-word mask.
//-------------------------------------------------

bool atari_motion_objects_device::sprite_parameter::set(const uint16_t input[4])
{
	// determine the word and make sure it's only 1
	m_word = 0xffff;
	for (int i = 0; i < 4; i++)
		if (input[i])
		{
			if (m_word == 0xffff)
				m_word = i;
			else
				return false;
		}

	// if all-zero, it's valid
	if (m_word == 0xffff)
	{
		m_word = m_shift = m_mask = 0;
		return true;
	}

	// determine the shift and final mask
	m_shift = 0;
	uint16_t temp = input[m_word];
	while (!(temp & 1))
	{
		m_shift++;
		temp >>= 1;
	}
	m_mask = temp;
	return true;
}


//-------------------------------------------------
//  dual_sprite_parameter: Constructor
//-------------------------------------------------

atari_motion_objects_device::dual_sprite_parameter::dual_sprite_parameter()
	: m_uppershift(0)
{
}


//-------------------------------------------------
//  set: Sets the mask via an input 4-word mask.
//-------------------------------------------------

bool atari_motion_objects_device::dual_sprite_parameter::set(const atari_motion_objects_config::dual_entry &input)
{
	// convert the lower and upper parts
	if (!m_lower.set(input.data_lower))
		return false;
	if (!m_upper.set(input.data_upper))
		return false;

	// determine the upper shift amount
	uint16_t temp = m_lower.mask();
	m_uppershift = 0;
	while (temp != 0)
	{
		m_uppershift++;
		temp >>= 1;
	}
	return true;
}