summaryrefslogblamecommitdiffstatshomepage
path: root/src/emu/crsshair.cpp
blob: d976e49714f8301d841a5061b27219c6d6419724 (plain) (tree)
1
2
3
4
5
6
7
8
9
                       
                                

                                                                            
              

                       

                                                                            

                    
                     

                    
                     






                                                                            

                                                              


                                                                            


                                                                            

























































                                                                         






                              

  


                                                                            
 








                                                                                                                
 

                                                            
 
                                            

                                                                 
                                                                          
                         
                                                            
 
                                                             
 







                                                                                                                              
 























                                                                                                                                                                                                                  


                                           





                                                   
                                                 
 


                                               
 
                                                                      
                                          
                                                                     
                                                                                               
         
 

                                                                                 

                                                  

                                                                                 




                                                                      
                                                                                                 

                                                                 

                                                                                         
         
 
                                                       
                                       

                                                           

                                                                                   
 



                                                              

                                                                                             



                                                                                                              
                                                                                                 
                 
         
 
                                      
                                                                                                         

 
                                                   
                                  


                                                   
 
                                                                                          
 



                                               



                                                   
                                  



                                                   
                                                                                          
 


                                          


                                                  
                                                                                       

                                               

                                                             
                         
                                      






                                                   
                                                                         
 
                   
 


                                                                 

                                         
                                    

                                                                    

                                                                              
            
                                                                              
 
                                                        

                                                  

                                                                                                       

                                     
                                                                
                 
                                                                                                   

                                                                                 



                                                               



                                                                                              
                                                                                    
                                                                                                  
                                                                                       
                                                                          
                                                                                       
                                                                  

                                                                      
                                                 


                         



                                                   
                                  


                                                   
                                                     


                   

                                                          

                                                                                                      

                                                                                    



                                                                                                                                        
                 
 
 
                                                   
                                              


                                                   
                                                                                    






                                                                             
                                                      


                                     
                                  










                                                                                                                                                               
                                                                         




                                                                                                          
                                                             

                                                                          
                                                                                                     


                                                                                           
                                                                                                                               
                                           
                                              




                                                                       
                                     


                                                                                                                         
                                                       




                                                   
                                   


                                                   
                                                                                    






                                                                              
                                                      



                                                        
                                   

                                           
                                                                                        
 
                                                     




                                                                                       
                                                                                      
                                 
                                                                                                     



                                                                                         
                                                           
                                 
                                                                                                










                                                                                      
                                                                 

                                   
                                                                               
 
                                             
                                                                                 


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

    crsshair.c

    Crosshair handling.
***************************************************************************/

#include "emu.h"
#include "emuopts.h"
#include "rendutil.h"
#include "config.h"
#include "xmlfile.h"
#include "crsshair.h"



/***************************************************************************
    CONSTANTS
***************************************************************************/

#define CROSSHAIR_RAW_SIZE      100
#define CROSSHAIR_RAW_ROWBYTES  ((CROSSHAIR_RAW_SIZE + 7) / 8)


/***************************************************************************
    GLOBAL VARIABLES
***************************************************************************/

