#include #include #include #include #include namespace psemek::sdl2 { window::window(psemek::app::application::options const & options) : sdl_init_(init(SDL_INIT_EVENTS | SDL_INIT_VIDEO)) { 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); } std::uint32_t flags = SDL_WINDOW_OPENGL | SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE; if (options.highdpi) flags |= SDL_WINDOW_ALLOW_HIGHDPI; 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: "); gl_context_ = SDL_GL_CreateContext(window_); if (!gl_context_) sdl2::fail("Failed to create OpenGL context: "); SDL_GL_MakeCurrent(window_, gl_context_); } geom::vector window::size() const { geom::vector 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 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 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 (gl_context_) SDL_GL_DeleteContext(gl_context_); if (window_) SDL_DestroyWindow(window_); } }