From ab4d97ba2f2cf9b5a704ea5c027de397a642d0bb Mon Sep 17 00:00:00 2001 From: Jonian Guveli Date: Fri, 6 Sep 2024 19:36:41 +0300 Subject: [PATCH] Libretro: Add support for touch emulation with joystick --- src/libretro_core.cpp | 68 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/src/libretro_core.cpp b/src/libretro_core.cpp index 1e5b532d..bf452797 100644 --- a/src/libretro_core.cpp +++ b/src/libretro_core.cpp @@ -17,7 +17,13 @@ static retro_input_state_t inputStateCallback; static retro_hw_render_callback hwRender; static std::filesystem::path savePath; +static std::string touchScreenMode; static bool screenTouched; +static int lastMouseX; +static int lastMouseY; + +static int touchX = 0; +static int touchY = 0; std::unique_ptr emulator; RendererGL* renderer; @@ -123,8 +129,11 @@ static void inputInit() { {0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L"}, {0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "X"}, {0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Y"}, + {0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "Screen Touch"}, {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Circle Pad X"}, {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Circle Pad Y"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Pointer X"}, + {0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Pointer Y"}, {0}, }; @@ -182,6 +191,7 @@ static void configInit() { {"panda3ds_write_protect_virtual_sd", "Write protect virtual SD card; disabled|enabled"}, {"panda3ds_battery_level", "Battery percentage; 5|10|20|30|50|70|90|100"}, {"panda3ds_use_charger", "Charger plugged; enabled|disabled"}, + {"panda3ds_touchscreen_mode", "Touchscreen touch mode; Auto|Pointer|Joystick|None"}, {nullptr, nullptr}, }; @@ -212,8 +222,11 @@ static void configUpdate() { config.lightShadergenThreshold = fetchVariableRange("panda3ds_ubershader_lighting_override_threshold", 1, 8); config.discordRpcEnabled = false; + touchScreenMode = fetchVariable("panda3ds_touchscreen_mode", "Auto"); + // Handle any settings that might need the emulator core to be notified when they're changed, and save the config. emulator->setAudioEnabled(config.audioEnabled); + config.save(); } @@ -348,26 +361,57 @@ void retro_run() { bool touchScreen = false; - const int posX = inputStateCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X); - const int posY = inputStateCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y); - - const int newX = static_cast((posX + 0x7fff) / (float)(0x7fff * 2) * emulator->width); - const int newY = static_cast((posY + 0x7fff) / (float)(0x7fff * 2) * emulator->height); + int pointerX = touchX; + int pointerY = touchY; const int offsetX = 40; const int offsetY = emulator->height / 2; - const bool inScreenX = newX >= offsetX && newX <= emulator->width - offsetX; - const bool inScreenY = newY >= offsetY && newY <= emulator->height; + if (touchScreenMode == "Pointer" || touchScreenMode == "Auto") { + const int posX = inputStateCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X); + const int posY = inputStateCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y); - if (inScreenX && inScreenY) { - touchScreen |= inputStateCallback(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT); - touchScreen |= inputStateCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED); + const int newX = static_cast((posX + 0x7fff) / (float)(0x7fff * 2) * emulator->width); + const int newY = static_cast((posY + 0x7fff) / (float)(0x7fff * 2) * emulator->height); + + const bool inScreenX = newX >= offsetX && newX <= emulator->width - offsetX; + const bool inScreenY = newY >= offsetY && newY <= emulator->height; + + if (inScreenX && inScreenY) { + touchScreen |= inputStateCallback(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT); + touchScreen |= inputStateCallback(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED); + } + + if ((posX != 0 || posY != 0) && (lastMouseX != newX || lastMouseY != newY)) { + lastMouseX = newX; + lastMouseY = newY; + + pointerX = newX - offsetX; + pointerY = newY - offsetY; + } } + if (touchScreenMode == "Joystick" || touchScreenMode == "Auto") { + const float speedX = (emulator->width / 60.0); + const float speedY = (emulator->height / 2 / 60.0); + + const float moveX = getAxisState(RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X); + const float moveY = getAxisState(RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y); + + touchScreen |= getButtonState(RETRO_DEVICE_ID_JOYPAD_R3); + + if (moveX != 0 || moveY != 0) { + pointerX += static_cast((moveX / 32767) * speedX); + pointerY += static_cast((moveY / 32767) * speedY); + } + } + + touchX = std::clamp(pointerX, 0, (int)(emulator->width - (offsetX * 2))); + touchY = std::clamp(pointerY, 0, (int)(emulator->height - offsetY)); + if (touchScreen) { - u16 x = static_cast(newX - offsetX); - u16 y = static_cast(newY - offsetY); + u16 x = static_cast(touchX); + u16 y = static_cast(touchY); hid.setTouchScreenPress(x, y); screenTouched = true;