diff --git a/Machines/Amiga/Chipset.cpp b/Machines/Amiga/Chipset.cpp index a9dafbd82..38882cc86 100644 --- a/Machines/Amiga/Chipset.cpp +++ b/Machines/Amiga/Chipset.cpp @@ -1193,121 +1193,6 @@ void Chipset::set_component_prefers_clocking(ClockingHint::Source *, ClockingHin disk_controller_is_sleeping_ = preference == ClockingHint::Preference::None; } -// MARK: - Mouse. - -int Chipset::Mouse::get_number_of_buttons() { - return 2; -} - -void Chipset::Mouse::set_button_pressed(int button, bool is_set) { - switch(button) { - case 0: - cia_state_ = (cia_state_ &~ 0x40) | (is_set ? 0 : 0x40); - break; - default: - break; - } -} - -uint8_t Chipset::Mouse::get_cia_button() const { - return cia_state_; -} - -void Chipset::Mouse::reset_all_buttons() { - cia_state_ = 0xff; -} - -void Chipset::Mouse::move(int x, int y) { - position_[0] += x; - position_[1] += y; -} - -Inputs::Mouse &Chipset::get_mouse() { - return mouse_; -} - -uint16_t Chipset::Mouse::get_position() { - // The Amiga hardware retains only eight bits of position - // for the mouse; its software polls frequently and maps - // changes into a larger space. - // - // On modern computers with 5k+ displays and trackpads, it - // proved empirically possible to overflow the hardware - // counters more quickly than software would poll. - // - // Therefore the approach taken for mapping mouse motion - // into the Amiga is to do it in steps of no greater than - // [-128, +127], as per the below. - const int pending[] = { - position_[0], position_[1] - }; - - const int8_t change[] = { - int8_t(std::clamp(pending[0], -128, 127)), - int8_t(std::clamp(pending[1], -128, 127)) - }; - - position_[0] -= change[0]; - position_[1] -= change[1]; - declared_position_[0] += change[0]; - declared_position_[1] += change[1]; - - return uint16_t( - (declared_position_[1] << 8) | - declared_position_[0] - ); -} - -// MARK: - Joystick. - -// TODO: add second fire button. - -Chipset::Joystick::Joystick() : - ConcreteJoystick({ - Input(Input::Up), - Input(Input::Down), - Input(Input::Left), - Input(Input::Right), - Input(Input::Fire, 0), - }) {} - -void Chipset::Joystick::did_set_input(const Input &input, bool is_active) { - // Accumulate state. - inputs_[input.type] = is_active; - - // Determine what that does to the two position bits. - const auto low = - (inputs_[Input::Type::Down] ^ inputs_[Input::Type::Right]) | - (inputs_[Input::Type::Right] << 1); - const auto high = - (inputs_[Input::Type::Up] ^ inputs_[Input::Type::Left]) | - (inputs_[Input::Type::Left] << 1); - - // Ripple upwards if that affects the mouse position counters. - const uint8_t previous_low = position_ & 3; - uint8_t low_upper = (position_ >> 2) & 0x3f; - const uint8_t previous_high = (position_ >> 8) & 3; - uint8_t high_upper = (position_ >> 10) & 0x3f; - - if(!low && previous_low == 3) ++low_upper; - if(!previous_low && low == 3) --low_upper; - if(!high && previous_high == 3) ++high_upper; - if(!previous_high && high == 3) --high_upper; - - position_ = uint16_t( - low | ((low_upper & 0x3f) << 2) | - (high << 8) | ((high_upper & 0x3f) << 10) - ); -} - -uint16_t Chipset::Joystick::get_position() const { - return position_; -} - -uint8_t Chipset::Joystick::get_cia_button() const { - return inputs_[Input::Type::Fire] ? 0xbf : 0xff; -} - // MARK: - Synchronisation. void Chipset::flush() { diff --git a/Machines/Amiga/Chipset.hpp b/Machines/Amiga/Chipset.hpp index 51d20fa68..307311256 100644 --- a/Machines/Amiga/Chipset.hpp +++ b/Machines/Amiga/Chipset.hpp @@ -19,8 +19,6 @@ #include "../../ClockReceiver/ClockingHintSource.hpp" #include "../../ClockReceiver/JustInTime.hpp" #include "../../Components/6526/6526.hpp" -#include "../../Inputs/Joystick.hpp" -#include "../../Inputs/Mouse.hpp" #include "../../Outputs/CRT/CRT.hpp" #include "../../Processors/68000/68000.hpp" #include "../../Storage/Disk/Controller/DiskController.hpp" @@ -32,6 +30,7 @@ #include "DMADevice.hpp" #include "Flags.hpp" #include "Keyboard.hpp" +#include "MouseJoystick.hpp" #include "MemoryMap.hpp" #include "Sprites.hpp" @@ -284,41 +283,15 @@ class Chipset: private ClockingHint::Observer { // MARK: - Mouse. private: - class Mouse: public Inputs::Mouse { - public: - uint16_t get_position(); - uint8_t get_cia_button() const; - - private: - int get_number_of_buttons() final; - void set_button_pressed(int, bool) final; - void reset_all_buttons() final; - void move(int, int) final; - - uint8_t declared_position_[2]{}; - uint8_t cia_state_ = 0xff; - std::array<std::atomic<int>, 2> position_{}; - } mouse_; + Mouse mouse_; public: - Inputs::Mouse &get_mouse(); + Inputs::Mouse &get_mouse() { + return mouse_; + } // MARK: - Joystick. private: - class Joystick: public Inputs::ConcreteJoystick { - public: - Joystick(); - - uint16_t get_position() const; - uint8_t get_cia_button() const; - - private: - void did_set_input(const Input &input, bool is_active) final; - - bool inputs_[Joystick::Input::Type::Max]{}; - uint16_t position_ = 0; - }; - std::vector<std::unique_ptr<Inputs::Joystick>> joysticks_; Joystick &joystick(size_t index) const { return *static_cast<Joystick *>(joysticks_[index].get()); diff --git a/Machines/Amiga/MouseJoystick.cpp b/Machines/Amiga/MouseJoystick.cpp new file mode 100644 index 000000000..b7e1519a2 --- /dev/null +++ b/Machines/Amiga/MouseJoystick.cpp @@ -0,0 +1,122 @@ +// +// MouseJoystick.cpp +// Clock Signal +// +// Created by Thomas Harte on 26/11/2021. +// Copyright © 2021 Thomas Harte. All rights reserved. +// + +#include "MouseJoystick.hpp" + +using namespace Amiga; + +// MARK: - Mouse. + +int Mouse::get_number_of_buttons() { + return 2; +} + +void Mouse::set_button_pressed(int button, bool is_set) { + switch(button) { + case 0: + cia_state_ = (cia_state_ &~ 0x40) | (is_set ? 0 : 0x40); + break; + default: + break; + } +} + +uint8_t Mouse::get_cia_button() const { + return cia_state_; +} + +void Mouse::reset_all_buttons() { + cia_state_ = 0xff; +} + +void Mouse::move(int x, int y) { + position_[0] += x; + position_[1] += y; +} + +uint16_t Mouse::get_position() { + // The Amiga hardware retains only eight bits of position + // for the mouse; its software polls frequently and maps + // changes into a larger space. + // + // On modern computers with 5k+ displays and trackpads, it + // proved empirically possible to overflow the hardware + // counters more quickly than software would poll. + // + // Therefore the approach taken for mapping mouse motion + // into the Amiga is to do it in steps of no greater than + // [-128, +127], as per the below. + const int pending[] = { + position_[0], position_[1] + }; + + const int8_t change[] = { + int8_t(std::clamp(pending[0], -128, 127)), + int8_t(std::clamp(pending[1], -128, 127)) + }; + + position_[0] -= change[0]; + position_[1] -= change[1]; + declared_position_[0] += change[0]; + declared_position_[1] += change[1]; + + return uint16_t( + (declared_position_[1] << 8) | + declared_position_[0] + ); +} + +// MARK: - Joystick. + +// TODO: add second fire button. + +Joystick::Joystick() : + ConcreteJoystick({ + Input(Input::Up), + Input(Input::Down), + Input(Input::Left), + Input(Input::Right), + Input(Input::Fire, 0), + }) {} + +void Joystick::did_set_input(const Input &input, bool is_active) { + // Accumulate state. + inputs_[input.type] = is_active; + + // Determine what that does to the two position bits. + const auto low = + (inputs_[Input::Type::Down] ^ inputs_[Input::Type::Right]) | + (inputs_[Input::Type::Right] << 1); + const auto high = + (inputs_[Input::Type::Up] ^ inputs_[Input::Type::Left]) | + (inputs_[Input::Type::Left] << 1); + + // Ripple upwards if that affects the mouse position counters. + const uint8_t previous_low = position_ & 3; + uint8_t low_upper = (position_ >> 2) & 0x3f; + const uint8_t previous_high = (position_ >> 8) & 3; + uint8_t high_upper = (position_ >> 10) & 0x3f; + + if(!low && previous_low == 3) ++low_upper; + if(!previous_low && low == 3) --low_upper; + if(!high && previous_high == 3) ++high_upper; + if(!previous_high && high == 3) --high_upper; + + position_ = uint16_t( + low | ((low_upper & 0x3f) << 2) | + (high << 8) | ((high_upper & 0x3f) << 10) + ); +} + +uint16_t Joystick::get_position() { + return position_; +} + +uint8_t Joystick::get_cia_button() const { + return inputs_[Input::Type::Fire] ? 0xbf : 0xff; +} diff --git a/Machines/Amiga/MouseJoystick.hpp b/Machines/Amiga/MouseJoystick.hpp new file mode 100644 index 000000000..32037fc9c --- /dev/null +++ b/Machines/Amiga/MouseJoystick.hpp @@ -0,0 +1,57 @@ +// +// MouseJoystick.hpp +// Clock Signal +// +// Created by Thomas Harte on 26/11/2021. +// Copyright © 2021 Thomas Harte. All rights reserved. +// + +#ifndef MouseJoystick_hpp +#define MouseJoystick_hpp + +#include <array> +#include <atomic> + +#include "../../Inputs/Joystick.hpp" +#include "../../Inputs/Mouse.hpp" + +namespace Amiga { + +struct MouseJoystickInput { + virtual uint16_t get_position() = 0; + virtual uint8_t get_cia_button() const = 0; +}; + +class Mouse: public Inputs::Mouse, public MouseJoystickInput { + public: + uint16_t get_position() final; + uint8_t get_cia_button() const final; + + private: + int get_number_of_buttons() final; + void set_button_pressed(int, bool) final; + void reset_all_buttons() final; + void move(int, int) final; + + uint8_t declared_position_[2]{}; + uint8_t cia_state_ = 0xff; + std::array<std::atomic<int>, 2> position_{}; +}; + +class Joystick: public Inputs::ConcreteJoystick, public MouseJoystickInput { + public: + Joystick(); + + uint16_t get_position() final; + uint8_t get_cia_button() const final; + + private: + void did_set_input(const Input &input, bool is_active) final; + + bool inputs_[Joystick::Input::Type::Max]{}; + uint16_t position_ = 0; +}; + +} + +#endif /* MouseJoystick_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 1ca3d5e8d..7df4cb0c8 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -435,6 +435,8 @@ 4B7BC7F51F58F27800D1B1B4 /* 6502AllRAM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B6A4C911F58F09E00E3F787 /* 6502AllRAM.cpp */; }; 4B7C681627517A59001671EC /* Sprites.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7C681427517A59001671EC /* Sprites.cpp */; }; 4B7C681727517A59001671EC /* Sprites.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7C681427517A59001671EC /* Sprites.cpp */; }; + 4B7C681A275196E8001671EC /* MouseJoystick.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7C6818275196E8001671EC /* MouseJoystick.cpp */; }; + 4B7C681B275196E8001671EC /* MouseJoystick.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7C6818275196E8001671EC /* MouseJoystick.cpp */; }; 4B7F188E2154825E00388727 /* MasterSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7F188C2154825D00388727 /* MasterSystem.cpp */; }; 4B7F188F2154825E00388727 /* MasterSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7F188C2154825D00388727 /* MasterSystem.cpp */; }; 4B7F1897215486A200388727 /* StaticAnalyser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7F1896215486A100388727 /* StaticAnalyser.cpp */; }; @@ -1429,6 +1431,8 @@ 4B7BA03F23D55E7900B98D9E /* LFSR.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LFSR.hpp; sourceTree = "<group>"; }; 4B7C681427517A59001671EC /* Sprites.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Sprites.cpp; sourceTree = "<group>"; }; 4B7C681527517A59001671EC /* Sprites.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Sprites.hpp; sourceTree = "<group>"; }; + 4B7C6818275196E8001671EC /* MouseJoystick.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MouseJoystick.cpp; sourceTree = "<group>"; }; + 4B7C6819275196E8001671EC /* MouseJoystick.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MouseJoystick.hpp; sourceTree = "<group>"; }; 4B7F188C2154825D00388727 /* MasterSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MasterSystem.cpp; sourceTree = "<group>"; }; 4B7F188D2154825D00388727 /* MasterSystem.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MasterSystem.hpp; sourceTree = "<group>"; }; 4B7F1895215486A100388727 /* StaticAnalyser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaticAnalyser.hpp; sourceTree = "<group>"; }; @@ -4310,6 +4314,7 @@ 4BC6236C26F4235400F83DFE /* Copper.cpp */, 4B1A1B1C27320FBB00119335 /* Disk.cpp */, 4B9EC0E826B384080060A31F /* Keyboard.cpp */, + 4B7C6818275196E8001671EC /* MouseJoystick.cpp */, 4B7C681427517A59001671EC /* Sprites.cpp */, 4BC080D726A25ADA00D03FD8 /* Amiga.hpp */, 4B2130E1273A7A0A008A77B4 /* Audio.hpp */, @@ -4321,6 +4326,7 @@ 4B9EC0E926B384080060A31F /* Keyboard.hpp */, 4BD1552E270B14AC00410C6E /* MemoryMap.hpp */, 4BC6237026F94A5B00F83DFE /* Minterms.hpp */, + 4B7C6819275196E8001671EC /* MouseJoystick.hpp */, 4B7C681527517A59001671EC /* Sprites.hpp */, ); path = Amiga; @@ -5445,6 +5451,7 @@ 4B055AC91FAE9AFB0060FFFF /* Keyboard.cpp in Sources */, 4B055A991FAE85CB0060FFFF /* DiskController.cpp in Sources */, 4B25B5F925BD083C00362C84 /* DiskIIDrive.cpp in Sources */, + 4B7C681B275196E8001671EC /* MouseJoystick.cpp in Sources */, 4B055ACC1FAE9B030060FFFF /* Electron.cpp in Sources */, 4B2E86B825D7490E0024F1E9 /* ReactiveDevice.cpp in Sources */, 4B74CF822312FA9C00500CE8 /* HFV.cpp in Sources */, @@ -5652,6 +5659,7 @@ 4B74CF85231370BC00500CE8 /* MacintoshVolume.cpp in Sources */, 4B0F1C232605996900B85C66 /* ZXSpectrumTAP.cpp in Sources */, 4B4518A51F75FD1C00926311 /* SSD.cpp in Sources */, + 4B7C681A275196E8001671EC /* MouseJoystick.cpp in Sources */, 4B55CE5F1C3B7D960093A61B /* MachineDocument.swift in Sources */, 4B1B58FF246E19FD009C171E /* State.cpp in Sources */, 4B2B3A4C1F9B8FA70062DABF /* MemoryFuzzer.cpp in Sources */,