// license:BSD-3-Clause // copyright-holders:R. Belmont /********************************************************************* computereyes2.c Implemention of the Digital Vision ComputerEyes/2 card. *********************************************************************/ #include "emu.h" #include "computereyes2.h" #include "imagedev/picture.h" #include "bitmap.h" namespace { //************************************************************************** // TYPE DEFINITIONS //************************************************************************** class a2bus_computereyes2_device: public device_t, public device_a2bus_card_interface { public: // construction/destruction a2bus_computereyes2_device(const machine_config &mconfig, const char *tag, device_t *owner, const XTAL &clock); protected: a2bus_computereyes2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, const XTAL &clock); virtual void device_start() override; virtual void device_reset() override; virtual void device_add_mconfig(machine_config &config) override; // overrides of standard a2bus slot functions virtual uint8_t read_c0nx(uint8_t offset) override; virtual void write_c0nx(uint8_t offset, uint8_t data) override; private: required_device m_picture; int m_x, m_y, m_cer0, m_cer1, m_cer2; u8 m_a2_bitmap[280*193]; u8 m_threshold; bool m_bActive; }; /*************************************************************************** FUNCTION PROTOTYPES ***************************************************************************/ //------------------------------------------------- // device_add_mconfig - add device configuration //------------------------------------------------- void a2bus_computereyes2_device::device_add_mconfig(machine_config &config) { IMAGE_PICTURE(config, m_picture); } //************************************************************************** // LIVE DEVICE //************************************************************************** a2bus_computereyes2_device::a2bus_computereyes2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, const XTAL &clock) : device_t(mconfig, type, tag, owner, clock), device_a2bus_card_interface(mconfig, *this), m_picture(*this, "srcimg") { } a2bus_computereyes2_device::a2bus_computereyes2_device(const machine_config &mconfig, const char *tag, device_t *owner, const XTAL &clock) : a2bus_computereyes2_device(mconfig, A2BUS_COMPUTEREYES2, tag, owner, clock) { } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void a2bus_computereyes2_device::device_start() { save_item(NAME(m_x)); save_item(NAME(m_y)); save_item(NAME(m_cer0)); save_item(NAME(m_cer1)); save_item(NAME(m_cer2)); save_item(NAME(m_threshold)); save_item(NAME(m_bActive)); save_item(NAME(m_a2_bitmap)); } void a2bus_computereyes2_device::device_reset() { m_x = m_y = 0; m_cer0 = m_cer2 = 0; m_cer1 = 0x80; // interface disabled } /*------------------------------------------------- read_c0nx - called for reads from this card's c0nx space CER0 read bits 01 = capture data bit (read) 10 = sync (read) 20 = test bit (used in detection) (read) CER0 write bits 0F = brightness (write) 40 = monitor relay (write) 80 = turn on test bit (write) CER1 write bits 0F = contrast (guessing bits 0..3?) 80 = interface on (bit 7) CER2 write bits (any) resets the threshold for a new pixel -------------------------------------------------*/ uint8_t a2bus_computereyes2_device::read_c0nx(uint8_t offset) { switch (offset) { case 0: if (m_cer0 & 0x80) { return m_cer0 | 0x20; } else { u8 ret = (m_cer0 & 0xc0) | 0x10; u64 video_ticks = machine().time().as_ticks(1021800); int frame_time = video_ticks % (65 * 262); // 65 clocks per scanline, 262 scanlines per frame int h = frame_time % 65; int v = frame_time / 65; // generate sync bit if (v > 224) { // vsync ret &= ~0x10; } else if (h > 49) { // hsync ret &= ~0x10; } // is the interface enabled? (Active low, 0 = enabled) if (!(m_cer1 & 0x80)) { { if (m_bActive) { //printf("read at X=%d Y=%d CX=%d CY=%d thr=%02x\n", h, v, m_x, m_y, m_threshold); ret |= (m_a2_bitmap[m_x + ((v-2) * 280)] > m_threshold) ? 0 : 1; if (m_threshold > 0x20) { m_threshold -= 0x20; } else { m_y++; if (m_y >= 192) { if (m_x < 280) { m_x++; } else { m_x = 0; } m_bActive = false; } } } /* else { printf("SYNC at X=%d Y=%d CX=%d CY=%d thr=%02x\n", h, v, m_x, m_y, m_threshold); }*/ } } return ret; } break; case 1: return m_cer1; case 2: return m_cer2; } return 0; } /*------------------------------------------------- write_c0nx - called for writes to this card's c0nx space -------------------------------------------------*/ void a2bus_computereyes2_device::write_c0nx(uint8_t offset, uint8_t data) { switch (offset) { case 0: m_cer0 = data & 0xcf; break; case 1: if (!(data & 0x80)) { m_bActive = false; } m_y = 0; if (!(data & 0x80) && (m_cer1 & 0x80)) { m_x = m_y = 0; std::fill_n(m_a2_bitmap, 280*193, 0); const bitmap_argb32 &bitmap = m_picture->get_bitmap(); if (bitmap.valid()) { // convert arbitrary sized ARGB32 image to a 188x193 image with 256 levels of grayscale double stepx = (double)bitmap.width() / 188.0; double stepy = (double)bitmap.height() / 193.0; for (int y = 0; y < 193; y++) { for (int x = 0; x < 280; x++) { u32 pixel = bitmap.pix(int((double)y * stepy), int((double)x * stepx)); double mono = ((0.2126 * double(((pixel>>16) & 0xff) / 255.0)) + (0.7152 * double(((pixel>>8) & 0xff) / 255.0)) + (0.0722 * double((pixel& 0xff) / 255.0))); m_a2_bitmap[(y*280)+x] = u8(mono * 255.0); } } } } m_cer1 = data; break; case 2: // written to initialize a sample m_cer2 = data; m_threshold = 0xe0; if (!m_bActive) { m_y = 0; } m_bActive = true; break; } } } // anonymous namespace //************************************************************************** // GLOBAL VARIABLES //************************************************************************** DEFINE_DEVICE_TYPE_PRIVATE(A2BUS_COMPUTEREYES2, device_a2bus_card_interface, a2bus_computereyes2_device, "a2ceyes2", "Digital Vision ComputerEyes/2")