mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2024-11-10 07:12:07 +00:00
Fork the clients SDL 2 backends into SDL 3 versions.
At this time they are just copies. The actual porting will be done in upcoming commits.
This commit is contained in:
parent
126c2ea10b
commit
9b0c95daaa
4 changed files with 3225 additions and 2 deletions
3
Makefile
3
Makefile
|
@ -875,6 +875,7 @@ CLIENT_OBJS_ := \
|
||||||
src/client/sound/ogg.o \
|
src/client/sound/ogg.o \
|
||||||
src/client/sound/openal.o \
|
src/client/sound/openal.o \
|
||||||
src/client/sound/qal.o \
|
src/client/sound/qal.o \
|
||||||
|
src/client/sound/sdl.o \
|
||||||
src/client/sound/sound.o \
|
src/client/sound/sound.o \
|
||||||
src/client/sound/wave.o \
|
src/client/sound/wave.o \
|
||||||
src/client/vid/vid.o \
|
src/client/vid/vid.o \
|
||||||
|
@ -915,12 +916,10 @@ CLIENT_OBJS_ := \
|
||||||
ifeq ($(WITH_SDL3),yes)
|
ifeq ($(WITH_SDL3),yes)
|
||||||
CLIENT_OBJS_ += \
|
CLIENT_OBJS_ += \
|
||||||
src/client/input/sdl3.o \
|
src/client/input/sdl3.o \
|
||||||
src/client/sound/sdl3.o \
|
|
||||||
src/client/vid/glimp_sdl3.o
|
src/client/vid/glimp_sdl3.o
|
||||||
else
|
else
|
||||||
CLIENT_OBJS_ += \
|
CLIENT_OBJS_ += \
|
||||||
src/client/input/sdl2.o \
|
src/client/input/sdl2.o \
|
||||||
src/client/sound/sdl2.o \
|
|
||||||
src/client/vid/glimp_sdl2.o
|
src/client/vid/glimp_sdl2.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
2387
src/client/input/sdl3.c
Normal file
2387
src/client/input/sdl3.c
Normal file
File diff suppressed because it is too large
Load diff
837
src/client/vid/glimp_sdl3.c
Normal file
837
src/client/vid/glimp_sdl3.c
Normal file
|
@ -0,0 +1,837 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2010 Yamagi Burmeister
|
||||||
|
* Copyright (C) 1997-2001 Id Software, Inc.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or (at
|
||||||
|
* your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* See the GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
|
* 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* =======================================================================
|
||||||
|
*
|
||||||
|
* This is the client side of the render backend, implemented trough SDL.
|
||||||
|
* The SDL window and related functrion (mouse grap, fullscreen switch)
|
||||||
|
* are implemented here, everything else is in the renderers.
|
||||||
|
*
|
||||||
|
* =======================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../../common/header/common.h"
|
||||||
|
#include "header/ref.h"
|
||||||
|
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
#include <SDL2/SDL_video.h>
|
||||||
|
|
||||||
|
int glimp_refreshRate = -1;
|
||||||
|
|
||||||
|
static cvar_t *vid_displayrefreshrate;
|
||||||
|
static cvar_t *vid_displayindex;
|
||||||
|
static cvar_t *vid_highdpiaware;
|
||||||
|
static cvar_t *vid_rate;
|
||||||
|
|
||||||
|
static int last_flags = 0;
|
||||||
|
static int last_display = 0;
|
||||||
|
static int last_position_x = SDL_WINDOWPOS_UNDEFINED;
|
||||||
|
static int last_position_y = SDL_WINDOWPOS_UNDEFINED;
|
||||||
|
static SDL_Window* window = NULL;
|
||||||
|
static qboolean initSuccessful = false;
|
||||||
|
static char **displayindices = NULL;
|
||||||
|
static int num_displays = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resets the display index Cvar if out of bounds
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ClampDisplayIndexCvar(void)
|
||||||
|
{
|
||||||
|
if (!vid_displayindex)
|
||||||
|
{
|
||||||
|
// uninitialized render?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vid_displayindex->value < 0 || vid_displayindex->value >= num_displays)
|
||||||
|
{
|
||||||
|
Cvar_SetValue("vid_displayindex", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ClearDisplayIndices(void)
|
||||||
|
{
|
||||||
|
if ( displayindices )
|
||||||
|
{
|
||||||
|
for ( int i = 0; i < num_displays; i++ )
|
||||||
|
{
|
||||||
|
free( displayindices[ i ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
free( displayindices );
|
||||||
|
displayindices = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean
|
||||||
|
CreateSDLWindow(int flags, int w, int h)
|
||||||
|
{
|
||||||
|
if (SDL_WINDOWPOS_ISUNDEFINED(last_position_x) || SDL_WINDOWPOS_ISUNDEFINED(last_position_y) || last_position_x < 0 ||last_position_y < 24)
|
||||||
|
{
|
||||||
|
last_position_x = last_position_y = SDL_WINDOWPOS_UNDEFINED_DISPLAY((int)vid_displayindex->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force the window to minimize when focus is lost. This was the
|
||||||
|
* default behavior until SDL 2.0.12 and changed with 2.0.14.
|
||||||
|
* The windows staying maximized has some odd implications for
|
||||||
|
* window ordering under Windows and some X11 window managers
|
||||||
|
* like kwin. See:
|
||||||
|
* * https://github.com/libsdl-org/SDL/issues/4039
|
||||||
|
* * https://github.com/libsdl-org/SDL/issues/3656 */
|
||||||
|
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "1");
|
||||||
|
|
||||||
|
window = SDL_CreateWindow("Yamagi Quake II", last_position_x, last_position_y, w, h, flags);
|
||||||
|
|
||||||
|
if (window)
|
||||||
|
{
|
||||||
|
|
||||||
|
/* save current display as default */
|
||||||
|
last_display = SDL_GetWindowDisplayIndex(window);
|
||||||
|
SDL_GetWindowPosition(window, &last_position_x, &last_position_y);
|
||||||
|
|
||||||
|
/* Check if we're really in the requested diplay mode. There is
|
||||||
|
(or was) an SDL bug were SDL switched into the wrong mode
|
||||||
|
without giving an error code. See the bug report for details:
|
||||||
|
https://bugzilla.libsdl.org/show_bug.cgi?id=4700 */
|
||||||
|
SDL_DisplayMode real_mode;
|
||||||
|
|
||||||
|
if ((flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)) == SDL_WINDOW_FULLSCREEN)
|
||||||
|
{
|
||||||
|
if (SDL_GetWindowDisplayMode(window, &real_mode) != 0)
|
||||||
|
{
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
window = NULL;
|
||||||
|
|
||||||
|
Com_Printf("Can't get display mode: %s\n", SDL_GetError());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* SDL_WINDOW_FULLSCREEN_DESKTOP implies SDL_WINDOW_FULLSCREEN! */
|
||||||
|
if (((flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)) == SDL_WINDOW_FULLSCREEN)
|
||||||
|
&& ((real_mode.w != w) || (real_mode.h != h)))
|
||||||
|
{
|
||||||
|
|
||||||
|
Com_Printf("Current display mode isn't requested display mode\n");
|
||||||
|
Com_Printf("Likely SDL bug #4700, trying to work around it\n");
|
||||||
|
|
||||||
|
/* Mkay, try to hack around that. */
|
||||||
|
SDL_DisplayMode wanted_mode = {0};
|
||||||
|
|
||||||
|
wanted_mode.w = w;
|
||||||
|
wanted_mode.h = h;
|
||||||
|
|
||||||
|
if (SDL_SetWindowDisplayMode(window, &wanted_mode) != 0)
|
||||||
|
{
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
window = NULL;
|
||||||
|
|
||||||
|
Com_Printf("Can't force resolution to %ix%i: %s\n", w, h, SDL_GetError());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The SDL doku says, that SDL_SetWindowSize() shouldn't be
|
||||||
|
used on fullscreen windows. But at least in my test with
|
||||||
|
SDL 2.0.9 the subsequent SDL_GetWindowDisplayMode() fails
|
||||||
|
if I don't call it. */
|
||||||
|
SDL_SetWindowSize(window, wanted_mode.w, wanted_mode.h);
|
||||||
|
|
||||||
|
if (SDL_GetWindowDisplayMode(window, &real_mode) != 0)
|
||||||
|
{
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
window = NULL;
|
||||||
|
|
||||||
|
Com_Printf("Can't get display mode: %s\n", SDL_GetError());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((real_mode.w != w) || (real_mode.h != h))
|
||||||
|
{
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
window = NULL;
|
||||||
|
|
||||||
|
Com_Printf("Still in wrong display mode: %ix%i instead of %ix%i\n", real_mode.w, real_mode.h, w, h);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Normally SDL stays at desktop refresh rate or chooses something
|
||||||
|
sane. Some player may want to override that.
|
||||||
|
|
||||||
|
Reminder: SDL_WINDOW_FULLSCREEN_DESKTOP implies SDL_WINDOW_FULLSCREEN! */
|
||||||
|
if ((flags & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)) == SDL_WINDOW_FULLSCREEN)
|
||||||
|
{
|
||||||
|
if (vid_rate->value > 0)
|
||||||
|
{
|
||||||
|
SDL_DisplayMode closest_mode;
|
||||||
|
SDL_DisplayMode requested_mode = real_mode;
|
||||||
|
|
||||||
|
requested_mode.refresh_rate = (int)vid_rate->value;
|
||||||
|
|
||||||
|
if (SDL_GetClosestDisplayMode(last_display, &requested_mode, &closest_mode) == NULL)
|
||||||
|
{
|
||||||
|
Com_Printf("SDL was unable to find a mode close to %ix%i@%i\n", w, h, requested_mode.refresh_rate);
|
||||||
|
Cvar_SetValue("vid_rate", -1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Com_Printf("User requested %ix%i@%i, setting closest mode %ix%i@%i\n",
|
||||||
|
w, h, requested_mode.refresh_rate, w, h, closest_mode.refresh_rate);
|
||||||
|
|
||||||
|
if (SDL_SetWindowDisplayMode(window, &closest_mode) != 0)
|
||||||
|
{
|
||||||
|
Com_Printf("Couldn't switch to mode %ix%i@%i, staying at current mode\n",
|
||||||
|
w, h, closest_mode.refresh_rate);
|
||||||
|
Cvar_SetValue("vid_rate", -1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Cvar_SetValue("vid_rate", closest_mode.refresh_rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Com_Printf("Creating window failed: %s\n", SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
GetFullscreenType()
|
||||||
|
{
|
||||||
|
if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN_DESKTOP)
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
else if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean
|
||||||
|
GetWindowSize(int* w, int* h)
|
||||||
|
{
|
||||||
|
if (window == NULL || w == NULL || h == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_DisplayMode m;
|
||||||
|
|
||||||
|
if (SDL_GetWindowDisplayMode(window, &m) != 0)
|
||||||
|
{
|
||||||
|
Com_Printf("Can't get Displaymode: %s\n", SDL_GetError());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*w = m.w;
|
||||||
|
*h = m.h;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
InitDisplayIndices()
|
||||||
|
{
|
||||||
|
displayindices = malloc((num_displays + 1) * sizeof(char *));
|
||||||
|
|
||||||
|
for ( int i = 0; i < num_displays; i++ )
|
||||||
|
{
|
||||||
|
/* There are a maximum of 10 digits in 32 bit int + 1 for the NULL terminator. */
|
||||||
|
displayindices[ i ] = malloc(11 * sizeof( char ));
|
||||||
|
YQ2_COM_CHECK_OOM(displayindices[i], "malloc()", 11 * sizeof( char ))
|
||||||
|
|
||||||
|
snprintf( displayindices[ i ], 11, "%d", i );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The last entry is NULL to indicate the list of strings ends. */
|
||||||
|
displayindices[ num_displays ] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lists all available display modes.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
PrintDisplayModes(void)
|
||||||
|
{
|
||||||
|
int curdisplay = window ? SDL_GetWindowDisplayIndex(window) : 0;
|
||||||
|
|
||||||
|
// On X11 (at least for me)
|
||||||
|
// curdisplay is always -1.
|
||||||
|
// DG: probably because window was NULL?
|
||||||
|
if (curdisplay < 0) {
|
||||||
|
curdisplay = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nummodes = SDL_GetNumDisplayModes(curdisplay);
|
||||||
|
|
||||||
|
if (nummodes < 1)
|
||||||
|
{
|
||||||
|
Com_Printf("Can't get display modes: %s\n", SDL_GetError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < nummodes; i++)
|
||||||
|
{
|
||||||
|
SDL_DisplayMode mode;
|
||||||
|
|
||||||
|
if (SDL_GetDisplayMode(curdisplay, i, &mode) != 0)
|
||||||
|
{
|
||||||
|
Com_Printf("Can't get display mode: %s\n", SDL_GetError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Com_Printf(" - Mode %2i: %ix%i@%i\n", i, mode.w, mode.h, mode.refresh_rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets the window icon
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
SetSDLIcon()
|
||||||
|
{
|
||||||
|
#include "icon/q2icon64.h" // 64x64 32 Bit
|
||||||
|
|
||||||
|
/* these masks are needed to tell SDL_CreateRGBSurface(From)
|
||||||
|
to assume the data it gets is byte-wise RGB(A) data */
|
||||||
|
Uint32 rmask, gmask, bmask, amask;
|
||||||
|
|
||||||
|
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||||
|
int shift = (q2icon64.bytes_per_pixel == 3) ? 8 : 0;
|
||||||
|
rmask = 0xff000000 >> shift;
|
||||||
|
gmask = 0x00ff0000 >> shift;
|
||||||
|
bmask = 0x0000ff00 >> shift;
|
||||||
|
amask = 0x000000ff >> shift;
|
||||||
|
#else /* little endian, like x86 */
|
||||||
|
rmask = 0x000000ff;
|
||||||
|
gmask = 0x0000ff00;
|
||||||
|
bmask = 0x00ff0000;
|
||||||
|
amask = (q2icon64.bytes_per_pixel == 3) ? 0 : 0xff000000;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SDL_Surface* icon = SDL_CreateRGBSurfaceFrom((void*)q2icon64.pixel_data, q2icon64.width,
|
||||||
|
q2icon64.height, q2icon64.bytes_per_pixel*8, q2icon64.bytes_per_pixel*q2icon64.width,
|
||||||
|
rmask, gmask, bmask, amask);
|
||||||
|
SDL_SetWindowIcon(window, icon);
|
||||||
|
SDL_FreeSurface(icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: We need a header for this.
|
||||||
|
// Maybe we could put it in vid.h.
|
||||||
|
void GLimp_GrabInput(qboolean grab);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shuts the SDL render backend down
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
ShutdownGraphics(void)
|
||||||
|
{
|
||||||
|
ClampDisplayIndexCvar();
|
||||||
|
|
||||||
|
if (window)
|
||||||
|
{
|
||||||
|
/* save current display as default */
|
||||||
|
last_display = SDL_GetWindowDisplayIndex(window);
|
||||||
|
|
||||||
|
/* or if current display isn't the desired default */
|
||||||
|
if (last_display != vid_displayindex->value) {
|
||||||
|
last_position_x = last_position_y = SDL_WINDOWPOS_UNDEFINED;
|
||||||
|
last_display = vid_displayindex->value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SDL_GetWindowPosition(window,
|
||||||
|
&last_position_x, &last_position_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cleanly ungrab input (needs window) */
|
||||||
|
GLimp_GrabInput(false);
|
||||||
|
SDL_DestroyWindow(window);
|
||||||
|
|
||||||
|
window = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure that after vid_restart the refreshrate will be queried from SDL2 again.
|
||||||
|
glimp_refreshRate = -1;
|
||||||
|
|
||||||
|
initSuccessful = false; // not initialized anymore
|
||||||
|
}
|
||||||
|
// --------
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initializes the SDL video subsystem. Must
|
||||||
|
* be called before anything else.
|
||||||
|
*/
|
||||||
|
qboolean
|
||||||
|
GLimp_Init(void)
|
||||||
|
{
|
||||||
|
vid_displayrefreshrate = Cvar_Get("vid_displayrefreshrate", "-1", CVAR_ARCHIVE);
|
||||||
|
vid_displayindex = Cvar_Get("vid_displayindex", "0", CVAR_ARCHIVE);
|
||||||
|
vid_highdpiaware = Cvar_Get("vid_highdpiaware", "0", CVAR_ARCHIVE);
|
||||||
|
vid_rate = Cvar_Get("vid_rate", "-1", CVAR_ARCHIVE);
|
||||||
|
|
||||||
|
if (!SDL_WasInit(SDL_INIT_VIDEO))
|
||||||
|
{
|
||||||
|
if (SDL_Init(SDL_INIT_VIDEO) == -1)
|
||||||
|
{
|
||||||
|
Com_Printf("Couldn't init SDL video: %s.\n", SDL_GetError());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_version version;
|
||||||
|
|
||||||
|
SDL_GetVersion(&version);
|
||||||
|
Com_Printf("-------- vid initialization --------\n");
|
||||||
|
Com_Printf("SDL version is: %i.%i.%i\n", (int)version.major, (int)version.minor, (int)version.patch);
|
||||||
|
Com_Printf("SDL video driver is \"%s\".\n", SDL_GetCurrentVideoDriver());
|
||||||
|
|
||||||
|
num_displays = SDL_GetNumVideoDisplays();
|
||||||
|
InitDisplayIndices();
|
||||||
|
ClampDisplayIndexCvar();
|
||||||
|
Com_Printf("SDL display modes:\n");
|
||||||
|
|
||||||
|
PrintDisplayModes();
|
||||||
|
Com_Printf("------------------------------------\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shuts the SDL video subsystem down. Must
|
||||||
|
* be called after evrything's finished and
|
||||||
|
* clean up.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
GLimp_Shutdown(void)
|
||||||
|
{
|
||||||
|
ShutdownGraphics();
|
||||||
|
|
||||||
|
// SDL_INIT_VIDEO implies SDL_INIT_EVENTS
|
||||||
|
const Uint32 subsystems = SDL_INIT_VIDEO | SDL_INIT_EVENTS;
|
||||||
|
if (SDL_WasInit(SDL_INIT_EVERYTHING) == subsystems)
|
||||||
|
{
|
||||||
|
SDL_Quit();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearDisplayIndices();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine if we want to be high dpi aware. If
|
||||||
|
* we are we must scale ourself. If we are not the
|
||||||
|
* compositor might scale us.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
Glimp_DetermineHighDPISupport(int flags)
|
||||||
|
{
|
||||||
|
#if SDL_VERSION_ATLEAST(2, 26, 0)
|
||||||
|
/* Make sure that high dpi is never set when we don't want it. */
|
||||||
|
flags &= ~SDL_WINDOW_ALLOW_HIGHDPI;
|
||||||
|
|
||||||
|
if (vid_highdpiaware->value == 0)
|
||||||
|
{
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle high dpi awareness based on the render backend.
|
||||||
|
SDL doesn't support high dpi awareness for all backends
|
||||||
|
and the quality and behavior differs between them. */
|
||||||
|
if ((strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0))
|
||||||
|
{
|
||||||
|
flags |= SDL_WINDOW_ALLOW_HIGHDPI;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (Re)initializes the actual window.
|
||||||
|
*/
|
||||||
|
qboolean
|
||||||
|
GLimp_InitGraphics(int fullscreen, int *pwidth, int *pheight)
|
||||||
|
{
|
||||||
|
int flags;
|
||||||
|
int curWidth, curHeight;
|
||||||
|
int width = *pwidth;
|
||||||
|
int height = *pheight;
|
||||||
|
unsigned int fs_flag = 0;
|
||||||
|
|
||||||
|
if (fullscreen == 1)
|
||||||
|
{
|
||||||
|
fs_flag = SDL_WINDOW_FULLSCREEN;
|
||||||
|
}
|
||||||
|
else if (fullscreen == 2)
|
||||||
|
{
|
||||||
|
fs_flag = SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only do this if we already have a working window and a fully
|
||||||
|
initialized rendering backend GLimp_InitGraphics() is also
|
||||||
|
called when recovering if creating GL context fails or the
|
||||||
|
one we got is unusable. */
|
||||||
|
if (initSuccessful && GetWindowSize(&curWidth, &curHeight)
|
||||||
|
&& (curWidth == width) && (curHeight == height))
|
||||||
|
{
|
||||||
|
/* If we want fullscreen, but aren't */
|
||||||
|
if (GetFullscreenType())
|
||||||
|
{
|
||||||
|
SDL_SetWindowFullscreen(window, fs_flag);
|
||||||
|
Cvar_SetValue("vid_fullscreen", fullscreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Are we now? */
|
||||||
|
if (GetFullscreenType())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is the surface used? */
|
||||||
|
if (window)
|
||||||
|
{
|
||||||
|
re.ShutdownContext();
|
||||||
|
ShutdownGraphics();
|
||||||
|
|
||||||
|
window = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(last_flags != -1 && (last_flags & SDL_WINDOW_OPENGL))
|
||||||
|
{
|
||||||
|
/* Reset SDL. */
|
||||||
|
SDL_GL_ResetAttributes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Let renderer prepare things (set OpenGL attributes).
|
||||||
|
FIXME: This is no longer necessary, the renderer
|
||||||
|
could and should pass the flags when calling this
|
||||||
|
function. */
|
||||||
|
flags = re.PrepareForWindow();
|
||||||
|
|
||||||
|
if (flags == -1)
|
||||||
|
{
|
||||||
|
/* It's PrepareForWindow() job to log an error */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs_flag)
|
||||||
|
{
|
||||||
|
flags |= fs_flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for high dpi support. */
|
||||||
|
flags = Glimp_DetermineHighDPISupport(flags);
|
||||||
|
|
||||||
|
/* Mkay, now the hard work. Let's create the window. */
|
||||||
|
cvar_t *gl_msaa_samples = Cvar_Get("r_msaa_samples", "0", CVAR_ARCHIVE);
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (!CreateSDLWindow(flags, width, height))
|
||||||
|
{
|
||||||
|
if((flags & SDL_WINDOW_OPENGL) && gl_msaa_samples->value)
|
||||||
|
{
|
||||||
|
int msaa_samples = gl_msaa_samples->value;
|
||||||
|
|
||||||
|
if (msaa_samples > 0)
|
||||||
|
{
|
||||||
|
msaa_samples /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Com_Printf("SDL SetVideoMode failed: %s\n", SDL_GetError());
|
||||||
|
Com_Printf("Reverting to %s r_mode %i (%ix%i) with %dx MSAA.\n",
|
||||||
|
(flags & fs_flag) ? "fullscreen" : "windowed",
|
||||||
|
(int) Cvar_VariableValue("r_mode"), width, height,
|
||||||
|
msaa_samples);
|
||||||
|
|
||||||
|
/* Try to recover */
|
||||||
|
Cvar_SetValue("r_msaa_samples", msaa_samples);
|
||||||
|
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS,
|
||||||
|
msaa_samples > 0 ? 1 : 0);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES,
|
||||||
|
msaa_samples);
|
||||||
|
}
|
||||||
|
else if (width != 640 || height != 480 || (flags & fs_flag))
|
||||||
|
{
|
||||||
|
Com_Printf("SDL SetVideoMode failed: %s\n", SDL_GetError());
|
||||||
|
Com_Printf("Reverting to windowed r_mode 4 (640x480).\n");
|
||||||
|
|
||||||
|
/* Try to recover */
|
||||||
|
Cvar_SetValue("r_mode", 4);
|
||||||
|
Cvar_SetValue("vid_fullscreen", 0);
|
||||||
|
Cvar_SetValue("vid_rate", -1);
|
||||||
|
|
||||||
|
fullscreen = 0;
|
||||||
|
*pwidth = width = 640;
|
||||||
|
*pheight = height = 480;
|
||||||
|
flags &= ~fs_flag;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Com_Printf("Failed to revert to r_mode 4. Will try another render backend...\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
last_flags = flags;
|
||||||
|
|
||||||
|
/* Now that we've got a working window print it's mode. */
|
||||||
|
int curdisplay = SDL_GetWindowDisplayIndex(window);
|
||||||
|
|
||||||
|
if (curdisplay < 0) {
|
||||||
|
curdisplay = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_DisplayMode mode;
|
||||||
|
|
||||||
|
if (SDL_GetCurrentDisplayMode(curdisplay, &mode) != 0)
|
||||||
|
{
|
||||||
|
Com_Printf("Can't get current display mode: %s\n", SDL_GetError());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Com_Printf("Real display mode: %ix%i@%i\n", mode.w, mode.h, mode.refresh_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Initialize rendering context. */
|
||||||
|
if (!re.InitContext(window))
|
||||||
|
{
|
||||||
|
/* InitContext() should have logged an error. */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need the actual drawable size for things like the
|
||||||
|
console, the menus, etc. This might be different to
|
||||||
|
the resolution due to high dpi awareness.
|
||||||
|
|
||||||
|
The fullscreen window is special. We want it to fill
|
||||||
|
the screen when native resolution is requestes, all
|
||||||
|
other cases should look broken. */
|
||||||
|
if (flags & SDL_WINDOW_ALLOW_HIGHDPI)
|
||||||
|
{
|
||||||
|
if (fullscreen != 2)
|
||||||
|
{
|
||||||
|
re.GetDrawableSize(&viddef.width, &viddef.height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cvar_t *r_mode = Cvar_Get("r_mode", "4", 0);
|
||||||
|
|
||||||
|
if (r_mode->value == -2 )
|
||||||
|
{
|
||||||
|
re.GetDrawableSize(&viddef.width, &viddef.height);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* User likes it broken. */
|
||||||
|
viddef.width = *pwidth;
|
||||||
|
viddef.height = *pheight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Another bug or design failure in SDL: When we are
|
||||||
|
not high dpi aware the drawable size returned by
|
||||||
|
SDL may be too small. It seems like the window
|
||||||
|
decoration are taken into account when they shouldn't.
|
||||||
|
It can be seen when creating a fullscreen window.
|
||||||
|
|
||||||
|
Work around that by always using the resolution and
|
||||||
|
not the drawable size when we are not high dpi aware. */
|
||||||
|
viddef.width = *pwidth;
|
||||||
|
viddef.height = *pheight;
|
||||||
|
}
|
||||||
|
|
||||||
|
Com_Printf("Drawable size: %ix%i\n", viddef.width, viddef.height);
|
||||||
|
|
||||||
|
/* Set the window icon - For SDL2, this must be done after creating the window */
|
||||||
|
SetSDLIcon();
|
||||||
|
|
||||||
|
/* No cursor */
|
||||||
|
SDL_ShowCursor(0);
|
||||||
|
|
||||||
|
initSuccessful = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Shuts the window down.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
GLimp_ShutdownGraphics(void)
|
||||||
|
{
|
||||||
|
SDL_GL_ResetAttributes();
|
||||||
|
ShutdownGraphics();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (Un)grab Input
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
GLimp_GrabInput(qboolean grab)
|
||||||
|
{
|
||||||
|
if(window != NULL)
|
||||||
|
{
|
||||||
|
SDL_SetWindowGrab(window, grab ? SDL_TRUE : SDL_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SDL_SetRelativeMouseMode(grab ? SDL_TRUE : SDL_FALSE) < 0)
|
||||||
|
{
|
||||||
|
Com_Printf("WARNING: Setting Relative Mousemode failed, reason: %s\n", SDL_GetError());
|
||||||
|
Com_Printf(" You should probably update to SDL 2.0.3 or newer!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns the current display refresh rate. There're 2 limitations:
|
||||||
|
*
|
||||||
|
* * The timing code in frame.c only understands full integers, so
|
||||||
|
* values given by vid_displayrefreshrate are always round up. For
|
||||||
|
* example 59.95 become 60. Rounding up is the better choice for
|
||||||
|
* most users because assuming a too high display refresh rate
|
||||||
|
* avoids micro stuttering caused by missed frames if the vsync
|
||||||
|
* is enabled. The price are small and hard to notice timing
|
||||||
|
* problems.
|
||||||
|
*
|
||||||
|
* * SDL returns only full integers. In most cases they're rounded
|
||||||
|
* up, but in some cases - likely depending on the GPU driver -
|
||||||
|
* they're rounded down. If the value is rounded up, we'll see
|
||||||
|
* some small and nard to notice timing problems. If the value
|
||||||
|
* is rounded down frames will be missed. Both is only relevant
|
||||||
|
* if the vsync is enabled.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
GLimp_GetRefreshRate(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (vid_displayrefreshrate->value > -1 ||
|
||||||
|
vid_displayrefreshrate->modified)
|
||||||
|
{
|
||||||
|
glimp_refreshRate = ceil(vid_displayrefreshrate->value);
|
||||||
|
vid_displayrefreshrate->modified = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (glimp_refreshRate == -1)
|
||||||
|
{
|
||||||
|
SDL_DisplayMode mode;
|
||||||
|
|
||||||
|
int i = SDL_GetWindowDisplayIndex(window);
|
||||||
|
|
||||||
|
if (i >= 0 && SDL_GetCurrentDisplayMode(i, &mode) == 0)
|
||||||
|
{
|
||||||
|
glimp_refreshRate = mode.refresh_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Something went wrong, use default.
|
||||||
|
if (glimp_refreshRate <= 0)
|
||||||
|
{
|
||||||
|
glimp_refreshRate = 60;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return glimp_refreshRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Detect current desktop mode
|
||||||
|
*/
|
||||||
|
qboolean
|
||||||
|
GLimp_GetDesktopMode(int *pwidth, int *pheight)
|
||||||
|
{
|
||||||
|
// Declare display mode structure to be filled in.
|
||||||
|
SDL_DisplayMode mode;
|
||||||
|
|
||||||
|
if (window)
|
||||||
|
{
|
||||||
|
/* save current display as default */
|
||||||
|
last_display = SDL_GetWindowDisplayIndex(window);
|
||||||
|
SDL_GetWindowPosition(window, &last_position_x, &last_position_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_display < 0)
|
||||||
|
{
|
||||||
|
// In case of error...
|
||||||
|
Com_Printf("Can't detect current desktop.\n");
|
||||||
|
last_display = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can't get desktop where we start, so use first desktop
|
||||||
|
if(SDL_GetCurrentDisplayMode(last_display, &mode) != 0)
|
||||||
|
{
|
||||||
|
// In case of error...
|
||||||
|
Com_Printf("Can't detect default desktop mode: %s\n",
|
||||||
|
SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*pwidth = mode.w;
|
||||||
|
*pheight = mode.h;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char**
|
||||||
|
GLimp_GetDisplayIndices(void)
|
||||||
|
{
|
||||||
|
return (const char**)displayindices;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
GLimp_GetNumVideoDisplays(void)
|
||||||
|
{
|
||||||
|
return num_displays;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
GLimp_GetWindowDisplayIndex(void)
|
||||||
|
{
|
||||||
|
return last_display;
|
||||||
|
}
|
Loading…
Reference in a new issue