Skip to content

Commit

Permalink
Merge pull request #2669 from ivan-mogilko/362--selectmonitor
Browse files Browse the repository at this point in the history
Implement initial display selection
  • Loading branch information
ivan-mogilko authored Jan 29, 2025
2 parents 7a28299 + 5536174 commit fae882d
Show file tree
Hide file tree
Showing 30 changed files with 368 additions and 173 deletions.
1 change: 1 addition & 0 deletions Common/core/platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@
AGS_PLATFORM_OS_MACOS)
#define AGS_PLATFORM_MOBILE ((AGS_PLATFORM_OS_ANDROID) || (AGS_PLATFORM_OS_IOS))

#define AGS_SUPPORT_MULTIDISPLAY (AGS_PLATFORM_DESKTOP)
#define AGS_HAS_DIRECT3D (AGS_PLATFORM_OS_WINDOWS)
#define AGS_HAS_OPENGL (AGS_PLATFORM_OS_WINDOWS || \
AGS_PLATFORM_OS_ANDROID || \
Expand Down
13 changes: 9 additions & 4 deletions Engine/gfx/ali3dogl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,11 @@ bool OGLGraphicsDriver::InitGlScreen(const DisplayMode &mode)
}
else
{
#if (AGS_SUPPORT_MULTIDISPLAY)
sys_window_fit_in_display(mode.DisplayIndex);
#endif
sys_window_set_style(mode.Mode, Size(mode.Width, mode.Height));
sys_window_bring_to_front();
}

SDL_GL_GetDrawableSize(_sdlWindow, &device_screen_physical_width, &device_screen_physical_height);
Expand Down Expand Up @@ -302,7 +306,7 @@ bool OGLGraphicsDriver::CreateWindowAndGlContext(const DisplayMode &mode)
if (SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1) != 0)
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "Error occured setting attribute SDL_GL_DOUBLEBUFFER: %s", SDL_GetError());

SDL_Window *sdl_window = sys_window_create("", mode.Width, mode.Height, mode.Mode, SDL_WINDOW_OPENGL);
SDL_Window *sdl_window = sys_window_create("", mode.DisplayIndex, mode.Width, mode.Height, mode.Mode, SDL_WINDOW_OPENGL);
if (!sdl_window)
{
Debug::Printf(kDbgMsg_Error, "Error opening window for OpenGL: %s", SDL_GetError());
Expand Down Expand Up @@ -760,6 +764,7 @@ bool OGLGraphicsDriver::SetDisplayMode(const DisplayMode &mode)
// On certain platforms OpenGL renderer ignores requested screen sizes
// and uses values imposed by the operating system (device).
DisplayMode final_mode = mode;
final_mode.DisplayIndex = sys_get_window_display_index();
final_mode.Width = device_screen_physical_width;
final_mode.Height = device_screen_physical_height;
OnModeSet(final_mode);
Expand Down Expand Up @@ -805,14 +810,14 @@ int OGLGraphicsDriver::GetDisplayDepthForNativeDepth(int /*native_color_depth*/)
return 32;
}

