diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index 01dd5b214d9..0d1768426a0 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -3038,6 +3038,8 @@ if (BUSES["NES_CTRL"]~=null) then MAME_DIR .. "src/devices/bus/nes_ctrl/partytap.h", MAME_DIR .. "src/devices/bus/nes_ctrl/powerpad.cpp", MAME_DIR .. "src/devices/bus/nes_ctrl/powerpad.h", + MAME_DIR .. "src/devices/bus/nes_ctrl/rob.cpp", + MAME_DIR .. "src/devices/bus/nes_ctrl/rob.h", MAME_DIR .. "src/devices/bus/nes_ctrl/snesadapter.cpp", MAME_DIR .. "src/devices/bus/nes_ctrl/snesadapter.h", MAME_DIR .. "src/devices/bus/nes_ctrl/suborkey.cpp", @@ -3046,10 +3048,12 @@ if (BUSES["NES_CTRL"]~=null) then MAME_DIR .. "src/devices/bus/nes_ctrl/turbofile.h", MAME_DIR .. "src/devices/bus/nes_ctrl/zapper.cpp", MAME_DIR .. "src/devices/bus/nes_ctrl/zapper.h", + MAME_DIR .. "src/devices/bus/nes_ctrl/zapper_sensor.cpp", + MAME_DIR .. "src/devices/bus/nes_ctrl/zapper_sensor.h", } dependency { - { MAME_DIR .. "src/devices/bus/nes_ctrl/zapper.cpp", GEN_DIR .. "emu/layout/nes_rob.lh" }, + { MAME_DIR .. "src/devices/bus/nes_ctrl/rob.cpp", GEN_DIR .. "emu/layout/nes_rob.lh" }, } custombuildtask { diff --git a/src/devices/bus/nes_ctrl/ctrl.cpp b/src/devices/bus/nes_ctrl/ctrl.cpp index 16c595b9ae3..a505b687783 100644 --- a/src/devices/bus/nes_ctrl/ctrl.cpp +++ b/src/devices/bus/nes_ctrl/ctrl.cpp @@ -58,6 +58,7 @@ #include "pachinko.h" #include "partytap.h" #include "powerpad.h" +#include "rob.h" #include "snesadapter.h" #include "suborkey.h" #include "turbofile.h" diff --git a/src/devices/bus/nes_ctrl/rob.cpp b/src/devices/bus/nes_ctrl/rob.cpp new file mode 100644 index 00000000000..24747e6a088 --- /dev/null +++ b/src/devices/bus/nes_ctrl/rob.cpp @@ -0,0 +1,140 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/********************************************************************** + + Nintendo HVC-012 Family Computer Robot / Nintendo NES-012 R.O.B. + + TODO: + - does nes_rob have motor sensors? (eg. limit switches, or optical + sensor to determine position) + - can't really play anything with nes_rob, because of interaction + with physical objects (gyromite especially, since it has a gadget + to make the robot press joypad buttons) + +**********************************************************************/ + +#include "emu.h" +#include "rob.h" + +#include "nes_rob.lh" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(NES_ROB, nes_rob_device, "nes_rob", "Nintendo R.O.B. / Family Computer Robot") + + +static INPUT_PORTS_START( nes_rob ) + PORT_START("EYE_X") + PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(70) PORT_KEYDELTA(30) PORT_MINMAX(0, 255) + PORT_START("EYE_Y") + PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(30) PORT_MINMAX(0, 239) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor nes_rob_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( nes_rob ); +} + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +nes_rob_device::nes_rob_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, NES_ROB, tag, owner, clock) + , device_nes_control_port_interface(mconfig, *this) + , m_maincpu(*this, "maincpu") + , m_sensor(*this, "sensor") + , m_eye_x(*this, "EYE_X") + , m_eye_y(*this, "EYE_Y") + , m_motor_out(*this, "rob_motor.%u", 0U) + , m_led_out(*this, "rob_led") +{ +} + + +//------------------------------------------------- +// device_start +//------------------------------------------------- + +void nes_rob_device::device_start() +{ + // resolve handlers + m_motor_out.resolve(); + m_led_out.resolve(); +} + + +//------------------------------------------------- +// R.O.B. specific handlers +//------------------------------------------------- + +u8 nes_rob_device::input_r() +{ + // R00: lightsensor + return !m_sensor->detect_light(m_eye_x->read(), m_eye_y->read()); +} + +void nes_rob_device::output_w(offs_t offset, u8 data) +{ + switch (offset & 3) + { + case 0: + // R03: led + m_led_out = BIT(data, 3); + break; + + case 1: + // R10-R13: motors: down, up, close, open + for (int i = 0; i < 4; i++) + m_motor_out[i] = BIT(data, i); + break; + + case 2: + // R20,R21: motors: right, left + for (int i = 0; i < 2; i++) + m_motor_out[i + 4] = BIT(data, i); + break; + + default: + break; + } +} + +void nes_rob_device::device_add_mconfig(machine_config &config) +{ + SM590(config, m_maincpu, 455_kHz_XTAL); + m_maincpu->read_r<0>().set(FUNC(nes_rob_device::input_r)); + m_maincpu->write_r<0>().set(FUNC(nes_rob_device::output_w)); + m_maincpu->write_r<1>().set(FUNC(nes_rob_device::output_w)); + m_maincpu->write_r<2>().set(FUNC(nes_rob_device::output_w)); + m_maincpu->write_r<3>().set(FUNC(nes_rob_device::output_w)); + + NES_ZAPPER_SENSOR(config, m_sensor, 0); + if (m_port != nullptr) + m_sensor->set_screen_tag(m_port->m_screen); + + // must use -numscreens 2 to see the output status + config.set_default_layout(layout_nes_rob); +} + +ROM_START( nes_rob ) + ROM_REGION( 0x200, "maincpu", 0 ) + ROM_LOAD( "rfc-cpu10.ic1", 0x000, 0x200, CRC(f9c96b9c) SHA1(a87e2f0f5e454c093d1352ac368aa9e82e9f6790) ) +ROM_END + +const tiny_rom_entry *nes_rob_device::device_rom_region() const +{ + return ROM_NAME(nes_rob); +} diff --git a/src/devices/bus/nes_ctrl/rob.h b/src/devices/bus/nes_ctrl/rob.h new file mode 100644 index 00000000000..449c109871a --- /dev/null +++ b/src/devices/bus/nes_ctrl/rob.h @@ -0,0 +1,55 @@ +// license:BSD-3-Clause +// copyright-holders:hap +/********************************************************************** + + Nintendo HVC-012 Family Computer Robot / Nintendo NES-012 R.O.B. + +**********************************************************************/ + +#ifndef MAME_BUS_NES_CTRL_ROB +#define MAME_BUS_NES_CTRL_ROB + +#pragma once + +#include "ctrl.h" +#include "cpu/sm510/sm590.h" +#include "zapper_sensor.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_rob_device + +class nes_rob_device : public device_t, + public device_nes_control_port_interface +{ +public: + // construction/destruction + nes_rob_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + virtual ioport_constructor device_input_ports() const override; + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; + +private: + required_device m_maincpu; + required_device m_sensor; + required_ioport m_eye_x; + required_ioport m_eye_y; + output_finder<6> m_motor_out; + output_finder<> m_led_out; + + u8 input_r(); + void output_w(offs_t offset, u8 data); +}; + +// device type definition +DECLARE_DEVICE_TYPE(NES_ROB, nes_rob_device) + +#endif // MAME_BUS_NES_CTRL_ROB diff --git a/src/devices/bus/nes_ctrl/zapper.cpp b/src/devices/bus/nes_ctrl/zapper.cpp index 4906db2ce7a..5d55b1f2d3f 100644 --- a/src/devices/bus/nes_ctrl/zapper.cpp +++ b/src/devices/bus/nes_ctrl/zapper.cpp @@ -4,33 +4,18 @@ Nintendo Family Computer & Entertainment System Zapper Lightgun Nintendo Family Computer Bandai Hyper Shot Lightgun - Nintendo R.O.B. - - TODO: - - nes_rob is in here because it needs the zapper light sensor, - in reality it's not connected to the control port at all, but how - would it be interfaced with the NES driver otherwise? - - does nes_rob have motor sensors? (eg. limit switches, or optical - sensor to determine position) - - can't really play anything with nes_rob, because of interaction - with physical objects (gyromite especially, since it has a gadget - to make the robot press joypad buttons) **********************************************************************/ #include "emu.h" -#include "screen.h" #include "zapper.h" -#include "nes_rob.lh" - //************************************************************************** // DEVICE DEFINITIONS //************************************************************************** DEFINE_DEVICE_TYPE(NES_ZAPPER, nes_zapper_device, "nes_zapper", "Nintendo Zapper Lightgun") DEFINE_DEVICE_TYPE(NES_BANDAIHS, nes_bandaihs_device, "nes_bandaihs", "Bandai Hyper Shot Lightgun") -DEFINE_DEVICE_TYPE(NES_ROB, nes_rob_device, "nes_rob", "Nintendo R.O.B.") static INPUT_PORTS_START( nes_zapper ) @@ -58,15 +43,6 @@ static INPUT_PORTS_START( nes_bandaihs ) INPUT_PORTS_END -static INPUT_PORTS_START( nes_rob ) - PORT_INCLUDE( nes_zapper ) - - // it has the x/y for aiming the 'eyes', but there is no lightgun trigger - PORT_MODIFY("ZAPPER_T") - PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED ) -INPUT_PORTS_END - - //------------------------------------------------- // input_ports - device-specific input ports //------------------------------------------------- @@ -81,9 +57,15 @@ ioport_constructor nes_bandaihs_device::device_input_ports() const return INPUT_PORTS_NAME( nes_bandaihs ); } -ioport_constructor nes_rob_device::device_input_ports() const +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void nes_zapper_device::device_add_mconfig(machine_config &config) { - return INPUT_PORTS_NAME( nes_rob ); + NES_ZAPPER_SENSOR(config, m_sensor, 0); + if (m_port != nullptr) + m_sensor->set_screen_tag(m_port->m_screen); } @@ -98,6 +80,7 @@ ioport_constructor nes_rob_device::device_input_ports() const nes_zapper_device::nes_zapper_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock) : device_t(mconfig, type, tag, owner, clock) , device_nes_control_port_interface(mconfig, *this) + , m_sensor(*this, "sensor") , m_lightx(*this, "ZAPPER_X") , m_lighty(*this, "ZAPPER_Y") , m_trigger(*this, "ZAPPER_T") @@ -116,14 +99,6 @@ nes_bandaihs_device::nes_bandaihs_device(const machine_config &mconfig, const ch { } -nes_rob_device::nes_rob_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) - : nes_zapper_device(mconfig, NES_ROB, tag, owner, clock) - , m_maincpu(*this, "maincpu") - , m_motor_out(*this, "rob_motor.%u", 0U) - , m_led_out(*this, "rob_led") -{ -} - //------------------------------------------------- // device_start @@ -140,15 +115,6 @@ void nes_bandaihs_device::device_start() save_item(NAME(m_strobe)); } -void nes_rob_device::device_start() -{ - nes_zapper_device::device_start(); - - // resolve handlers - m_motor_out.resolve(); - m_led_out.resolve(); -} - //------------------------------------------------- // read @@ -157,44 +123,8 @@ void nes_rob_device::device_start() u8 nes_zapper_device::read_bit34() { u8 ret = m_trigger->read(); - int x = m_lightx->read(); - int y = m_lighty->read(); - // radius of circle picked up by the gun's photodiode - constexpr int radius = 5; - // brightness threshold - constexpr int bright = 0xc0; - // # of CRT scanlines that sustain brightness - constexpr int sustain = 22; - - int vpos = m_port->m_screen->vpos(); - int hpos = m_port->m_screen->hpos(); - - // update the screen if necessary - if (!m_port->m_screen->vblank()) - if (vpos > y - radius || (vpos == y - radius && hpos >= x - radius)) - m_port->m_screen->update_now(); - - int sum = 0; - int scanned = 0; - - // sum brightness of pixels nearby the gun position - for (int i = x - radius; i <= x + radius; i++) - for (int j = y - radius; j <= y + radius; j++) - // look at pixels within circular sensor - if ((x - i) * (x - i) + (y - j) * (y - j) <= radius * radius) - { - rgb_t pix = m_port->m_screen->pixel(i, j); - - // only detect light if gun position is near, and behind, where the PPU is drawing on the CRT, from NesDev wiki: - // "Zap Ruder test ROM show that the photodiode stays on for about 26 scanlines with pure white, 24 scanlines with light gray, or 19 lines with dark gray." - if (j <= vpos && j > vpos - sustain && (j != vpos || i <= hpos)) - sum += pix.r() + pix.g() + pix.b(); - scanned++; - } - - // light not detected if average brightness is below threshold (default bit 3 is 0: light detected) - if (sum < bright * scanned) + if (!m_sensor->detect_light(m_lightx->read(), m_lighty->read())) ret |= 0x08; return ret; @@ -236,63 +166,3 @@ void nes_bandaihs_device::write(u8 data) if (write_strobe(data)) m_latch = m_joypad->read(); } - - -//------------------------------------------------- -// R.O.B. specific handlers -//------------------------------------------------- - -u8 nes_rob_device::input_r() -{ - // R00: lightsensor - return (read_bit34() & 8) ? 1 : 0; -} - -void nes_rob_device::output_w(offs_t offset, u8 data) -{ - switch (offset & 3) - { - case 0: - // R03: led - m_led_out = BIT(data, 3); - break; - - case 1: - // R10-R13: motors: down, up, close, open - for (int i = 0; i < 4; i++) - m_motor_out[i] = BIT(data, i); - break; - - case 2: - // R20,R21: motors: right, left - for (int i = 0; i < 2; i++) - m_motor_out[i + 4] = BIT(data, i); - break; - - default: - break; - } -} - -void nes_rob_device::device_add_mconfig(machine_config &config) -{ - SM590(config, m_maincpu, 455_kHz_XTAL); - m_maincpu->read_r<0>().set(FUNC(nes_rob_device::input_r)); - m_maincpu->write_r<0>().set(FUNC(nes_rob_device::output_w)); - m_maincpu->write_r<1>().set(FUNC(nes_rob_device::output_w)); - m_maincpu->write_r<2>().set(FUNC(nes_rob_device::output_w)); - m_maincpu->write_r<3>().set(FUNC(nes_rob_device::output_w)); - - // must use -numscreens 2 to see the output status - config.set_default_layout(layout_nes_rob); -} - -ROM_START( nes_rob ) - ROM_REGION( 0x200, "maincpu", 0 ) - ROM_LOAD( "rfc-cpu10.ic1", 0x000, 0x200, CRC(f9c96b9c) SHA1(a87e2f0f5e454c093d1352ac368aa9e82e9f6790) ) -ROM_END - -const tiny_rom_entry *nes_rob_device::device_rom_region() const -{ - return ROM_NAME(nes_rob); -} diff --git a/src/devices/bus/nes_ctrl/zapper.h b/src/devices/bus/nes_ctrl/zapper.h index 3761ecd7583..50fe4e8528a 100644 --- a/src/devices/bus/nes_ctrl/zapper.h +++ b/src/devices/bus/nes_ctrl/zapper.h @@ -4,7 +4,6 @@ Nintendo Family Computer & Entertainment System Zapper Lightgun Nintendo Family Computer Bandai Hyper Shot Lightgun - Nintendo R.O.B. **********************************************************************/ @@ -13,9 +12,9 @@ #pragma once - #include "ctrl.h" -#include "cpu/sm510/sm590.h" +#include "zapper_sensor.h" + //************************************************************************** // TYPE DEFINITIONS @@ -38,11 +37,13 @@ protected: // device-level overrides virtual void device_start() override; + virtual void device_add_mconfig(machine_config &config) override; virtual u8 read_bit34() override; virtual u8 read_exp(offs_t offset) override; private: + required_device m_sensor; required_ioport m_lightx; required_ioport m_lighty; required_ioport m_trigger; @@ -72,37 +73,8 @@ private: }; -// ======================> nes_rob_device - -class nes_rob_device : public nes_zapper_device -{ -public: - // construction/destruction - nes_rob_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); - - virtual ioport_constructor device_input_ports() const override; - -protected: - // device-level overrides - virtual void device_start() override; - virtual void device_add_mconfig(machine_config &config) override; - virtual const tiny_rom_entry *device_rom_region() const override; - - virtual u8 read_exp(offs_t offset) override { return 0; } - -private: - required_device m_maincpu; - output_finder<6> m_motor_out; - output_finder<> m_led_out; - - u8 input_r(); - void output_w(offs_t offset, u8 data); -}; - - // device type definition DECLARE_DEVICE_TYPE(NES_ZAPPER, nes_zapper_device) DECLARE_DEVICE_TYPE(NES_BANDAIHS, nes_bandaihs_device) -DECLARE_DEVICE_TYPE(NES_ROB, nes_rob_device) #endif // MAME_BUS_NES_CTRL_ZAPPER diff --git a/src/devices/bus/nes_ctrl/zapper_sensor.cpp b/src/devices/bus/nes_ctrl/zapper_sensor.cpp new file mode 100644 index 00000000000..6e2e01c9661 --- /dev/null +++ b/src/devices/bus/nes_ctrl/zapper_sensor.cpp @@ -0,0 +1,72 @@ +// license:BSD-3-Clause +// copyright-holders:kmg +/********************************************************************** + + HLE of the common photodiode reading routine used in the NES, + Vs. System, and Playchoice-10 light guns, and R.O.B. + + These all use a Sharp IR3T07, though the NES zapper is (always?) + seen with the IR3T07A revision. + +**********************************************************************/ + +#include "emu.h" +#include "zapper_sensor.h" + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(NES_ZAPPER_SENSOR, nes_zapper_sensor_device, "nes_zapper_sensor", "Nintendo Zapper Lightgun Photodiode") + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// constructor +//------------------------------------------------- + +nes_zapper_sensor_device::nes_zapper_sensor_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, NES_ZAPPER_SENSOR, tag, owner, clock) + , m_screen(*this, finder_base::DUMMY_TAG) +{ +} + + +//------------------------------------------------- +// detect_light +//------------------------------------------------- + +bool nes_zapper_sensor_device::detect_light(int x, int y) +{ + int vpos = m_screen->vpos(); + int hpos = m_screen->hpos(); + + // update the screen if necessary + if (!m_screen->vblank()) + if (vpos > y - radius || (vpos == y - radius && hpos >= x - radius)) + m_screen->update_now(); + + int sum = 0; + int scanned = 0; + + // sum brightness of pixels nearby the gun position + for (int i = x - radius; i <= x + radius; i++) + for (int j = y - radius; j <= y + radius; j++) + // look at pixels within circular sensor + if ((x - i) * (x - i) + (y - j) * (y - j) <= radius * radius) + { + rgb_t pix = m_screen->pixel(i, j); + + // only detect light if gun position is near, and behind, where the PPU is drawing on the CRT, from NesDev wiki: + // "Zap Ruder test ROM show that the photodiode stays on for about 26 scanlines with pure white, 24 scanlines with light gray, or 19 lines with dark gray." + if (j <= vpos && j > vpos - sustain && (j != vpos || i <= hpos)) + sum += pix.r() + pix.g() + pix.b(); + scanned++; + } + + // light detected if average brightness is above threshold + return sum >= bright * scanned; +} diff --git a/src/devices/bus/nes_ctrl/zapper_sensor.h b/src/devices/bus/nes_ctrl/zapper_sensor.h new file mode 100644 index 00000000000..1e546f937f6 --- /dev/null +++ b/src/devices/bus/nes_ctrl/zapper_sensor.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:kmg +/********************************************************************** + + HLE of the common photodiode reading routine used in the NES, + Vs. System, and Playchoice-10 light guns, and R.O.B. + +**********************************************************************/ + +#ifndef MAME_BUS_NES_CTRL_ZAPPER_SENSOR +#define MAME_BUS_NES_CTRL_ZAPPER_SENSOR + +#pragma once + +#include "screen.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> nes_zapper_sensor_device + +class nes_zapper_sensor_device : public device_t +{ +public: + // construction/destruction + nes_zapper_sensor_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + + template void set_screen_tag(T &&tag) { m_screen.set_tag(std::forward(tag)); } + + bool detect_light(int x, int y); + +protected: + // device-level overrides + virtual void device_start() override { } + +private: + // radius of circle picked up by the gun's photodiode + static constexpr int radius = 5; + // brightness threshold + static constexpr int bright = 0xc0; + // # of CRT scanlines that sustain brightness + static constexpr int sustain = 22; + + required_device m_screen; +}; + + +// device type definition +DECLARE_DEVICE_TYPE(NES_ZAPPER_SENSOR, nes_zapper_sensor_device) + +#endif // MAME_BUS_NES_CTRL_ZAPPER_SENSOR diff --git a/src/mame/drivers/playch10.cpp b/src/mame/drivers/playch10.cpp index 20d4134b7b2..7bdc01066f6 100644 --- a/src/mame/drivers/playch10.cpp +++ b/src/mame/drivers/playch10.cpp @@ -808,6 +808,8 @@ void playch10_state::playch10(machine_config &config) m_ppu->int_callback().set_inputline(m_cartcpu, INPUT_LINE_NMI); m_ppu->int_callback().append(FUNC(playch10_state::int_detect_w)); + NES_ZAPPER_SENSOR(config, m_sensor, 0).set_screen_tag("bottom"); + SPEAKER(config, "mono").front_center(); m_cartcpu->add_route(ALL_OUTPUTS, "mono", 0.50); diff --git a/src/mame/drivers/vsnes.cpp b/src/mame/drivers/vsnes.cpp index 43540a362e5..cc1974a16d3 100644 --- a/src/mame/drivers/vsnes.cpp +++ b/src/mame/drivers/vsnes.cpp @@ -1770,6 +1770,8 @@ void vsnes_state::vsnes(machine_config &config) m_ppu1->set_cpu_tag(m_maincpu); m_ppu1->int_callback().set_inputline(m_maincpu, INPUT_LINE_NMI); + NES_ZAPPER_SENSOR(config, m_sensor, 0).set_screen_tag("screen1"); + /* sound hardware */ SPEAKER(config, "mono").front_center(); maincpu.add_route(ALL_OUTPUTS, "mono", 0.50); diff --git a/src/mame/includes/playch10.h b/src/mame/includes/playch10.h index 0c5387fce6f..ab2c01c1dcb 100644 --- a/src/mame/includes/playch10.h +++ b/src/mame/includes/playch10.h @@ -5,6 +5,7 @@ #pragma once +#include "bus/nes_ctrl/zapper_sensor.h" #include "cpu/m6502/n2a03.h" #include "machine/rp5h01.h" #include "video/ppu2c0x.h" @@ -23,6 +24,7 @@ public: , m_ram_8w(*this, "ram_8w") , m_videoram(*this, "videoram") , m_gfxdecode(*this, "gfxdecode") + , m_sensor(*this, "sensor") , m_prg_banks(*this, "prg%u", 0U) , m_prg_view(*this, "prg_view") , m_vrom_region(*this, "gfx2") @@ -149,6 +151,7 @@ private: required_shared_ptr m_ram_8w; required_shared_ptr m_videoram; required_device m_gfxdecode; + required_device m_sensor; void init_prg_banking(); void prg32(int bank); diff --git a/src/mame/includes/vsnes.h b/src/mame/includes/vsnes.h index d4a7a81d79f..cffe866a053 100644 --- a/src/mame/includes/vsnes.h +++ b/src/mame/includes/vsnes.h @@ -1,6 +1,7 @@ // license:BSD-3-Clause // copyright-holders:Pierpaolo Prazzoli +#include "bus/nes_ctrl/zapper_sensor.h" #include "machine/nvram.h" #include "sound/sn76496.h" #include "video/ppu2c0x.h" @@ -16,6 +17,7 @@ public: , m_ppu2(*this, "ppu2") , m_sn1(*this, "sn1") , m_sn2(*this, "sn2") + , m_sensor(*this, "sensor") , m_nvram(*this, "nvram") , m_gfx1_rom(*this, "gfx1") , m_chr_banks(*this, "chr%u", 0U) @@ -56,6 +58,7 @@ private: optional_device m_sn1; optional_device m_sn2; + optional_device m_sensor; optional_device m_nvram; optional_memory_region m_gfx1_rom; diff --git a/src/mame/machine/playch10.cpp b/src/mame/machine/playch10.cpp index 549110abcf9..fbae83e4288 100644 --- a/src/mame/machine/playch10.cpp +++ b/src/mame/machine/playch10.cpp @@ -207,44 +207,8 @@ uint8_t playch10_state::pc10_in1_r() if (m_pc10_gun_controller) { int trigger = ioport("P1")->read(); - int x = ioport("GUNX")->read(); - int y = ioport("GUNY")->read(); - // radius of circle picked up by gun's photodiode - constexpr int radius = 5; - // brightness threshold - constexpr int bright = 0xc0; - // # of CRT scanlines that sustain brightness - constexpr int sustain = 22; - - int vpos = m_ppu->screen().vpos(); - int hpos = m_ppu->screen().hpos(); - - // update the screen if necessary - if (!m_ppu->screen().vblank()) - if (vpos > y - radius || (vpos == y - radius && hpos >= x - radius)) - m_ppu->screen().update_now(); - - int sum = 0; - int scanned = 0; - - // sum brightness of pixels nearby the gun position - for (int i = x - radius; i <= x + radius; i++) - for (int j = y - radius; j <= y + radius; j++) - // look at pixels within circular sensor - if ((x - i) * (x - i) + (y - j) * (y - j) <= radius * radius) - { - rgb_t pix = m_ppu->screen().pixel(i, j); - - // only detect light if gun position is near, and behind, where the PPU is drawing on the CRT, from NesDev wiki: - // "Zap Ruder test ROM show that the photodiode stays on for about 26 scanlines with pure white, 24 scanlines with light gray, or 19 lines with dark gray." - if (j <= vpos && j > vpos - sustain && (j != vpos || i <= hpos)) - sum += pix.r() + pix.g() + pix.b(); - scanned++; - } - - // light not detected if average brightness is below threshold (default bit 3 is 0: light detected) - if (sum < bright * scanned) + if (!m_sensor->detect_light(ioport("GUNX")->read(), ioport("GUNY")->read())) ret |= 0x08; // now, add the trigger if not masked diff --git a/src/mame/machine/vsnes.cpp b/src/mame/machine/vsnes.cpp index b87d44e1675..243d48440b6 100644 --- a/src/mame/machine/vsnes.cpp +++ b/src/mame/machine/vsnes.cpp @@ -116,45 +116,7 @@ void vsnes_state::gun_in0_w(u8 data) // load up the latch m_input_latch[0] = ioport("IN0")->read(); - // do the gun thing - int x = ioport("GUNX")->read(); - int y = ioport("GUNY")->read(); - - // radius of circle picked up by the gun's photodiode - constexpr int radius = 5; - // brightness threshold - constexpr int bright = 0xc0; - // # of CRT scanlines that sustain brightness - constexpr int sustain = 22; - - int vpos = m_ppu1->screen().vpos(); - int hpos = m_ppu1->screen().hpos(); - - // update the screen if necessary - if (!m_ppu1->screen().vblank()) - if (vpos > y - radius || (vpos == y - radius && hpos >= x - radius)) - m_ppu1->screen().update_now(); - - int sum = 0; - int scanned = 0; - - // sum brightness of pixels nearby the gun position - for (int i = x - radius; i <= x + radius; i++) - for (int j = y - radius; j <= y + radius; j++) - // look at pixels within circular sensor - if ((x - i) * (x - i) + (y - j) * (y - j) <= radius * radius) - { - rgb_t pix = m_ppu1->screen().pixel(i, j); - - // only detect light if gun position is near, and behind, where the PPU is drawing on the CRT, from NesDev wiki: - // "Zap Ruder test ROM show that the photodiode stays on for about 26 scanlines with pure white, 24 scanlines with light gray, or 19 lines with dark gray." - if (j <= vpos && j > vpos - sustain && (j != vpos || i <= hpos)) - sum += pix.r() + pix.g() + pix.b(); - scanned++; - } - - // light detected if average brightness is above threshold - if (sum >= bright * scanned) + if (m_sensor->detect_light(ioport("GUNX")->read(), ioport("GUNY")->read())) m_input_latch[0] |= 0x40; }