/* raw bitmap */
static const UINT8 crosshair_raw_top[] =
{
	0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,
	0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x00,
	0x00,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xf0,0x00,
	0x01,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xf8,0x00,
	0x03,0xfc,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xfc,0x00,
	0x07,0xfe,0x00,0x00,0x00,0x0f,0xfe,0x00,0x00,0x00,0x07,0xfe,0x00,
	0x0f,0xff,0x00,0x00,0x01,0xff,0xff,0xf0,0x00,0x00,0x0f,0xff,0x00,
	0x1f,0xff,0x80,0x00,0x1f,0xff,0xff,0xff,0x00,0x00,0x1f,0xff,0x80,
	0x3f,0xff,0x80,0x00,0xff,0xff,0xff,0xff,0xe0,0x00,0x1f,0xff,0xc0,
	0x7f,0xff,0xc0,0x03,0xff,0xff,0xff,0xff,0xf8,0x00,0x3f,0xff,0xe0,
	0xff,0xff,0xe0,0x07,0xff,0xff,0xff,0xff,0xfc,0x00,0x7f,0xff,0xf0,
	0x7f,0xff,0xf0,0x1f,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xe0,
	0x3f,0xff,0xf8,0x7f,0xff,0xff,0xff,0xff,0xff,0xc1,0xff,0xff,0xc0,
	0x0f,0xff,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xe1,0xff,0xff,0x00,
	0x07,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfb,0xff,0xfe,0x00,
	0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0x00,
	0x01,0xff,0xff,0xff,0xff,0xf0,0x01,0xff,0xff,0xff,0xff,0xf8,0x00,
	0x00,0x7f,0xff,0xff,0xff,0x00,0x00,0x1f,0xff,0xff,0xff,0xe0,0x00,
	0x00,0x3f,0xff,0xff,0xf8,0x00,0x00,0x03,0xff,0xff,0xff,0xc0,0x00,
	0x00,0x1f,0xff,0xff,0xe0,0x00,0x00,0x00,0xff,0xff,0xff,0x80,0x00,
	0x00,0x0f,0xff,0xff,0x80,0x00,0x00,0x00,0x3f,0xff,0xff,0x00,0x00,
	0x00,0x03,0xff,0xfe,0x00,0x00,0x00,0x00,0x0f,0xff,0xfc,0x00,0x00,
	0x00,0x01,0xff,0xfc,0x00,0x00,0x00,0x00,0x07,0xff,0xf8,0x00,0x00,
	0x00,0x03,0xff,0xf8,0x00,0x00,0x00,0x00,0x01,0xff,0xf8,0x00,0x00,
	0x00,0x07,0xff,0xfc,0x00,0x00,0x00,0x00,0x03,0xff,0xfc,0x00,0x00,
	0x00,0x0f,0xff,0xfe,0x00,0x00,0x00,0x00,0x07,0xff,0xfe,0x00,0x00,
	0x00,0x0f,0xff,0xff,0x00,0x00,0x00,0x00,0x0f,0xff,0xfe,0x00,0x00,
	0x00,0x1f,0xff,0xff,0x80,0x00,0x00,0x00,0x1f,0xff,0xff,0x00,0x00,
	0x00,0x1f,0xff,0xff,0x80,0x00,0x00,0x00,0x1f,0xff,0xff,0x00,0x00,
	0x00,0x3f,0xfe,0xff,0xc0,0x00,0x00,0x00,0x3f,0xff,0xff,0x80,0x00,
	0x00,0x7f,0xfc,0x7f,0xe0,0x00,0x00,0x00,0x7f,0xe7,0xff,0xc0,0x00,
	0x00,0x7f,0xf8,0x3f,0xf0,0x00,0x00,0x00,0xff,0xc3,0xff,0xc0,0x00,
	0x00,0xff,0xf8,0x1f,0xf8,0x00,0x00,0x01,0xff,0x83,0xff,0xe0,0x00,
	0x00,0xff,0xf0,0x07,0xf8,0x00,0x00,0x01,0xfe,0x01,0xff,0xe0,0x00,
	0x00,0xff,0xf0,0x03,0xfc,0x00,0x00,0x03,0xfc,0x01,0xff,0xe0,0x00,
	0x01,0xff,0xe0,0x01,0xfe,0x00,0x00,0x07,0xf8,0x00,0xff,0xf0,0x00,
	0x01,0xff,0xe0,0x00,0xff,0x00,0x00,0x0f,0xf0,0x00,0xff,0xf0,0x00,
	0x01,0xff,0xc0,0x00,0x3f,0x80,0x00,0x1f,0xc0,0x00,0x7f,0xf0,0x00,
	0x01,0xff,0xc0,0x00,0x1f,0x80,0x00,0x1f,0x80,0x00,0x7f,0xf0,0x00,
	0x03,0xff,0xc0,0x00,0x0f,0xc0,0x00,0x3f,0x00,0x00,0x7f,0xf8,0x00,
	0x03,0xff,0x80,0x00,0x07,0xe0,0x00,0x7e,0x00,0x00,0x3f,0xf8,0x00,
	0x03,0xff,0x80,0x00,0x01,0xf0,0x00,0xf8,0x00,0x00,0x3f,0xf8,0x00,
	0x03,0xff,0x80,0x00,0x00,0xf8,0x01,0xf0,0x00,0x00,0x3f,0xf8,0x00,
	0x03,0xff,0x80,0x00,0x00,0x78,0x01,0xe0,0x00,0x00,0x3f,0xf8,0x00,
	0x07,0xff,0x00,0x00,0x00,0x3c,0x03,0xc0,0x00,0x00,0x3f,0xfc,0x00,
	0x07,0xff,0x00,0x00,0x00,0x0e,0x07,0x00,0x00,0x00,0x1f,0xfc,0x00,
	0x07,0xff,0x00,0x00,0x00,0x07,0x0e,0x00,0x00,0x00,0x1f,0xfc,0x00,
	0x07,0xff,0x00,0x00,0x00,0x03,0x9c,0x00,0x00,0x00,0x1f,0xfc,0x00,
	0x07,0xff,0x00,0x00,0x00,0x01,0x98,0x00,0x00,0x00,0x1f,0xfc,0x00,
	0x07,0xff,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x1f,0xfc,0x00
};

