diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index 2b94b22976c..8096a161189 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -3141,6 +3141,8 @@ end if (BUSES["A2GAMEIO"]~=null) then files { + MAME_DIR .. "src/devices/bus/a2gameio/brightpen.cpp", + MAME_DIR .. "src/devices/bus/a2gameio/brightpen.h", MAME_DIR .. "src/devices/bus/a2gameio/computereyes.cpp", MAME_DIR .. "src/devices/bus/a2gameio/computereyes.h", MAME_DIR .. "src/devices/bus/a2gameio/gameio.cpp", diff --git a/src/devices/bus/a2gameio/brightpen.cpp b/src/devices/bus/a2gameio/brightpen.cpp new file mode 100644 index 00000000000..6429b16b5f2 --- /dev/null +++ b/src/devices/bus/a2gameio/brightpen.cpp @@ -0,0 +1,140 @@ +// license:BSD-3-Clause +// copyright-holders:kmg +/********************************************************************* + + Apple II Softape Bright Pen interface for the Apple ][/][+ + +*********************************************************************/ + +#include "emu.h" +#include "bus/a2gameio/brightpen.h" +#include "screen.h" + + +namespace { + +#define BRIGHTPEN_POINT "BRIGHTPEN_POINT" +#define BRIGHTPEN_X "BRIGHTPEN_X" +#define BRIGHTPEN_Y "BRIGHTPEN_Y" + +// ======================> apple2_brightpen_device + +class apple2_brightpen_device : public device_t, public device_a2gameio_interface +{ +public: + // construction/destruction + apple2_brightpen_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, APPLE2_BRIGHTPEN, tag, owner, clock) + , device_a2gameio_interface(mconfig, *this) + , m_brightpen_point(*this, BRIGHTPEN_POINT) + , m_brightpen_x(*this, BRIGHTPEN_X) + , m_brightpen_y(*this, BRIGHTPEN_Y) + { + } + +protected: + // device_t implementation + virtual ioport_constructor device_input_ports() const override; + virtual void device_start() override; + + // device_a2gameio_interface implementation + virtual int sw0_r() override; + +private: + // input ports + required_ioport m_brightpen_point; + required_ioport m_brightpen_x; + required_ioport m_brightpen_y; + + // radius of circle picked up by the bright pen + static constexpr int PEN_X_RADIUS = 2; + static constexpr int PEN_Y_RADIUS = 1; + // brightness threshold + static constexpr int BRIGHTNESS_THRESHOLD = 0x20; + // # of CRT scanlines that sustain brightness + static constexpr int SUSTAIN = 22; +}; + +//************************************************************************** +// INPUT PORTS +//************************************************************************** + +static INPUT_PORTS_START( apple2_brightpen ) + PORT_START(BRIGHTPEN_X) + PORT_BIT( 0x3ff, 0x80, IPT_LIGHTGUN_X ) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(45) PORT_KEYDELTA(15) PORT_MINMAX(0, 559) PORT_NAME("Bright Pen X") + PORT_START(BRIGHTPEN_Y) + PORT_BIT( 0x3ff, 0x80, IPT_LIGHTGUN_Y ) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(45) PORT_KEYDELTA(15) PORT_MINMAX(0, 191) PORT_NAME("Bright Pen Y") + PORT_START(BRIGHTPEN_POINT) + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Bright Pen pointed at screen") + PORT_BIT( 0xfe, IP_ACTIVE_LOW, IPT_UNUSED ) +INPUT_PORTS_END + +ioport_constructor apple2_brightpen_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(apple2_brightpen); +} + +void apple2_brightpen_device::device_start() +{ +} + +// light detection logic based on zapper_sensor.cpp nes_zapper_sensor_device::detect_light + +int apple2_brightpen_device::sw0_r() +{ + if (!BIT(m_brightpen_point->read(), 0)) return 0; + + int pen_x_pos = m_brightpen_x->read(); + int pen_y_pos = m_brightpen_y->read(); + int beam_vpos = m_screen->vpos(); + int beam_hpos = m_screen->hpos(); + + // update the screen if the beam position is within the radius of the pen + if (!machine().side_effects_disabled()) + { + if (!m_screen->vblank()) + { + if (beam_vpos > pen_y_pos - PEN_Y_RADIUS || (beam_vpos == pen_y_pos - PEN_Y_RADIUS && beam_hpos >= pen_x_pos - PEN_X_RADIUS)) + { + m_screen->update_now(); + } + } + } + + int brightness_sum = 0; + int pixels_scanned = 0; + + // sum brightness of pixels nearby the pen position + for (int i = pen_x_pos - PEN_X_RADIUS; i <= pen_x_pos + PEN_X_RADIUS; i++) + { + for (int j = pen_y_pos - PEN_Y_RADIUS; j <= pen_y_pos + PEN_Y_RADIUS; j++) + { + // look at pixels within circular sensor + if ((pen_x_pos - i) * (pen_x_pos - i) + (pen_y_pos - j) * (pen_y_pos - j) <= PEN_X_RADIUS * PEN_Y_RADIUS) + { + rgb_t pix = m_screen->pixel(i, j); + + // only detect light if pen position is near, and behind, + // where the video generator is drawing on the CRT, + if (j <= beam_vpos && j > beam_vpos - SUSTAIN && (j != beam_vpos || i <= beam_hpos)) + { + brightness_sum += pix.r() + pix.g() + pix.b(); + } + pixels_scanned++; + } + } + } + + // light detected if average brightness is above threshold + return (brightness_sum >= BRIGHTNESS_THRESHOLD * pixels_scanned); +} + +} // anonymous namespace + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +DEFINE_DEVICE_TYPE_PRIVATE(APPLE2_BRIGHTPEN, device_a2gameio_interface, apple2_brightpen_device, "a2brightpen", "Softape Bright Pen") diff --git a/src/devices/bus/a2gameio/brightpen.h b/src/devices/bus/a2gameio/brightpen.h new file mode 100644 index 00000000000..9c47c3d47d4 --- /dev/null +++ b/src/devices/bus/a2gameio/brightpen.h @@ -0,0 +1,18 @@ +// license:BSD-3-Clause +/********************************************************************* + + Apple II Softape Bright Pen interface for a lightpen + +*********************************************************************/ + +#ifndef MAME_BUS_A2GAMEIO_BRIGHTPEN_H +#define MAME_BUS_A2GAMEIO_BRIGHTPEN_H + +#pragma once + +#include "bus/a2gameio/gameio.h" + +// device type declaration +DECLARE_DEVICE_TYPE(APPLE2_BRIGHTPEN, device_a2gameio_interface) + +#endif // MAME_BUS_A2GAMEIO_BRIGHTPEN_H diff --git a/src/devices/bus/a2gameio/gameio.cpp b/src/devices/bus/a2gameio/gameio.cpp index e0eb1405530..fa1f1accf71 100644 --- a/src/devices/bus/a2gameio/gameio.cpp +++ b/src/devices/bus/a2gameio/gameio.cpp @@ -50,6 +50,7 @@ #include "emu.h" #include "bus/a2gameio/gameio.h" +#include "bus/a2gameio/brightpen.h" #include "bus/a2gameio/joystick.h" #include "bus/a2gameio/joyport.h" #include "bus/a2gameio/joyport_paddles.h" @@ -68,6 +69,7 @@ DEFINE_DEVICE_TYPE(APPLE2_GAMEIO, apple2_gameio_device, "a2gameio", "Apple II Ga apple2_gameio_device::apple2_gameio_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : device_t(mconfig, APPLE2_GAMEIO, tag, owner, clock) , device_single_card_slot_interface(mconfig, *this) + , m_screen(*this, finder_base::DUMMY_TAG) , m_intf(nullptr) , m_sw_pullups(false) { @@ -82,6 +84,7 @@ void apple2_gameio_device::iiandplus_options(device_slot_interface &slot) slot.option_add("gizmo", APPLE2_GIZMO); slot.option_add("compeyes", APPLE2_COMPUTEREYES); slot.option_add("wicojoy", APPLE2_WICO_JOYSTICK); + slot.option_add("brightpen", APPLE2_BRIGHTPEN); } void apple2_gameio_device::default_options(device_slot_interface &slot) @@ -105,8 +108,10 @@ void apple2_gameio_device::device_config_complete() void apple2_gameio_device::device_resolve_objects() { - if (m_intf) + if (m_intf) { m_intf->m_connector = this; + m_intf->set_screen(m_screen); + } } void apple2_gameio_device::device_start() diff --git a/src/devices/bus/a2gameio/gameio.h b/src/devices/bus/a2gameio/gameio.h index 1f8d53a8c20..dfe2f3716bd 100644 --- a/src/devices/bus/a2gameio/gameio.h +++ b/src/devices/bus/a2gameio/gameio.h @@ -11,6 +11,7 @@ #pragma once +#include "screen.h" //************************************************************************** // TYPE DEFINITIONS @@ -37,6 +38,13 @@ public: set_fixed(false); } + template + apple2_gameio_device(const machine_config &mconfig, const char *tag, device_t *owner, T &&screen_tag, U &&opts, const char *dflt) + : apple2_gameio_device(mconfig, tag, owner, opts, dflt) + { + m_screen.set_tag(std::forward(screen_tag)); + } + // configuration void set_sw_pullups(bool enabled) { m_sw_pullups = enabled; } bool has_sw_pullups() const { return m_sw_pullups; } @@ -77,6 +85,8 @@ protected: virtual void device_resolve_objects() override; virtual void device_start() override; + optional_device m_screen; + private: // selected device device_a2gameio_interface *m_intf; @@ -115,6 +125,8 @@ protected: virtual void an4_w(int state) { } virtual void strobe_w(int state) { } + void set_screen(screen_device *screen) { m_screen = screen; } + screen_device *m_screen; private: apple2_gameio_device *m_connector; }; diff --git a/src/mame/apple/apple2.cpp b/src/mame/apple/apple2.cpp index 2ff28d76335..37d068bbaa8 100644 --- a/src/mame/apple/apple2.cpp +++ b/src/mame/apple/apple2.cpp @@ -1155,7 +1155,7 @@ void apple2_state::apple2_common(machine_config &config) m_softlatch->q_out_cb<6>().append(m_video, FUNC(a2_video_device::an2_w)); m_softlatch->q_out_cb<7>().set(m_gameio, FUNC(apple2_gameio_device::an3_w)); - APPLE2_GAMEIO(config, m_gameio, apple2_gameio_device::iiandplus_options, nullptr); + APPLE2_GAMEIO(config, m_gameio, m_screen, apple2_gameio_device::iiandplus_options, nullptr); /* keyboard controller */ AY3600(config, m_ay3600, 0);