From a7c272e62f1486a759d2b6ee29f181b8fc6a0eaa Mon Sep 17 00:00:00 2001 From: Ignacio Sanchez Gines <863613+drhelius@users.noreply.github.com> Date: Tue, 26 Dec 2023 23:01:54 +0100 Subject: [PATCH] Add support for SAC Spinners, Wheel Controller and Roller Controller. Fixes #38 --- platforms/desktop-shared/application.cpp | 57 +++++++++++++++++++ platforms/desktop-shared/config.cpp | 6 +- platforms/desktop-shared/config.h | 2 + platforms/desktop-shared/emu.cpp | 10 ++++ platforms/desktop-shared/emu.h | 2 + platforms/desktop-shared/gui.cpp | 16 +++++- src/GearcolecoCore.cpp | 13 ++++- src/GearcolecoCore.h | 2 + src/Input.cpp | 70 ++++++++++++------------ src/Input.h | 14 ++--- src/Processor.cpp | 1 + src/definitions.h | 2 +- 12 files changed, 144 insertions(+), 51 deletions(-) diff --git a/platforms/desktop-shared/application.cpp b/platforms/desktop-shared/application.cpp index e7c8ee5..efb02c2 100644 --- a/platforms/desktop-shared/application.cpp +++ b/platforms/desktop-shared/application.cpp @@ -237,6 +237,63 @@ static void sdl_events_emu(const SDL_Event* event) { switch(event->type) { + case (SDL_MOUSEMOTION): + { + if (config_emulator.spinner > 0) + { + int sen = config_emulator.spinner_sensitivity - 1; + if (sen < 0) + sen = 0; + float senf = (float)(sen / 2.0f) + 1.0f; + float relx = (float)(event->motion.xrel) * senf; + + // roller controller + switch (config_emulator.spinner) + { + // SAC + case (1): + { + emu_spinner1(relx); + break; + } + // Wheel + case (2): + { + emu_spinner1(relx); + break; + } + // Roller + case (3): + { + float rely = (float)(event->motion.yrel) * senf; + emu_spinner1(relx); + emu_spinner2(rely); + break; + } + default: + break; + } + } + + break; + } + case (SDL_MOUSEWHEEL): + { + // SAC + if (config_emulator.spinner == 1) + { + int sen = (config_emulator.spinner_sensitivity - 1) * 20; + if (sen < 0) + sen = 0; + + float senf = (float)(sen / 2.0f) + 1.0f; + float rely = (float)(event->wheel.y) * senf; + + emu_spinner2(rely); + } + + break; + } case (SDL_DROPFILE): { char* dropped_filedir = event->drop.file; diff --git a/platforms/desktop-shared/config.cpp b/platforms/desktop-shared/config.cpp index 8897c1a..808c6d7 100644 --- a/platforms/desktop-shared/config.cpp +++ b/platforms/desktop-shared/config.cpp @@ -175,6 +175,8 @@ void config_read(void) config_emulator.last_open_path = read_string("Emulator", "LastOpenPath"); config_emulator.window_width = read_int("Emulator", "WindowWidth", 770); config_emulator.window_height = read_int("Emulator", "WindowHeight", 600); + config_emulator.spinner = read_int("Emulator", "Spinner", 0); + config_emulator.spinner_sensitivity = read_int("Emulator", "SpinnerSensitivity", 4); if (config_emulator.savefiles_path.empty()) { @@ -338,7 +340,9 @@ void config_write(void) write_string("Emulator", "LastOpenPath", config_emulator.last_open_path); write_int("Emulator", "WindowWidth", config_emulator.window_width); write_int("Emulator", "WindowHeight", config_emulator.window_height); - + write_int("Emulator", "Spinner", config_emulator.spinner); + write_int("Emulator", "SpinnerSensitivity", config_emulator.spinner_sensitivity); + for (int i = 0; i < config_max_recent_roms; i++) { std::string item = "RecentROM" + std::to_string(i); diff --git a/platforms/desktop-shared/config.h b/platforms/desktop-shared/config.h index 70a1890..c96e985 100644 --- a/platforms/desktop-shared/config.h +++ b/platforms/desktop-shared/config.h @@ -54,6 +54,8 @@ struct config_Emulator std::string last_open_path; int window_width = 770; int window_height = 600; + int spinner = 0; + int spinner_sensitivity = 0; }; struct config_Video diff --git a/platforms/desktop-shared/emu.cpp b/platforms/desktop-shared/emu.cpp index 7631d47..59b3407 100644 --- a/platforms/desktop-shared/emu.cpp +++ b/platforms/desktop-shared/emu.cpp @@ -142,6 +142,16 @@ void emu_key_released(GC_Controllers controller, GC_Keys key) gearcoleco->KeyReleased(controller, key); } +void emu_spinner1(int movement) +{ + gearcoleco->Spinner1(movement); +} + +void emu_spinner2(int movement) +{ + gearcoleco->Spinner2(movement); +} + void emu_pause(void) { gearcoleco->Pause(true); diff --git a/platforms/desktop-shared/emu.h b/platforms/desktop-shared/emu.h index 5142350..dfc0465 100644 --- a/platforms/desktop-shared/emu.h +++ b/platforms/desktop-shared/emu.h @@ -48,6 +48,8 @@ EXTERN void emu_update(void); EXTERN void emu_load_rom(const char* file_path, Cartridge::ForceConfiguration config); EXTERN void emu_key_pressed(GC_Controllers controller, GC_Keys key); EXTERN void emu_key_released(GC_Controllers controller, GC_Keys key); +EXTERN void emu_spinner1(int movement); +EXTERN void emu_spinner2(int movement); EXTERN void emu_pause(void); EXTERN void emu_resume(void); EXTERN bool emu_is_paused(void); diff --git a/platforms/desktop-shared/gui.cpp b/platforms/desktop-shared/gui.cpp index b2c743b..32b8d27 100644 --- a/platforms/desktop-shared/gui.cpp +++ b/platforms/desktop-shared/gui.cpp @@ -515,7 +515,7 @@ static void main_menu(void) { gui_in_use = true; - if (ImGui::BeginMenu("Keyboard Configuration")) + if (ImGui::BeginMenu("Keyboard")) { if (ImGui::BeginMenu("Player 1")) { @@ -576,8 +576,6 @@ static void main_menu(void) ImGui::EndMenu(); } - ImGui::Separator(); - if (ImGui::BeginMenu("Gamepads")) { if (ImGui::BeginMenu("Player 1")) @@ -661,6 +659,18 @@ static void main_menu(void) ImGui::EndMenu(); } + if (ImGui::BeginMenu("Spinners")) + { + ImGui::Combo("##spinner", &config_emulator.spinner, "Disabled\0Super Action Controller\0Steering Wheel\0Roller Controller\0\0", 4); + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) + { + ImGui::SetTooltip("SAC Spinner for P1 is controlled with mouse movement.\nSAC Spinner for P2 is controlled with mouse wheel.\nSteering Wheel is controlled with mouse movement.\nRoller Controller is controlled with mouse movement."); + } + ImGui::SliderInt("##spinner_sensitivity", &config_emulator.spinner_sensitivity, 1, 10, "Sensitivity = %d"); + + ImGui::EndMenu(); + } + ImGui::EndMenu(); } diff --git a/src/GearcolecoCore.cpp b/src/GearcolecoCore.cpp index bb291fa..7ced21c 100644 --- a/src/GearcolecoCore.cpp +++ b/src/GearcolecoCore.cpp @@ -63,7 +63,7 @@ void GearcolecoCore::Init(GC_Color_Format pixelFormat) m_pProcessor = new Processor(m_pMemory); m_pAudio = new Audio(); m_pVideo = new Video(m_pMemory, m_pProcessor); - m_pInput = new Input(); + m_pInput = new Input(m_pProcessor); m_pColecoVisionIOPorts = new ColecoVisionIOPorts(m_pAudio, m_pVideo, m_pInput, m_pCartridge, m_pMemory, m_pProcessor); m_pMemory->Init(); @@ -93,7 +93,6 @@ bool GearcolecoCore::RunToVBlank(u8* pFrameBuffer, s16* pSampleBuffer, int* pSam #endif vblank = m_pVideo->Tick(clockCycles); m_pAudio->Tick(clockCycles); - m_pInput->Tick(clockCycles); totalClocks += clockCycles; @@ -251,6 +250,16 @@ void GearcolecoCore::KeyReleased(GC_Controllers controller, GC_Keys key) m_pInput->KeyReleased(controller, key); } +void GearcolecoCore::Spinner1(int movement) +{ + m_pInput->Spinner1(movement); +} + +void GearcolecoCore::Spinner2(int movement) +{ + m_pInput->Spinner2(movement); +} + void GearcolecoCore::Pause(bool paused) { if (paused) diff --git a/src/GearcolecoCore.h b/src/GearcolecoCore.h index 4421af8..901bac3 100644 --- a/src/GearcolecoCore.h +++ b/src/GearcolecoCore.h @@ -44,6 +44,8 @@ class GearcolecoCore bool GetRuntimeInfo(GC_RuntimeInfo& runtime_info); void KeyPressed(GC_Controllers controller, GC_Keys key); void KeyReleased(GC_Controllers controller, GC_Keys key); + void Spinner1(int movement); + void Spinner2(int movement); void Pause(bool paused); bool IsPaused(); void ResetROM(Cartridge::ForceConfiguration* config = NULL); diff --git a/src/Input.cpp b/src/Input.cpp index a9dce7e..83100e3 100644 --- a/src/Input.cpp +++ b/src/Input.cpp @@ -18,11 +18,11 @@ */ #include "Input.h" -#include "Memory.h" +#include "Processor.h" -Input::Input() +Input::Input(Processor* pProcessor) { - Reset(); + m_pProcessor = pProcessor; } void Input::Init() @@ -32,24 +32,10 @@ void Input::Init() void Input::Reset() { - m_iInputCycles = 0; m_Segment = SegmentKeypadRightButtons; m_Gamepad[0] = m_Gamepad[1] = 0xFF; - m_Keypad[0] = m_Keypad[1] = 0x0F; - m_InputState[0][0] = m_InputState[0][1] = 0xFF; - m_InputState[1][0] = m_InputState[1][1] = 0xFF; -} - -void Input::Tick(unsigned int clockCycles) -{ - m_iInputCycles += clockCycles; - - // Joypad Poll Speed - if (m_iInputCycles >= 10000) - { - m_iInputCycles -= 10000; - Update(); - } + m_Keypad[0] = m_Keypad[1] = 0xFF; + m_iSpinnerRel[0] = m_iSpinnerRel[1] = 0; } void Input::SetInputSegment(InputSegments segment) @@ -59,16 +45,33 @@ void Input::SetInputSegment(InputSegments segment) u8 Input::ReadInput(u8 port) { - u8 controller = (port & 0x02) >> 1; + u8 c = (port & 0x02) >> 1; + u8 ret = 0xFF; + + int rel = m_iSpinnerRel[c] / 4; + m_iSpinnerRel[c] -= rel; if (m_Segment == SegmentKeypadRightButtons) { - return m_InputState[controller][0]; + ret = (m_Keypad[c] & 0x0F) | (IsSetBit(m_Gamepad[c], 5) ? 0x70 : 0x30); } else { - return m_InputState[controller][1]; + ret = (m_Gamepad[c] & 0x0F) | (IsSetBit(m_Gamepad[c], 4) ? 0x70 : 0x30); + + if (rel > 0) + { + ret &= c ? 0xEF : 0xCF; + m_pProcessor->RequestINT(true); + } + else if (rel < 0) + { + ret &= c ? 0xCF : 0xEF; + m_pProcessor->RequestINT(true); + } } + + return ret; } void Input::KeyPressed(GC_Controllers controller, GC_Keys key) @@ -95,33 +98,28 @@ void Input::KeyReleased(GC_Controllers controller, GC_Keys key) } } -void Input::Update() +void Input::Spinner1(int movement) { - for (int c = 0; c < 2; c++) - { - m_InputState[c][0] = (m_Keypad[c] & 0x0F) | (IsSetBit(m_Gamepad[c], 5) ? 0x70 : 0x30); - m_InputState[c][1] = (m_Gamepad[c] & 0x0F) | (IsSetBit(m_Gamepad[c], 4) ? 0x70 : 0x30); - } + m_iSpinnerRel[0] = movement; +} + +void Input::Spinner2(int movement) +{ + m_iSpinnerRel[1] = movement; } void Input::SaveState(std::ostream& stream) { - u8 dummy = 0xFF; stream.write(reinterpret_cast (m_Gamepad), sizeof(m_Gamepad)); stream.write(reinterpret_cast (m_Keypad), sizeof(m_Keypad)); - stream.write(reinterpret_cast (m_InputState), sizeof(m_InputState)); - stream.write(reinterpret_cast (&dummy), sizeof(dummy)); stream.write(reinterpret_cast (&m_Segment), sizeof(m_Segment)); - stream.write(reinterpret_cast (&m_iInputCycles), sizeof(m_iInputCycles)); + stream.write(reinterpret_cast (&m_iSpinnerRel), sizeof(m_iSpinnerRel)); } void Input::LoadState(std::istream& stream) { - u8 dummy = 0xFF; stream.read(reinterpret_cast (m_Gamepad), sizeof(m_Gamepad)); stream.read(reinterpret_cast (m_Keypad), sizeof(m_Keypad)); - stream.read(reinterpret_cast (m_InputState), sizeof(m_InputState)); - stream.read(reinterpret_cast (&dummy), sizeof(dummy)); stream.read(reinterpret_cast (&m_Segment), sizeof(m_Segment)); - stream.read(reinterpret_cast (&m_iInputCycles), sizeof(m_iInputCycles)); + stream.read(reinterpret_cast (&m_iSpinnerRel), sizeof(m_iSpinnerRel)); } diff --git a/src/Input.h b/src/Input.h index 426e561..6963a9c 100644 --- a/src/Input.h +++ b/src/Input.h @@ -22,7 +22,7 @@ #include "definitions.h" -class Memory; +class Processor; class Input { @@ -34,26 +34,24 @@ class Input }; public: - Input(); + Input(Processor* pProcessor); void Init(); void Reset(); - void Tick(unsigned int clockCycles); void KeyPressed(GC_Controllers controller, GC_Keys key); void KeyReleased(GC_Controllers controller, GC_Keys key); + void Spinner1(int movement); + void Spinner2(int movement); void SaveState(std::ostream& stream); void LoadState(std::istream& stream); void SetInputSegment(InputSegments segment); u8 ReadInput(u8 port); private: - void Update(); - -private: + Processor* m_pProcessor; u8 m_Gamepad[2]; u8 m_Keypad[2]; - int m_iInputCycles; InputSegments m_Segment; - u8 m_InputState[2][2]; + int m_iSpinnerRel[2]; }; #endif /* INPUT_H */ diff --git a/src/Processor.cpp b/src/Processor.cpp index 0046053..9b88519 100644 --- a/src/Processor.cpp +++ b/src/Processor.cpp @@ -149,6 +149,7 @@ unsigned int Processor::RunFor(unsigned int tstates) else if (m_bIFF1 && m_bINTRequested && !m_bAfterEI) { LeaveHalt(); + m_bINTRequested = false; m_bIFF1 = false; m_bIFF2 = false; StackPush(&PC); diff --git a/src/definitions.h b/src/definitions.h index bcbd2e1..b813751 100644 --- a/src/definitions.h +++ b/src/definitions.h @@ -104,7 +104,7 @@ typedef void (*RamChangedCallback) (void); #define GC_AUDIO_BUFFER_SIZE 8192 -#define GC_SAVESTATE_MAGIC 0x83190128 +#define GC_SAVESTATE_MAGIC 0x09200902 struct GC_Color {