summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/nes_ctrl/zapper_sensor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/nes_ctrl/zapper_sensor.cpp')
-rw-r--r--src/devices/bus/nes_ctrl/zapper_sensor.cpp72
1 files changed, 72 insertions, 0 deletions
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..6d0bf53fc6d
--- /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;
+}