summaryrefslogtreecommitdiffstats
path: root/src/devices/bus/sms_ctrl/lphaser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/sms_ctrl/lphaser.cpp')
-rw-r--r--src/devices/bus/sms_ctrl/lphaser.cpp80
1 files changed, 33 insertions, 47 deletions
diff --git a/src/devices/bus/sms_ctrl/lphaser.cpp b/src/devices/bus/sms_ctrl/lphaser.cpp
index d9fb0443ec8..7e64e7c7236 100644
--- a/src/devices/bus/sms_ctrl/lphaser.cpp
+++ b/src/devices/bus/sms_ctrl/lphaser.cpp
@@ -45,7 +45,9 @@ READ_LINE_MEMBER( sms_light_phaser_device::th_pin_r )
INPUT_CHANGED_MEMBER( sms_light_phaser_device::position_changed )
{
if (newval != oldval)
- sensor_check();
+ {
+ sensor_check(0);
+ }
}
@@ -87,7 +89,9 @@ sms_light_phaser_device::sms_light_phaser_device(const machine_config &mconfig,
device_sms_control_port_interface(mconfig, *this),
m_lphaser_pins(*this, "CTRL_PORT"),
m_lphaser_x(*this, "LPHASER_X"),
- m_lphaser_y(*this, "LPHASER_Y"), m_sensor_last_state(0), m_lphaser_timer(nullptr)
+ m_lphaser_y(*this, "LPHASER_Y"),
+ m_sensor_last_state(0),
+ m_lphaser_timer(nullptr)
{
}
@@ -99,7 +103,7 @@ sms_light_phaser_device::sms_light_phaser_device(const machine_config &mconfig,
void sms_light_phaser_device::device_start()
{
save_item(NAME(m_sensor_last_state));
- m_lphaser_timer = timer_alloc(TIMER_LPHASER);
+ m_lphaser_timer = timer_alloc(FUNC(sms_light_phaser_device::sensor_check), this);
}
@@ -121,28 +125,28 @@ uint8_t sms_light_phaser_device::peripheral_r()
/*
Light Phaser (light gun) emulation notes:
- - The sensor is activated based on color brightness of some individual
- pixels being drawn by the beam, at circular area where the gun is aiming.
+ - The sensor is activated based on the brightness of individual pixels being
+ drawn by the beam, in circular area where the gun is aiming.
- Currently, brightness is calculated based only on single pixels.
- In general, after the trigger is pressed, games draw the next frame using
- a light color pattern, to make sure sensor will be activated. If emulation
- skips that frame, sensor may stay deactivated. Frameskip set to 0 (no skip)
+ a bright pattern, to make sure the sensor will be activated. If the emulation
+ skips that frame, the sensor may stay deactivated. Setting frameskip to 0
is recommended to avoid problems.
- - When sensor switches from on (0) to off (1), a value is latched for the
+ - When the sensor switches from on (0) to off (1), a value is latched for the
HCount register.
- - When sensor switches from off to on, a flag is set. The emulation uses the
- flag to signal that TH line is activated when the status of the input port
- is read. After read, the flag is cleared, or else it is cleared later when
- the Pause status is read (end of a frame). This is necessary because the
+ - When the sensor switches from off to on, a flag is set. The emulation uses
+ this flag to signal that the TH line is activated during status reads of the
+ input port. After reading, the flag is cleared, or it is cleared when the
+ Pause status is read at the end of a frame. This is necessary because the
"Color & Switch Test" ROM only reads the TH state after VINT occurs.
- - The gun test of "Color & Switch Test" is an example that requires checks
- of sensor status independent of other events, like trigger press or TH bit
+ - The gun test in "Color & Switch Test" is an example that requires checks
+ of the sensor status independent of other events, like trigger press or TH bit
reads. Another example is the title screen of "Hang-On & Safari Hunt", where
- the game only reads HCount register in a loop, expecting a latch by the gun.
- - The whole procedure is managed by a timer callback, that always reschedule
- itself to run in some intervals when the beam is at the circular area.
+ the game only reads the HCount register in a loop, expecting a latch by the gun.
+ - The whole procedure is managed by a periodic timer callback, which is scheduled
+ to run in intervals when the beam is within the circular area.
*/
-int sms_light_phaser_device::bright_aim_area( emu_timer *timer, int lgun_x, int lgun_y )
+int sms_light_phaser_device::bright_aim_area(int lgun_x, int lgun_y)
{
const int r_x_r = LGUN_RADIUS * LGUN_RADIUS;
const rectangle &visarea = m_port->m_screen->visible_area();
@@ -151,8 +155,7 @@ int sms_light_phaser_device::bright_aim_area( emu_timer *timer, int lgun_x, int
int beam_y = m_port->m_screen->vpos();
int beam_x_orig = beam_x;
int beam_y_orig = beam_y;
- int dy, result = 1;
- double dx_radius;
+ int result = 1;
bool new_check_point = false;
aim_area.min_y = std::max(lgun_y - LGUN_RADIUS, visarea.min_y);
@@ -166,23 +169,21 @@ int sms_light_phaser_device::bright_aim_area( emu_timer *timer, int lgun_x, int
{
beam_y = aim_area.min_y;
}
- dy = abs(beam_y - lgun_y);
+ int dy = abs(beam_y - lgun_y);
/* Caculate distance in x of the radius, relative to beam's y distance.
First try some shortcuts. */
- switch (dy)
+ double dx_radius = 0;
+ if (dy == 0)
{
- case LGUN_RADIUS:
- dx_radius = 0;
- break;
- case 0:
dx_radius = LGUN_RADIUS;
- break;
- default:
+ }
+ else if (dy != LGUN_RADIUS)
+ {
/* step 1: r^2 = dx^2 + dy^2 */
/* step 2: dx^2 = r^2 - dy^2 */
/* step 3: dx = sqrt(r^2 - dy^2) */
- dx_radius = ceil((float) sqrt((float) (r_x_r - (dy * dy))));
+ dx_radius = ceil(sqrt(double(r_x_r - (dy * dy))));
}
aim_area.min_x = std::max(int32_t(lgun_x - dx_radius), visarea.min_x);
@@ -252,7 +253,7 @@ int sms_light_phaser_device::bright_aim_area( emu_timer *timer, int lgun_x, int
}
}
- timer->adjust(m_port->m_screen->time_until_pos(beam_y, beam_x));
+ m_lphaser_timer->adjust(m_port->m_screen->time_until_pos(beam_y, beam_x));
return result;
}
@@ -273,30 +274,15 @@ uint16_t sms_light_phaser_device::screen_vpos_nonscaled(int scaled_vpos)
}
-void sms_light_phaser_device::sensor_check()
+TIMER_CALLBACK_MEMBER(sms_light_phaser_device::sensor_check)
{
- int sensor_new_state;
-
const int x = screen_hpos_nonscaled(m_lphaser_x->read());
const int y = screen_vpos_nonscaled(m_lphaser_y->read());
- sensor_new_state = bright_aim_area(m_lphaser_timer, x, y);
+ int sensor_new_state = bright_aim_area(x, y);
if (sensor_new_state != m_sensor_last_state)
{
m_port->th_pin_w(sensor_new_state);
m_sensor_last_state = sensor_new_state;
}
}
-
-
-void sms_light_phaser_device::device_timer(emu_timer &timer, device_timer_id id, int param)
-{
- switch (id)
- {
- case TIMER_LPHASER:
- sensor_check();
- break;
- default:
- throw emu_fatalerror("sms_light_phaser_device(%s): Unknown timer ID", tag());
- }
-}