/* per-player colors */
static const rgb_t crosshair_colors[] =
{
	rgb_t(0x40,0x40,0xff),
	rgb_t(0xff,0x40,0x40),
	rgb_t(0x40,0xff,0x40),
	rgb_t(0xff,0xff,0x40),
	rgb_t(0xff,0x40,0xff),
	rgb_t(0x40,0xff,0xff),
	rgb_t(0xff,0xff,0xff)
};

//**************************************************************************
//  CROSSHAIR MANAGER
//**************************************************************************

//-------------------------------------------------
//  crosshair_manager - constructor
//-------------------------------------------------

crosshair_manager::crosshair_manager(running_machine &machine)
	: m_machine(machine)
{
	/* request a callback upon exiting */
	machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(crosshair_manager::exit), this));

	/* setup the default auto visibility time */
	m_auto_time = CROSSHAIR_VISIBILITY_AUTOTIME_DEFAULT;

	/* determine who needs crosshairs */
	for (auto &port : machine.ioport().ports())
		for (ioport_field &field : port.second->fields())
			if (field.crosshair_axis() != CROSSHAIR_AXIS_NONE)
			{
				int player = field.player();

				assert(player < MAX_PLAYERS);

				/* mark as used and set the default visibility and mode */
				m_usage = TRUE;
				m_used[player] = TRUE;
				m_mode[player] = CROSSHAIR_VISIBILITY_DEFAULT;
				m_visible[player] = (CROSSHAIR_VISIBILITY_DEFAULT == CROSSHAIR_VISIBILITY_OFF) ? FALSE : TRUE;

				/* for now, use the main screen */
				m_screen[player] = machine.first_screen();

				create_bitmap(player);
			}

	/* register callbacks for when we load/save configurations */
	if (m_usage)
		machine.configuration().config_register("crosshairs", config_saveload_delegate(FUNC(crosshair_manager::config_load), this), config_saveload_delegate(FUNC(crosshair_manager::config_save), this));

	/* register the animation callback */
	if (machine.first_screen() != nullptr)
		machine.first_screen()->register_vblank_callback(vblank_state_delegate(FUNC(crosshair_manager::animate), this));
}

/*-------------------------------------------------
exit - free memory allocated for
the crosshairs
-------------------------------------------------*/

void crosshair_manager::exit()
{
	/* free bitmaps and textures for each player */
	for (int player = 0; player < MAX_PLAYERS; player++)
	{
		machine().render().texture_free(m_texture[player]);
		m_texture[player] = nullptr;
		m_bitmap[player] = nullptr;
	}
}

/*-------------------------------------------------
    create_bitmap - create the rendering
    structures for the given player
-------------------------------------------------*/

void crosshair_manager::create_bitmap(int player)
{
	int x, y;
	char filename[20];
	rgb_t color = crosshair_colors[player];

	/* if we have a bitmap and texture for this player, kill it */
	if (m_bitmap[player] == nullptr) {
		m_bitmap[player] = std::make_unique<bitmap_argb32>();
		m_texture[player] = machine().render().texture_alloc(render_texture::hq_scale);
	}

	emu_file crossfile(machine().options().crosshair_path(), OPEN_FLAG_READ);
	if (m_name[player][0] != 0)
	{
		/* look for user specified file */
		sprintf(filename, "%s.png", m_name[player]);
		render_load_png(*m_bitmap[player], crossfile, nullptr, filename);
	}
	else
	{
		/* look for default cross?.png in crsshair\game dir */
		sprintf(filename, "cross%d.png", player + 1);
		render_load_png(*m_bitmap[player], crossfile, machine().system().name, filename);

		/* look for default cross?.png in crsshair dir */
		if (!m_bitmap[player]->valid())
			render_load_png(*m_bitmap[player], crossfile, nullptr, filename);
	}

	/* if that didn't work, use the built-in one */
	if (!m_bitmap[player]->valid())
	{
		/* allocate a blank bitmap to start with */
		m_bitmap[player]->allocate(CROSSHAIR_RAW_SIZE, CROSSHAIR_RAW_SIZE);
		m_bitmap[player]->fill(rgb_t(0x00,0xff,0xff,0xff));

		/* extract the raw source data to it */
		for (y = 0; y < CROSSHAIR_RAW_SIZE / 2; y++)
		{
			/* assume it is mirrored vertically */
			UINT32 *dest0 = &m_bitmap[player]->pix32(y);
			UINT32 *dest1 = &m_bitmap[player]->pix32(CROSSHAIR_RAW_SIZE - 1 - y);

			/* extract to two rows simultaneously */
			for (x = 0; x < CROSSHAIR_RAW_SIZE; x++)
				if ((crosshair_raw_top[y * CROSSHAIR_RAW_ROWBYTES + x / 8] << (x % 8)) & 0x80)
					dest0[x] = dest1[x] = rgb_t(0xff,0x00,0x00,0x00) | color;
		}
	}

	/* reference the new bitmap */
	m_texture[player]->set_bitmap(*m_bitmap[player], m_bitmap[player]->cliprect(), TEXFORMAT_ARGB32);
}

