From d6c32cd49bc76c3fb280568daf9b2be36f66ab72 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Thu, 3 Jan 2013 05:50:51 +0100 Subject: [PATCH] Support resizing windows + improve fullscreen for SDL2 By implementing GLimp_SetScreenParms() and enhancing the event handling --- neo/renderer/RenderSystem_init.cpp | 6 + neo/sys/sdl/sdl_events.cpp | 45 +++++++- neo/sys/sdl/sdl_glimp.cpp | 174 ++++++++++++++++++++++++++++- 3 files changed, 218 insertions(+), 7 deletions(-) diff --git a/neo/renderer/RenderSystem_init.cpp b/neo/renderer/RenderSystem_init.cpp index c10b83e1..66dfcefc 100644 --- a/neo/renderer/RenderSystem_init.cpp +++ b/neo/renderer/RenderSystem_init.cpp @@ -53,7 +53,13 @@ idCVar r_skipIntelWorkarounds( "r_skipIntelWorkarounds", "0", CVAR_RENDERER | CV idCVar r_multiSamples( "r_multiSamples", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "number of antialiasing samples" ); idCVar r_vidMode( "r_vidMode", "0", CVAR_ARCHIVE | CVAR_RENDERER | CVAR_INTEGER, "fullscreen video mode number" ); idCVar r_displayRefresh( "r_displayRefresh", "0", CVAR_RENDERER | CVAR_INTEGER | CVAR_NOCHEAT, "optional display refresh rate option for vid mode", 0.0f, 240.0f ); +#ifdef WIN32 idCVar r_fullscreen( "r_fullscreen", "1", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "0 = windowed, 1 = full screen on monitor 1, 2 = full screen on monitor 2, etc" ); +#else +// DG: add mode -2 for SDL, also defaulting to windowed mode, as that causes less trouble on linux +idCVar r_fullscreen( "r_fullscreen", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "-2 = use current monitor, -1 = (reserved), 0 = windowed, 1 = full screen on monitor 1, 2 = full screen on monitor 2, etc" ); +// DG end +#endif idCVar r_customWidth( "r_customWidth", "1280", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "custom screen width. set r_vidMode to -1 to activate" ); idCVar r_customHeight( "r_customHeight", "720", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "custom screen height. set r_vidMode to -1 to activate" ); idCVar r_windowX( "r_windowX", "0", CVAR_RENDERER | CVAR_ARCHIVE | CVAR_INTEGER, "Non-fullscreen parameter" ); diff --git a/neo/sys/sdl/sdl_events.cpp b/neo/sys/sdl/sdl_events.cpp index 7fd4c890..b7988c6a 100644 --- a/neo/sys/sdl/sdl_events.cpp +++ b/neo/sys/sdl/sdl_events.cpp @@ -5,6 +5,7 @@ Doom 3 GPL Source Code Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. Copyright (C) 2012 dhewg (dhewm3) Copyright (C) 2012 Robert Beckebans +Copyright (C) 2013 Daniel Gibson This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). @@ -28,9 +29,10 @@ If you have questions concerning this license or the applicable additional terms =========================================================================== */ +#include "../../idlib/precompiled.h" + #include -#include "../../idlib/precompiled.h" #include "renderer/tr_local.h" #include "sdl_local.h" #include "../posix/posix_public.h" @@ -58,6 +60,13 @@ If you have questions concerning this license or the applicable additional terms // DG end #endif +// DG: those are needed for moving/resizing windows +extern idCVar r_windowX; +extern idCVar r_windowY; +extern idCVar r_windowWidth; +extern idCVar r_windowHeight; +// DG end + const char* kbdNames[] = { "english", "french", "german", "italian", "spanish", "turkish", "norwegian", NULL @@ -742,7 +751,28 @@ sysEvent_t Sys_GetEvent() GLimp_GrabInput( 0 ); break; - // TODO: SDL_WINDOWEVENT_RESIZED + // DG: handle resizing and moving of window + case SDL_WINDOWEVENT_RESIZED: + { + int w = ev.window.data1; + int h = ev.window.data2; + r_windowWidth.SetInteger( w ); + r_windowHeight.SetInteger( h ); + + glConfig.nativeScreenWidth = w; + glConfig.nativeScreenHeight = h; + break; + } + + case SDL_WINDOWEVENT_MOVED: + { + int x = ev.window.data1; + int y = ev.window.data2; + r_windowX.SetInteger( x ); + r_windowY.SetInteger( y ); + break; + } + // DG end } return res_none; @@ -777,7 +807,16 @@ sysEvent_t Sys_GetEvent() case SDL_KEYDOWN: if( ev.key.keysym.sym == SDLK_RETURN && ( ev.key.keysym.mod & KMOD_ALT ) > 0 ) { - cvarSystem->SetCVarBool( "r_fullscreen", !renderSystem->IsFullScreen() ); + // DG: go to fullscreen on current display, instead of always first display + int fullscreen = 0; + if( ! renderSystem->IsFullScreen() ) + { + // this will be handled as "fullscreen on current window" + // r_fullscreen 1 means "fullscreen on first window" in d3 bfg + fullscreen = -2; + } + cvarSystem->SetCVarInteger( "r_fullscreen", fullscreen ); + // DG end PushConsoleEvent( "vid_restart" ); return res_none; } diff --git a/neo/sys/sdl/sdl_glimp.cpp b/neo/sys/sdl/sdl_glimp.cpp index 556112c0..fc1022d2 100644 --- a/neo/sys/sdl/sdl_glimp.cpp +++ b/neo/sys/sdl/sdl_glimp.cpp @@ -5,6 +5,7 @@ Doom 3 GPL Source Code Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. Copyright (C) 2012 dhewg (dhewm3) Copyright (C) 2012 Robert Beckebans +Copyright (C) 2013 Daniel Gibson This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). @@ -89,7 +90,9 @@ bool GLimp_Init( glimpParms_t parms ) GLimp_PreInit(); // DG: make sure SDL is initialized - Uint32 flags = SDL_WINDOW_OPENGL; + // DG: make window resizable + Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; + // DG end if( parms.fullScreen ) flags |= SDL_WINDOW_FULLSCREEN; @@ -198,10 +201,34 @@ bool GLimp_Init( glimpParms_t parms ) } // RB end + // DG: set display num for fullscreen + int windowPos = SDL_WINDOWPOS_UNDEFINED; + if( parms.fullScreen > 0 ) + { + if( parms.fullScreen > SDL_GetNumVideoDisplays() ) + { + common->Warning( "Couldn't set display to num %i because we only have %i displays", + parms.fullScreen, SDL_GetNumVideoDisplays() ); + } + else + { + // -1 because SDL starts counting displays at 0, while parms.fullScreen starts at 1 + windowPos = SDL_WINDOWPOS_UNDEFINED_DISPLAY( ( parms.fullScreen - 1 ) ); + } + } + // TODO: if parms.fullScreen == -1 there should be a borderless window spanning multiple displays + /* + * NOTE that this implicitly handles parms.fullScreen == -2 (from r_fullscreen -2) meaning + * "do fullscreen, but I don't care on what monitor", at least on my box it's the monitor with + * the mouse cursor. + */ + + window = SDL_CreateWindow( GAME_NAME, - SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, + windowPos, + windowPos, parms.width, parms.height, flags ); + // DG end context = SDL_GL_CreateContext( window ); if( !window ) @@ -273,6 +300,113 @@ bool GLimp_Init( glimpParms_t parms ) return true; } +/* +=================== + Helper functions for GLimp_SetScreenParms() +=================== +*/ + +#if SDL_VERSION_ATLEAST(2, 0, 0) +// SDL1 doesn't support multiple displays +// makes sure the window will be full-screened on the right display and returns the SDL display index +static int ScreenParmsHandleDisplayIndex( glimpParms_t parms ) +{ + int displayIdx; + if( parms.fullScreen > 0 ) + { + displayIdx = parms.fullScreen - 1; // first display for SDL is 0, in parms it's 1 + } + else // -2 == use current display + { + displayIdx = SDL_GetWindowDisplay( window ); + if( displayIdx < 0 ) // for some reason the display for the window couldn't be detected + displayIdx = 0; + } + + if( parms.fullScreen > SDL_GetNumVideoDisplays() ) + { + common->Warning( "Can't set fullscreen mode to display number %i, because SDL2 only knows about %i displays!", + parms.fullScreen, SDL_GetNumVideoDisplays() ); + return -1; + } + + if( parms.fullScreen != glConfig.isFullscreen ) + { + // we have to switch to another display + if( glConfig.isFullscreen ) + { + // if we're already in fullscreen mode but want to switch to another monitor + // we have to go to windowed mode first to move the window.. SDL-oddity. + SDL_SetWindowFullscreen( window, SDL_FALSE ); + } + // select display ; SDL_WINDOWPOS_UNDEFINED_DISPLAY() doesn't work. + int x = SDL_WINDOWPOS_CENTERED_DISPLAY( displayIdx ); + // move window to the center of selected display + SDL_SetWindowPosition( window, x, x ); + } + return displayIdx; +} +#endif // SDL_VERSION_ATLEAST(2, 0, 0) + +static bool SetScreenParmsFullscreen( glimpParms_t parms ) +{ +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_DisplayMode m = {0}; + int displayIdx = ScreenParmsHandleDisplayIndex( parms ); + if( displayIdx < 0 ) + return false; + + // get current mode of display the window should be full-screened on + SDL_GetCurrentDisplayMode( displayIdx, &m ); + + // change settings in that display mode according to parms + // FIXME: check if refreshrate, width and height are supported? + // m.refresh_rate = parms.displayHz; + m.w = parms.width; + m.h = parms.height; + + // set that displaymode + if( SDL_SetWindowDisplayMode( window, &m ) < 0 ) + { + common->Warning( "Couldn't set window mode for fullscreen, reason: %s", SDL_GetError() ); + return false; + } + + // if we're currently not in fullscreen mode, we need to switch to fullscreen + if( !( SDL_GetWindowFlags( window ) & SDL_WINDOW_FULLSCREEN ) ) + { + if( SDL_SetWindowFullscreen( window, SDL_TRUE ) < 0 ) + { + common->Warning( "Couldn't switch to fullscreen mode, reason: %s!", SDL_GetError() ); + return false; + } + } +#else // ! SDL_VERSION_ATLEAST(2, 0, 0) => SDL1.2 + // TODO: SDL1.2 fullscreen handling +#endif // SDL_VERSION_ATLEAST(2, 0, 0) + return true; +} + +static bool SetScreenParmsWindowed( glimpParms_t parms ) +{ +#if SDL_VERSION_ATLEAST(2, 0, 0) + SDL_SetWindowSize( window, parms.width, parms.height ); + SDL_SetWindowPosition( window, parms.x, parms.y ); + + // if we're currently in fullscreen mode, we need to disable that + if( SDL_GetWindowFlags( window ) & SDL_WINDOW_FULLSCREEN ) + { + if( SDL_SetWindowFullscreen( window, SDL_FALSE ) < 0 ) + { + common->Warning( "Couldn't switch to windowed mode, reason: %s!", SDL_GetError() ); + return false; + } + } +#else // SDL 1.2 + // TODO: SDL1.2 windowed handling +#endif + return true; +} /* =================== @@ -281,7 +415,39 @@ GLimp_SetScreenParms */ bool GLimp_SetScreenParms( glimpParms_t parms ) { - common->DPrintf( "TODO: GLimp_SetScreenParms\n" ); +#if SDL_VERSION_ATLEAST(2, 0, 0) + if( parms.fullScreen > 0 || parms.fullScreen == -2 ) + { + if( !SetScreenParmsFullscreen( parms ) ) + return false; + } + else if( parms.fullScreen == 0 ) // windowed mode + { + if( !SetScreenParmsWindowed( parms ) ) + return false; + } + else + { + common->Warning( "GLimp_SetScreenParms: fullScreen -1 (borderless window for multiple displays) currently unsupported!" ); + return false; + } + + // Note: the following stuff would also work with SDL1.2 + SDL_GL_SetAttribute( SDL_GL_STEREO, parms.stereo ? 1 : 0 ); + + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, parms.multiSamples ? 1 : 0 ); + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, parms.multiSamples ); + + glConfig.isFullscreen = parms.fullScreen; + glConfig.isStereoPixelFormat = parms.stereo; + glConfig.nativeScreenWidth = parms.width; + glConfig.nativeScreenHeight = parms.height; + glConfig.displayFrequency = parms.displayHz; + glConfig.multisamples = parms.multiSamples; +#else // SDL 1.2 + common->Printf( "TODO: Implement GLimp_SetScreenParms() for SDL1.2\n" ); +#endif + return true; }