198 lines
6.1 KiB
C++
198 lines
6.1 KiB
C++
#include <psemek/sdl2/window.hpp>
|
|
#include <psemek/sdl2/init.hpp>
|
|
#include <psemek/geom/box.hpp>
|
|
#include <psemek/log/log.hpp>
|
|
|
|
#if defined(PSEMEK_SDL2_OPENGL)
|
|
#include <psemek/gfx/gl.hpp>
|
|
#elif defined(PSEMEK_SDL2_WEBGPU)
|
|
#include <psemek/wgpu/instance.hpp>
|
|
#endif
|
|
|
|
#include <SDL2/SDL_syswm.h>
|
|
|
|
namespace psemek::sdl2
|
|
{
|
|
|
|
window::window(psemek::app::application::options const & options)
|
|
: sdl_init_(init(SDL_INIT_EVENTS | SDL_INIT_VIDEO))
|
|
{
|
|
std::uint32_t flags = SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE;
|
|
if (options.highdpi) flags |= SDL_WINDOW_ALLOW_HIGHDPI;
|
|
|
|
#if defined(PSEMEK_SDL2_OPENGL)
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, gl::sys::major_version());
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, gl::sys::minor_version());
|
|
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
|
|
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
|
|
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
|
|
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
|
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
|
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
|
|
|
|
if (options.multisampling == 0)
|
|
{
|
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0);
|
|
}
|
|
else
|
|
{
|
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
|
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, options.multisampling);
|
|
}
|
|
|
|
flags |= SDL_WINDOW_OPENGL;
|
|
#endif
|
|
|
|
SDL_DisplayMode display_mode;
|
|
SDL_GetCurrentDisplayMode(0, &display_mode);
|
|
|
|
window_ = SDL_CreateWindow(options.name.data(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, display_mode.w, display_mode.h, flags);
|
|
if (!window_)
|
|
sdl2::fail("Failed to create window: ");
|
|
|
|
#if defined(PSEMEK_SDL2_OPENGL)
|
|
gl_context_ = SDL_GL_CreateContext(window_);
|
|
if (!gl_context_)
|
|
sdl2::fail("Failed to create OpenGL context: ");
|
|
|
|
SDL_GL_MakeCurrent(window_, gl_context_);
|
|
|
|
gfx::init();
|
|
#elif defined(PSEMEK_SDL2_WEBGPU)
|
|
auto instance = wgpu::instance::create({});
|
|
|
|
SDL_SysWMinfo wminfo;
|
|
SDL_VERSION(&wminfo.version);
|
|
SDL_GetWindowWMInfo(window_, &wminfo);
|
|
|
|
wgpu::surface::descriptor surface_descriptor;
|
|
#if defined(_WIN32)
|
|
surface_descriptor.chain = {wgpu::surface::from_windows_hwnd{ .hinstance = wminfo.info.win.hinstance, .hwnd = wminfo.info.win.window }};
|
|
#else
|
|
surface_descriptor.chain = {wgpu::surface::from_xlib_window{ .display = wminfo.info.x11.display, .window = wminfo.info.x11.window }};
|
|
#endif
|
|
wgpu_surface_ = instance.create_surface(surface_descriptor);
|
|
|
|
wgpu::adapter::request_options adapter_request_options;
|
|
adapter_request_options.compatible_surface = wgpu_surface_;
|
|
#if defined(_WIN32)
|
|
adapter_request_options.backend_type = wgpu::backend_type::d3d12;
|
|
#else
|
|
adapter_request_options.backend_type = wgpu::backend_type::vulkan;
|
|
#endif
|
|
|
|
instance.request_adapter(adapter_request_options, [this](wgpu::adapter::request_status status, wgpu::adapter adapter_in, std::string const & message)
|
|
{
|
|
if (status != wgpu::adapter::request_status::success)
|
|
throw std::runtime_error("Failed to request WebGPU adapter: " + message);
|
|
|
|
wgpu_adapter_ = std::move(adapter_in);
|
|
});
|
|
|
|
wgpu::device::descriptor device_descriptor
|
|
{
|
|
.required_features = options.required_features,
|
|
.required_limits = options.required_limits ? std::optional(wgpu::device::required_limits{.limits = *options.required_limits}) : std::nullopt,
|
|
};
|
|
|
|
wgpu_adapter_.request_device(device_descriptor, [this](wgpu::device::request_status status, wgpu::device device_in, std::string const & message)
|
|
{
|
|
if (status != wgpu::device::request_status::success)
|
|
throw std::runtime_error("Failed to request WebGPU device: " + message);
|
|
wgpu_device_ = std::move(device_in);
|
|
});
|
|
|
|
auto adapter_properties = wgpu_adapter_.get_properties();
|
|
log::info() << "Initialized WebGPU: " << adapter_properties.name;
|
|
#endif
|
|
}
|
|
|
|
geom::vector<int, 2> window::size() const
|
|
{
|
|
geom::vector<int, 2> result;
|
|
SDL_GL_GetDrawableSize(window_, &result[0], &result[1]);
|
|
return result;
|
|
}
|
|
|
|
void window::show()
|
|
{
|
|
SDL_ShowWindow(window_);
|
|
}
|
|
|
|
void window::swap()
|
|
{
|
|
SDL_GL_SwapWindow(window_);
|
|
}
|
|
|
|
void window::show_cursor(bool show)
|
|
{
|
|
log::info() << (show ? "Cursor shown" : "Cursor hidden");
|
|
SDL_ShowCursor(show ? SDL_TRUE : SDL_FALSE);
|
|
SDL_SetRelativeMouseMode(show ? SDL_FALSE : SDL_TRUE);
|
|
}
|
|
|
|
void window::vsync(bool on)
|
|
{
|
|
log::info() << "Turning VSync " << (on ? "on" : "off");
|
|
if (on)
|
|
{
|
|
// try adaptive vsync
|
|
if (SDL_GL_SetSwapInterval(-1) != 0)
|
|
{
|
|
// failed, try usual vsync then
|
|
SDL_GL_SetSwapInterval(1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SDL_GL_SetSwapInterval(0);
|
|
}
|
|
}
|
|
|
|
void window::windowed(bool on)
|
|
{
|
|
log::info() << "Entering " << (on ? "windowed" : "fullscreen") << " mode";
|
|
|
|
SDL_SetWindowFullscreen(window_, on ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP);
|
|
SDL_SetWindowBordered(window_, on ? SDL_TRUE : SDL_FALSE);
|
|
SDL_RestoreWindow(window_);
|
|
if (on)
|
|
{
|
|
SDL_Rect display_usable_bounds;
|
|
SDL_GetDisplayUsableBounds(0, &display_usable_bounds);
|
|
|
|
int top_border, left_border, bottom_border, right_border;
|
|
SDL_GetWindowBordersSize(window_, &top_border, &left_border, &bottom_border, &right_border);
|
|
|
|
geom::box<int, 2> bounds_rect;
|
|
bounds_rect[0] = {display_usable_bounds.x, display_usable_bounds.x + display_usable_bounds.w};
|
|
bounds_rect[1] = {display_usable_bounds.y, display_usable_bounds.y + display_usable_bounds.h};
|
|
|
|
log::info() << "Display usable bounds: " << bounds_rect;
|
|
log::info() << "Window borders: left " << left_border << ", right " << right_border << ", top " << top_border << ", bottom " << bottom_border;
|
|
|
|
geom::box<int, 2> window_rect = bounds_rect;
|
|
window_rect[0].min += left_border;
|
|
window_rect[0].max -= right_border;
|
|
window_rect[1].min += top_border;
|
|
window_rect[1].max -= bottom_border;
|
|
|
|
log::info() << "Computed window rect: " << window_rect;
|
|
|
|
SDL_SetWindowSize(window_, window_rect.dimensions()[0], window_rect.dimensions()[1]);
|
|
SDL_SetWindowPosition(window_, window_rect[0].min, window_rect[1].min);
|
|
}
|
|
}
|
|
|
|
window::~window()
|
|
{
|
|
#if defined(PSEMEK_SDL2_OPENGL)
|
|
if (gl_context_)
|
|
SDL_GL_DeleteContext(gl_context_);
|
|
#endif
|
|
if (window_)
|
|
SDL_DestroyWindow(window_);
|
|
}
|
|
|
|
}
|