/*-------------------------------------------------
    get_user_settings - return the
    current crosshair settings for a player
    Note: auto_time is common for all players
-------------------------------------------------*/

void crosshair_manager::get_user_settings(UINT8 player, crosshair_user_settings *settings)
{
	settings->auto_time = m_auto_time;
	settings->used = m_used[player];
	settings->mode = m_mode[player];
	strcpy(settings->name, m_name[player]);
}


/*-------------------------------------------------
    set_user_settings - modify the
    current crosshair settings for a player
    Note: auto_time is common for all players
-------------------------------------------------*/

void crosshair_manager::set_user_settings(UINT8 player, crosshair_user_settings *settings)
{
	m_auto_time = settings->auto_time;
	m_used[player] = settings->used;
	m_mode[player] = settings->mode;

	/* set visibility as specified by mode */
	/* auto mode starts with visibility off */
	m_visible[player] = (settings->mode == CROSSHAIR_VISIBILITY_ON) ? TRUE : FALSE;

	/* update bitmap if name has changed */
	int changed = strcmp(settings->name, m_name[player]);
	strcpy(m_name[player], settings->name);
	if (changed != 0)
		create_bitmap(player);
}


/*-------------------------------------------------
    animate - animates the crosshair once a frame
-------------------------------------------------*/

void crosshair_manager::animate(screen_device &device, bool vblank_state)
{
	int player;

	/* only animate once per frame, when vblank_state is 1 */
	if (!vblank_state)
		return;

	/* increment animation counter */
	m_animation_counter += 0x08;

	/* compute a fade factor from the current animation value */
	if (m_animation_counter < 0x80)
		m_fade = 0xa0 + (0x60 * ( m_animation_counter & 0x7f) / 0x80);
	else
		m_fade = 0xa0 + (0x60 * (~m_animation_counter & 0x7f) / 0x80);

	for (player = 0; player < MAX_PLAYERS; player++)
	{
		/* read all the lightgun values */
		if (m_used[player])
			device.machine().ioport().crosshair_position(player, m_x[player], m_y[player]);

		/* auto visibility */
		if (m_mode[player] == CROSSHAIR_VISIBILITY_AUTO)
		{
			if ((m_x[player] != m_last_x[player]) || (m_y[player] != m_last_y[player]))
			{
				/* crosshair has moved, keep crosshair visible */
				m_visible[player] = TRUE;
				m_last_x[player] = m_x[player];
				m_last_y[player] = m_y[player];
				m_time[player] = 0;
			}
			else
			{
				/* see if the player has been motionless for time specified */
				/* slightly confusing formula, but the effect is: */
				/* auto_time = 0 makes the crosshair barely visible while moved */
				/* every increment in auto_time is about .2s at 60Hz */
				if (m_time[player] > m_auto_time * 12 + 2)
					/* time exceeded so turn crosshair invisible */
					m_visible[player] = FALSE;

				/* increment player visibility time */
				m_time[player]++;
			}
		}
	}
}


/*-------------------------------------------------
    render - render the crosshairs
    for the given screen
-------------------------------------------------*/

