implemented SDL3 as an option for window manager

This commit is contained in:
2026-03-23 19:00:56 +01:00
parent 226f60e9ae
commit a596028ed9
152 changed files with 84309 additions and 247 deletions

View File

@@ -0,0 +1,264 @@
#include "Sdl3Input.hpp"
#include "SDL3/SDL.h"
void TSE::SDL3::Sdl3Input::Init()
{
Instance = new Sdl3Input();
}
void TSE::SDL3::Sdl3Input::Delete()
{
delete(Instance);
}
void TSE::SDL3::Sdl3Input::KeyCallback(uint key, int action, ushort mods)
{
switch (action)
{
case 1: //down
for(auto handler : ((Sdl3Input*)instance())->keyHandler)
{
handler->OnKeyDown(SDL3ToTSEKeycode(key), SDL3ToTSEModifier(mods));
}
break;
case 0: //up
for(auto handler : ((Sdl3Input*)instance())->keyHandler)
{
handler->OnKeyUp(SDL3ToTSEKeycode(key), SDL3ToTSEModifier(mods));
}
break;
case 2: //hold
for(auto handler : ((Sdl3Input*)instance())->keyHandler)
{
handler->OnKeyHold(SDL3ToTSEKeycode(key), SDL3ToTSEModifier(mods));
}
break;
}
}
void TSE::SDL3::Sdl3Input::MouseButtonCallback(int button, int action)
{
SDL_Keymod mods = SDL_GetModState();
switch (action)
{
case 1: //down
for(auto handler : ((Sdl3Input*)instance())->cursorHandler)
{
handler->OnMouseButtonDown(SDL3ToTSEMouseBtn(button), SDL3ToTSEModifier(mods));
}
break;
case 0: //up
for(auto handler : ((Sdl3Input*)instance())->cursorHandler)
{
handler->OnMouseButtonUp(SDL3ToTSEMouseBtn(button), SDL3ToTSEModifier(mods));
}
break;
case 2: //hold
for(auto handler : ((Sdl3Input*)instance())->cursorHandler)
{
handler->OnMouseButtonHold(SDL3ToTSEMouseBtn(button), SDL3ToTSEModifier(mods));
}
break;
}
}
void TSE::SDL3::Sdl3Input::CursorPosCallback(float xpos, float ypos)
{
for(auto handler : ((Sdl3Input*)instance())->cursorHandler)
{
handler->OnMousePosition(Vector2(xpos, ypos));
}
}
void TSE::SDL3::Sdl3Input::ScrollCallback(float xoffset, float yoffset)
{
for(auto handler : ((Sdl3Input*)instance())->cursorHandler)
{
handler->OnMouseScroll(Vector2(xoffset, yoffset));
}
}
void TSE::SDL3::Sdl3Input::CharCallback(std::string msg)
{
for(auto handler : ((Sdl3Input*)instance())->keyHandler)
{
handler->OnChar(msg);
}
}
TSE::Key TSE::SDL3::Sdl3Input::SDL3ToTSEKeycode(uint code)
{
switch (code)
{
case SDLK_SPACE: return Key::Space;
case SDLK_APOSTROPHE: return Key::Apostrophe;
case SDLK_COMMA: return Key::Comma;
case SDLK_MINUS: return Key::Minus;
case SDLK_PERIOD: return Key::Period;
case SDLK_SLASH: return Key::Slash;
case SDLK_0: return Key::Alpha0;
case SDLK_1: return Key::Alpha1;
case SDLK_2: return Key::Alpha2;
case SDLK_3: return Key::Alpha3;
case SDLK_4: return Key::Alpha4;
case SDLK_5: return Key::Alpha5;
case SDLK_6: return Key::Alpha6;
case SDLK_7: return Key::Alpha7;
case SDLK_8: return Key::Alpha8;
case SDLK_9: return Key::Alpha9;
case SDLK_SEMICOLON: return Key::SemiColon;
case SDLK_EQUALS: return Key::Equal;
case SDLK_A: return Key::A;
case SDLK_B: return Key::B;
case SDLK_C: return Key::C;
case SDLK_D: return Key::D;
case SDLK_E: return Key::E;
case SDLK_F: return Key::F;
case SDLK_G: return Key::G;
case SDLK_H: return Key::H;
case SDLK_I: return Key::I;
case SDLK_J: return Key::J;
case SDLK_K: return Key::K;
case SDLK_L: return Key::L;
case SDLK_M: return Key::M;
case SDLK_N: return Key::N;
case SDLK_O: return Key::O;
case SDLK_P: return Key::P;
case SDLK_Q: return Key::Q;
case SDLK_R: return Key::R;
case SDLK_S: return Key::S;
case SDLK_T: return Key::T;
case SDLK_U: return Key::U;
case SDLK_V: return Key::V;
case SDLK_W: return Key::W;
case SDLK_X: return Key::X;
case SDLK_Y: return Key::Y;
case SDLK_Z: return Key::Z;
case SDLK_LEFTBRACKET: return Key::LeftBracket;
case SDLK_BACKSLASH: return Key::Backslash;
case SDLK_RIGHTBRACKET: return Key::RightBracket;
case SDLK_GRAVE: return Key::GraveAccent;
case SDLK_ESCAPE: return Key::Escape;
case SDLK_RETURN: return Key::Enter;
case SDLK_TAB: return Key::Tab;
case SDLK_BACKSPACE: return Key::Backspace;
case SDLK_INSERT: return Key::Insert;
case SDLK_DELETE: return Key::Delete;
case SDLK_RIGHT: return Key::Right;
case SDLK_LEFT: return Key::Left;
case SDLK_DOWN: return Key::Down;
case SDLK_UP: return Key::Up;
case SDLK_PAGEUP: return Key::PageUp;
case SDLK_PAGEDOWN: return Key::PageDown;
case SDLK_HOME: return Key::Home;
case SDLK_END: return Key::End;
case SDLK_CAPSLOCK: return Key::CapsLock;
case SDLK_SCROLLLOCK: return Key::ScrollLock;
case SDLK_NUMLOCKCLEAR: return Key::NumLock;
case SDLK_PRINTSCREEN: return Key::PrintScreen;
case SDLK_PAUSE: return Key::Pause;
case SDLK_F1: return Key::F1;
case SDLK_F2: return Key::F2;
case SDLK_F3: return Key::F3;
case SDLK_F4: return Key::F4;
case SDLK_F5: return Key::F5;
case SDLK_F6: return Key::F6;
case SDLK_F7: return Key::F7;
case SDLK_F8: return Key::F8;
case SDLK_F9: return Key::F9;
case SDLK_F10: return Key::F10;
case SDLK_F11: return Key::F11;
case SDLK_F12: return Key::F12;
case SDLK_F13: return Key::F13;
case SDLK_F14: return Key::F14;
case SDLK_F15: return Key::F15;
case SDLK_F16: return Key::F16;
case SDLK_F17: return Key::F17;
case SDLK_F18: return Key::F18;
case SDLK_F19: return Key::F19;
case SDLK_F20: return Key::F20;
case SDLK_F21: return Key::F21;
case SDLK_F22: return Key::F22;
case SDLK_F23: return Key::F23;
case SDLK_F24: return Key::F24;
case SDLK_KP_0: return Key::Numpad0;
case SDLK_KP_1: return Key::Numpad1;
case SDLK_KP_2: return Key::Numpad2;
case SDLK_KP_3: return Key::Numpad3;
case SDLK_KP_4: return Key::Numpad4;
case SDLK_KP_5: return Key::Numpad5;
case SDLK_KP_6: return Key::Numpad6;
case SDLK_KP_7: return Key::Numpad7;
case SDLK_KP_8: return Key::Numpad8;
case SDLK_KP_9: return Key::Numpad9;
case SDLK_KP_PERIOD: return Key::NumpadDecimal;
case SDLK_KP_DIVIDE: return Key::NumpadDivide;
case SDLK_KP_MULTIPLY: return Key::NumpadMultiply;
case SDLK_KP_MINUS: return Key::NumpadSubtract;
case SDLK_KP_PLUS: return Key::NumpadAdd;
case SDLK_KP_ENTER: return Key::NumpadEnter;
case SDLK_KP_EQUALS: return Key::NumpadEqual;
case SDLK_LSHIFT: return Key::LeftShift;
case SDLK_LCTRL: return Key::LeftControl;
case SDLK_LALT: return Key::LeftAlt;
case SDLK_LGUI: return Key::LeftSuper;
case SDLK_RSHIFT: return Key::RightShift;
case SDLK_RCTRL: return Key::RightControl;
case SDLK_RALT: return Key::RightAlt;
case SDLK_RGUI: return Key::RightSuper;
case SDLK_MENU: return Key::Menu;
default: return Key::Unknown;
}
}
TSE::MouseBtn TSE::SDL3::Sdl3Input::SDL3ToTSEMouseBtn(int btn)
{
switch (btn)
{
case 1:
return Button1;
break;
case 2:
return Button3;
break;
case 3:
return Button2;
break;
case 4:
return Button4;
break;
case 5:
return Button5;
break;
default:
return Button8;
}
}
TSE::Modifier TSE::SDL3::Sdl3Input::SDL3ToTSEModifier(ushort mod)
{
int res = None;
if((mod & SDL_KMOD_LSHIFT) == SDL_KMOD_LSHIFT || (mod & SDL_KMOD_RSHIFT) == SDL_KMOD_RSHIFT) res = res | ShiftMod;
if((mod & SDL_KMOD_LCTRL) == SDL_KMOD_LCTRL || (mod & SDL_KMOD_RCTRL) == SDL_KMOD_RCTRL) res = res | ControlMod;
if((mod & SDL_KMOD_LALT) == SDL_KMOD_LALT || (mod & SDL_KMOD_RALT) == SDL_KMOD_RALT) res = res | AltMod;
if((mod & SDL_KMOD_LGUI) == SDL_KMOD_LGUI || (mod & SDL_KMOD_RGUI) == SDL_KMOD_RGUI) res = res | SuperMod;
if((mod & SDL_KMOD_NUM) == SDL_KMOD_NUM) res = res | NumLockMod;
if((mod & SDL_KMOD_CAPS) == SDL_KMOD_CAPS) res = res | CapsLockMod;
return (Modifier)res;
}

