diff --git a/port/fast3d/gfx_api.h b/port/fast3d/gfx_api.h index 3bf8427ad..271e8abb6 100644 --- a/port/fast3d/gfx_api.h +++ b/port/fast3d/gfx_api.h @@ -20,6 +20,12 @@ struct GfxDimensions { float aspect_ratio; }; +struct GfxInitSettings { + struct GfxWindowManagerAPI *wapi; + struct GfxRenderingAPI *rapi; + struct GfxWindowInitSettings window_settings; +}; + extern struct GfxDimensions gfx_current_window_dimensions; // The dimensions of the window extern struct GfxDimensions gfx_current_dimensions; // The dimensions of the draw area the game draws to, before scaling (if applicable) @@ -30,9 +36,7 @@ extern struct XYWidthHeight gfx_current_native_viewport; // The internal/native extern float gfx_current_native_aspect; // The aspect ratio of the above mode extern bool gfx_framebuffers_enabled; -void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAPI* rapi, const char* game_name, - bool start_in_fullscreen, bool start_maximized, uint32_t width, uint32_t height, - uint32_t posX, uint32_t posY); +void gfx_init(const struct GfxInitSettings *settings); void gfx_destroy(void); struct GfxRenderingAPI* gfx_get_current_rendering_api(void); void gfx_start_frame(void); diff --git a/port/fast3d/gfx_pc.cpp b/port/fast3d/gfx_pc.cpp index fe989e085..a9fd646a0 100644 --- a/port/fast3d/gfx_pc.cpp +++ b/port/fast3d/gfx_pc.cpp @@ -2520,16 +2520,15 @@ extern "C" void gfx_get_dimensions(uint32_t* width, uint32_t* height, int32_t* p gfx_wapi->get_dimensions(width, height, posX, posY); } -extern "C" void gfx_init(struct GfxWindowManagerAPI* wapi, struct GfxRenderingAPI* rapi, const char* game_name, - bool start_in_fullscreen, bool start_maximized, uint32_t width, uint32_t height, uint32_t posX, uint32_t posY) { - gfx_wapi = wapi; - gfx_rapi = rapi; - gfx_wapi->init(game_name, rapi->get_name(), start_in_fullscreen, start_maximized, width, height, posX, posY); +extern "C" void gfx_init(const GfxInitSettings *settings) { + gfx_wapi = settings->wapi; + gfx_rapi = settings->rapi; + gfx_wapi->init(&settings->window_settings); gfx_rapi->init(); - gfx_rapi->update_framebuffer_parameters(0, width, height, 1, false, true, true, true); + gfx_rapi->update_framebuffer_parameters(0, settings->window_settings.width, settings->window_settings.height, 1, false, true, true, true); gfx_current_dimensions.internal_mul = 1; - gfx_current_game_window_viewport.width = gfx_current_dimensions.width = width; - gfx_current_game_window_viewport.height = gfx_current_dimensions.height = height; + gfx_current_game_window_viewport.width = gfx_current_dimensions.width = settings->window_settings.width; + gfx_current_game_window_viewport.height = gfx_current_dimensions.height = settings->window_settings.height; game_framebuffer = gfx_rapi->create_framebuffer(); game_framebuffer_msaa_resolved = gfx_rapi->create_framebuffer(); diff --git a/port/fast3d/gfx_sdl2.cpp b/port/fast3d/gfx_sdl2.cpp index bd6e4def7..181038d26 100644 --- a/port/fast3d/gfx_sdl2.cpp +++ b/port/fast3d/gfx_sdl2.cpp @@ -17,6 +17,7 @@ static bool vsync_enabled = true; // OTRTODO: These are redundant. Info can be queried from SDL. static int window_width = DESIRED_SCREEN_WIDTH; static int window_height = DESIRED_SCREEN_HEIGHT; +static uint32_t fullscreen_flag = SDL_WINDOW_FULLSCREEN_DESKTOP; static bool fullscreen_state; static bool maximized_state; static bool is_running = true; @@ -34,7 +35,7 @@ static void set_fullscreen(bool on, bool call_callback) { return; } fullscreen_state = on; - SDL_SetWindowFullscreen(wnd, on ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); + SDL_SetWindowFullscreen(wnd, on ? fullscreen_flag : 0); if (call_callback && on_fullscreen_changed_callback) { on_fullscreen_changed_callback(on); } @@ -60,10 +61,20 @@ static void gfx_sdl_get_active_window_refresh_rate(uint32_t* refresh_rate) { *refresh_rate = mode.refresh_rate; } -static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool start_in_fullscreen, bool start_maximized, uint32_t width, - uint32_t height, int32_t posX, int32_t posY) { - window_width = width; - window_height = height; +static void gfx_sdl_init(const struct GfxWindowInitSettings *set) { + window_width = set->width; + window_height = set->height; + +#ifdef SDL_HINT_VIDEO_HIGHDPI_DISABLED + if (!set->allow_hidpi) { + // HiDPI control, if available + SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1"); +#if defined(PLATFORM_WIN32) && defined(SDL_HINT_WINDOWS_DPI_AWARENESS) + // if HiDPI is disabled, declare ourselves DPI aware to get 1:1 window size on Windows + SDL_SetHint(SDL_HINT_WINDOWS_DPI_AWARENESS, "permonitor"); +#endif + } +#endif if (SDL_Init(SDL_INIT_VIDEO) != 0) { sysFatalError("Could not init SDL:\n%s", SDL_GetError()); @@ -77,18 +88,38 @@ static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool s SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG); } - char title[512]; - snprintf(title, sizeof(title), "%s (%s)", game_name, gfx_api_name); - + int posX = set->x; + int posY = set->y; int display_in_use = SDL_GetWindowDisplayIndex(wnd); if (display_in_use < 0) { // Fallback to default if out of bounds posX = 100; posY = 100; } - const Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_OPENGL; + if (set->fullscreen_is_exclusive) { + fullscreen_flag = SDL_WINDOW_FULLSCREEN; + } - wnd = SDL_CreateWindow(title, posX, posY, window_width, window_height, flags); + Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL; + + // if fullscreen was requested, start the window in fullscreen right away + if (set->fullscreen) { + flags |= fullscreen_flag; + fullscreen_state = true; + } + + if (set->maximized) { + flags |= SDL_WINDOW_MAXIMIZED; + maximized_state = true; + } + +#ifdef SDL_WINDOW_ALLOW_HIGHDPI + if (set->allow_hidpi) { + flags |= SDL_WINDOW_ALLOW_HIGHDPI; + } +#endif + + wnd = SDL_CreateWindow(set->title, posX, posY, window_width, window_height, flags); if (!wnd) { sysFatalError("Could not open SDL window:\n%s", SDL_GetError()); } @@ -143,9 +174,6 @@ static void gfx_sdl_init(const char* game_name, const char* gfx_api_name, bool s SDL_GL_SetSwapInterval(1); qpc_freq = SDL_GetPerformanceFrequency(); - - set_maximize_window(start_maximized); - set_fullscreen(start_in_fullscreen, false); } static void gfx_sdl_close(void) { @@ -160,6 +188,18 @@ static void gfx_sdl_set_fullscreen(bool enable) { set_fullscreen(enable, true); } +static void gfx_sdl_set_fullscreen_exclusive(bool enable) { + const uint32_t newflag = enable ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_FULLSCREEN_DESKTOP; + if (fullscreen_flag != newflag) { + fullscreen_flag = newflag; + // reset fullscreen to take new value into account if it already is in fullscreen + if (fullscreen_state) { + fullscreen_state = false; + set_fullscreen(enable, true); + } + } +} + static void gfx_sdl_set_maximize_window(bool enable) { set_maximize_window(enable); } @@ -284,6 +324,7 @@ struct GfxWindowManagerAPI gfx_sdl = { gfx_sdl_close, gfx_sdl_set_fullscreen_changed_callback, gfx_sdl_set_fullscreen, + gfx_sdl_set_fullscreen_exclusive, gfx_sdl_set_maximize_window, gfx_sdl_get_active_window_refresh_rate, gfx_sdl_set_cursor_visibility, diff --git a/port/fast3d/gfx_window_manager_api.h b/port/fast3d/gfx_window_manager_api.h index 44eda4160..61b05315f 100644 --- a/port/fast3d/gfx_window_manager_api.h +++ b/port/fast3d/gfx_window_manager_api.h @@ -4,12 +4,24 @@ #include #include +struct GfxWindowInitSettings { + const char *title; + uint32_t width; + uint32_t height; + int32_t x; + int32_t y; + bool fullscreen; + bool fullscreen_is_exclusive; + bool maximized; + bool allow_hidpi; +}; + struct GfxWindowManagerAPI { - void (*init)(const char* game_name, const char* gfx_api_name, bool start_in_fullscreen, bool start_maximized, uint32_t width, - uint32_t height, int32_t posX, int32_t posY); + void (*init)(const struct GfxWindowInitSettings *settings); void (*close)(void); void (*set_fullscreen_changed_callback)(void (*on_fullscreen_changed)(bool is_now_fullscreen)); void (*set_fullscreen)(bool enable); + void (*set_fullscreen_exclusive)(bool exc); void (*set_maximize)(bool enable); void (*get_active_window_refresh_rate)(uint32_t* refresh_rate); void (*set_cursor_visibility)(bool visible); diff --git a/port/src/video.c b/port/src/video.c index 4e9244234..3d8bb08fb 100644 --- a/port/src/video.c +++ b/port/src/video.c @@ -21,7 +21,9 @@ static s32 vidWidth = 640; static s32 vidHeight = 480; static s32 vidFramebuffers = true; static s32 vidFullscreen = false; +static s32 vidFullscreenExclusive = false; static s32 vidMaximize = false; +static s32 vidAllowHiDpi = false; static s32 vidVsync = 1; static s32 vidMSAA = 1; static s32 vidFramerateLimit = 0; @@ -45,7 +47,23 @@ s32 videoInit(void) gfx_framebuffers_enabled = (bool)vidFramebuffers; gfx_msaa_level = vidMSAA; - gfx_init(wmAPI, renderingAPI, "PD", vidFullscreen, vidMaximize, vidWidth, vidHeight, 100, 100); + struct GfxInitSettings set = { + .wapi = wmAPI, + .rapi = renderingAPI, + .window_settings = { + .title = "Perfect Dark", + .width = vidWidth, + .height = vidHeight, + .x = 100, + .y = 100, + .fullscreen = vidFullscreen, + .fullscreen_is_exclusive = vidFullscreenExclusive, + .maximized = vidMaximize, + .allow_hidpi = vidAllowHiDpi + } + }; + + gfx_init(&set); if (!wmAPI->set_swap_interval(vidVsync)) { vidVsync = 0; @@ -257,6 +275,8 @@ PD_CONSTRUCTOR static void videoConfigInit(void) configRegisterInt("Video.DefaultMaximize", &vidMaximize, 0, 1); configRegisterInt("Video.DefaultWidth", &vidWidth, 0, 32767); configRegisterInt("Video.DefaultHeight", &vidHeight, 0, 32767); + configRegisterInt("Video.ExclusiveFullscreen", &vidFullscreenExclusive, 0, 1); + configRegisterInt("Video.AllowHiDpi", &vidAllowHiDpi, 0, 1); configRegisterInt("Video.VSync", &vidVsync, -1, 10); configRegisterInt("Video.FramebufferEffects", &vidFramebuffers, 0, 1); configRegisterInt("Video.FramerateLimit", &vidFramerateLimit, 0, VIDEO_MAX_FPS);