diff --git a/.gitmodules b/.gitmodules index d56f6999e..f593b25aa 100644 --- a/.gitmodules +++ b/.gitmodules @@ -48,7 +48,7 @@ url = https://github.com/sonicnext-dev/MarathonRecompResources [submodule "thirdparty/plume"] path = thirdparty/plume - url = https://github.com/renderbag/plume + url = https://github.com/IsaacMarovitz/plume [submodule "thirdparty/ffmpeg-core"] path = thirdparty/ffmpeg-core url = https://github.com/sonicnext-dev/ffmpeg-core diff --git a/MarathonRecomp/CMakeLists.txt b/MarathonRecomp/CMakeLists.txt index e6b592b88..b00530890 100644 --- a/MarathonRecomp/CMakeLists.txt +++ b/MarathonRecomp/CMakeLists.txt @@ -127,7 +127,7 @@ set(MARATHON_RECOMP_APU_CXX_SOURCES "apu/audio.cpp" "apu/xma_decoder.cpp" "apu/embedded_player.cpp" - "apu/driver/sdl2_driver.cpp" + "apu/driver/sdl3_driver.cpp" ) set(MARATHON_RECOMP_HID_CXX_SOURCES @@ -200,7 +200,7 @@ set(MARATHON_RECOMP_UTILS_CXX_SOURCES ) set(MARATHON_RECOMP_THIRDPARTY_SOURCES - "${MARATHON_RECOMP_THIRDPARTY_ROOT}/imgui/backends/imgui_impl_sdl2.cpp" + "${MARATHON_RECOMP_THIRDPARTY_ROOT}/imgui/backends/imgui_impl_sdl3.cpp" "${MARATHON_RECOMP_THIRDPARTY_ROOT}/imgui/imgui.cpp" "${MARATHON_RECOMP_THIRDPARTY_ROOT}/imgui/imgui_demo.cpp" "${MARATHON_RECOMP_THIRDPARTY_ROOT}/imgui/imgui_draw.cpp" @@ -383,8 +383,8 @@ target_link_libraries(MarathonRecomp PRIVATE nfd::nfd o1heap XenonUtils - SDL2::SDL2-static - SDL2_mixer + SDL3::SDL3-static + SDL3_mixer::SDL3_mixer tomlplusplus::tomlplusplus MarathonRecompLib xxHash::xxhash diff --git a/MarathonRecomp/app.cpp b/MarathonRecomp/app.cpp index d29e16b72..bcb8a840c 100644 --- a/MarathonRecomp/app.cpp +++ b/MarathonRecomp/app.cpp @@ -93,7 +93,7 @@ PPC_FUNC(sub_825EA610) if (std::this_thread::get_id() == g_mainThreadId) { SDL_PumpEvents(); - SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT); + SDL_FlushEvents(SDL_EVENT_FIRST, SDL_EVENT_LAST); GameWindow::Update(); } diff --git a/MarathonRecomp/apu/driver/sdl2_driver.cpp b/MarathonRecomp/apu/driver/sdl3_driver.cpp similarity index 77% rename from MarathonRecomp/apu/driver/sdl2_driver.cpp rename to MarathonRecomp/apu/driver/sdl3_driver.cpp index a2615f44f..4733ddc93 100644 --- a/MarathonRecomp/apu/driver/sdl2_driver.cpp +++ b/MarathonRecomp/apu/driver/sdl3_driver.cpp @@ -7,47 +7,46 @@ static PPCFunc* g_clientCallback{}; static uint32_t g_clientCallbackParam{}; // pointer in guest memory -static SDL_AudioDeviceID g_audioDevice{}; +static SDL_AudioStream* g_audioStream{}; static bool g_downMixToStereo; static void CreateAudioDevice() { - if (g_audioDevice != NULL) - SDL_CloseAudioDevice(g_audioDevice); + if (g_audioStream != nullptr) + { + SDL_DestroyAudioStream(g_audioStream); + g_audioStream = nullptr; + } bool surround = Config::ChannelConfiguration == EChannelConfiguration::Surround; - int allowedChanges = surround ? SDL_AUDIO_ALLOW_CHANNELS_CHANGE : 0; - SDL_AudioSpec desired{}, obtained{}; + SDL_AudioSpec deviceSpec{}; + if (surround && SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &deviceSpec, nullptr)) + surround = deviceSpec.channels >= XAUDIO_NUM_CHANNELS; + + SDL_AudioSpec desired{}; desired.freq = XAUDIO_SAMPLES_HZ; - desired.format = AUDIO_F32SYS; + desired.format = SDL_AUDIO_F32; desired.channels = surround ? XAUDIO_NUM_CHANNELS : 2; - desired.samples = XAUDIO_NUM_SAMPLES; - g_audioDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, allowedChanges); - - if (obtained.channels != 2 && obtained.channels != XAUDIO_NUM_CHANNELS) // This check may fail only when surround sound is enabled. - { - SDL_CloseAudioDevice(g_audioDevice); - g_audioDevice = SDL_OpenAudioDevice(nullptr, 0, &desired, &obtained, 0); - } + g_audioStream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &desired, nullptr, nullptr); - if (!g_audioDevice) + if (!g_audioStream) LOGFN_ERROR("Failed to open audio device: {}", SDL_GetError()); - g_downMixToStereo = (obtained.channels == 2); + g_downMixToStereo = (desired.channels == 2); } void XAudioInitializeSystem() { #ifdef _WIN32 // Force wasapi on Windows. - SDL_setenv("SDL_AUDIODRIVER", "wasapi", true); + SDL_SetHint(SDL_HINT_AUDIO_DRIVER, "wasapi"); #endif SDL_SetHint(SDL_HINT_AUDIO_CATEGORY, "playback"); - SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, "Marathon Recompiled"); + SDL_SetAppMetadataProperty(SDL_PROP_APP_METADATA_NAME_STRING, "Marathon Recompiled"); - if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) + if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) { LOGFN_ERROR("Failed to init audio subsystem: {}", SDL_GetError()); return; @@ -69,11 +68,11 @@ static void AudioThread() while (!g_audioThreadShouldExit) { - uint32_t queuedAudioSize = SDL_GetQueuedAudioSize(g_audioDevice); + int queuedAudioSize = SDL_GetAudioStreamQueued(g_audioStream); constexpr size_t MAX_LATENCY = 10; const size_t callbackAudioSize = channels * XAUDIO_NUM_SAMPLES * sizeof(float); - if ((queuedAudioSize / callbackAudioSize) <= MAX_LATENCY) + if (queuedAudioSize >= 0 && (queuedAudioSize / callbackAudioSize) <= MAX_LATENCY) { ctx.ppcContext.r3.u32 = g_clientCallbackParam; g_clientCallback(ctx.ppcContext, g_memory.base); @@ -92,7 +91,7 @@ static void AudioThread() static void CreateAudioThread() { - SDL_PauseAudioDevice(g_audioDevice, 0); + SDL_ResumeAudioStreamDevice(g_audioStream); g_audioThreadShouldExit = false; g_audioThread = std::make_unique(AudioThread); } @@ -143,7 +142,7 @@ void XAudioSubmitFrame(void* samples) audioFrames[i * 2 + 1] = isnan(samp1) ? 0.0f : samp1; } - SDL_QueueAudio(g_audioDevice, &audioFrames, sizeof(audioFrames)); + SDL_PutAudioStreamData(g_audioStream, &audioFrames, sizeof(audioFrames)); } else { @@ -158,7 +157,7 @@ void XAudioSubmitFrame(void* samples) } } - SDL_QueueAudio(g_audioDevice, &audioFrames, sizeof(audioFrames)); + SDL_PutAudioStreamData(g_audioStream, &audioFrames, sizeof(audioFrames)); } } diff --git a/MarathonRecomp/apu/embedded_player.cpp b/MarathonRecomp/apu/embedded_player.cpp index cd1ad0a0e..842b7b262 100644 --- a/MarathonRecomp/apu/embedded_player.cpp +++ b/MarathonRecomp/apu/embedded_player.cpp @@ -25,9 +25,14 @@ enum class EmbeddedSound struct EmbeddedSoundData { - Mix_Chunk* chunk{}; + MIX_Audio* audio{}; }; +static constexpr size_t EMBEDDED_TRACK_COUNT = 8; + +static MIX_Mixer* g_mixer; +static std::array g_tracks = {}; + static std::array g_embeddedSoundData = {}; static const std::unordered_map g_embeddedSoundMap = { @@ -40,12 +45,12 @@ static const std::unordered_map g_embeddedSound { "cannot_deside", EmbeddedSound::CannotDeside }, }; -static size_t g_channelIndex; +static size_t g_trackIndex; static void PlayEmbeddedSound(EmbeddedSound s) { EmbeddedSoundData &data = g_embeddedSoundData[size_t(s)]; - if (data.chunk == nullptr) + if (data.audio == nullptr) { // The sound hasn't been created yet, create it and pick it. const void *soundData = nullptr; @@ -85,25 +90,41 @@ static void PlayEmbeddedSound(EmbeddedSound s) return; } - data.chunk = Mix_LoadWAV_RW(SDL_RWFromConstMem(soundData, soundDataSize), 1); + data.audio = MIX_LoadAudio_IO(g_mixer, SDL_IOFromConstMem(soundData, soundDataSize), true, true); } - - Mix_VolumeChunk(data.chunk, (Config::MasterVolume * Config::EffectsVolume * EmbeddedPlayer::EFFECTS_VOLUME) * MIX_MAX_VOLUME); - Mix_PlayChannel(g_channelIndex % MIX_CHANNELS, data.chunk, 0); - ++g_channelIndex; + + MIX_Track *track = g_tracks[g_trackIndex % EMBEDDED_TRACK_COUNT]; + ++g_trackIndex; + + MIX_SetTrackGain(track, Config::MasterVolume * Config::EffectsVolume * EmbeddedPlayer::EFFECTS_VOLUME); + MIX_SetTrackAudio(track, data.audio); + MIX_PlayTrack(track, 0); } -static Mix_Music* g_installerMusic; +static MIX_Audio* g_installerMusic; +static MIX_Track* g_musicTrack; -void EmbeddedPlayer::Init() +void EmbeddedPlayer::Init() { - Mix_OpenAudio(XAUDIO_SAMPLES_HZ, AUDIO_F32SYS, 2, 4096); - g_installerMusic = Mix_LoadMUS_RW(SDL_RWFromConstMem(g_installer_music, sizeof(g_installer_music)), 1); + MIX_Init(); + + SDL_AudioSpec spec{}; + spec.freq = XAUDIO_SAMPLES_HZ; + spec.format = SDL_AUDIO_F32; + spec.channels = 2; + g_mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec); + + for (MIX_Track *&track : g_tracks) + track = MIX_CreateTrack(g_mixer); + + g_installerMusic = MIX_LoadAudio_IO(g_mixer, SDL_IOFromConstMem(g_installer_music, sizeof(g_installer_music)), false, true); + g_musicTrack = MIX_CreateTrack(g_mixer); + MIX_SetTrackAudio(g_musicTrack, g_installerMusic); s_isActive = true; } -void EmbeddedPlayer::Play(const char *name) +void EmbeddedPlayer::Play(const char *name) { assert(s_isActive && "Playback shouldn't be requested if the Embedded Player isn't active."); @@ -118,32 +139,37 @@ void EmbeddedPlayer::Play(const char *name) void EmbeddedPlayer::PlayMusic() { - if (!Mix_PlayingMusic()) + if (!MIX_TrackPlaying(g_musicTrack)) { - Mix_PlayMusic(g_installerMusic, INT_MAX); - Mix_VolumeMusic(Config::MasterVolume * Config::MusicVolume * MUSIC_VOLUME * MIX_MAX_VOLUME); + SDL_PropertiesID options = SDL_CreateProperties(); + SDL_SetNumberProperty(options, MIX_PROP_PLAY_LOOPS_NUMBER, -1); + + MIX_SetTrackGain(g_musicTrack, Config::MasterVolume * Config::MusicVolume * MUSIC_VOLUME); + MIX_PlayTrack(g_musicTrack, options); + + SDL_DestroyProperties(options); } } void EmbeddedPlayer::FadeOutMusic() { - if (Mix_PlayingMusic()) - Mix_FadeOutMusic(1000); + if (MIX_TrackPlaying(g_musicTrack)) + MIX_StopTrack(g_musicTrack, MIX_TrackMSToFrames(g_musicTrack, 1000)); } -void EmbeddedPlayer::Shutdown() +void EmbeddedPlayer::Shutdown() { + MIX_DestroyMixer(g_mixer); + for (EmbeddedSoundData &data : g_embeddedSoundData) { - if (data.chunk != nullptr) - Mix_FreeChunk(data.chunk); + if (data.audio != nullptr) + MIX_DestroyAudio(data.audio); } - Mix_HaltMusic(); - Mix_FreeMusic(g_installerMusic); + MIX_DestroyAudio(g_installerMusic); - Mix_CloseAudio(); - Mix_Quit(); + MIX_Quit(); s_isActive = false; } diff --git a/MarathonRecomp/gpu/video.cpp b/MarathonRecomp/gpu/video.cpp index 7c7032b15..257af6f90 100644 --- a/MarathonRecomp/gpu/video.cpp +++ b/MarathonRecomp/gpu/video.cpp @@ -1697,7 +1697,7 @@ static void CreateImGuiBackend() OptionsMenu::Init(); InstallerWizard::Init(); - ImGui_ImplSDL2_InitForOther(GameWindow::s_pWindow); + ImGui_ImplSDL3_InitForOther(GameWindow::s_pWindow); #ifdef ENABLE_IM_FONT_ATLAS_SNAPSHOT g_imFontTexture = LoadTexture( @@ -3010,7 +3010,7 @@ static void DrawFPS() static void DrawImGui() { - ImGui_ImplSDL2_NewFrame(); + ImGui_ImplSDL3_NewFrame(); auto& io = ImGui::GetIO(); io.DisplaySize = { float(Video::s_viewportWidth), float(Video::s_viewportHeight) }; diff --git a/MarathonRecomp/hid/driver/sdl_hid.cpp b/MarathonRecomp/hid/driver/sdl_hid.cpp index 2e6b5521a..0a8dd97ba 100644 --- a/MarathonRecomp/hid/driver/sdl_hid.cpp +++ b/MarathonRecomp/hid/driver/sdl_hid.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -7,50 +7,44 @@ #include #include -#define TRANSLATE_INPUT(S, X) SDL_GameControllerGetButton(controller, S) << FirstBitLow(X) +#define TRANSLATE_INPUT(S, X) SDL_GetGamepadButton(controller, S) << FirstBitLow(X) #define VIBRATION_TIMEOUT_MS 5000 class Controller { public: - SDL_GameController* controller{}; + SDL_Gamepad* controller{}; SDL_Joystick* joystick{}; - SDL_JoystickID id{ -1 }; + SDL_JoystickID id{}; XAMINPUT_GAMEPAD state{}; XAMINPUT_VIBRATION vibration{ 0, 0 }; - int index{}; Controller() = default; - explicit Controller(int index) : Controller(SDL_GameControllerOpen(index)) - { - this->index = index; - } - - Controller(SDL_GameController* controller) : controller(controller) + Controller(SDL_Gamepad* controller) : controller(controller) { if (!controller) return; - joystick = SDL_GameControllerGetJoystick(controller); - id = SDL_JoystickInstanceID(joystick); + joystick = SDL_GetGamepadJoystick(controller); + id = SDL_GetJoystickID(joystick); } - SDL_GameControllerType GetControllerType() const + SDL_GamepadType GetControllerType() const { - return SDL_GameControllerGetType(controller); + return SDL_GetGamepadType(controller); } hid::EInputDevice GetInputDevice() const { switch (GetControllerType()) { - case SDL_CONTROLLER_TYPE_PS3: - case SDL_CONTROLLER_TYPE_PS4: - case SDL_CONTROLLER_TYPE_PS5: + case SDL_GAMEPAD_TYPE_PS3: + case SDL_GAMEPAD_TYPE_PS4: + case SDL_GAMEPAD_TYPE_PS5: return hid::EInputDevice::PlayStation; - case SDL_CONTROLLER_TYPE_XBOX360: - case SDL_CONTROLLER_TYPE_XBOXONE: + case SDL_GAMEPAD_TYPE_XBOX360: + case SDL_GAMEPAD_TYPE_XBOXONE: return hid::EInputDevice::Xbox; default: return hid::EInputDevice::Unknown; @@ -59,7 +53,7 @@ class Controller const char* GetControllerName() const { - auto result = SDL_GameControllerName(controller); + auto result = SDL_GetGamepadName(controller); if (!result) return "Unknown Device"; @@ -72,11 +66,11 @@ class Controller if (!controller) return; - SDL_GameControllerClose(controller); + SDL_CloseGamepad(controller); controller = nullptr; joystick = nullptr; - id = -1; + id = 0; } bool CanPoll() @@ -91,14 +85,14 @@ class Controller auto& pad = state; - pad.sThumbLX = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); - pad.sThumbLY = ~SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); + pad.sThumbLX = SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_LEFTX); + pad.sThumbLY = ~SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_LEFTY); - pad.sThumbRX = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); - pad.sThumbRY = ~SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY); + pad.sThumbRX = SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTX); + pad.sThumbRY = ~SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHTY); - pad.bLeftTrigger = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERLEFT) >> 7; - pad.bRightTrigger = SDL_GameControllerGetAxis(controller, SDL_CONTROLLER_AXIS_TRIGGERRIGHT) >> 7; + pad.bLeftTrigger = SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_LEFT_TRIGGER) >> 7; + pad.bRightTrigger = SDL_GetGamepadAxis(controller, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) >> 7; } void Poll() @@ -110,25 +104,25 @@ class Controller pad.wButtons = 0; - pad.wButtons |= TRANSLATE_INPUT(SDL_CONTROLLER_BUTTON_DPAD_UP, XAMINPUT_GAMEPAD_DPAD_UP); - pad.wButtons |= TRANSLATE_INPUT(SDL_CONTROLLER_BUTTON_DPAD_DOWN, XAMINPUT_GAMEPAD_DPAD_DOWN); - pad.wButtons |= TRANSLATE_INPUT(SDL_CONTROLLER_BUTTON_DPAD_LEFT, XAMINPUT_GAMEPAD_DPAD_LEFT); - pad.wButtons |= TRANSLATE_INPUT(SDL_CONTROLLER_BUTTON_DPAD_RIGHT, XAMINPUT_GAMEPAD_DPAD_RIGHT); + pad.wButtons |= TRANSLATE_INPUT(SDL_GAMEPAD_BUTTON_DPAD_UP, XAMINPUT_GAMEPAD_DPAD_UP); + pad.wButtons |= TRANSLATE_INPUT(SDL_GAMEPAD_BUTTON_DPAD_DOWN, XAMINPUT_GAMEPAD_DPAD_DOWN); + pad.wButtons |= TRANSLATE_INPUT(SDL_GAMEPAD_BUTTON_DPAD_LEFT, XAMINPUT_GAMEPAD_DPAD_LEFT); + pad.wButtons |= TRANSLATE_INPUT(SDL_GAMEPAD_BUTTON_DPAD_RIGHT, XAMINPUT_GAMEPAD_DPAD_RIGHT); - pad.wButtons |= TRANSLATE_INPUT(SDL_CONTROLLER_BUTTON_START, XAMINPUT_GAMEPAD_START); - pad.wButtons |= TRANSLATE_INPUT(SDL_CONTROLLER_BUTTON_BACK, XAMINPUT_GAMEPAD_BACK); - pad.wButtons |= TRANSLATE_INPUT(SDL_CONTROLLER_BUTTON_TOUCHPAD, XAMINPUT_GAMEPAD_BACK); + pad.wButtons |= TRANSLATE_INPUT(SDL_GAMEPAD_BUTTON_START, XAMINPUT_GAMEPAD_START); + pad.wButtons |= TRANSLATE_INPUT(SDL_GAMEPAD_BUTTON_BACK, XAMINPUT_GAMEPAD_BACK); + pad.wButtons |= TRANSLATE_INPUT(SDL_GAMEPAD_BUTTON_TOUCHPAD, XAMINPUT_GAMEPAD_BACK); - pad.wButtons |= TRANSLATE_INPUT(SDL_CONTROLLER_BUTTON_LEFTSTICK, XAMINPUT_GAMEPAD_LEFT_THUMB); - pad.wButtons |= TRANSLATE_INPUT(SDL_CONTROLLER_BUTTON_RIGHTSTICK, XAMINPUT_GAMEPAD_RIGHT_THUMB); + pad.wButtons |= TRANSLATE_INPUT(SDL_GAMEPAD_BUTTON_LEFT_STICK, XAMINPUT_GAMEPAD_LEFT_THUMB); + pad.wButtons |= TRANSLATE_INPUT(SDL_GAMEPAD_BUTTON_RIGHT_STICK, XAMINPUT_GAMEPAD_RIGHT_THUMB); - pad.wButtons |= TRANSLATE_INPUT(SDL_CONTROLLER_BUTTON_LEFTSHOULDER, XAMINPUT_GAMEPAD_LEFT_SHOULDER); - pad.wButtons |= TRANSLATE_INPUT(SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, XAMINPUT_GAMEPAD_RIGHT_SHOULDER); + pad.wButtons |= TRANSLATE_INPUT(SDL_GAMEPAD_BUTTON_LEFT_SHOULDER, XAMINPUT_GAMEPAD_LEFT_SHOULDER); + pad.wButtons |= TRANSLATE_INPUT(SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, XAMINPUT_GAMEPAD_RIGHT_SHOULDER); - pad.wButtons |= TRANSLATE_INPUT(SDL_CONTROLLER_BUTTON_A, XAMINPUT_GAMEPAD_A); - pad.wButtons |= TRANSLATE_INPUT(SDL_CONTROLLER_BUTTON_B, XAMINPUT_GAMEPAD_B); - pad.wButtons |= TRANSLATE_INPUT(SDL_CONTROLLER_BUTTON_X, XAMINPUT_GAMEPAD_X); - pad.wButtons |= TRANSLATE_INPUT(SDL_CONTROLLER_BUTTON_Y, XAMINPUT_GAMEPAD_Y); + pad.wButtons |= TRANSLATE_INPUT(SDL_GAMEPAD_BUTTON_SOUTH, XAMINPUT_GAMEPAD_A); + pad.wButtons |= TRANSLATE_INPUT(SDL_GAMEPAD_BUTTON_EAST, XAMINPUT_GAMEPAD_B); + pad.wButtons |= TRANSLATE_INPUT(SDL_GAMEPAD_BUTTON_WEST, XAMINPUT_GAMEPAD_X); + pad.wButtons |= TRANSLATE_INPUT(SDL_GAMEPAD_BUTTON_NORTH, XAMINPUT_GAMEPAD_Y); } void SetVibration(const XAMINPUT_VIBRATION& vibration) @@ -138,12 +132,12 @@ class Controller this->vibration = vibration; - SDL_GameControllerRumble(controller, vibration.wLeftMotorSpeed * 256, vibration.wRightMotorSpeed * 256, VIBRATION_TIMEOUT_MS); + SDL_RumbleGamepad(controller, vibration.wLeftMotorSpeed * 256, vibration.wRightMotorSpeed * 256, VIBRATION_TIMEOUT_MS); } void SetLED(const uint8_t r, const uint8_t g, const uint8_t b) const { - SDL_GameControllerSetLED(controller, r, g, b); + SDL_SetGamepadLED(controller, r, g, b); } }; @@ -169,7 +163,7 @@ inline size_t FindFreeController() return -1; } -inline Controller* FindController(int which) +inline Controller* FindController(SDL_JoystickID which) { for (auto& controller : g_controllers) { @@ -241,17 +235,17 @@ static void SetControllerTimeOfDayLED(Controller& controller, EPlayerCharacter p controller.SetLED(r, g, b); } -int HID_OnSDLEvent(void*, SDL_Event* event) +bool HID_OnSDLEvent(void*, SDL_Event* event) { switch (event->type) { - case SDL_CONTROLLERDEVICEADDED: + case SDL_EVENT_GAMEPAD_ADDED: { const auto freeIndex = FindFreeController(); if (freeIndex != -1) { - auto controller = Controller(event->cdevice.which); + auto controller = Controller(SDL_OpenGamepad(event->gdevice.which)); g_controllers[freeIndex] = controller; @@ -261,9 +255,9 @@ int HID_OnSDLEvent(void*, SDL_Event* event) break; } - case SDL_CONTROLLERDEVICEREMOVED: + case SDL_EVENT_GAMEPAD_REMOVED: { - auto* controller = FindController(event->cdevice.which); + auto* controller = FindController(event->gdevice.which); if (controller) controller->Close(); @@ -271,21 +265,21 @@ int HID_OnSDLEvent(void*, SDL_Event* event) break; } - case SDL_CONTROLLERBUTTONDOWN: - case SDL_CONTROLLERBUTTONUP: - case SDL_CONTROLLERAXISMOTION: - case SDL_CONTROLLERTOUCHPADDOWN: + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_GAMEPAD_BUTTON_UP: + case SDL_EVENT_GAMEPAD_AXIS_MOTION: + case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN: { - auto* controller = FindController(event->cdevice.which); + auto* controller = FindController(event->gdevice.which); if (!controller) break; - if (event->type == SDL_CONTROLLERAXISMOTION) + if (event->type == SDL_EVENT_GAMEPAD_AXIS_MOTION) { - if (abs(event->caxis.value) > 8000) + if (abs(event->gaxis.value) > 8000) { - SDL_ShowCursor(SDL_DISABLE); + SDL_HideCursor(); SetControllerInputDevice(controller); } @@ -293,7 +287,7 @@ int HID_OnSDLEvent(void*, SDL_Event* event) } else { - SDL_ShowCursor(SDL_DISABLE); + SDL_HideCursor(); SetControllerInputDevice(controller); controller->Poll(); @@ -302,36 +296,33 @@ int HID_OnSDLEvent(void*, SDL_Event* event) break; } - case SDL_KEYDOWN: - case SDL_KEYUP: + case SDL_EVENT_KEY_DOWN: + case SDL_EVENT_KEY_UP: hid::g_inputDevice = hid::EInputDevice::Keyboard; break; - case SDL_MOUSEMOTION: - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: + case SDL_EVENT_MOUSE_MOTION: + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: { if (!GameWindow::IsFullscreen() || GameWindow::s_isFullscreenCursorVisible) - SDL_ShowCursor(SDL_ENABLE); + SDL_ShowCursor(); hid::g_inputDevice = hid::EInputDevice::Mouse; break; } - case SDL_WINDOWEVENT: + case SDL_EVENT_WINDOW_FOCUS_LOST: { - if (event->window.event == SDL_WINDOWEVENT_FOCUS_LOST) - { - // Stop vibrating controllers on focus lost. - for (auto& controller : g_controllers) - controller.SetVibration({ 0, 0 }); - } + // Stop vibrating controllers on focus lost. + for (auto& controller : g_controllers) + controller.SetVibration({ 0, 0 }); break; } - case SDL_USER_PLAYER_CHAR: + case SDL_EVENT_USER_PLAYER_CHAR: { for (auto& controller : g_controllers) SetControllerTimeOfDayLED(controller, static_cast(event->user.code)); @@ -340,7 +331,7 @@ int HID_OnSDLEvent(void*, SDL_Event* event) } } - return 0; + return true; } void hid::Init() @@ -349,24 +340,20 @@ void hid::Init() SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS3, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_WII, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_STEAM, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_STEAMDECK, "1"); SDL_SetHint(SDL_HINT_XINPUT_ENABLED, "1"); - - SDL_SetHint(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, "0"); // Uses Button Labels. This hint is disabled for Nintendo Controllers. SDL_InitSubSystem(SDL_INIT_EVENTS); SDL_AddEventWatch(HID_OnSDLEvent, nullptr); - SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER); + SDL_InitSubSystem(SDL_INIT_GAMEPAD); // Load controller mappings from SDL_GameControllerDB - if (int mappings = SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt"); mappings > 0) { + if (int mappings = SDL_AddGamepadMappingsFromFile("gamecontrollerdb.txt"); mappings > 0) { LOGFN("Loaded {} controller mapping(s) from SDL_GameControllerDB ({})", mappings, "gamecontrollerdb.txt"); } } diff --git a/MarathonRecomp/kernel/xam.cpp b/MarathonRecomp/kernel/xam.cpp index 8e13a58ec..a6b0b7117 100644 --- a/MarathonRecomp/kernel/xam.cpp +++ b/MarathonRecomp/kernel/xam.cpp @@ -10,7 +10,7 @@ #include #include "xxHashMap.h" #include -#include +#include struct XamListener : KernelObject { diff --git a/MarathonRecomp/patches/frontend_listener.cpp b/MarathonRecomp/patches/frontend_listener.cpp index 58c22ea70..6a668a4b8 100644 --- a/MarathonRecomp/patches/frontend_listener.cpp +++ b/MarathonRecomp/patches/frontend_listener.cpp @@ -16,9 +16,9 @@ static class FrontendListener : public SDLEventListener switch (event->type) { - case SDL_KEYDOWN: + case SDL_EVENT_KEY_DOWN: { - if (event->key.keysym.sym != SDLK_F8 || m_isF8KeyDown) + if (event->key.key != SDLK_F8 || m_isF8KeyDown) break; // TODO @@ -28,8 +28,8 @@ static class FrontendListener : public SDLEventListener break; } - case SDL_KEYUP: - m_isF8KeyDown = event->key.keysym.sym != SDLK_F8; + case SDL_EVENT_KEY_UP: + m_isF8KeyDown = event->key.key != SDLK_F8; break; } diff --git a/MarathonRecomp/sdl_events.h b/MarathonRecomp/sdl_events.h index 05044bc4d..fd9d9ab2b 100644 --- a/MarathonRecomp/sdl_events.h +++ b/MarathonRecomp/sdl_events.h @@ -1,15 +1,14 @@ #pragma once -#include +#include #include -#define SDL_USER_PLAYER_CHAR (SDL_USEREVENT + 1) +#define SDL_EVENT_USER_PLAYER_CHAR (SDL_EVENT_USER + 1) inline void SDL_ResizeEvent(SDL_Window* pWindow, int width, int height) { SDL_Event event{}; - event.type = SDL_WINDOWEVENT; - event.window.event = SDL_WINDOWEVENT_RESIZED; + event.type = SDL_EVENT_WINDOW_RESIZED; event.window.windowID = SDL_GetWindowID(pWindow); event.window.data1 = width; event.window.data2 = height; @@ -20,8 +19,7 @@ inline void SDL_ResizeEvent(SDL_Window* pWindow, int width, int height) inline void SDL_MoveEvent(SDL_Window* pWindow, int x, int y) { SDL_Event event{}; - event.type = SDL_WINDOWEVENT; - event.window.event = SDL_WINDOWEVENT_MOVED; + event.type = SDL_EVENT_WINDOW_MOVED; event.window.windowID = SDL_GetWindowID(pWindow); event.window.data1 = x; event.window.data2 = y; @@ -32,7 +30,7 @@ inline void SDL_MoveEvent(SDL_Window* pWindow, int x, int y) inline void SDL_User_PlayerChar(EPlayerCharacter character) { SDL_Event event{}; - event.type = SDL_USER_PLAYER_CHAR; + event.type = SDL_EVENT_USER_PLAYER_CHAR; event.user.code = static_cast(character); SDL_PushEvent(&event); diff --git a/MarathonRecomp/stdafx.h b/MarathonRecomp/stdafx.h index 4489026b0..cd57dd5b1 100644 --- a/MarathonRecomp/stdafx.h +++ b/MarathonRecomp/stdafx.h @@ -35,12 +35,12 @@ using Microsoft::WRL::ComPtr; #include #include #include -#include -#include +#include +#include #include #include #include -#include +#include #include #include #include diff --git a/MarathonRecomp/ui/common_menu.h b/MarathonRecomp/ui/common_menu.h index 4663d4844..d02eb1a74 100644 --- a/MarathonRecomp/ui/common_menu.h +++ b/MarathonRecomp/ui/common_menu.h @@ -28,8 +28,8 @@ class CommonMenu bool OnSDLEvent(SDL_Event* event) override { - if (event->type == SDL_CONTROLLERAXISMOTION && event->caxis.axis == SDL_CONTROLLER_AXIS_RIGHTX) - RightStickX = event->caxis.value / 32767.0f; + if (event->type == SDL_EVENT_GAMEPAD_AXIS_MOTION && event->gaxis.axis == SDL_GAMEPAD_AXIS_RIGHTX) + RightStickX = event->gaxis.value / 32767.0f; return false; } diff --git a/MarathonRecomp/ui/game_window.cpp b/MarathonRecomp/ui/game_window.cpp index 11f6122df..292538514 100644 --- a/MarathonRecomp/ui/game_window.cpp +++ b/MarathonRecomp/ui/game_window.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #if _WIN32 #include @@ -17,22 +16,44 @@ static bool g_isFullscreenKeyReleased = true; static bool g_isResizing = false; -int Window_OnSDLEvent(void*, SDL_Event* event) +static SDL_DisplayID GetDisplayID(int displayIndex) +{ + int displayCount = 0; + auto displays = SDL_GetDisplays(&displayCount); + SDL_DisplayID result = 0; + + if (displays) + { + if (displayIndex >= 0 && displayIndex < displayCount) + result = displays[displayIndex]; + + SDL_free(displays); + } + + return result; +} + +static void OnWindowDisplayChanged() +{ + GameWindow::s_windowModes = GameWindow::GetDisplayModes(true, true); +} + +bool Window_OnSDLEvent(void*, SDL_Event* event) { if (ImGui::GetIO().BackendPlatformUserData != nullptr) - ImGui_ImplSDL2_ProcessEvent(event); + ImGui_ImplSDL3_ProcessEvent(event); for (auto listener : GetEventListeners()) { if (listener->OnSDLEvent(event)) { - return 0; + return true; } } switch (event->type) { - case SDL_QUIT: + case SDL_EVENT_QUIT: { if (App::s_isSaving) break; @@ -42,14 +63,14 @@ int Window_OnSDLEvent(void*, SDL_Event* event) break; } - case SDL_KEYDOWN: + case SDL_EVENT_KEY_DOWN: { - switch (event->key.keysym.sym) + switch (event->key.key) { // Toggle fullscreen on ALT+ENTER. case SDLK_RETURN: { - if (!(event->key.keysym.mod & KMOD_ALT) || !g_isFullscreenKeyReleased) + if (!(event->key.mod & SDL_KMOD_ALT) || !g_isFullscreenKeyReleased) break; Config::Fullscreen = GameWindow::SetFullscreen(!GameWindow::IsFullscreen()); @@ -90,80 +111,87 @@ int Window_OnSDLEvent(void*, SDL_Event* event) break; } - case SDL_KEYUP: + case SDL_EVENT_KEY_UP: { - switch (event->key.keysym.sym) + switch (event->key.key) { // Allow user to input ALT+ENTER again. case SDLK_RETURN: g_isFullscreenKeyReleased = true; break; } + + break; } - case SDL_WINDOWEVENT: - { - switch (event->window.event) - { - case SDL_WINDOWEVENT_FOCUS_LOST: - GameWindow::s_isFocused = false; - SDL_ShowCursor(SDL_ENABLE); - break; + case SDL_EVENT_WINDOW_FOCUS_LOST: + GameWindow::s_isFocused = false; + SDL_ShowCursor(); + break; - case SDL_WINDOWEVENT_FOCUS_GAINED: - { - GameWindow::s_isFocused = true; + case SDL_EVENT_WINDOW_FOCUS_GAINED: + { + GameWindow::s_isFocused = true; - if (GameWindow::IsFullscreen()) - SDL_ShowCursor(GameWindow::s_isFullscreenCursorVisible ? SDL_ENABLE : SDL_DISABLE); + if (GameWindow::IsFullscreen()) + { + if (GameWindow::s_isFullscreenCursorVisible) + SDL_ShowCursor(); + else + SDL_HideCursor(); + } - break; - } + break; + } - case SDL_WINDOWEVENT_RESTORED: - Config::WindowState = EWindowState::Normal; - break; + case SDL_EVENT_WINDOW_RESTORED: + Config::WindowState = EWindowState::Normal; + break; - case SDL_WINDOWEVENT_MAXIMIZED: - Config::WindowState = EWindowState::Maximised; - break; + case SDL_EVENT_WINDOW_MAXIMIZED: + Config::WindowState = EWindowState::Maximised; + break; - case SDL_WINDOWEVENT_RESIZED: - g_isResizing = true; - Config::WindowSize = -1; - GameWindow::s_width = event->window.data1; - GameWindow::s_height = event->window.data2; - GameWindow::SetTitle(fmt::format("{} - [{}x{}]", GameWindow::GetTitle(), GameWindow::s_width, GameWindow::s_height).c_str()); - break; + case SDL_EVENT_WINDOW_RESIZED: + g_isResizing = true; + Config::WindowSize = -1; + GameWindow::s_width = event->window.data1; + GameWindow::s_height = event->window.data2; + GameWindow::SetTitle(fmt::format("{} - [{}x{}]", GameWindow::GetTitle(), GameWindow::s_width, GameWindow::s_height).c_str()); + break; - case SDL_WINDOWEVENT_MOVED: - GameWindow::s_x = event->window.data1; - GameWindow::s_y = event->window.data2; - break; - } + case SDL_EVENT_WINDOW_MOVED: + GameWindow::s_x = event->window.data1; + GameWindow::s_y = event->window.data2; + break; + case SDL_EVENT_WINDOW_DISPLAY_CHANGED: + OnWindowDisplayChanged(); break; - } - case SDL_USER_PLAYER_CHAR: + case SDL_EVENT_USER_PLAYER_CHAR: GameWindow::s_playerCharacter = static_cast(event->user.code); GameWindow::SetIcon(GameWindow::s_playerCharacter); break; } - return 0; + return false; } void GameWindow::Init(const char* sdlVideoDriver) { #ifdef __linux__ - SDL_SetHint("SDL_APP_ID", "io.github.sonicnext_dev.marathonrecomp"); + SDL_SetHint(SDL_HINT_APP_ID, "io.github.sonicnext_dev.marathonrecomp"); #endif - if (SDL_VideoInit(sdlVideoDriver) != 0 && sdlVideoDriver) + if (sdlVideoDriver) + SDL_SetHint(SDL_HINT_VIDEO_DRIVER, sdlVideoDriver); + + if (!SDL_InitSubSystem(SDL_INIT_VIDEO) && sdlVideoDriver) { LOGFN_ERROR("Failed to initialise the SDL video driver: \"{}\". Falling back to default.", sdlVideoDriver); - SDL_VideoInit(nullptr); + SDL_ResetHint(SDL_HINT_VIDEO_DRIVER); + SDL_InitSubSystem(SDL_INIT_VIDEO); } auto videoDriverName = SDL_GetCurrentVideoDriver(); @@ -171,59 +199,48 @@ void GameWindow::Init(const char* sdlVideoDriver) if (videoDriverName) LOGFN("SDL video driver: \"{}\"", videoDriverName); - SDL_EventState(SDL_SYSWMEVENT, SDL_ENABLE); SDL_AddEventWatch(Window_OnSDLEvent, s_pWindow); #ifdef _WIN32 SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); #endif - s_x = Config::WindowX; - s_y = Config::WindowY; - s_width = Config::WindowWidth; - s_height = Config::WindowHeight; - - if (s_x == -1 && s_y == -1) - s_x = s_y = SDL_WINDOWPOS_CENTERED; + SetDimensions(Config::WindowWidth, Config::WindowHeight, Config::WindowX, Config::WindowY); if (!IsPositionValid()) GameWindow::ResetDimensions(); - s_pWindow = SDL_CreateWindow("Marathon Recompiled", s_x, s_y, s_width, s_height, GetWindowFlags()); + s_pWindow = SDL_CreateWindow("Marathon Recompiled", s_width, s_height, GetWindowFlags()); + SDL_SetWindowPosition(s_pWindow, s_x, s_y); + + OnWindowDisplayChanged(); if (IsFullscreen()) - SDL_ShowCursor(SDL_DISABLE); + SDL_HideCursor(); SetDisplay(Config::Monitor); SetIcon(); SetTitle(); - SDL_SetWindowMinimumSize(s_pWindow, MIN_WIDTH, MIN_HEIGHT); - - SDL_SysWMinfo info; - SDL_VERSION(&info.version); - SDL_GetWindowWMInfo(s_pWindow, &info); + SDL_SetWindowMinimumSize(s_pWindow, k_minWidth, k_minHeight); #if defined(_WIN32) - s_renderWindow = info.info.win.window; - - if (Config::DisableDWMRoundedCorners) - { - DWM_WINDOW_CORNER_PREFERENCE wcp = DWMWCP_DONOTROUND; - DwmSetWindowAttribute(s_renderWindow, DWMWA_WINDOW_CORNER_PREFERENCE, &wcp, sizeof(wcp)); - } + s_renderWindow = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(s_pWindow), SDL_PROP_WINDOW_WIN32_HWND_POINTER, nullptr); #elif defined(PLUME_SDL_VULKAN_ENABLED) s_renderWindow = s_pWindow; #elif defined(__linux__) - s_renderWindow = { info.info.x11.display, info.info.x11.window }; + s_renderWindow = { + (Display*)SDL_GetPointerProperty(SDL_GetWindowProperties(s_pWindow), SDL_PROP_WINDOW_X11_DISPLAY_POINTER, nullptr), + (Window)SDL_GetNumberProperty(SDL_GetWindowProperties(s_pWindow), SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0) + }; #elif defined(__APPLE__) - s_renderWindow.window = info.info.cocoa.window; + s_renderWindow.window = SDL_GetPointerProperty(SDL_GetWindowProperties(s_pWindow), SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, nullptr); s_renderWindow.view = SDL_Metal_GetLayer(SDL_Metal_CreateView(s_pWindow)); #else static_assert(false, "Unknown platform."); #endif - SetTitleBarColour(); + ConfigurePlatformWindow(); SDL_ShowWindow(s_pWindow); } @@ -250,8 +267,8 @@ void GameWindow::Update() SDL_Surface* GameWindow::GetIconSurface(void* pIconBmp, size_t iconSize) { - auto rw = SDL_RWFromMem(pIconBmp, iconSize); - auto surface = SDL_LoadBMP_RW(rw, 1); + auto io = SDL_IOFromMem(pIconBmp, iconSize); + auto surface = SDL_LoadBMP_IO(io, true); if (!surface) LOGF_ERROR("Failed to load icon: {}", SDL_GetError()); @@ -264,7 +281,7 @@ void GameWindow::SetIcon(void* pIconBmp, size_t iconSize) if (auto icon = GetIconSurface(pIconBmp, iconSize)) { SDL_SetWindowIcon(s_pWindow, icon); - SDL_FreeSurface(icon); + SDL_DestroySurface(icon); } } @@ -308,9 +325,9 @@ void GameWindow::SetTitle(const char* title) SDL_SetWindowTitle(s_pWindow, title ? title : GetTitle()); } -void GameWindow::SetTitleBarColour() +void GameWindow::ConfigurePlatformWindow() { -#if _WIN32 +#ifdef _WIN32 if (os::user::IsDarkTheme()) { auto version = os::version::GetOSVersion(); @@ -325,44 +342,56 @@ void GameWindow::SetTitleBarColour() const DWORD useImmersiveDarkMode = 1; DwmSetWindowAttribute(s_renderWindow, flag, &useImmersiveDarkMode, sizeof(useImmersiveDarkMode)); } + + if (Config::DisableDWMRoundedCorners) + { + DWM_WINDOW_CORNER_PREFERENCE wcp = DWMWCP_DONOTROUND; + DwmSetWindowAttribute(GameWindow::s_renderWindow, DWMWA_WINDOW_CORNER_PREFERENCE, &wcp, sizeof(wcp)); + } #endif } bool GameWindow::IsFullscreen() { - return SDL_GetWindowFlags(s_pWindow) & SDL_WINDOW_FULLSCREEN_DESKTOP; + return SDL_GetWindowFlags(s_pWindow) & SDL_WINDOW_FULLSCREEN; } bool GameWindow::SetFullscreen(bool isEnabled) { if (isEnabled) { - SDL_SetWindowFullscreen(s_pWindow, SDL_WINDOW_FULLSCREEN_DESKTOP); - SDL_ShowCursor(s_isFullscreenCursorVisible ? SDL_ENABLE : SDL_DISABLE); + SDL_SetWindowFullscreenMode(s_pWindow, nullptr); + SDL_SetWindowFullscreen(s_pWindow, true); + + if (s_isFullscreenCursorVisible) + SDL_ShowCursor(); + else + SDL_HideCursor(); } else { - SDL_SetWindowFullscreen(s_pWindow, 0); - SDL_ShowCursor(SDL_ENABLE); + SDL_SetWindowFullscreen(s_pWindow, false); + SDL_ShowCursor(); SetIcon(GameWindow::s_playerCharacter); SetDimensions(Config::WindowWidth, Config::WindowHeight, Config::WindowX, Config::WindowY); + ConfigurePlatformWindow(); } return isEnabled; } - + void GameWindow::SetFullscreenCursorVisibility(bool isVisible) { s_isFullscreenCursorVisible = isVisible; - if (IsFullscreen()) + if (IsFullscreen() && !s_isFullscreenCursorVisible) { - SDL_ShowCursor(s_isFullscreenCursorVisible ? SDL_ENABLE : SDL_DISABLE); + SDL_HideCursor(); } else { - SDL_ShowCursor(SDL_ENABLE); + SDL_ShowCursor(); } } @@ -406,22 +435,53 @@ void GameWindow::SetDimensions(int w, int h, int x, int y) { s_width = w; s_height = h; - s_x = x; - s_y = y; - SDL_SetWindowSize(s_pWindow, w, h); - SDL_ResizeEvent(s_pWindow, w, h); + const auto isCentredX = SDL_WINDOWPOS_ISCENTERED(x); + const auto isCentredY = SDL_WINDOWPOS_ISCENTERED(y); + + if (isCentredX || isCentredY) + { + SDL_Rect bounds{}; + SDL_DisplayID display = SDL_GetDisplayForWindow(s_pWindow); + + if (!display) + display = SDL_GetPrimaryDisplay(); + + if (SDL_GetDisplayBounds(display, &bounds)) + { + s_x = isCentredX + ? bounds.x + (bounds.w / 2 - s_width / 2) + : x; + + s_y = isCentredY + ? bounds.y + (bounds.h / 2 - s_height / 2) + : y; + } + else + { + s_x = isCentredX ? 0 : x; + s_y = isCentredY ? 0 : y; + } + } + else + { + s_x = x; + s_y = y; + } + + if (!s_pWindow) + return; + + SDL_SetWindowSize(s_pWindow, s_width, s_height); + SDL_ResizeEvent(s_pWindow, s_width, s_height); - SDL_SetWindowPosition(s_pWindow, x, y); - SDL_MoveEvent(s_pWindow, x, y); + SDL_SetWindowPosition(s_pWindow, s_x, s_y); + SDL_MoveEvent(s_pWindow, s_x, s_y); } void GameWindow::ResetDimensions() { - s_x = SDL_WINDOWPOS_CENTERED; - s_y = SDL_WINDOWPOS_CENTERED; - s_width = DEFAULT_WIDTH; - s_height = DEFAULT_HEIGHT; + SetDimensions(k_defaultWidth, k_defaultHeight); Config::WindowX = s_x; Config::WindowY = s_y; @@ -429,15 +489,15 @@ void GameWindow::ResetDimensions() Config::WindowHeight = s_height; } -uint32_t GameWindow::GetWindowFlags() +SDL_WindowFlags GameWindow::GetWindowFlags() { - uint32_t flags = SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI; + SDL_WindowFlags flags = SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY; if (Config::WindowState == EWindowState::Maximised) flags |= SDL_WINDOW_MAXIMIZED; if (Config::Fullscreen) - flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + flags |= SDL_WINDOW_FULLSCREEN; #ifdef PLUME_SDL_VULKAN_ENABLED flags |= SDL_WINDOW_VULKAN; @@ -448,20 +508,42 @@ uint32_t GameWindow::GetWindowFlags() int GameWindow::GetDisplayCount() { - auto result = SDL_GetNumVideoDisplays(); + int result = 0; + auto displays = SDL_GetDisplays(&result); - if (result < 0) + if (!displays) { LOGF_ERROR("Failed to get display count: {}", SDL_GetError()); return 1; } + SDL_free(displays); + return result; } int GameWindow::GetDisplay() { - return SDL_GetWindowDisplayIndex(s_pWindow); + auto displayID = SDL_GetDisplayForWindow(s_pWindow); + int displayCount = 0; + auto displays = SDL_GetDisplays(&displayCount); + int result = -1; + + if (displays) + { + for (int i = 0; i < displayCount; i++) + { + if (displays[i] == displayID) + { + result = i; + break; + } + } + + SDL_free(displays); + } + + return result; } void GameWindow::SetDisplay(int displayIndex) @@ -476,7 +558,7 @@ void GameWindow::SetDisplay(int displayIndex) SDL_Rect bounds; - if (SDL_GetDisplayBounds(displayIndex, &bounds) == 0) + if (SDL_GetDisplayBounds(GetDisplayID(displayIndex), &bounds)) { SetFullscreen(false); SetDimensions(bounds.w, bounds.h, bounds.x, bounds.y); @@ -492,69 +574,72 @@ std::vector GameWindow::GetDisplayModes(bool ignoreInvalidModes { auto result = std::vector(); auto uniqueResolutions = std::set>(); - auto displayIndex = GetDisplay(); - auto modeCount = SDL_GetNumDisplayModes(displayIndex); + auto displayID = GetDisplayID(GetDisplay()); + auto modeCount = 0; + auto modes = SDL_GetFullscreenDisplayModes(displayID, &modeCount); - if (modeCount <= 0) + if (!modes) return result; for (int i = modeCount - 1; i >= 0; i--) { - SDL_DisplayMode mode; + const SDL_DisplayMode& mode = *modes[i]; - if (SDL_GetDisplayMode(displayIndex, i, &mode) == 0) + if (ignoreInvalidModes) { - if (ignoreInvalidModes) - { - if (mode.w < MIN_WIDTH || mode.h < MIN_HEIGHT) - continue; + if (mode.w < k_minWidth || mode.h < k_minHeight) + continue; - SDL_DisplayMode desktopMode; + auto desktopMode = SDL_GetDesktopDisplayMode(displayID); - if (SDL_GetDesktopDisplayMode(displayIndex, &desktopMode) == 0) - { - if (mode.w >= desktopMode.w || mode.h >= desktopMode.h) - continue; - } - } + if (desktopMode && (mode.w >= desktopMode->w || mode.h >= desktopMode->h)) + continue; + } - if (ignoreRefreshRates) - { - auto res = std::make_pair(mode.w, mode.h); + if (ignoreRefreshRates) + { + auto res = std::make_pair(mode.w, mode.h); - if (uniqueResolutions.find(res) == uniqueResolutions.end()) - { - uniqueResolutions.insert(res); - result.push_back(mode); - } - } - else + if (uniqueResolutions.find(res) == uniqueResolutions.end()) { + uniqueResolutions.insert(res); result.push_back(mode); } } + else + { + result.push_back(mode); + } } + SDL_free(modes); + return result; } -int GameWindow::FindNearestDisplayMode() +int GameWindow::FindNearestDisplayMode(const std::vector& displayModes) { - auto result = -1; - auto displayModes = GetDisplayModes(); - auto currentDiff = std::numeric_limits::max(); + int result = -1; + int smallestDiff{}; for (int i = 0; i < displayModes.size(); i++) { - auto& mode = displayModes[i]; + const auto& mode = displayModes[i]; - auto widthDiff = abs(mode.w - s_width); - auto heightDiff = abs(mode.h - s_height); - auto totalDiff = widthDiff + heightDiff; + const auto widthDiff = abs(mode.w - s_width); + const auto heightDiff = abs(mode.h - s_height); + const auto currentDiff = widthDiff + heightDiff; - if (totalDiff < currentDiff) + // Display mode matches exact resolution. + if (!currentDiff) { - currentDiff = totalDiff; + result = i; + break; + } + + if (currentDiff < smallestDiff) + { + smallestDiff = currentDiff; result = i; } } @@ -562,36 +647,47 @@ int GameWindow::FindNearestDisplayMode() return result; } +int GameWindow::FindNearestDisplayMode(bool ignoreInvalidModes, bool ignoreRefreshRates) +{ + return FindNearestDisplayMode(GetDisplayModes(ignoreInvalidModes, ignoreRefreshRates)); +} + +int GameWindow::FindNearestWindowMode() +{ + return FindNearestDisplayMode(s_windowModes); +} + bool GameWindow::IsPositionValid() { - auto displayCount = GetDisplayCount(); + bool result{}; + + int displayCount{}; + const auto displays = SDL_GetDisplays(&displayCount); + + if (!displays) + return result; for (int i = 0; i < displayCount; i++) { - SDL_Rect bounds; + SDL_Rect bounds{}; - if (SDL_GetDisplayBounds(i, &bounds) == 0) - { - auto x = s_x; - auto y = s_y; + if (!SDL_GetDisplayBounds(displays[i], &bounds)) + continue; - // Window spans across the entire display in windowed mode, which is invalid. + if (s_x >= bounds.x && s_x < bounds.x + bounds.w && + s_y >= bounds.y && s_y < bounds.y + bounds.h) + { + // Window covers the display in windowed mode, which is invalid. if (!Config::Fullscreen && s_width == bounds.w && s_height == bounds.h) - return false; - - if (x == SDL_WINDOWPOS_CENTERED_DISPLAY(i)) - x = bounds.w / 2 - s_width / 2; + break; - if (y == SDL_WINDOWPOS_CENTERED_DISPLAY(i)) - y = bounds.h / 2 - s_height / 2; + result = true; - if (x >= bounds.x && x < bounds.x + bounds.w && - y >= bounds.y && y < bounds.y + bounds.h) - { - return true; - } + break; } } - return false; + SDL_free(displays); + + return result; } diff --git a/MarathonRecomp/ui/game_window.h b/MarathonRecomp/ui/game_window.h index 187c6b184..745c2bfce 100644 --- a/MarathonRecomp/ui/game_window.h +++ b/MarathonRecomp/ui/game_window.h @@ -4,21 +4,23 @@ #include #include -#define DEFAULT_WIDTH 1280 -#define DEFAULT_HEIGHT 720 -#define MIN_WIDTH 640 -#define MIN_HEIGHT 480 - class GameWindow { public: + static constexpr int k_defaultWidth = 1280; + static constexpr int k_defaultHeight = 720; + static constexpr int k_minWidth = 640; + static constexpr int k_minHeight = 480; + static inline SDL_Window* s_pWindow = nullptr; static inline plume::RenderWindow s_renderWindow; static inline int s_x; static inline int s_y; - static inline int s_width = DEFAULT_WIDTH; - static inline int s_height = DEFAULT_HEIGHT; + static inline int s_width = k_defaultWidth; + static inline int s_height = k_defaultHeight; + + static inline std::vector s_windowModes{}; static inline EPlayerCharacter s_playerCharacter; @@ -31,7 +33,7 @@ class GameWindow static void SetIcon(EPlayerCharacter player = EPlayerCharacter::Sonic); static const char* GetTitle(); static void SetTitle(const char* title = nullptr); - static void SetTitleBarColour(); + static void ConfigurePlatformWindow(); static bool IsFullscreen(); static bool SetFullscreen(bool isEnabled); static void SetFullscreenCursorVisibility(bool isVisible); @@ -41,12 +43,14 @@ class GameWindow static void GetSizeInPixels(int *w, int *h); static void SetDimensions(int w, int h, int x = SDL_WINDOWPOS_CENTERED, int y = SDL_WINDOWPOS_CENTERED); static void ResetDimensions(); - static uint32_t GetWindowFlags(); + static uint64_t GetWindowFlags(); static int GetDisplayCount(); static int GetDisplay(); static void SetDisplay(int displayIndex); static std::vector GetDisplayModes(bool ignoreInvalidModes = true, bool ignoreRefreshRates = true); - static int FindNearestDisplayMode(); + static int FindNearestDisplayMode(const std::vector& displayModes); + static int FindNearestDisplayMode(bool ignoreInvalidModes = true, bool ignoreRefreshRates = true); + static int FindNearestWindowMode(); static bool IsPositionValid(); static void Init(const char* sdlVideoDriver = nullptr); static void Update(); diff --git a/MarathonRecomp/ui/imgui_utils.h b/MarathonRecomp/ui/imgui_utils.h index 103d0d5f5..952044e34 100644 --- a/MarathonRecomp/ui/imgui_utils.h +++ b/MarathonRecomp/ui/imgui_utils.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -13,7 +14,7 @@ #define CENTRE_TEXT_HORZ(min, max, textSize) min.x + ((max.x - min.x) - textSize.x) / 2 #define CENTRE_TEXT_VERT(min, max, textSize) min.y + ((max.y - min.y) - textSize.y) / 2 -#define BREATHE_MOTION(start, end, time, rate) Lerp(start, end, (sin((ImGui::GetTime() - time) * (2.0f * M_PI / rate)) + 1.0f) / 2.0f) +#define BREATHE_MOTION(start, end, time, rate) Lerp(start, end, (sin((ImGui::GetTime() - time) * (2.0f * std::numbers::pi / rate)) + 1.0f) / 2.0f) #define IM_COL32_WHITE_TRANS IM_COL32(255, 255, 255, 0) diff --git a/MarathonRecomp/ui/installer_wizard.cpp b/MarathonRecomp/ui/installer_wizard.cpp index bcb25a944..eac2e9fd7 100644 --- a/MarathonRecomp/ui/installer_wizard.cpp +++ b/MarathonRecomp/ui/installer_wizard.cpp @@ -183,7 +183,7 @@ class SDLEventListenerForInstaller : public SDLEventListener auto noModals = g_currentMessagePrompt.empty() && !g_currentPickerVisible; - if (event->type == SDL_QUIT && g_currentPage == WizardPage::Installing) + if (event->type == SDL_EVENT_QUIT && g_currentPage == WizardPage::Installing) { // Pretend the back button was pressed if the user tried quitting during installation. // This condition is above the rest of the event processing as we want to block the exit @@ -204,18 +204,18 @@ class SDLEventListenerForInstaller : public SDLEventListener switch (event->type) { - case SDL_KEYDOWN: + case SDL_EVENT_KEY_DOWN: { - switch (event->key.keysym.scancode) + switch (event->key.scancode) { case SDL_SCANCODE_LEFT: case SDL_SCANCODE_RIGHT: - tapDirection.x = (event->key.keysym.scancode == SDL_SCANCODE_RIGHT) ? 1.0f : -1.0f; + tapDirection.x = (event->key.scancode == SDL_SCANCODE_RIGHT) ? 1.0f : -1.0f; break; case SDL_SCANCODE_UP: case SDL_SCANCODE_DOWN: - tapDirection.y = (event->key.keysym.scancode == SDL_SCANCODE_DOWN) ? 1.0f : -1.0f; + tapDirection.y = (event->key.scancode == SDL_SCANCODE_DOWN) ? 1.0f : -1.0f; break; case SDL_SCANCODE_RETURN: @@ -231,31 +231,31 @@ class SDLEventListenerForInstaller : public SDLEventListener break; } - case SDL_CONTROLLERBUTTONDOWN: + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: { - switch (event->cbutton.button) + switch (event->gbutton.button) { - case SDL_CONTROLLER_BUTTON_DPAD_LEFT: + case SDL_GAMEPAD_BUTTON_DPAD_LEFT: tapDirection = { -1.0f, 0.0f }; break; - case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: + case SDL_GAMEPAD_BUTTON_DPAD_RIGHT: tapDirection = { 1.0f, 0.0f }; break; - case SDL_CONTROLLER_BUTTON_DPAD_UP: + case SDL_GAMEPAD_BUTTON_DPAD_UP: tapDirection = { 0.0f, -1.0f }; break; - case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + case SDL_GAMEPAD_BUTTON_DPAD_DOWN: tapDirection = { 0.0f, 1.0f }; break; - case SDL_CONTROLLER_BUTTON_A: + case SDL_GAMEPAD_BUTTON_SOUTH: g_currentCursorAccepted = (g_currentCursorIndex >= 0); break; - case SDL_CONTROLLER_BUTTON_B: + case SDL_GAMEPAD_BUTTON_EAST: g_currentCursorBack = true; break; } @@ -263,26 +263,26 @@ class SDLEventListenerForInstaller : public SDLEventListener break; } - case SDL_CONTROLLERAXISMOTION: + case SDL_EVENT_GAMEPAD_AXIS_MOTION: { - if (event->caxis.axis < 2) + if (event->gaxis.axis < 2) { - auto newAxisValue = event->caxis.value / axisValueRange; - auto sameDirection = (newAxisValue * m_joypadAxis[event->caxis.axis]) > 0.0f; - auto wasInRange = abs(m_joypadAxis[event->caxis.axis]) > axisTapRange; + auto newAxisValue = event->gaxis.value / axisValueRange; + auto sameDirection = (newAxisValue * m_joypadAxis[event->gaxis.axis]) > 0.0f; + auto wasInRange = abs(m_joypadAxis[event->gaxis.axis]) > axisTapRange; auto isInRange = abs(newAxisValue) > axisTapRange; if (sameDirection && !wasInRange && isInRange) - tapDirection[event->caxis.axis] = newAxisValue; + tapDirection[event->gaxis.axis] = newAxisValue; - m_joypadAxis[event->caxis.axis] = newAxisValue; + m_joypadAxis[event->gaxis.axis] = newAxisValue; } break; } - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEMOTION: + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_MOTION: { for (size_t i = 0; i < g_currentCursorRects.size(); i++) { @@ -292,7 +292,7 @@ class SDLEventListenerForInstaller : public SDLEventListener { newCursorIndex = int(i); - if (event->type == SDL_MOUSEBUTTONDOWN && event->button.button == SDL_BUTTON_LEFT) + if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN && event->button.button == SDL_BUTTON_LEFT) g_currentCursorAccepted = true; break; @@ -1388,7 +1388,7 @@ bool InstallerWizard::Run(std::filesystem::path installPath, bool skipGame) Video::WaitOnSwapChain(); EmbeddedPlayer::PlayMusic(); SDL_PumpEvents(); - SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT); + SDL_FlushEvents(SDL_EVENT_FIRST, SDL_EVENT_LAST); GameWindow::Update(); Video::Present(); } diff --git a/MarathonRecomp/ui/message_window.cpp b/MarathonRecomp/ui/message_window.cpp index 45353e656..5445362e5 100644 --- a/MarathonRecomp/ui/message_window.cpp +++ b/MarathonRecomp/ui/message_window.cpp @@ -47,9 +47,9 @@ class SDLEventListenerForMessageWindow : public SDLEventListener switch (event->type) { - case SDL_KEYDOWN: + case SDL_EVENT_KEY_DOWN: { - switch (event->key.keysym.scancode) + switch (event->key.scancode) { case SDL_SCANCODE_UP: g_joypadAxis.y = 1.0f; @@ -72,7 +72,7 @@ class SDLEventListenerForMessageWindow : public SDLEventListener break; } - case SDL_MOUSEBUTTONDOWN: + case SDL_EVENT_MOUSE_BUTTON_DOWN: { // Only accept left mouse button. if (event->button.button != SDL_BUTTON_LEFT) @@ -87,23 +87,23 @@ class SDLEventListenerForMessageWindow : public SDLEventListener break; } - case SDL_CONTROLLERBUTTONDOWN: + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: { - switch (event->cbutton.button) + switch (event->gbutton.button) { - case SDL_CONTROLLER_BUTTON_DPAD_UP: + case SDL_GAMEPAD_BUTTON_DPAD_UP: g_joypadAxis = { 0.0f, 1.0f }; break; - case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + case SDL_GAMEPAD_BUTTON_DPAD_DOWN: g_joypadAxis = { 0.0f, -1.0f }; break; - case SDL_CONTROLLER_BUTTON_A: + case SDL_GAMEPAD_BUTTON_SOUTH: g_isAccepted = true; break; - case SDL_CONTROLLER_BUTTON_B: + case SDL_GAMEPAD_BUTTON_EAST: g_isDeclined = true; break; } @@ -111,19 +111,19 @@ class SDLEventListenerForMessageWindow : public SDLEventListener break; } - case SDL_CONTROLLERAXISMOTION: + case SDL_EVENT_GAMEPAD_AXIS_MOTION: { - if (event->caxis.axis < 2) + if (event->gaxis.axis < 2) { - float newAxisValue = -(event->caxis.value / axisValueRange); - bool sameDirection = (newAxisValue * g_joypadAxis[event->caxis.axis]) > 0.0f; - bool wasInRange = abs(g_joypadAxis[event->caxis.axis]) > axisTapRange; + float newAxisValue = -(event->gaxis.value / axisValueRange); + bool sameDirection = (newAxisValue * g_joypadAxis[event->gaxis.axis]) > 0.0f; + bool wasInRange = abs(g_joypadAxis[event->gaxis.axis]) > axisTapRange; bool isInRange = abs(newAxisValue) > axisTapRange; if (sameDirection && !wasInRange && isInRange) - tapDirection[event->caxis.axis] = newAxisValue; + tapDirection[event->gaxis.axis] = newAxisValue; - g_joypadAxis[event->caxis.axis] = newAxisValue; + g_joypadAxis[event->gaxis.axis] = newAxisValue; } break; diff --git a/MarathonRecomp/ui/options_menu.cpp b/MarathonRecomp/ui/options_menu.cpp index cb159e3a6..3a4e4e49d 100644 --- a/MarathonRecomp/ui/options_menu.cpp +++ b/MarathonRecomp/ui/options_menu.cpp @@ -256,7 +256,7 @@ void DrawSelectionArrows(ImVec2 min, ImVec2 max, bool isSelected) auto arrowOffsetXMin = Scale(30, true); auto arrowOffsetXMax = Scale(20, true); - auto arrowOffsetX = Lerp(arrowOffsetXMin, arrowOffsetXMax, sin(motionTime * M_PI)); + auto arrowOffsetX = Lerp(arrowOffsetXMin, arrowOffsetXMax, sin(motionTime * std::numbers::pi)); auto arrowOffsetY = Scale(10, true); auto arrowLeftOffsetX = s_isLeftArrowMotion ? arrowOffsetX : arrowOffsetXMin; @@ -532,13 +532,17 @@ static void DrawOption { config->Value = s_oldValue; - VideoConfigValueChangedCallback(config); + // Don't run callbacks if Window Size change is cancelled. + if (static_cast(config) != &Config::WindowSize) + { + VideoConfigValueChangedCallback(config); - if (config->Callback) - config->Callback(config); + if (config->Callback) + config->Callback(config); - if (config->ApplyCallback) - config->ApplyCallback(config); + if (config->ApplyCallback) + config->ApplyCallback(config); + } } OptionsMenu::SetFlowState(OptionsMenuFlowState::OptionCursor); @@ -728,13 +732,13 @@ static void DrawOption } else { - auto displayModes = GameWindow::GetDisplayModes(); + const auto& windowModes = GameWindow::s_windowModes; - if (config->Value >= 0 && config->Value < displayModes.size()) + if (config->Value >= 0 && config->Value < windowModes.size()) { - auto& displayMode = displayModes[config->Value]; + const auto& windowMode = windowModes[config->Value]; - valueText = fmt::format("{}x{}", displayMode.w, displayMode.h); + valueText = fmt::format("{}x{}", windowMode.w, windowMode.h); } else { @@ -840,7 +844,7 @@ static void DrawOptions(ImVec2 min, ImVec2 max) { DrawOption(rowCount++, &Config::WindowSize, !Config::Fullscreen, &Localise("Options_Desc_NotAvailableFullscreen"), - 0, 0, (int)GameWindow::GetDisplayModes().size() - 1, false); + 0, 0, (int)GameWindow::s_windowModes.size() - 1, false); auto displayCount = GameWindow::GetDisplayCount(); auto canChangeMonitor = Config::Fullscreen && displayCount > 1; diff --git a/MarathonRecomp/user/config.cpp b/MarathonRecomp/user/config.cpp index 0070de613..0f4fab1ee 100644 --- a/MarathonRecomp/user/config.cpp +++ b/MarathonRecomp/user/config.cpp @@ -261,16 +261,12 @@ CONFIG_DEFINE_ENUM_TEMPLATE(SDL_Scancode) { "RIGHT ALT", SDL_SCANCODE_RALT }, { "RIGHT SUPER", SDL_SCANCODE_RGUI }, { "MODE", SDL_SCANCODE_MODE }, - { "AUDIO NEXT", SDL_SCANCODE_AUDIONEXT }, - { "AUDIO PREV", SDL_SCANCODE_AUDIOPREV }, - { "AUDIO STOP", SDL_SCANCODE_AUDIOSTOP }, - { "AUDIO PLAY", SDL_SCANCODE_AUDIOPLAY }, - { "AUDIO MUTE", SDL_SCANCODE_AUDIOMUTE }, - { "MEDIA SELECT", SDL_SCANCODE_MEDIASELECT }, - { "WWW", SDL_SCANCODE_WWW }, - { "MAIL", SDL_SCANCODE_MAIL }, - { "CALCULATOR", SDL_SCANCODE_CALCULATOR }, - { "COMPUTER", SDL_SCANCODE_COMPUTER }, + { "AUDIO NEXT", SDL_SCANCODE_MEDIA_NEXT_TRACK }, + { "AUDIO PREV", SDL_SCANCODE_MEDIA_PREVIOUS_TRACK }, + { "AUDIO STOP", SDL_SCANCODE_MEDIA_STOP }, + { "AUDIO PLAY", SDL_SCANCODE_MEDIA_PLAY }, + { "AUDIO MUTE", SDL_SCANCODE_MUTE }, + { "MEDIA SELECT", SDL_SCANCODE_MEDIA_SELECT }, { "AC SEARCH", SDL_SCANCODE_AC_SEARCH }, { "AC HOME", SDL_SCANCODE_AC_HOME }, { "AC BACK", SDL_SCANCODE_AC_BACK }, @@ -278,18 +274,10 @@ CONFIG_DEFINE_ENUM_TEMPLATE(SDL_Scancode) { "AC STOP", SDL_SCANCODE_AC_STOP }, { "AC REFRESH", SDL_SCANCODE_AC_REFRESH }, { "AC BOOKMARKS", SDL_SCANCODE_AC_BOOKMARKS }, - { "BRIGHTNESS DOWN", SDL_SCANCODE_BRIGHTNESSDOWN }, - { "BRIGHTNESS UP", SDL_SCANCODE_BRIGHTNESSUP }, - { "DISPLAY SWITCH", SDL_SCANCODE_DISPLAYSWITCH }, - { "KBD ILLUM TOGGLE", SDL_SCANCODE_KBDILLUMTOGGLE }, - { "KBD ILLUM DOWN", SDL_SCANCODE_KBDILLUMDOWN }, - { "KBD ILLUM UP", SDL_SCANCODE_KBDILLUMUP }, - { "EJECT", SDL_SCANCODE_EJECT }, + { "EJECT", SDL_SCANCODE_MEDIA_EJECT }, { "SLEEP", SDL_SCANCODE_SLEEP }, - { "APP 1", SDL_SCANCODE_APP1 }, - { "APP 2", SDL_SCANCODE_APP2 }, - { "AUDIO REWIND", SDL_SCANCODE_AUDIOREWIND }, - { "AUDIO FAST FORWARD", SDL_SCANCODE_AUDIOFASTFORWARD }, + { "AUDIO REWIND", SDL_SCANCODE_MEDIA_REWIND }, + { "AUDIO FAST FORWARD", SDL_SCANCODE_MEDIA_FAST_FORWARD }, { "SOFT LEFT", SDL_SCANCODE_SOFTLEFT }, { "SOFT RIGHT", SDL_SCANCODE_SOFTRIGHT }, { "CALL", SDL_SCANCODE_CALL }, @@ -788,21 +776,21 @@ void Config::CreateCallbacks() { // Try matching the current window size with a known configuration. if (def->Value < 0) - def->Value = GameWindow::FindNearestDisplayMode(); + def->Value = GameWindow::FindNearestWindowMode(); }; Config::WindowSize.ApplyCallback = [](ConfigDef* def) { - auto displayModes = GameWindow::GetDisplayModes(); + const auto& windowModes = GameWindow::s_windowModes; // Use largest supported resolution if overflowed. - if (def->Value >= displayModes.size()) - def->Value = displayModes.size() - 1; + if (def->Value >= windowModes.size()) + def->Value = windowModes.size() - 1; - auto& mode = displayModes[def->Value]; - auto centre = SDL_WINDOWPOS_CENTERED_DISPLAY(GameWindow::GetDisplay()); + const auto& mode = windowModes[def->Value]; - GameWindow::SetDimensions(mode.w, mode.h, centre, centre); + GameWindow::SetMaximised(false); + GameWindow::SetDimensions(mode.w, mode.h); }; Config::Monitor.Callback = [](ConfigDef* def) diff --git a/MarathonRecomp/user/config.h b/MarathonRecomp/user/config.h index 965c31d7d..8f0852eb1 100644 --- a/MarathonRecomp/user/config.h +++ b/MarathonRecomp/user/config.h @@ -34,7 +34,7 @@ class IConfigDef #define CONFIG_LOCK_CALLBACK(name) if (name.LockCallback) name.LockCallback(&name) #define CONFIG_APPLY_CALLBACK(name) if (name.ApplyCallback) name.ApplyCallback(&name) -#define WINDOWPOS_CENTRED 0x2FFF0000 +#define CONFIG_WINDOWPOS_CENTRED 0x2FFF0000 extern std::vector g_configDefinitions; diff --git a/MarathonRecomp/user/config_def.h b/MarathonRecomp/user/config_def.h index 8db352586..605b10849 100644 --- a/MarathonRecomp/user/config_def.h +++ b/MarathonRecomp/user/config_def.h @@ -49,8 +49,8 @@ CONFIG_DEFINE_LOCALISED("Audio", bool, MusicAttenuation, false, false); CONFIG_DEFINE("Video", std::string, GraphicsDevice, "", true); CONFIG_DEFINE_ENUM("Video", EGraphicsAPI, GraphicsAPI, EGraphicsAPI::Auto, true); -CONFIG_DEFINE("Video", int32_t, WindowX, WINDOWPOS_CENTRED, false); -CONFIG_DEFINE("Video", int32_t, WindowY, WINDOWPOS_CENTRED, false); +CONFIG_DEFINE("Video", int32_t, WindowX, CONFIG_WINDOWPOS_CENTRED, false); +CONFIG_DEFINE("Video", int32_t, WindowY, CONFIG_WINDOWPOS_CENTRED, false); CONFIG_DEFINE_LOCALISED("Video", int32_t, WindowSize, -1, false); CONFIG_DEFINE("Video", int32_t, WindowWidth, 1280, false); CONFIG_DEFINE("Video", int32_t, WindowHeight, 720, false); diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index f08beac32..fa077bf7a 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -5,15 +5,15 @@ set(MSDF_ATLAS_USE_SKIA OFF) set(MSDF_ATLAS_NO_ARTERY_FONT ON) set(MSDFGEN_DISABLE_PNG ON) -set(SDL2MIXER_DEPS_SHARED OFF) -set(SDL2MIXER_VENDORED ON) -set(SDL2MIXER_FLAC OFF) -set(SDL2MIXER_MOD OFF) -set(SDL2MIXER_MP3 OFF) -set(SDL2MIXER_MIDI OFF) -set(SDL2MIXER_OPUS OFF) -set(SDL2MIXER_VORBIS "VORBISFILE") -set(SDL2MIXER_WAVPACK OFF) +set(SDLMIXER_DEPS_SHARED OFF) +set(SDLMIXER_VENDORED ON) +set(SDLMIXER_FLAC OFF) +set(SDLMIXER_MOD OFF) +set(SDLMIXER_MP3 OFF) +set(SDLMIXER_MIDI OFF) +set(SDLMIXER_OPUS OFF) +set(SDLMIXER_VORBIS_STB OFF) +set(SDLMIXER_WAVPACK OFF) if (CMAKE_SYSTEM_NAME MATCHES "Linux") set(PLUME_SDL_VULKAN_ENABLED ON CACHE BOOL "") diff --git a/thirdparty/SDL b/thirdparty/SDL index 2e5b9a860..fa2c02bb6 160000 --- a/thirdparty/SDL +++ b/thirdparty/SDL @@ -1 +1 @@ -Subproject commit 2e5b9a860e69afc9fa5259c7b1f0bd52857d475e +Subproject commit fa2c02bb6e21974a89ea9824bc53c9932abe5f9c diff --git a/thirdparty/SDL_mixer b/thirdparty/SDL_mixer index 437992692..72a81869b 160000 --- a/thirdparty/SDL_mixer +++ b/thirdparty/SDL_mixer @@ -1 +1 @@ -Subproject commit 437992692cf9300f2b2f04be35adc7445a9055bf +Subproject commit 72a81869b45e249e8e67102db4e98dd2441f05a1 diff --git a/thirdparty/imgui b/thirdparty/imgui index 8199457a7..cb16568fc 160000 --- a/thirdparty/imgui +++ b/thirdparty/imgui @@ -1 +1 @@ -Subproject commit 8199457a7d9e453f8d3d9cadc14683fb54a858b5 +Subproject commit cb16568fca5297512ff6a8f3b877f461c4323fbe diff --git a/thirdparty/plume b/thirdparty/plume index 4f556be15..68e365981 160000 --- a/thirdparty/plume +++ b/thirdparty/plume @@ -1 +1 @@ -Subproject commit 4f556be1531698174a597e7e0a215c22d3238a24 +Subproject commit 68e36598110d9dbe93d3f1d988c6b192f59fc776