diff --git a/src/core.cpp b/src/core.cpp index 2793f526..1be327ab 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -52,7 +52,6 @@ static inline void *malloc_align(size_t alignment, size_t size) { extern unsigned char GMGSx_sf2[]; extern unsigned int GMGSx_sf2_len; -static size_t frame_number = 0; static ALCdevice *al_device = NULL; static ALCcontext *al_context = NULL; static LPALCRENDERSAMPLESSOFT alcRenderSamplesSOFT = NULL; @@ -259,12 +258,10 @@ static bool init_sandbox() { mkxp_retro::sandbox.emplace(); } catch (SandboxException) { log_printf(RETRO_LOG_ERROR, "Failed to initialize Ruby\n"); - mkxp_retro::sandbox.reset(); + deinit_sandbox(); return false; } - frame_number = 0; - return true; } @@ -362,17 +359,20 @@ extern "C" RETRO_API void retro_reset() { extern "C" RETRO_API void retro_run() { input_poll(); - if (mkxp_retro::sandbox.has_value()) { - log_printf(RETRO_LOG_INFO, "[Sandbox] Executing frame %zu\n", ++frame_number); - try { - if (sb().run()) { - log_printf(RETRO_LOG_INFO, "[Sandbox] Ruby terminated normally\n"); - mkxp_retro::sandbox.reset(); - } - } catch (SandboxException) { - log_printf(RETRO_LOG_ERROR, "[Sandbox] Ruby threw an exception\n"); - mkxp_retro::sandbox.reset(); + if (!mkxp_retro::sandbox.has_value()) { + return; + } + + try { + if (sb().run()) { + log_printf(RETRO_LOG_INFO, "[Sandbox] Ruby terminated normally\n"); + deinit_sandbox(); + return; } + } catch (SandboxException) { + log_printf(RETRO_LOG_ERROR, "[Sandbox] Ruby threw an exception\n"); + deinit_sandbox(); + return; } video_refresh(frame_buf, 640, 480, 640 * 4); diff --git a/src/input/input-retro.cpp b/src/input/input-retro.cpp index dc389174..df01dbd1 100644 --- a/src/input/input-retro.cpp +++ b/src/input/input-retro.cpp @@ -23,6 +23,10 @@ #include "binding-sandbox/core.h" #define JOYPAD_BUTTON_MAX 16 +#define REPEAT_NONE 255 +#define REPEAT_START 0.4 // TODO: should be 0.375 when RGSS version >= 2 +#define REPEAT_DELAY 0.1 +#define FPS 60.0 // TODO: use the actual FPS static std::unordered_map codeToJoypadId = { {Input::Down, RETRO_DEVICE_ID_JOYPAD_DOWN}, @@ -51,20 +55,20 @@ static const uint8_t otherDirs[4][3] = { struct InputPrivate { - int buttonRepeating; - size_t buttonRepeatingCount; - uint8_t currJoypadState; - uint8_t prevJoypadState; + uint32_t repeatCount; + uint16_t currJoypadState; + uint16_t prevJoypadState; + uint8_t repeat; uint8_t currDir4; uint8_t prevDir4; uint8_t dir8; bool joypadMaskSupported; InputPrivate() : - buttonRepeating(-1), - buttonRepeatingCount(0), + repeatCount(0), currJoypadState(0), prevJoypadState(0), + repeat(-1), currDir4(0), prevDir4(0), dir8(0), @@ -74,8 +78,9 @@ struct InputPrivate void updateJoypad() { prevJoypadState = currJoypadState; + if (joypadMaskSupported) { - currJoypadState = (uint8_t)mkxp_retro::input_state(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK); + currJoypadState = (uint16_t)mkxp_retro::input_state(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_MASK); } else { currJoypadState = 0; for (uint8_t i = 0; i < JOYPAD_BUTTON_MAX; ++i) { @@ -84,6 +89,23 @@ struct InputPrivate } } } + + if (repeat == REPEAT_NONE) { + if (currJoypadState != 0) { + for (uint8_t i = 0; i < JOYPAD_BUTTON_MAX; ++i) { + if (currJoypadState & (1 << i)) { + repeat = i; + repeatCount = 0; + break; + } + } + } + } else if (currJoypadState & (1 << repeat)) { + __builtin_add_overflow(repeatCount, 1, &repeatCount); + } else { + repeat = REPEAT_NONE; + repeatCount = 0; + } } void updateDir4() @@ -169,6 +191,12 @@ struct InputPrivate auto it = codeToJoypadId.find(button); return it != codeToJoypadId.end() && (prevJoypadState & (1 << it->second)); } + + bool isRepeat(int button) + { + auto it = codeToJoypadId.find(button); + return it != codeToJoypadId.end() && repeat == it->second; + } }; Input::Input() @@ -185,6 +213,7 @@ void Input::update() { p->updateJoypad(); p->updateDir4(); + p->updateDir8(); } bool Input::isPressed(int button) @@ -204,17 +233,17 @@ bool Input::isReleased(int button) bool Input::isRepeated(int button) { - return isPressed(button); // TODO + return p->isRepeat(button) && (p->repeatCount == 0 || (p->repeatCount >= (size_t)std::ceil(REPEAT_START * FPS) && (p->repeatCount + 1) % (size_t)std::ceil(REPEAT_DELAY * FPS) == 0)); } unsigned int Input::count(int button) { - return 0; // TODO + return p->isRepeat(button) ? p->repeatCount : 0; } double Input::repeatTime(int button) { - return 0.0; // TODO + return p->isRepeat(button) ? (double)p->repeatCount / FPS : 0; } bool Input::isPressedEx(int button, bool isVKey)