void crosshair_manager::render(screen_device &screen)
{
	int player;

	for (player = 0; player < MAX_PLAYERS; player++)
		/* draw if visible and the right screen */
		if (m_visible[player] &&
			((m_screen[player] == &screen) || (m_screen[player] == CROSSHAIR_SCREEN_ALL)))
		{
			/* add a quad assuming a 4:3 screen (this is not perfect) */
			screen.container().add_quad(m_x[player] - 0.03f, m_y[player] - 0.04f,
										m_x[player] + 0.03f, m_y[player] + 0.04f,
										rgb_t(0xc0, m_fade, m_fade, m_fade),
										m_texture[player], PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA));
		}
}

/*-------------------------------------------------
    config_load - read and apply data from the
    configuration file
-------------------------------------------------*/

void crosshair_manager::config_load(config_type cfg_type, xml_data_node *parentnode)
{
	/* Note: crosshair_load() is only registered if croshairs are used */

	xml_data_node *crosshairnode;
	int auto_time;

	/* we only care about game files */
	if (cfg_type != config_type::CONFIG_TYPE_GAME)
		return;

	/* might not have any data */
	if (parentnode == nullptr)
		return;

	/* loop and get player crosshair info */
	for (crosshairnode = xml_get_sibling(parentnode->child, "crosshair"); crosshairnode; crosshairnode = xml_get_sibling(crosshairnode->next, "crosshair"))
	{
		int  player, mode;

		player = xml_get_attribute_int(crosshairnode, "player", -1);

		/* check to make sure we have a valid player */
		/* also check if the player really uses a crosshair */
		if (player >=0 && player < MAX_PLAYERS && m_used[player])
		{
			/* get, check, and store visibility mode */
			mode = xml_get_attribute_int(crosshairnode, "mode", CROSSHAIR_VISIBILITY_DEFAULT);
			if (mode >= CROSSHAIR_VISIBILITY_OFF && mode <= CROSSHAIR_VISIBILITY_AUTO)
			{
				m_mode[player] = (UINT8)mode;
				/* set visibility as specified by mode */
				/* auto mode starts with visibility off */
				m_visible[player] = (mode == CROSSHAIR_VISIBILITY_ON) ? TRUE : FALSE;
			}

			/* get and store crosshair pic name, truncate name to max length */
			strncpy(m_name[player], xml_get_attribute_string(crosshairnode, "pic", ""), CROSSHAIR_PIC_NAME_LENGTH);
			/* update bitmap */
			create_bitmap(player);
		}
	}

	/* get, check, and store auto visibility time */
	crosshairnode = xml_get_sibling(parentnode->child, "autotime");
	if (crosshairnode != nullptr)
	{
		auto_time = xml_get_attribute_int(crosshairnode, "val", CROSSHAIR_VISIBILITY_AUTOTIME_DEFAULT);
		if ((auto_time >= CROSSHAIR_VISIBILITY_AUTOTIME_MIN) && (auto_time <= CROSSHAIR_VISIBILITY_AUTOTIME_MAX))
			m_auto_time = (UINT8)auto_time;
	}
}


/*-------------------------------------------------
    config_save -  save data to the
    configuration file
-------------------------------------------------*/

void crosshair_manager::config_save(config_type cfg_type, xml_data_node *parentnode)
{
	/* Note: crosshair_save() is only registered if crosshairs are used */

	xml_data_node *crosshairnode;
	int player;

	/* we only care about game files */
	if (cfg_type != config_type::CONFIG_TYPE_GAME)
		return;

	for (player = 0; player < MAX_PLAYERS; player++)
	{
		if (m_used[player])
		{
			/* create a node */
			crosshairnode = xml_add_child(parentnode, "crosshair", nullptr);

			if (crosshairnode != nullptr)
			{
				int changed = FALSE;

				xml_set_attribute_int(crosshairnode, "player", player);

				if (m_visible[player] != CROSSHAIR_VISIBILITY_DEFAULT)
				{
					xml_set_attribute_int(crosshairnode, "mode", m_mode[player]);
					changed = TRUE;
				}

				/* the default graphic name is "", so only save if not */
				if (*(m_name[player]) != 0)
				{
					xml_set_attribute(crosshairnode, "pic", m_name[player]);
					changed = TRUE;
				}

				/* if nothing changed, kill the node */
				if (!changed)
					xml_delete_node(crosshairnode);
			}
		}
	}

	/* always store autotime so that it stays at the user value if it is needed */
	if (m_auto_time != CROSSHAIR_VISIBILITY_AUTOTIME_DEFAULT)
	{
		/* create a node */
		crosshairnode = xml_add_child(parentnode, "autotime", nullptr);

		if (crosshairnode != nullptr)
			xml_set_attribute_int(crosshairnode, "val", m_auto_time);
	}

}