IGfxModeList *OGLGraphicsDriver::GetSupportedModeList(int color_depth)
IGfxModeList *OGLGraphicsDriver::GetSupportedModeList(int display_index, int color_depth)
{
std::vector<DisplayMode> modes {};
sys_get_desktop_modes(modes, color_depth);
sys_get_desktop_modes(display_index, modes, color_depth);
if ((modes.size() == 0) && color_depth == 32)
{
// Pretend that 24-bit are 32-bit
sys_get_desktop_modes(modes, 24);
sys_get_desktop_modes(display_index, modes, 24);
for (auto &m : modes) { m.ColorDepth = 32; }
}
return new OGLDisplayModeList(modes);
Expand Down
2 changes: 1 addition & 1 deletion Engine/gfx/ali3dogl.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ class OGLGraphicsDriver : public VideoMemoryGraphicsDriver
bool SetNativeResolution(const GraphicResolution &native_res) override;
bool SetRenderFrame(const Rect &dst_rect) override;
int GetDisplayDepthForNativeDepth(int native_color_depth) const override;
IGfxModeList *GetSupportedModeList(int color_depth) override;
IGfxModeList *GetSupportedModeList(int display_index, int color_depth) override;
bool IsModeSupported(const DisplayMode &mode) override;
PGfxFilter GetGraphicsFilter() const override;
void UnInit();
Expand Down
41 changes: 35 additions & 6 deletions Engine/gfx/ali3dsw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@
//=============================================================================
#include "gfx/ali3dsw.h"
#include <algorithm>
#include <array>
#include <stack>
#include "ac/sys_events.h"
#include "gfx/ali3dexception.h"
#include "gfx/gfxfilter_sdl_renderer.h"
#include "gfx/gfx_util.h"
#include "platform/base/agsplatformdriver.h"
#include "platform/base/sys_main.h"
#include "ac/timer.h"
#include "util/string_compat.h"


namespace AGS
{
Expand Down Expand Up @@ -79,14 +81,14 @@ int SDLRendererGraphicsDriver::GetDisplayDepthForNativeDepth(int /*native_color_
return 32;
}

IGfxModeList *SDLRendererGraphicsDriver::GetSupportedModeList(int color_depth)
IGfxModeList *SDLRendererGraphicsDriver::GetSupportedModeList(int display_index, int color_depth)
{
std::vector<DisplayMode> modes;
sys_get_desktop_modes(modes, color_depth);
sys_get_desktop_modes(display_index, modes, color_depth);
if ((modes.size() == 0) && color_depth == 32)
{
// Pretend that 24-bit are 32-bit
sys_get_desktop_modes(modes, 24);
sys_get_desktop_modes(display_index, modes, 24);
for (auto &m : modes) { m.ColorDepth = 32; }
}
return new SDLRendererGfxModeList(modes);
Expand Down Expand Up @@ -130,7 +132,7 @@ bool SDLRendererGraphicsDriver::SetDisplayMode(const DisplayMode &mode)
SDL_Window *window = sys_get_window();
if (!window)
{
window = sys_window_create("", mode.Width, mode.Height, mode.Mode);
window = sys_window_create("", mode.DisplayIndex, mode.Width, mode.Height, mode.Mode);

_hasGamma = SDL_GetWindowGammaRamp(window, _defaultGammaRed, _defaultGammaGreen, _defaultGammaBlue) == 0;

Expand All @@ -154,21 +156,48 @@ bool SDLRendererGraphicsDriver::SetDisplayMode(const DisplayMode &mode)
if (!_capsVsync)
Debug::Printf(kDbgMsg_Warn, "WARNING: Vertical sync is not supported. Setting will be kept at driver default.");
}

// Record if SDL have created a DirectX renderer - we use this info for some checks
const std::array<const char *, 3> directx_renderers = { { "direct3d", "direct3d11", "direct3d12" } };
for (const char *name : directx_renderers)
{
if (ags_stricmp(rinfo.name, name) == 0)
{
_isDirectX = true;
break;
}
}
} else {
Debug::Printf("SDLRenderer: failed to query renderer info: %s", SDL_GetError());
}
}
else
{
#if (AGS_SUPPORT_MULTIDISPLAY)
// This is a bit of a hack, but certain drivers do not support changing
// display in exclusive fullscreen mode, and here we find out if it's the case.
// NOTE: we may in theory support this, but we'd have to release and recreate
// ALL the resources, including all textures currently in memory.
if (_isDirectX && mode.IsRealFullscreen() &&
(_fullscreenDisplay > 0) && (sys_get_window_display_index() != _fullscreenDisplay))
{
sys_window_fit_in_display(_fullscreenDisplay);
}
#endif // AGS_SUPPORT_MULTIDISPLAY
sys_window_set_style(mode.Mode, Size(mode.Width, mode.Height));
sys_window_bring_to_front();
}

#if AGS_PLATFORM_MOBILE
SDL_RenderSetLogicalSize(_renderer,mode.Width,mode.Height);
#endif

OnInit();
OnModeSet(mode);
DisplayMode set_mode = mode;
set_mode.DisplayIndex = sys_get_window_display_index();
if ((_fullscreenDisplay < 0) || set_mode.IsRealFullscreen())
_fullscreenDisplay = set_mode.DisplayIndex;
OnModeSet(set_mode);
return true;
}

Expand Down
4 changes: 3 additions & 1 deletion Engine/gfx/ali3dsw.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ class SDLRendererGraphicsDriver : public GraphicsDriverBase
bool SetRenderFrame(const Rect &dst_rect) override;
bool IsModeSupported(const DisplayMode &mode) override;
int GetDisplayDepthForNativeDepth(int native_color_depth) const override;
IGfxModeList *GetSupportedModeList(int color_depth) override;
IGfxModeList *GetSupportedModeList(int display_index, int color_depth) override;
PGfxFilter GetGraphicsFilter() const override;
void UnInit();
// Clears the screen rectangle. The coordinates are expected in the **native game resolution**.
Expand Down Expand Up @@ -240,6 +240,8 @@ class SDLRendererGraphicsDriver : public GraphicsDriverBase

SDL_Renderer *_renderer = nullptr;
SDL_Texture *_screenTex = nullptr;
bool _isDirectX = false; // records if created DirectX based renderer
int _fullscreenDisplay = -1; // a display where exclusive fullscreen was created
// BITMAP struct for wrapping screen texture locked pixels, so that we may use blit()
BITMAP *_fakeTexBitmap = nullptr;
unsigned char *_lastTexPixels = nullptr;
Expand Down
7 changes: 5 additions & 2 deletions Engine/gfx/gfxdefines.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ enum WindowMode
struct DisplayMode : public GraphicResolution
{
WindowMode Mode = kWnd_Windowed;
int32_t RefreshRate = 0;
int DisplayIndex = 0; // 0-based display index
int RefreshRate = 0;
bool Vsync = false;

// Tells if this is logically a normal windowed mode
Expand All @@ -59,9 +60,11 @@ struct DisplayMode : public GraphicResolution
inline bool IsRealFullscreen() const { return Mode == kWnd_Fullscreen; }

DisplayMode() = default;
DisplayMode(const GraphicResolution &res, WindowMode mode = kWnd_Windowed, int32_t refresh = 0, bool vsync = false)
DisplayMode(const GraphicResolution &res, WindowMode mode = kWnd_Windowed,
int display_index = 0, int32_t refresh = 0, bool vsync = false)
: GraphicResolution(res)
, Mode(mode)
, DisplayIndex(display_index)
, RefreshRate(refresh)
, Vsync(vsync)
{}
Expand Down
2 changes: 1 addition & 1 deletion Engine/gfx/graphicsdriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ class IGraphicsDriver
virtual bool IsRenderFrameValid() const = 0;
// Report which color depth options are best suited for the given native color depth
virtual int GetDisplayDepthForNativeDepth(int native_color_depth) const = 0;
virtual IGfxModeList *GetSupportedModeList(int color_depth) = 0;
virtual IGfxModeList *GetSupportedModeList(int display_index, int color_depth) = 0;
virtual bool IsModeSupported(const DisplayMode &mode) = 0;
virtual DisplayMode GetDisplayMode() const = 0;
virtual PGfxFilter GetGraphicsFilter() const = 0;
Expand Down
30 changes: 16 additions & 14 deletions Engine/main/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ extern SpriteCache spriteset;
const String DefaultConfigFileName = "acsetup.cfg";


WindowSetup parse_window_mode(const String &option, bool as_windowed,
const Size &game_res, const Size &desktop_res, const WindowSetup &def_value)
WindowSetup parse_window_mode(const String &option, bool as_windowed, const WindowSetup &def_value)
{
// "full_window" option means pseudo fullscreen ("borderless fullscreen window")
if (!as_windowed && (option.CompareNoCase("full_window") == 0))
Expand All @@ -57,10 +56,10 @@ WindowSetup parse_window_mode(const String &option, bool as_windowed,
// Note that for "desktop" we return "default" for windowed, this will result
// in refering to the desktop size but resizing in accordance to the scaling style
if (option.CompareNoCase("desktop") == 0)
return as_windowed ? WindowSetup(exp_wmode) : WindowSetup(kWndSizeHint_Desktop, desktop_res, exp_wmode);
return as_windowed ? WindowSetup(exp_wmode) : WindowSetup(kWndSizeHint_Desktop, Size(), exp_wmode);
// "Native" means using game resolution as a window size
if (option.CompareNoCase("native") == 0)
return WindowSetup(kWndSizeHint_GameNative, game_res, exp_wmode);
return WindowSetup(kWndSizeHint_GameNative, Size(), exp_wmode);
// Try parse an explicit resolution type or game scale factor --
size_t at = option.FindChar('x');
if (at == 0)
Expand Down Expand Up @@ -164,7 +163,7 @@ void parse_asset_dirs(const String &option, std::vector<std::pair<String, String
}
}

String make_window_mode_option(const WindowSetup &ws, const Size &game_res, const Size &desktop_res)
String make_window_mode_option(const WindowSetup &ws)
{
if (ws.Mode == kWnd_FullDesktop)
return "full_window";
Expand Down Expand Up @@ -354,21 +353,24 @@ void override_config_ext(ConfigTree &cfg)
platform->ReadConfiguration(cfg);
}

void load_common_config(const ConfigTree &cfg, GameConfig &setup, const Size &desktop_res)
void load_common_config(const ConfigTree &cfg, GameConfig &setup)
{
// Legacy settings have to be translated into new options;
// they must be read first, to let newer options override them, if ones are present
read_legacy_config(cfg, setup);

// Graphics mode and options
setup.Display.DriverID = CfgReadString(cfg, "graphics", "driver", setup.Display.DriverID);
const int user_display_index = CfgReadInt(cfg, "graphics", "display", 0);
setup.Display.UseDefaultDisplay = user_display_index <= 0;
setup.Display.DisplayIndex = user_display_index <= 0 ? 0 : user_display_index - 1;
setup.Display.Windowed = CfgReadBoolInt(cfg, "graphics", "windowed", setup.Display.Windowed);
setup.Display.FsSetup =
parse_window_mode(CfgReadString(cfg, "graphics", "fullscreen", "default"), false,
game.GetGameRes(), desktop_res, setup.Display.FsSetup);
setup.Display.FsSetup);
setup.Display.WinSetup =
parse_window_mode(CfgReadString(cfg, "graphics", "window", "default"), true,
game.GetGameRes(), desktop_res, setup.Display.WinSetup);
setup.Display.WinSetup);

setup.Display.Filter.ID = CfgReadString(cfg, "graphics", "filter", "StdScale");
setup.Display.FsGameFrame =
Expand Down Expand Up @@ -431,9 +433,7 @@ void load_common_config(const ConfigTree &cfg, GameConfig &setup, const Size &de

void apply_config(const ConfigTree &cfg, GameSetup &setup)
{
const Size &desktop_res = get_desktop_size();

load_common_config(cfg, setup, desktop_res);
load_common_config(cfg, setup);

//
// Additional config applied by the engine
Expand Down Expand Up @@ -479,15 +479,17 @@ void post_config(GameSetup &setup)
}
}

void save_common_config(const GameConfig &setup, ConfigTree &cfg, const Size &game_res, const Size &desktop_res)
void save_common_config(const GameConfig &setup, ConfigTree &cfg)
{
CfgWriteString(cfg, "misc", "user_data_dir", setup.UserSaveDir);
CfgWriteString(cfg, "misc", "shared_data_dir", setup.AppDataDir);

CfgWriteString(cfg, "graphics", "driver", setup.Display.DriverID);
CfgWriteInt(cfg, "graphics", "display", (setup.Display.UseDefaultDisplay) ?
0 : setup.Display.DisplayIndex + 1);
CfgWriteString(cfg, "graphics", "filter", setup.Display.Filter.ID);
CfgWriteString(cfg, "graphics", "fullscreen", make_window_mode_option(setup.Display.FsSetup, game_res, desktop_res));
CfgWriteString(cfg, "graphics", "window", make_window_mode_option(setup.Display.WinSetup, game_res, desktop_res));
CfgWriteString(cfg, "graphics", "fullscreen", make_window_mode_option(setup.Display.FsSetup));
CfgWriteString(cfg, "graphics", "window", make_window_mode_option(setup.Display.WinSetup));
CfgWriteString(cfg, "graphics", "game_scale_fs", make_scaling_option(setup.Display.FsGameFrame));
CfgWriteString(cfg, "graphics", "game_scale_win", make_scaling_option(setup.Display.WinGameFrame));
CfgWriteInt(cfg, "graphics", "windowed", setup.Display.Windowed ? 1 : 0);
Expand Down
9 changes: 4 additions & 5 deletions Engine/main/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,18 @@ void apply_config(const ConfigTree &cfg, GameSetup &setup);
void post_config(GameSetup &setup);

// Load common configuration from the config tree into GameConfig struct
void load_common_config(const ConfigTree &cfg, GameConfig &setup, const Size &desktop_res);
void load_common_config(const ConfigTree &cfg, GameConfig &setup);
// Saves common configuration from GameConfig struct to the config tree
void save_common_config(const GameConfig &setup, ConfigTree &cfg, const Size &game_res, const Size &desktop_res);
void save_common_config(const GameConfig &setup, ConfigTree &cfg);

// Saves minimal runtime config using current engine state
void save_runtime_config_file();

WindowSetup parse_window_mode(const String &option, bool as_windowed,
const Size &game_res, const Size &desktop_res, const WindowSetup &def_value = WindowSetup());
WindowSetup parse_window_mode(const String &option, bool as_windowed, const WindowSetup &def_value = WindowSetup());
FrameScaleDef parse_scaling_option(const String &option, FrameScaleDef def_value = kFrame_Undefined);
SkipSpeechStyle parse_speechskip_style(const String &option, SkipSpeechStyle def_value = kSkipSpeechNone);
void parse_asset_dirs(const String &option, std::vector<std::pair<String, String>> &opt_dirs);
String make_window_mode_option(const WindowSetup &ws, const Size &game_res, const Size &desktop_res);
String make_window_mode_option(const WindowSetup &ws);
String make_scaling_option(FrameScaleDef scale_def);
String make_speechskip_option(SkipSpeechStyle style);
uint32_t convert_scaling_to_fp(int scale_factor);
Expand Down
9 changes: 5 additions & 4 deletions Engine/main/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1340,7 +1340,7 @@ bool engine_try_set_gfxmode_any(const DisplayModeSetup &setup)

sys_renderer_set_output(usetup.SoftwareRenderDriver);

const Size init_desktop = get_desktop_size();
const Size init_desktop = get_desktop_size(setup.DisplayIndex);
bool res = graphics_mode_init_any(GraphicResolution(game.GetGameRes(), game.color_depth * 8),
setup, ColorDepthOption(game.GetColorDepth()));

Expand All @@ -1363,7 +1363,7 @@ bool engine_try_switch_windowed_gfxmode()
// Release engine resources that depend on display mode
engine_pre_gfxmode_release();

Size init_desktop = get_desktop_size();
Size init_desktop = get_desktop_size(old_dm.DisplayIndex);
bool windowed = !old_dm.IsWindowed();
ActiveDisplaySetting setting = graphics_mode_get_last_setting(windowed);
DisplayMode last_opposite_mode = setting.Dm;
Expand All @@ -1376,7 +1376,8 @@ bool engine_try_switch_windowed_gfxmode()
// *and* if the window is on the same display where it's been last time,
// then use old params, otherwise - get default setup for the new mode.
bool res;
if (last_opposite_mode.IsValid() && (setting.DisplayIndex == sys_get_window_display_index()))
const int use_display_index = sys_get_window_display_index();
if (last_opposite_mode.IsValid() && (setting.Dm.DisplayIndex == use_display_index))
{
res = graphics_mode_set_dm(last_opposite_mode);
}
Expand All @@ -1385,7 +1386,7 @@ bool engine_try_switch_windowed_gfxmode()
WindowSetup ws = windowed ? usetup.Display.WinSetup : usetup.Display.FsSetup;
frame = windowed ? usetup.Display.WinGameFrame : usetup.Display.FsGameFrame;
res = graphics_mode_set_dm_any(game.GetGameRes(), ws, old_dm.ColorDepth,
frame, DisplaySetupEx(usetup.Display.RefreshRate, usetup.Display.VSync));
frame, DisplayParamsEx(use_display_index, usetup.Display.RefreshRate, usetup.Display.VSync));
}

// Apply corresponding frame render method
Expand Down
2 changes: 1 addition & 1 deletion Engine/main/engine_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ void engine_post_gfxmode_mouse_setup(const Size &init_desktop)
if (usetup.MouseSpeedDef == kMouseSpeed_CurrentDisplay)
{
Size cur_desktop;
if (sys_get_desktop_resolution(cur_desktop.Width, cur_desktop.Height) == 0)
if (sys_get_desktop_resolution(cur_desktop.Width, cur_desktop.Height))
Mouse::SetSpeedUnit(std::max((float)cur_desktop.Width / (float)init_desktop.Width,
(float)cur_desktop.Height / (float)init_desktop.Height));
}
Expand Down
Loading

0 comments on commit fae882d

Please sign in to comment.