Files
MacroLibX/runtime/Sources/Core/SDLManager.cpp
2026-03-23 21:45:36 +01:00

305 lines
9.4 KiB
C++

#include <PreCompiled.h>
#include <Core/SDLManager.h>
#include <Core/Memory.h>
#include <Embedded/IconMlx.h>
#include <Utils/Bits.h>
namespace mlx
{
namespace Internal
{
struct WindowInfos
{
SDL_Window* window;
SDL_Surface* icon;
};
}
SDLManager* SDLManager::s_instance = nullptr;
SDLManager::SDLManager()
{
MLX_PROFILE_FUNCTION();
s_instance = this;
m_drop_sdl_responsability = SDL_WasInit(SDL_INIT_VIDEO) || std::getenv("MLX_HEADLESS_MODE") != nullptr;
if(m_drop_sdl_responsability) // is case the mlx is running in a sandbox like MacroUnitTester where SDL is already init
return;
//SDL_SetMemoryFunctions(MemManager::Get().Malloc, MemManager::Get().Calloc, MemManager::Get().Realloc, MemManager::Get().Free);
#ifdef FORCE_WAYLAND
SDL_SetHint(SDL_HINT_VIDEODRIVER, "wayland,x11");
#endif
//SDL_SetHintWithPriority(SDL_HINT_SHUTDOWN_DBUS_ON_QUIT, "1", SDL_HINT_OVERRIDE);
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_TIMER) != 0)
FatalError("SDL: unable to init all subsystems; %", SDL_GetError());
DebugLog("SDL Manager initialized");
}
Handle SDLManager::CreateWindow(const mlx_window_create_info* info, std::int32_t& id, bool hidden)
{
Internal::WindowInfos* infos = new Internal::WindowInfos;
Verify(infos != nullptr, "SDL: window allocation failed");
std::uint32_t flags = 0;
if(hidden)
flags |= SDL_WINDOW_HIDDEN;
else
flags |= SDL_WINDOW_SHOWN;
if(info->is_resizable)
flags |= SDL_WINDOW_RESIZABLE;
if(info->is_fullscreen)
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
infos->window = SDL_CreateWindow(info->title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, info->width, info->height, flags);
if(!infos->window)
FatalError("SDL: unable to open a new window; %", SDL_GetError());
infos->icon = SDL_CreateRGBSurfaceFrom(static_cast<void*>(logo_mlx), logo_mlx_width, logo_mlx_height, 32, 4 * logo_mlx_width, Rmask(), Gmask(), Bmask(), Amask());
SDL_SetWindowIcon(infos->window, infos->icon);
m_windows_registry.insert(infos);
id = SDL_GetWindowID(infos->window);
return infos;
}
void SDLManager::DestroyWindow(Handle window) noexcept
{
Verify(m_windows_registry.find(window) != m_windows_registry.end(), "SDL: cannot destroy window; unknown window pointer");
Internal::WindowInfos* infos = static_cast<Internal::WindowInfos*>(window);
if(infos->window != nullptr)
SDL_DestroyWindow(infos->window);
if(infos->icon != nullptr)
SDL_FreeSurface(infos->icon);
m_windows_registry.erase(infos);
delete infos;
}
SDL_Window* SDLManager::GetRawWindow(Handle window) noexcept
{
Internal::WindowInfos* infos = static_cast<Internal::WindowInfos*>(window);
return infos->window;
}
VkSurfaceKHR SDLManager::CreateVulkanSurface(Handle window, VkInstance instance) const noexcept
{
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if(SDL_GetWindowWMInfo(static_cast<Internal::WindowInfos*>(window)->window, &info) != SDL_TRUE)
FatalError("SDL Manager: cannot retrieve window informations");
switch(info.subsystem)
{
#ifdef SDL_VIDEO_DRIVER_WINDOWS
case SDL_SYSWM_WINDOWS: return kvfCreateSurfaceKHR(instance, KVF_SURFACE_WINDOWS, static_cast<void*>(info.info.win.hinstance), static_cast<void*>(info.info.win.window));
#endif
#ifdef SDL_VIDEO_DRIVER_X11
case SDL_SYSWM_X11: return kvfCreateSurfaceKHR(instance, KVF_SURFACE_XLIB, static_cast<void*>(info.info.x11.display), static_cast<void*>(&info.info.x11.window));
#endif
#ifdef SDL_VIDEO_DRIVER_COCOA
case SDL_SYSWM_COCOA: FatalError("SDL Manager: Vulkan surfaces over Metal are not supported yet. Please fill an issue here https://github.com/seekrs/MacroLibX/issues/new");
#endif
#ifdef SDL_VIDEO_DRIVER_WAYLAND
case SDL_SYSWM_WAYLAND: return kvfCreateSurfaceKHR(instance, KVF_SURFACE_WAYLAND, static_cast<void*>(info.info.wl.display), static_cast<void*>(info.info.wl.surface));
#endif
#ifdef SDL_VIDEO_DRIVER_ANDROID
case SDL_SYSWM_ANDROID: return kvfCreateSurfaceKHR(instance, KVF_SURFACE_ANDROID, nullptr, static_cast<void*>(info.info.android.window));
#endif
default : FatalError("SDL Manager: unsupported windowing system"); break;
}
return VK_NULL_HANDLE;
}
Vec2ui SDLManager::GetVulkanDrawableSize(Handle window) const noexcept
{
Vec2i extent;
SDL_GetWindowSizeInPixels(static_cast<Internal::WindowInfos*>(window)->window, &extent.x, &extent.y);
return Vec2ui{ extent };
}
void SDLManager::MoveMouseOnWindow(Handle window, int x, int y) const noexcept
{
SDL_WarpMouseInWindow(static_cast<Internal::WindowInfos*>(window)->window, x, y);
SDL_PumpEvents();
}
void SDLManager::GetScreenSizeWindowIsOn(Handle window, int* x, int* y) const noexcept
{
SDL_DisplayMode DM;
SDL_GetDesktopDisplayMode(SDL_GetWindowDisplayIndex(static_cast<Internal::WindowInfos*>(window)->window), &DM);
*x = DM.w;
*y = DM.h;
}
void SDLManager::SetWindowPosition(Handle window, int x, int y) const noexcept
{
SDL_SetWindowPosition(static_cast<Internal::WindowInfos*>(window)->window, x, y);
}
void SDLManager::SetWindowSize(Handle window, int x, int y) const noexcept
{
SDL_SetWindowSize(static_cast<Internal::WindowInfos*>(window)->window, x, y);
}
void SDLManager::SetWindowTitle(Handle window, std::string_view title) const noexcept
{
SDL_SetWindowTitle(static_cast<Internal::WindowInfos*>(window)->window, title.data());
}
void SDLManager::SetWindowFullscreen(Handle window, bool enable) const noexcept
{
SDL_SetWindowFullscreen(static_cast<Internal::WindowInfos*>(window)->window, (enable ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0));
}
void SDLManager::SetWindowMaxSize(Handle window, int x, int y) const noexcept
{
SDL_SetWindowMaximumSize(static_cast<Internal::WindowInfos*>(window)->window, x, y);
}
void SDLManager::SetWindowMinSize(Handle window, int x, int y) const noexcept
{
SDL_SetWindowMinimumSize(static_cast<Internal::WindowInfos*>(window)->window, x, y);
}
void SDLManager::MaximizeWindow(Handle window) const noexcept
{
SDL_MaximizeWindow(static_cast<Internal::WindowInfos*>(window)->window);
}
void SDLManager::MinimizeWindow(Handle window) const noexcept
{
SDL_MinimizeWindow(static_cast<Internal::WindowInfos*>(window)->window);
}
void SDLManager::RestoreWindow(Handle window) const noexcept
{
SDL_RestoreWindow(static_cast<Internal::WindowInfos*>(window)->window);
}
void SDLManager::GetWindowPosition(Handle window, int* x, int* y) const noexcept
{
SDL_GetWindowPosition(static_cast<Internal::WindowInfos*>(window)->window, x, y);
}
void SDLManager::GetWindowSize(Handle window, int* x, int* y) const noexcept
{
SDL_GetWindowSize(static_cast<Internal::WindowInfos*>(window)->window, x, y);
}
void SDLManager::HideCursor() noexcept
{
SDL_ShowCursor(SDL_DISABLE);
}
void SDLManager::ShowCursor() noexcept
{
SDL_ShowCursor(SDL_ENABLE);
}
std::int32_t SDLManager::GetX() const noexcept
{
int dummy;
int x;
SDL_GetMouseState(&x, &dummy);
return x;
}
std::int32_t SDLManager::GetY() const noexcept
{
int dummy;
int y;
SDL_GetMouseState(&dummy, &y);
return y;
}
std::int32_t SDLManager::GetXRel() const noexcept
{
int dummy;
int x;
SDL_GetRelativeMouseState(&x, &dummy);
return x;
}
std::int32_t SDLManager::GetYRel() const noexcept
{
int dummy;
int y;
SDL_GetRelativeMouseState(&dummy, &y);
return y;
}
void SDLManager::SetInputBinding(std::function<void(SDL_Event*)> functor)
{
m_binding_hook = std::move(functor);
}
void SDLManager::InputsFetcher(std::function<void(mlx_event_type, int, int)> functor)
{
SDL_Event event;
while(SDL_PollEvent(&event))
{
std::uint32_t id = event.window.windowID;
switch(event.type)
{
case SDL_KEYUP: functor(MLX_KEYUP, id, event.key.keysym.scancode); break;
case SDL_KEYDOWN: functor(MLX_KEYDOWN, id, event.key.keysym.scancode); break;
case SDL_MOUSEBUTTONUP: functor(MLX_MOUSEUP, id, event.button.button); break;
case SDL_MOUSEBUTTONDOWN: functor(MLX_MOUSEDOWN, id, event.button.button); break;
case SDL_MOUSEWHEEL:
{
if(event.wheel.y > 0) // scroll up
functor(MLX_MOUSEWHEEL, id, 1);
else if(event.wheel.y < 0) // scroll down
functor(MLX_MOUSEWHEEL, id, 2);
if(event.wheel.x > 0) // scroll right
functor(MLX_MOUSEWHEEL, id, 3);
else if(event.wheel.x < 0) // scroll left
functor(MLX_MOUSEWHEEL, id, 4);
break;
}
case SDL_WINDOWEVENT:
{
switch(event.window.event)
{
case SDL_WINDOWEVENT_CLOSE: functor(MLX_WINDOW_EVENT, id, 0); break;
case SDL_WINDOWEVENT_MOVED: functor(MLX_WINDOW_EVENT, id, 1); break;
case SDL_WINDOWEVENT_MINIMIZED: functor(MLX_WINDOW_EVENT, id, 2); break;
case SDL_WINDOWEVENT_MAXIMIZED: functor(MLX_WINDOW_EVENT, id, 3); break;
case SDL_WINDOWEVENT_ENTER: functor(MLX_WINDOW_EVENT, id, 4); break;
case SDL_WINDOWEVENT_FOCUS_GAINED: functor(MLX_WINDOW_EVENT, id, 5); break;
case SDL_WINDOWEVENT_LEAVE: functor(MLX_WINDOW_EVENT, id, 6); break;
case SDL_WINDOWEVENT_FOCUS_LOST: functor(MLX_WINDOW_EVENT, id, 7); break;
case SDL_WINDOWEVENT_SIZE_CHANGED: functor(MLX_WINDOW_EVENT, id, 8); break;
case SDL_WINDOWEVENT_RESTORED: functor(MLX_WINDOW_EVENT, id, 11); break;
default : break;
}
break;
}
default: break;
}
if(m_binding_hook)
m_binding_hook(&event);
}
}
SDLManager::~SDLManager()
{
if(m_drop_sdl_responsability)
return;
SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS);
SDL_Quit();
s_instance = nullptr;
DebugLog("SDL Manager uninitialized");
}
}