From dbb4328ad55837fb56d20c8132fd6de79f753c18 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 30 Dec 2019 09:11:46 +0100 Subject: [PATCH 1/5] initial work on lightgun --- src/emucore/Console.cxx | 5 ++++ src/emucore/Control.cxx | 6 +++-- src/emucore/Control.hxx | 1 + src/emucore/ControllerDetector.cxx | 41 +++++++++++++++++++++++++++++- src/emucore/ControllerDetector.hxx | 4 +++ src/emucore/Event.hxx | 1 + src/emucore/EventHandler.cxx | 2 ++ src/emucore/FrameBuffer.cxx | 3 +++ src/gui/GameInfoDialog.cxx | 3 ++- src/gui/InputDialog.cxx | 3 +++ src/windows/Stella.vcxproj | 2 ++ src/windows/Stella.vcxproj.filters | 6 +++++ 12 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 9387509be..fb9bf6d2b 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -47,6 +47,7 @@ #include "AmigaMouse.hxx" #include "AtariMouse.hxx" #include "TrakBall.hxx" +#include "Lightgun.hxx" #include "FrameBuffer.hxx" #include "TIASurface.hxx" #include "OSystem.hxx" @@ -876,6 +877,10 @@ unique_ptr Console::getControllerPort(const Controller::Type type, controller = make_unique(port, myEvent, *mySystem); break; + case Controller::Type::Lightgun: + controller = make_unique(port, myEvent, *mySystem); + break; + default: // What else can we do? // always create because it may have been changed by user dialog diff --git a/src/emucore/Control.cxx b/src/emucore/Control.cxx index 569177f1f..de0edf85f 100644 --- a/src/emucore/Control.cxx +++ b/src/emucore/Control.cxx @@ -112,7 +112,8 @@ string Controller::getName(const Type type) "Unknown", "AmigaMouse", "AtariMouse", "AtariVox", "BoosterGrip", "CompuMate", "Driving", "Sega Genesis", "Joystick", "Keyboard", "KidVid", "MindLink", - "Paddles", "Paddles_IAxis", "Paddles_IAxDr", "SaveKey", "TrakBall" + "Paddles", "Paddles_IAxis", "Paddles_IAxDr", "SaveKey", "TrakBall", + "Lightgun" }; return NAMES[int(type)]; @@ -126,7 +127,8 @@ string Controller::getPropName(const Type type) "AUTO", "AMIGAMOUSE", "ATARIMOUSE", "ATARIVOX", "BOOSTERGRIP", "COMPUMATE", "DRIVING", "GENESIS", "JOYSTICK", "KEYBOARD", "KIDVID", "MINDLINK", - "PADDLES", "PADDLES_IAXIS", "PADDLES_IAXDR", "SAVEKEY", "TRAKBALL" + "PADDLES", "PADDLES_IAXIS", "PADDLES_IAXDR", "SAVEKEY", "TRAKBALL", + "LIGHTGUN" }; return PROP_NAMES[int(type)]; diff --git a/src/emucore/Control.hxx b/src/emucore/Control.hxx index 8b26f8588..28440deb5 100644 --- a/src/emucore/Control.hxx +++ b/src/emucore/Control.hxx @@ -94,6 +94,7 @@ class Controller : public Serializable AmigaMouse, AtariMouse, AtariVox, BoosterGrip, CompuMate, Driving, Genesis, Joystick, Keyboard, KidVid, MindLink, Paddles, PaddlesIAxis, PaddlesIAxDr, SaveKey, TrakBall, + Lightgun, LastType }; diff --git a/src/emucore/ControllerDetector.cxx b/src/emucore/ControllerDetector.cxx index 0a78d700e..298f24e20 100644 --- a/src/emucore/ControllerDetector.cxx +++ b/src/emucore/ControllerDetector.cxx @@ -70,8 +70,9 @@ Controller::Type ControllerDetector::autodetectPort(const uInt8* image, size_t s else if(usesKeyboard(image, size, port)) type = Controller::Type::Keyboard; else if(usesGenesisButton(image, size, port)) - type = Controller::Type::Genesis; + else if(isProbablyLightGun(image, size, port)) + type = Controller::Type::Lightgun; } else { @@ -643,3 +644,41 @@ bool ControllerDetector::isProbablySaveKey(const uInt8* image, size_t size, return false; } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool ControllerDetector::isProbablyLightGun(const uInt8* image, size_t size, + Controller::Jack port) +{ + if (port == Controller::Jack::Left) + { + // check for INPT4 after NOPs access + const int NUM_SIGS = 2; + const int SIG_SIZE = 6; + uInt8 signature[NUM_SIGS][SIG_SIZE] = { + { 0xea, 0xea, 0xea, 0x24, 0x0c, 0x10 }, + { 0xea, 0xea, 0xea, 0x24, 0x3c, 0x10 } + }; // all pattern checked, only 'Sentinel' and 'Shooting Arcade' match + + for (uInt32 i = 0; i < NUM_SIGS; ++i) + if (searchForBytes(image, size, signature[i], SIG_SIZE)) + return true; + + return false; + } + else if(port == Controller::Jack::Right) + { + // check for INPT5 after NOPs access + const int NUM_SIGS = 2; + const int SIG_SIZE = 6; + uInt8 signature[NUM_SIGS][SIG_SIZE] = { + { 0xea, 0xea, 0xea, 0x24, 0x0d, 0x10 }, + { 0xea, 0xea, 0xea, 0x24, 0x3d, 0x10 } + }; // all pattern checked, only 'Bobby is Hungry' matches + + for (uInt32 i = 0; i < NUM_SIGS; ++i) + if (searchForBytes(image, size, signature[i], SIG_SIZE)) + return true; + } + + return false; +} diff --git a/src/emucore/ControllerDetector.hxx b/src/emucore/ControllerDetector.hxx index 16374569f..f28482e04 100644 --- a/src/emucore/ControllerDetector.hxx +++ b/src/emucore/ControllerDetector.hxx @@ -111,6 +111,10 @@ class ControllerDetector // Returns true if a SaveKey code pattern is found. static bool isProbablySaveKey(const uInt8* image, size_t size, Controller::Jack port); + // Returns true if a Lightgun code pattern is found + static bool isProbablyLightGun(const uInt8* image, size_t size, Controller::Jack port); + + private: // Following constructors and assignment operators not supported ControllerDetector() = delete; diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index 2fea72dd8..41cbf7997 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -121,6 +121,7 @@ class Event CompuMateSlash, ToggleInter, + LightgunZeroFire, LightgunZeroPos, LightgunOneFire, LightgunOnePos, LastType }; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index dcb2cf696..3aa30d136 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -27,6 +27,7 @@ #include "OSystem.hxx" #include "Joystick.hxx" #include "Paddles.hxx" +#include "Lightgun.hxx" #include "PointingDevice.hxx" #include "PropsSet.hxx" #include "Settings.hxx" @@ -100,6 +101,7 @@ void EventHandler::initialize() Paddles::setDejitterDiff(myOSystem.settings().getInt("dejitter.diff")); Paddles::setDigitalSensitivity(myOSystem.settings().getInt("dsense")); Paddles::setMouseSensitivity(myOSystem.settings().getInt("msense")); + Lightgun::setMouseSensitivity(myOSystem.settings().getInt("msense")); PointingDevice::setSensitivity(myOSystem.settings().getInt("tsense")); #ifdef GUI_SUPPORT diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index 922c694dd..46368f5d9 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -841,6 +841,9 @@ void FrameBuffer::setCursorState() bool analog = myOSystem.hasConsole() ? (myOSystem.console().leftController().isAnalog() || myOSystem.console().rightController().isAnalog()) : false; + bool lightgun = emulation && myOSystem.hasConsole() ? + myOSystem.console().leftController().type() == Controller::Type::Lightgun || + myOSystem.console().rightController().type() == Controller::Type::Lightgun : false; bool alwaysUseMouse = BSPF::equalsIgnoreCase("always", myOSystem.settings().getString("usemouse")); grabMouse(emulation && (analog || alwaysUseMouse) && myGrabMouse); diff --git a/src/gui/GameInfoDialog.cxx b/src/gui/GameInfoDialog.cxx index 7b2e213ea..28006e760 100644 --- a/src/gui/GameInfoDialog.cxx +++ b/src/gui/GameInfoDialog.cxx @@ -220,8 +220,9 @@ GameInfoDialog::GameInfoDialog( VarList::push_back(ctrls, "SaveKey", "SAVEKEY"); VarList::push_back(ctrls, "Sega Genesis", "GENESIS"); VarList::push_back(ctrls, "KidVid", "KIDVID"); + VarList::push_back(ctrls, "Lightgun", "LIGHTGUN"); VarList::push_back(ctrls, "MindLink", "MINDLINK"); - + ypos = VBORDER; pwidth = font.getStringWidth("Paddles_IAxis"); myLeftPortLabel = new StaticTextWidget(myTab, font, HBORDER, ypos+1, "Left port "); diff --git a/src/gui/InputDialog.cxx b/src/gui/InputDialog.cxx index 476633e98..de192a18d 100644 --- a/src/gui/InputDialog.cxx +++ b/src/gui/InputDialog.cxx @@ -21,6 +21,7 @@ #include "EventHandler.hxx" #include "Joystick.hxx" #include "Paddles.hxx" +#include "Lightgun.hxx" #include "PointingDevice.hxx" #include "SaveKey.hxx" #include "AtariVox.hxx" @@ -349,6 +350,8 @@ void InputDialog::saveConfig() sensitivity = myMPaddleSpeed->getValue(); instance().settings().setValue("msense", sensitivity); Paddles::setMouseSensitivity(sensitivity); + Lightgun::setMouseSensitivity(sensitivity); + // Trackball speed sensitivity = myTrackBallSpeed->getValue(); diff --git a/src/windows/Stella.vcxproj b/src/windows/Stella.vcxproj index 7bd655b92..a3f520dbb 100644 --- a/src/windows/Stella.vcxproj +++ b/src/windows/Stella.vcxproj @@ -487,6 +487,7 @@ + @@ -1210,6 +1211,7 @@ + diff --git a/src/windows/Stella.vcxproj.filters b/src/windows/Stella.vcxproj.filters index 37ae6f984..4d0d3964f 100644 --- a/src/windows/Stella.vcxproj.filters +++ b/src/windows/Stella.vcxproj.filters @@ -996,6 +996,9 @@ Source Files + + Source Files\emucore + @@ -2036,6 +2039,9 @@ Header Files + + Header Files\emucore + From 5330dcdba6b500b26241814fb90c22d2e238841b Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 30 Dec 2019 09:47:31 +0100 Subject: [PATCH 2/5] add missing files --- src/emucore/Lightgun.cxx | 72 ++++++++++++++++++++++++++++++ src/emucore/Lightgun.hxx | 96 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+) create mode 100644 src/emucore/Lightgun.cxx create mode 100644 src/emucore/Lightgun.hxx diff --git a/src/emucore/Lightgun.cxx b/src/emucore/Lightgun.cxx new file mode 100644 index 000000000..43c582998 --- /dev/null +++ b/src/emucore/Lightgun.cxx @@ -0,0 +1,72 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#include "Lightgun.hxx" + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Lightgun::Lightgun(Jack jack, const Event& event, const System& system) + : Controller(jack, event, system, Controller::Type::Lightgun) +{ + if (myJack == Jack::Left) + { + myFireEvent = Event::JoystickZeroFire; + //myFireEvent = Event::LightgunZeroFire; + myPosValue = Event::LightgunZeroPos; + } + else + { + myFireEvent = Event::JoystickOneFire; + //myFireEvent = Event::LightgunOneFire; + myPosValue = Event::LightgunOnePos; + } + + // Digital pins 1, 2 and 6 are not connected (TOOD: check) + //setPin(DigitalPin::One, true); + //setPin(DigitalPin::Two, true); + //setPin(DigitalPin::Six, true); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Lightgun::update() +{ + // | | Left port | Right port | + // | Fire button | SWCHA bit 4 | SWCHA bit 0 | DP:1 + // | Detect light | INPT4 bit 7 | INPT5 bit 7 | DP:6 + + myCharge = BSPF::clamp(myEvent.get(Event::MouseAxisXValue) * MOUSE_SENSITIVITY, TRIGMIN, TRIGMAX); + + if (myCharge != myLastCharge) + { + setPin(DigitalPin::Six, Int32(MAX_RESISTANCE * (myCharge / double(TRIGMAX)))); + myLastCharge = myCharge; + } + + setPin(DigitalPin::One, myEvent.get(Event::MouseButtonLeftValue) ? false : true); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +void Lightgun::setMouseSensitivity(int sensitivity) +{ + MOUSE_SENSITIVITY = BSPF::clamp(sensitivity, 1, MAX_MOUSE_SENSE); +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +int Lightgun::MOUSE_SENSITIVITY = -1; + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +//const Controller::DigitalPin Lightgun::ourButtonPin = DigitalPin::One; // TODO + diff --git a/src/emucore/Lightgun.hxx b/src/emucore/Lightgun.hxx new file mode 100644 index 000000000..850c3deba --- /dev/null +++ b/src/emucore/Lightgun.hxx @@ -0,0 +1,96 @@ +//============================================================================ +// +// SSSS tt lll lll +// SS SS tt ll ll +// SS tttttt eeee ll ll aaaa +// SSSS tt ee ee ll ll aa +// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" +// SS SS tt ee ll ll aa aa +// SSSS ttt eeeee llll llll aaaaa +// +// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony +// and the Stella Team +// +// See the file "License.txt" for information on usage and redistribution of +// this file, and for a DISCLAIMER OF ALL WARRANTIES. +//============================================================================ + +#ifndef LIGHTGUN_HXX +#define LIGHTGUN_HXX + +#include "bspf.hxx" +#include "Control.hxx" +#include "Event.hxx" + +/** + This class handles the lighgun controller + + @author Thomas Jentzsch +*/ + +class Lightgun : public Controller +{ +public: + /** + Create a new pair of paddle controllers plugged into the specified jack + + @param jack The jack the controller is plugged into + @param event The event object to use for events + @param system The system using this controller + */ + Lightgun(Jack jack, const Event& event, const System& system); + virtual ~Lightgun() = default; + +public: + static constexpr int MAX_MOUSE_SENSE = 20; + + /** + Update the entire digital and analog pin state according to the + events currently set. + */ + void update() override; + + /** + Returns the name of this controller. + */ + string name() const override { return "Lightgun"; } + + /** + Answers whether the controller is intrinsically an analog controller. + */ + bool isAnalog() const override { return true; } + + /** + Sets the sensitivity for analog emulation of lightgun movement + using a mouse. + + @param sensitivity Value from 1 to MAX_MOUSE_SENSE, with larger + values causing more movement + */ + static void setMouseSensitivity(int sensitivity); + +private: + // Pre-compute the events we care about based on given port + // This will eliminate test for left or right port in update() + Event::Type myPosValue, myFireEvent; + + int myCharge, myLastCharge; + + static constexpr int TRIGMIN = 1; + static constexpr int TRIGMAX = 4096; + + static int MOUSE_SENSITIVITY; + + // Lookup table for associating paddle buttons with controller pins + static const Controller::DigitalPin ourButtonPin; + +private: + // Following constructors and assignment operators not supported + Lightgun() = delete; + Lightgun(const Lightgun&) = delete; + Lightgun(Lightgun&&) = delete; + Lightgun& operator=(const Lightgun&) = delete; + Lightgun& operator=(Lightgun&&) = delete; +}; + +#endif From 1295bd5cf6c57b08babe14b063ada5f279640838 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 30 Dec 2019 17:27:28 +0100 Subject: [PATCH 3/5] get lightgun working preliminary --- src/emucore/Booster.cxx | 4 +- src/emucore/Driving.cxx | 6 +-- src/emucore/Event.hxx | 4 +- src/emucore/EventHandler.cxx | 13 +++--- src/emucore/FrameBuffer.cxx | 6 ++- src/emucore/Genesis.cxx | 4 +- src/emucore/Joystick.cxx | 4 +- src/emucore/Lightgun.cxx | 82 +++++++++++++++++++--------------- src/emucore/Lightgun.hxx | 33 ++++++-------- src/emucore/MindLink.cxx | 2 +- src/emucore/Paddles.cxx | 8 ++-- src/emucore/PointingDevice.cxx | 4 +- src/emucore/module.mk | 1 + src/gui/InputDialog.cxx | 3 -- 14 files changed, 91 insertions(+), 83 deletions(-) diff --git a/src/emucore/Booster.cxx b/src/emucore/Booster.cxx index 3e931547c..26b6e276a 100644 --- a/src/emucore/Booster.cxx +++ b/src/emucore/Booster.cxx @@ -99,8 +99,8 @@ void BoosterGrip::update() { // The following code was taken from z26 #define MJ_Threshold 2 - int mousex = myEvent.get(Event::MouseAxisXValue), - mousey = myEvent.get(Event::MouseAxisYValue); + int mousex = myEvent.get(Event::MouseAxisXMove), + mousey = myEvent.get(Event::MouseAxisYMove); if(mousex || mousey) { if((!(abs(mousey) > abs(mousex) << 1)) && (abs(mousex) >= MJ_Threshold)) diff --git a/src/emucore/Driving.cxx b/src/emucore/Driving.cxx index 5b634b15d..bb24b9cb8 100644 --- a/src/emucore/Driving.cxx +++ b/src/emucore/Driving.cxx @@ -62,7 +62,7 @@ void Driving::update() // Mouse motion and button events if(myControlID > -1) { - int m_axis = myEvent.get(Event::MouseAxisXValue); + int m_axis = myEvent.get(Event::MouseAxisXMove); if(m_axis < -2) --myCounter; else if(m_axis > 2) ++myCounter; if(myEvent.get(Event::MouseButtonLeftValue) || @@ -75,7 +75,7 @@ void Driving::update() // mapped to a separate driving controller if(myControlIDX > -1) { - int m_axis = myEvent.get(Event::MouseAxisXValue); + int m_axis = myEvent.get(Event::MouseAxisXMove); if(m_axis < -2) --myCounter; else if(m_axis > 2) ++myCounter; if(myEvent.get(Event::MouseButtonLeftValue)) @@ -83,7 +83,7 @@ void Driving::update() } if(myControlIDY > -1) { - int m_axis = myEvent.get(Event::MouseAxisYValue); + int m_axis = myEvent.get(Event::MouseAxisYMove); if(m_axis < -2) --myCounter; else if(m_axis > 2) ++myCounter; if(myEvent.get(Event::MouseButtonRightValue)) diff --git a/src/emucore/Event.hxx b/src/emucore/Event.hxx index 41cbf7997..481689fab 100644 --- a/src/emucore/Event.hxx +++ b/src/emucore/Event.hxx @@ -68,7 +68,7 @@ class Event Combo1, Combo2, Combo3, Combo4, Combo5, Combo6, Combo7, Combo8, Combo9, Combo10, Combo11, Combo12, Combo13, Combo14, Combo15, Combo16, - MouseAxisXValue, MouseAxisYValue, + MouseAxisXMove, MouseAxisYMove, MouseButtonLeftValue, MouseButtonRightValue, ChangeState, LoadState, SaveState, TakeSnapshot, Quit, @@ -121,7 +121,7 @@ class Event CompuMateSlash, ToggleInter, - LightgunZeroFire, LightgunZeroPos, LightgunOneFire, LightgunOnePos, + MouseAxisXValue, MouseAxisYValue, LastType }; diff --git a/src/emucore/EventHandler.cxx b/src/emucore/EventHandler.cxx index 9da143eb0..3e26c3692 100644 --- a/src/emucore/EventHandler.cxx +++ b/src/emucore/EventHandler.cxx @@ -95,7 +95,6 @@ void EventHandler::initialize() Paddles::setDejitterDiff(myOSystem.settings().getInt("dejitter.diff")); Paddles::setDigitalSensitivity(myOSystem.settings().getInt("dsense")); Paddles::setMouseSensitivity(myOSystem.settings().getInt("msense")); - Lightgun::setMouseSensitivity(myOSystem.settings().getInt("msense")); PointingDevice::setSensitivity(myOSystem.settings().getInt("tsense")); #ifdef GUI_SUPPORT @@ -249,8 +248,8 @@ void EventHandler::poll(uInt64 time) // Turn off all mouse-related items; if they haven't been taken care of // in the previous ::update() methods, they're now invalid - myEvent.set(Event::MouseAxisXValue, 0); - myEvent.set(Event::MouseAxisYValue, 0); + myEvent.set(Event::MouseAxisXMove, 0); + myEvent.set(Event::MouseAxisYMove, 0); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -271,8 +270,10 @@ void EventHandler::handleMouseMotionEvent(int x, int y, int xrel, int yrel) { if(!mySkipMouseMotion) { - myEvent.set(Event::MouseAxisXValue, xrel); - myEvent.set(Event::MouseAxisYValue, yrel); + myEvent.set(Event::MouseAxisXValue, x); // required for Lightgun controller + myEvent.set(Event::MouseAxisYValue, y); // required for Lightgun controller + myEvent.set(Event::MouseAxisXMove, xrel); + myEvent.set(Event::MouseAxisYMove, yrel); } mySkipMouseMotion = false; } @@ -1954,7 +1955,7 @@ const Event::EventSet EventHandler::MiscEvents = { Event::Quit, Event::ReloadConsole, Event::Fry, Event::StartPauseMode, Event::TogglePauseMode, Event::OptionsMenuMode, Event::CmdMenuMode, Event::ExitMode, Event::TakeSnapshot, Event::ToggleContSnapshots, Event::ToggleContSnapshotsFrame, - // Event::MouseAxisXValue, Event::MouseAxisYValue, + // Event::MouseAxisXMove, Event::MouseAxisYMove, // Event::MouseButtonLeftValue, Event::MouseButtonRightValue, Event::HandleMouseControl, Event::ToggleGrabMouse, Event::ToggleSAPortOrder, diff --git a/src/emucore/FrameBuffer.cxx b/src/emucore/FrameBuffer.cxx index e07c8ad87..5ed99d6fb 100644 --- a/src/emucore/FrameBuffer.cxx +++ b/src/emucore/FrameBuffer.cxx @@ -841,13 +841,17 @@ void FrameBuffer::setCursorState() bool analog = myOSystem.hasConsole() ? (myOSystem.console().leftController().isAnalog() || myOSystem.console().rightController().isAnalog()) : false; - bool lightgun = emulation && myOSystem.hasConsole() ? + bool usesLightgun = emulation && myOSystem.hasConsole() ? myOSystem.console().leftController().type() == Controller::Type::Lightgun || myOSystem.console().rightController().type() == Controller::Type::Lightgun : false; bool alwaysUseMouse = BSPF::equalsIgnoreCase("always", myOSystem.settings().getString("usemouse")); // Show/hide cursor in UI/emulation mode based on 'cursor' setting int cursor = myOSystem.settings().getInt("cursor"); + // always enable cursor in lightgun games + if (usesLightgun) + cursor |= 1; + switch(cursor) { case 0: diff --git a/src/emucore/Genesis.cxx b/src/emucore/Genesis.cxx index 30e4055db..8623b0ea6 100644 --- a/src/emucore/Genesis.cxx +++ b/src/emucore/Genesis.cxx @@ -67,8 +67,8 @@ void Genesis::update() { // The following code was taken from z26 #define MJ_Threshold 2 - int mousex = myEvent.get(Event::MouseAxisXValue), - mousey = myEvent.get(Event::MouseAxisYValue); + int mousex = myEvent.get(Event::MouseAxisXMove), + mousey = myEvent.get(Event::MouseAxisYMove); if(mousex || mousey) { if((!(abs(mousey) > abs(mousex) << 1)) && (abs(mousex) >= MJ_Threshold)) diff --git a/src/emucore/Joystick.cxx b/src/emucore/Joystick.cxx index 0a988eb73..4b08e843d 100644 --- a/src/emucore/Joystick.cxx +++ b/src/emucore/Joystick.cxx @@ -81,8 +81,8 @@ void Joystick::update() { // The following code was taken from z26 #define MJ_Threshold 2 - int mousex = myEvent.get(Event::MouseAxisXValue), - mousey = myEvent.get(Event::MouseAxisYValue); + int mousex = myEvent.get(Event::MouseAxisXMove), + mousey = myEvent.get(Event::MouseAxisYMove); if(mousex || mousey) { if((!(abs(mousey) > abs(mousex) << 1)) && (abs(mousex) >= MJ_Threshold)) diff --git a/src/emucore/Lightgun.cxx b/src/emucore/Lightgun.cxx index 43c582998..2b116a0ac 100644 --- a/src/emucore/Lightgun.cxx +++ b/src/emucore/Lightgun.cxx @@ -15,29 +15,55 @@ // this file, and for a DISCLAIMER OF ALL WARRANTIES. //============================================================================ + +#include "TIA.hxx" +#include "System.hxx" + #include "Lightgun.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Lightgun::Lightgun(Jack jack, const Event& event, const System& system) : Controller(jack, event, system, Controller::Type::Lightgun) { - if (myJack == Jack::Left) - { - myFireEvent = Event::JoystickZeroFire; - //myFireEvent = Event::LightgunZeroFire; - myPosValue = Event::LightgunZeroPos; - } - else - { - myFireEvent = Event::JoystickOneFire; - //myFireEvent = Event::LightgunOneFire; - myPosValue = Event::LightgunOnePos; - } +} - // Digital pins 1, 2 and 6 are not connected (TOOD: check) - //setPin(DigitalPin::One, true); - //setPin(DigitalPin::Two, true); - //setPin(DigitalPin::Six, true); +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool Lightgun::read(DigitalPin pin) +{ + + // We need to override the Controller::read() method, since the lightgun + // checks this multiple times per frame + // (we can't just read 60 times per second in the ::update() method) + switch (pin) + { + // Pin 6: INPT4/5 + case DigitalPin::Six: + { + // TODO: scale correctly, current code assumes 2x zoom and no vertical scaling + Int32 xpos = myMouseX / 4; + Int32 ypos = myMouseY / 2; + uInt32 ux; + uInt32 uy; + + mySystem.tia().electronBeamPos(ux, uy); + Int32 x = mySystem.tia().clocksThisLine() - TIAConstants::H_BLANK_CLOCKS + X_OFS; + + if (x < 0) + x += TIAConstants::H_CLOCKS; + Int32 y = uy + Y_OFS; + + //cerr << "mouse:" << xpos << " " << ypos << endl; + //cerr << " beam:" << x << " " << y << endl; + + + bool enable = !((x - xpos) >= 0 && (x - xpos) < 15 && (y - ypos) >= 0); + + return enable; + } + + default: + return Controller::read(pin); + } } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -47,26 +73,12 @@ void Lightgun::update() // | Fire button | SWCHA bit 4 | SWCHA bit 0 | DP:1 // | Detect light | INPT4 bit 7 | INPT5 bit 7 | DP:6 - myCharge = BSPF::clamp(myEvent.get(Event::MouseAxisXValue) * MOUSE_SENSITIVITY, TRIGMIN, TRIGMAX); + Int32 xVal = myEvent.get(Event::MouseAxisXValue); + Int32 yVal = myEvent.get(Event::MouseAxisYValue); - if (myCharge != myLastCharge) - { - setPin(DigitalPin::Six, Int32(MAX_RESISTANCE * (myCharge / double(TRIGMAX)))); - myLastCharge = myCharge; - } + myMouseX = xVal ? xVal : myMouseX; + myMouseY = yVal ? yVal : myMouseY; - setPin(DigitalPin::One, myEvent.get(Event::MouseButtonLeftValue) ? false : true); + setPin(DigitalPin::One, myEvent.get(Event::MouseButtonLeftValue) || myEvent.get(Event::MouseButtonRightValue)); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -void Lightgun::setMouseSensitivity(int sensitivity) -{ - MOUSE_SENSITIVITY = BSPF::clamp(sensitivity, 1, MAX_MOUSE_SENSE); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -int Lightgun::MOUSE_SENSITIVITY = -1; - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -//const Controller::DigitalPin Lightgun::ourButtonPin = DigitalPin::One; // TODO - diff --git a/src/emucore/Lightgun.hxx b/src/emucore/Lightgun.hxx index 850c3deba..34de0f7a6 100644 --- a/src/emucore/Lightgun.hxx +++ b/src/emucore/Lightgun.hxx @@ -23,7 +23,7 @@ #include "Event.hxx" /** - This class handles the lighgun controller + This class handles the lightgun controller @author Thomas Jentzsch */ @@ -42,7 +42,15 @@ public: virtual ~Lightgun() = default; public: - static constexpr int MAX_MOUSE_SENSE = 20; + using Controller::read; + + /** + Read the value of the specified digital pin for this controller. + + @param pin The pin of the controller jack to read + @return The state of the pin + */ + bool read(DigitalPin pin) override; /** Update the entire digital and analog pin state according to the @@ -60,26 +68,11 @@ public: */ bool isAnalog() const override { return true; } - /** - Sets the sensitivity for analog emulation of lightgun movement - using a mouse. - - @param sensitivity Value from 1 to MAX_MOUSE_SENSE, with larger - values causing more movement - */ - static void setMouseSensitivity(int sensitivity); - private: - // Pre-compute the events we care about based on given port - // This will eliminate test for left or right port in update() - Event::Type myPosValue, myFireEvent; + Int32 myMouseX{0}, myMouseY{0}; - int myCharge, myLastCharge; - - static constexpr int TRIGMIN = 1; - static constexpr int TRIGMAX = 4096; - - static int MOUSE_SENSITIVITY; + static constexpr Int32 X_OFS = -21; + static constexpr Int32 Y_OFS = 10; // Lookup table for associating paddle buttons with controller pins static const Controller::DigitalPin ourButtonPin; diff --git a/src/emucore/MindLink.cxx b/src/emucore/MindLink.cxx index bca8c92f1..50d43785a 100644 --- a/src/emucore/MindLink.cxx +++ b/src/emucore/MindLink.cxx @@ -40,7 +40,7 @@ void MindLink::update() return; myMindlinkPos = (myMindlinkPos & 0x3fffffff) + - (myEvent.get(Event::MouseAxisXValue) << 3); + (myEvent.get(Event::MouseAxisXMove) << 3); if(myMindlinkPos < 0x2800) myMindlinkPos = 0x2800; if(myMindlinkPos >= 0x3800) diff --git a/src/emucore/Paddles.cxx b/src/emucore/Paddles.cxx index 601850018..45e1398b6 100644 --- a/src/emucore/Paddles.cxx +++ b/src/emucore/Paddles.cxx @@ -162,13 +162,13 @@ Paddles::Paddles(Jack jack, const Event& event, const System& system, abs(MOUSE_SENSITIVITY); if(!swapaxis) { - myAxisMouseMotion = Event::MouseAxisXValue; + myAxisMouseMotion = Event::MouseAxisXMove; myAxisDigitalZero = 0; myAxisDigitalOne = 1; } else { - myAxisMouseMotion = Event::MouseAxisYValue; + myAxisMouseMotion = Event::MouseAxisYMove; myAxisDigitalZero = 1; myAxisDigitalOne = 0; } @@ -277,7 +277,7 @@ void Paddles::update() if(myMPaddleIDX > -1) { myCharge[myMPaddleIDX] = BSPF::clamp(myCharge[myMPaddleIDX] - - (myEvent.get(Event::MouseAxisXValue) * MOUSE_SENSITIVITY), + (myEvent.get(Event::MouseAxisXMove) * MOUSE_SENSITIVITY), TRIGMIN, TRIGRANGE); if(myEvent.get(Event::MouseButtonLeftValue)) setPin(ourButtonPin[myMPaddleIDX], false); @@ -285,7 +285,7 @@ void Paddles::update() if(myMPaddleIDY > -1) { myCharge[myMPaddleIDY] = BSPF::clamp(myCharge[myMPaddleIDY] - - (myEvent.get(Event::MouseAxisYValue) * MOUSE_SENSITIVITY), + (myEvent.get(Event::MouseAxisYMove) * MOUSE_SENSITIVITY), TRIGMIN, TRIGRANGE); if(myEvent.get(Event::MouseButtonRightValue)) setPin(ourButtonPin[myMPaddleIDY], false); diff --git a/src/emucore/PointingDevice.cxx b/src/emucore/PointingDevice.cxx index 507998730..e23a4399e 100644 --- a/src/emucore/PointingDevice.cxx +++ b/src/emucore/PointingDevice.cxx @@ -79,11 +79,11 @@ void PointingDevice::update() return; // Update horizontal direction - updateDirection( myEvent.get(Event::MouseAxisXValue), myHCounterRemainder, + updateDirection( myEvent.get(Event::MouseAxisXMove), myHCounterRemainder, myTrackBallLeft, myTrackBallLinesH, myScanCountH, myFirstScanOffsetH); // Update vertical direction - updateDirection(-myEvent.get(Event::MouseAxisYValue), myVCounterRemainder, + updateDirection(-myEvent.get(Event::MouseAxisYMove), myVCounterRemainder, myTrackBallDown, myTrackBallLinesV, myScanCountV, myFirstScanOffsetV); // Get mouse button state diff --git a/src/emucore/module.mk b/src/emucore/module.mk index 7fd311126..e02fcdc2d 100644 --- a/src/emucore/module.mk +++ b/src/emucore/module.mk @@ -66,6 +66,7 @@ MODULE_OBJS := \ src/emucore/Joystick.o \ src/emucore/Keyboard.o \ src/emucore/KidVid.o \ + src/emucore/Lightgun.o \ src/emucore/MindLink.o \ src/emucore/M6502.o \ src/emucore/M6532.o \ diff --git a/src/gui/InputDialog.cxx b/src/gui/InputDialog.cxx index bbbb4e122..7a30b20a3 100644 --- a/src/gui/InputDialog.cxx +++ b/src/gui/InputDialog.cxx @@ -21,7 +21,6 @@ #include "EventHandler.hxx" #include "Joystick.hxx" #include "Paddles.hxx" -#include "Lightgun.hxx" #include "PointingDevice.hxx" #include "SaveKey.hxx" #include "AtariVox.hxx" @@ -350,8 +349,6 @@ void InputDialog::saveConfig() sensitivity = myMPaddleSpeed->getValue(); instance().settings().setValue("msense", sensitivity); Paddles::setMouseSensitivity(sensitivity); - Lightgun::setMouseSensitivity(sensitivity); - // Trackball speed sensitivity = myTrackBallSpeed->getValue(); From 86e01bc8b9e1571b62d158b7d0e87998a290bcd3 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 30 Dec 2019 22:37:50 +0100 Subject: [PATCH 4/5] apply screen scaling to lightgun controller --- src/emucore/Console.cxx | 2 +- src/emucore/Lightgun.cxx | 24 ++++++++++-------------- src/emucore/Lightgun.hxx | 5 +++-- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/emucore/Console.cxx b/src/emucore/Console.cxx index 08aade138..cc0d7157b 100644 --- a/src/emucore/Console.cxx +++ b/src/emucore/Console.cxx @@ -873,7 +873,7 @@ unique_ptr Console::getControllerPort(const Controller::Type type, break; case Controller::Type::Lightgun: - controller = make_unique(port, myEvent, *mySystem); + controller = make_unique(port, myEvent, *mySystem, myOSystem.frameBuffer()); break; default: diff --git a/src/emucore/Lightgun.cxx b/src/emucore/Lightgun.cxx index 2b116a0ac..8f23f34d3 100644 --- a/src/emucore/Lightgun.cxx +++ b/src/emucore/Lightgun.cxx @@ -18,12 +18,14 @@ #include "TIA.hxx" #include "System.hxx" +#include "FrameBuffer.hxx" #include "Lightgun.hxx" // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Lightgun::Lightgun(Jack jack, const Event& event, const System& system) - : Controller(jack, event, system, Controller::Type::Lightgun) +Lightgun::Lightgun(Jack jack, const Event& event, const System& system, const FrameBuffer& frameBuffer) + : Controller(jack, event, system, Controller::Type::Lightgun), + myFrameBuffer(frameBuffer) { } @@ -39,22 +41,16 @@ bool Lightgun::read(DigitalPin pin) // Pin 6: INPT4/5 case DigitalPin::Six: { - // TODO: scale correctly, current code assumes 2x zoom and no vertical scaling - Int32 xpos = myMouseX / 4; - Int32 ypos = myMouseY / 2; - uInt32 ux; - uInt32 uy; - - mySystem.tia().electronBeamPos(ux, uy); + const Common::Rect& rect = myFrameBuffer.imageRect(); + // scale mouse coordinates into TIA coordinates + Int32 xpos = (myMouseX - rect.x()) * TIAConstants::H_PIXEL / rect.w(); + Int32 ypos = (myMouseY - rect.y()) * 210 / rect.h(); // TODO: replace "magic number" + // get adjusted TIA coordinates Int32 x = mySystem.tia().clocksThisLine() - TIAConstants::H_BLANK_CLOCKS + X_OFS; + Int32 y = mySystem.tia().scanlines() - mySystem.tia().startLine() + Y_OFS; if (x < 0) x += TIAConstants::H_CLOCKS; - Int32 y = uy + Y_OFS; - - //cerr << "mouse:" << xpos << " " << ypos << endl; - //cerr << " beam:" << x << " " << y << endl; - bool enable = !((x - xpos) >= 0 && (x - xpos) < 15 && (y - ypos) >= 0); diff --git a/src/emucore/Lightgun.hxx b/src/emucore/Lightgun.hxx index 34de0f7a6..739dcd22a 100644 --- a/src/emucore/Lightgun.hxx +++ b/src/emucore/Lightgun.hxx @@ -38,7 +38,7 @@ public: @param event The event object to use for events @param system The system using this controller */ - Lightgun(Jack jack, const Event& event, const System& system); + Lightgun(Jack jack, const Event& event, const System& system, const FrameBuffer& frameBuffer); virtual ~Lightgun() = default; public: @@ -69,10 +69,11 @@ public: bool isAnalog() const override { return true; } private: + const FrameBuffer& myFrameBuffer; Int32 myMouseX{0}, myMouseY{0}; static constexpr Int32 X_OFS = -21; - static constexpr Int32 Y_OFS = 10; + static constexpr Int32 Y_OFS = 5; // Lookup table for associating paddle buttons with controller pins static const Controller::DigitalPin ourButtonPin; From 8bf1f0c4042b806f30121cdc964ed1e2419cb305 Mon Sep 17 00:00:00 2001 From: thrust26 Date: Mon, 30 Dec 2019 23:00:49 +0100 Subject: [PATCH 5/5] code cleanup added Light Gun to docs --- docs/index.html | 11 ++++++++++- src/emucore/Lightgun.cxx | 41 ++++++++++++++++++---------------------- src/emucore/Lightgun.hxx | 13 ------------- 3 files changed, 28 insertions(+), 37 deletions(-) diff --git a/docs/index.html b/docs/index.html index 5ed085294..fd07a52f6 100644 --- a/docs/index.html +++ b/docs/index.html @@ -275,7 +275,7 @@
  • Emulates Spectravideo CompuMate system using your computer's keyboard, including mapping of CompuMate 'Backspace', 'Space' and 'Enter' functionality to to the actual keys on your keyboard
  • -
  • Emulates the Mindlink Controller using your computer's mouse
  • +
  • Emulates the Mindlink Controller and the Light Gun using your computer's mouse
  • Supports autodetection for most common controller types
  • Support for real Atari 2600 controllers using the Stelladaptor and @@ -1784,6 +1784,14 @@ ✕ ✕ + + Light Gun + ✕ + ✕ + ✓ + ✕ + ✕ + Mindlink ✕ @@ -3817,6 +3825,7 @@ Ms Pac-Man (Stella extended codes): SaveKeyA 32K EEPROM for saving high scores, etc. (the EEPROM portion of an AtariVox). Genesis Sega Genesis controller, which can be used similar to a BoosterGrip, giving an extra button. CompuMate ¹Spectravideo CompuMate (if either left or right is set, CompuMate is used for both). + LightgunAtari XG-1 compatible Light Gun Mindlink ¹Mindlink controller. diff --git a/src/emucore/Lightgun.cxx b/src/emucore/Lightgun.cxx index 8f23f34d3..41fc5a882 100644 --- a/src/emucore/Lightgun.cxx +++ b/src/emucore/Lightgun.cxx @@ -16,12 +16,16 @@ //============================================================================ +#include "Event.hxx" #include "TIA.hxx" -#include "System.hxx" #include "FrameBuffer.hxx" #include "Lightgun.hxx" +// | | Left port | Right port | +// | Fire button | SWCHA bit 4 | SWCHA bit 0 | DP:1 +// | Detect light | INPT4 bit 7 | INPT5 bit 7 | DP:6 + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Lightgun::Lightgun(Jack jack, const Event& event, const System& system, const FrameBuffer& frameBuffer) : Controller(jack, event, system, Controller::Type::Lightgun), @@ -32,31 +36,30 @@ Lightgun::Lightgun(Jack jack, const Event& event, const System& system, const Fr // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool Lightgun::read(DigitalPin pin) { - // We need to override the Controller::read() method, since the lightgun // checks this multiple times per frame // (we can't just read 60 times per second in the ::update() method) switch (pin) { - // Pin 6: INPT4/5 - case DigitalPin::Six: + case DigitalPin::Six: // INPT4/5 { const Common::Rect& rect = myFrameBuffer.imageRect(); // scale mouse coordinates into TIA coordinates - Int32 xpos = (myMouseX - rect.x()) * TIAConstants::H_PIXEL / rect.w(); - Int32 ypos = (myMouseY - rect.y()) * 210 / rect.h(); // TODO: replace "magic number" + Int32 xMouse = (myEvent.get(Event::MouseAxisXValue) - rect.x()) + * TIAConstants::H_PIXEL / rect.w(); + Int32 yMouse = (myEvent.get(Event::MouseAxisYValue) - rect.y()) + * 210 / rect.h(); // TODO: replace "magic number" // get adjusted TIA coordinates - Int32 x = mySystem.tia().clocksThisLine() - TIAConstants::H_BLANK_CLOCKS + X_OFS; - Int32 y = mySystem.tia().scanlines() - mySystem.tia().startLine() + Y_OFS; + Int32 xTia = mySystem.tia().clocksThisLine() - TIAConstants::H_BLANK_CLOCKS + X_OFS; + Int32 yTia = mySystem.tia().scanlines() - mySystem.tia().startLine() + Y_OFS; - if (x < 0) - x += TIAConstants::H_CLOCKS; + if (xTia < 0) + xTia += TIAConstants::H_CLOCKS; - bool enable = !((x - xpos) >= 0 && (x - xpos) < 15 && (y - ypos) >= 0); + bool enable = !((xTia - xMouse) >= 0 && (xTia - xMouse) < 15 && (yTia - yMouse) >= 0); return enable; } - default: return Controller::read(pin); } @@ -65,16 +68,8 @@ bool Lightgun::read(DigitalPin pin) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Lightgun::update() { - // | | Left port | Right port | - // | Fire button | SWCHA bit 4 | SWCHA bit 0 | DP:1 - // | Detect light | INPT4 bit 7 | INPT5 bit 7 | DP:6 - - Int32 xVal = myEvent.get(Event::MouseAxisXValue); - Int32 yVal = myEvent.get(Event::MouseAxisYValue); - - myMouseX = xVal ? xVal : myMouseX; - myMouseY = yVal ? yVal : myMouseY; - - setPin(DigitalPin::One, myEvent.get(Event::MouseButtonLeftValue) || myEvent.get(Event::MouseButtonRightValue)); + // we allow left and right mouse buttons for fire button + setPin(DigitalPin::One, myEvent.get(Event::MouseButtonLeftValue) + || myEvent.get(Event::MouseButtonRightValue)); } diff --git a/src/emucore/Lightgun.hxx b/src/emucore/Lightgun.hxx index 739dcd22a..928f705b0 100644 --- a/src/emucore/Lightgun.hxx +++ b/src/emucore/Lightgun.hxx @@ -18,10 +18,6 @@ #ifndef LIGHTGUN_HXX #define LIGHTGUN_HXX -#include "bspf.hxx" -#include "Control.hxx" -#include "Event.hxx" - /** This class handles the lightgun controller @@ -63,21 +59,12 @@ public: */ string name() const override { return "Lightgun"; } - /** - Answers whether the controller is intrinsically an analog controller. - */ - bool isAnalog() const override { return true; } - private: const FrameBuffer& myFrameBuffer; - Int32 myMouseX{0}, myMouseY{0}; static constexpr Int32 X_OFS = -21; static constexpr Int32 Y_OFS = 5; - // Lookup table for associating paddle buttons with controller pins - static const Controller::DigitalPin ourButtonPin; - private: // Following constructors and assignment operators not supported Lightgun() = delete;