View File

@@ -0,0 +1,24 @@
#pragma once
#include "interfaces/IInputManager.hpp"
namespace TSE::SDL3
{
class Sdl3Input : public IInputManager
{
public:
static void Init();
void Delete() override;
static void KeyCallback(uint key, int action, ushort mods);
static void MouseButtonCallback(int button, int action);
static void CursorPosCallback(float xpos, float ypos);
static void ScrollCallback(float xoffset, float yoffset);
static void CharCallback(std::string msg);
private:
static Key SDL3ToTSEKeycode(uint code);
static MouseBtn SDL3ToTSEMouseBtn(int btn);
static Modifier SDL3ToTSEModifier(ushort mod);
};
} // namespace TSE::SDL3

View File

@@ -0,0 +1,42 @@
#include "Sdl3Poller.hpp"
#include "Sdl3Input.hpp"
void TSE::SDL3::Sdl3Poller::PollEvent(SDL_Event &event)
{
switch (event.type)
{
case SDL_EVENT_KEY_DOWN:
{
int action = 1;
if(event.key.repeat)
{
action = 2;
}
Sdl3Input::KeyCallback(event.key.key, action, event.key.mod);
break;
}
case SDL_EVENT_KEY_UP:
Sdl3Input::KeyCallback(event.key.key, 0, event.key.mod);
break;
case SDL_EVENT_MOUSE_BUTTON_DOWN:
Sdl3Input::MouseButtonCallback(event.button.button, 1);
break;
case SDL_EVENT_MOUSE_BUTTON_UP:
Sdl3Input::MouseButtonCallback(event.button.button, 0);
break;
case SDL_EVENT_MOUSE_MOTION:
Sdl3Input::CursorPosCallback(event.motion.x, event.motion.y);
break;
case SDL_EVENT_MOUSE_WHEEL:
Sdl3Input::ScrollCallback(event.wheel.x, event.wheel.y);
break;
case SDL_EVENT_TEXT_INPUT: // SDL_StartTextInput() must be called fist, before it takes text.
Sdl3Input::CharCallback(event.text.text);
break;
}
}
void TSE::SDL3::Sdl3Poller::Init()
{
Sdl3Input::Init();
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include "SDL3/SDL.h"
namespace TSE::SDL3
{
class Sdl3Poller
{
public:
static void PollEvent(SDL_Event& event);
static void Init();
};
} // namespace TSE::SDL3

View File

@@ -0,0 +1,7 @@
#include "TimeInterfaceSdl3.hpp"
#include "SDL3/SDL.h"
float TSE::SDL3::TimeInterfaceSdl3::GetTotalEllapsedTime()
{
return SDL_GetTicks() / 1000.0f;
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include "interfaces/ITimeInterface.hpp"
namespace TSE::SDL3
{
class TimeInterfaceSdl3 : public ITimeInterface
{
public:
float GetTotalEllapsedTime() override;
};
} // namespace TSE::SDL3

View File

@@ -0,0 +1,3 @@
#pragma once
#define TSE_SDL3

View File

@@ -0,0 +1,162 @@
#include "WindowSdl3.hpp"
#include "utils/Time.hpp"
#include "TimeInterfaceSdl3.hpp"
#include "Debug.hpp"
#include "extern/imgui_impl_sdl3.h"
#include "Sdl3Poller.hpp"
TSE::SDL3::WindowSdl3::WindowSdl3(string _title, int _width, int _height, IRenderingBackend *backend)
: WindowSdl3(_title, _width, _height, backend, WindowType::Windowed, 32){ }
TSE::SDL3::WindowSdl3::WindowSdl3(string _title, int _width, int _height, IRenderingBackend *backend, TSE::WindowType type)
: WindowSdl3(_title, _width, _height, backend, type, 32){ }
TSE::SDL3::WindowSdl3::WindowSdl3(string _title, int _width, int _height, IRenderingBackend *backend, TSE::WindowType type, int ppu)
{
width = _width;
height = _height;
title = _title;
windowType = type;
renderingBackend = backend;
renderingBackend->window = this;
IWindow::lastWindow = this;
if(!Init())
{
SDL_Quit();
running = false;
}
}
TSE::SDL3::WindowSdl3::~WindowSdl3()
{
SDL_GL_DestroyContext(context);
SDL_DestroyWindow(window);
SDL_Quit();
}
bool TSE::SDL3::WindowSdl3::Init()
{
if(!BaseInit() || !SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD))
{
Debug::Log("SDL3 Error");
return false;
}
TSE::SDL3::Sdl3Poller::Init();
Time::Init(new TimeInterfaceSdl3());
renderingBackend->InitPreWindow();
SDL_WindowFlags flags = SDL_WINDOW_MOUSE_FOCUS | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_RESIZABLE;
window = NULL;
if(windowType == WindowType::Maximized)
{
window = SDL_CreateWindow(title.c_str(), width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_MAXIMIZED | flags);
}
else if(windowType == WindowType::Fullscreen)
{
window = SDL_CreateWindow(title.c_str(), width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN | flags);
}
else if(windowType == WindowType::FullscreenWindowed)
{
window = SDL_CreateWindow(title.c_str(), width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS | flags);
}
else
{
window = SDL_CreateWindow(title.c_str(), width, height, SDL_WINDOW_OPENGL | flags);
}
if(!window)
{
Debug::Log("Failed to create window. Maybe try another WindowType.");
return false;
}
if(!renderingBackend->InitPostWindow())
{
return false;
}
Debug::Log("SDL:" + std::to_string(SDL_VERSION));
if(!renderingBackend->InitEnd())
{
return false;
}
return true;
}
void TSE::SDL3::WindowSdl3::ResizeWindow(int w, int h)
{
width = w;
height = h;
renderingBackend->onResize(width, height);
for (auto const& i : objectsToResize)
{
i->OnResize(width, height, this);
}
}
void TSE::SDL3::WindowSdl3::Clear() const
{
renderingBackend->onClear();
}
void TSE::SDL3::WindowSdl3::Update()
{
BaseUpdate();
PollEvents();
renderingBackend->onUpdate();
}
void TSE::SDL3::WindowSdl3::ClearDepthBuffer() const
{
renderingBackend->onClearDepthBuffer();
}
bool TSE::SDL3::WindowSdl3::ShouldClose() const
{
return !running;
}
void TSE::SDL3::WindowSdl3::DoneSetup()
{
renderingBackend->onResize(width, height);
for (auto const& i : objectsToResize)
{
i->OnResize(width, height, this);
}
}
void TSE::SDL3::WindowSdl3::PollEvents()
{
SDL_Event event;
while (SDL_PollEvent(&event)) {
if(useImGui)
{
ImGui_ImplSDL3_ProcessEvent(&event);
}
TSE::SDL3::Sdl3Poller::PollEvent(event);
switch (event.type)
{
case SDL_EVENT_QUIT:
running = false;
break;
case SDL_EVENT_WINDOW_RESIZED:
ResizeWindow(event.window.data1, event.window.data2);
break;
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
ResizeWindow(event.window.data1, event.window.data2);
break;
default:
break;
}
}
}

View File

@@ -0,0 +1,43 @@
#pragma once
#include "SDL3/SDL.h"
#include "Types.hpp"
#include "interfaces/IWindow.hpp"
#include "interfaces/IRenderingBackend.hpp"
#include "enums/WindowType.hpp"
#include "Color.hpp"
namespace TSE::SDL3
{
class WindowSdl3 : public IWindow
{
private:
IRenderingBackend* renderingBackend;
bool running = true;
public:
WindowType windowType;
bool useImGui = false;
SDL_Window* window;
SDL_GLContext context;
WindowSdl3(string _title, int _width, int _height, IRenderingBackend* backend);
WindowSdl3(string _title, int _width, int _height, IRenderingBackend* backend, TSE::WindowType type);
WindowSdl3(string _title, int _width, int _height, IRenderingBackend* backend, TSE::WindowType type, int ppu);
~WindowSdl3();
protected:
bool Init() override;
void ResizeWindow(int width, int height);
public:
void Clear() const override;
void Update() override;
void ClearDepthBuffer() const override;
bool ShouldClose() const override;
inline void Bind() override { };
inline void Unbind() override { };
void DoneSetup() override;
void PollEvents();
};
} // namespace TSE::SDL3

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,50 @@
// dear imgui: Platform Backend for SDL3
// This needs to be used along with a Renderer (e.g. SDL_GPU, DirectX11, OpenGL3, Vulkan..)
// (Info: SDL3 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
// Implemented features:
// [X] Platform: Clipboard support.
// [X] Platform: Mouse support. Can discriminate Mouse/TouchScreen.
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy SDL_SCANCODE_* values are obsolete since 1.87 and not supported since 1.91.5]
// [X] Platform: Gamepad support.
// [X] Platform: Mouse cursor shape and visibility (ImGuiBackendFlags_HasMouseCursors). Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [x] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable' -> the OS animation effect when window gets created/destroyed is problematic. SDL2 backend doesn't have issue.
// Missing features or Issues:
// [ ] Platform: Multi-viewport: Minimized windows seems to break mouse wheel events (at least under Windows).
// [x] Platform: IME support. Position somehow broken in SDL3 + app needs to call 'SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");' before SDL_CreateWindow()!.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ https://dearimgui.com/faq
// - Getting Started https://dearimgui.com/getting-started
// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp
#pragma once
#include "imgui/imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
struct SDL_Window;
struct SDL_Renderer;
struct SDL_Gamepad;
typedef union SDL_Event SDL_Event;
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForVulkan(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForD3D(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForMetal(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer);
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForSDLGPU(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForOther(SDL_Window* window);
IMGUI_IMPL_API void ImGui_ImplSDL3_Shutdown();
IMGUI_IMPL_API void ImGui_ImplSDL3_NewFrame();
IMGUI_IMPL_API bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event);
// Gamepad selection automatically starts in AutoFirst mode, picking first available SDL_Gamepad. You may override this.
// When using manual mode, caller is responsible for opening/closing gamepad.
enum ImGui_ImplSDL3_GamepadMode { ImGui_ImplSDL3_GamepadMode_AutoFirst, ImGui_ImplSDL3_GamepadMode_AutoAll, ImGui_ImplSDL3_GamepadMode_Manual };
IMGUI_IMPL_API void ImGui_ImplSDL3_SetGamepadMode(ImGui_ImplSDL3_GamepadMode mode, SDL_Gamepad** manual_gamepads_array = nullptr, int manual_gamepads_count = -1);
#endif // #ifndef IMGUI_DISABLE