mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-06 20:30:36 +08:00
589 lines
14 KiB
C
589 lines
14 KiB
C
/*
|
|
vid_sdl3 - SDL3 vid component
|
|
Copyright (C) 2025 Xash3D FWGS contributors
|
|
|
|
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 3 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.
|
|
*/
|
|
|
|
#include "xash3d_types.h"
|
|
#include "platform_sdl3.h"
|
|
#include "vid_common.h"
|
|
#include "ref_common.h"
|
|
#include "xash3d_mathlib.h"
|
|
#include "common.h"
|
|
#include <SDL3/SDL_system.h>
|
|
|
|
static struct
|
|
{
|
|
int prev_width;
|
|
int prev_height;
|
|
|
|
vidmode_t *vidmodes;
|
|
int num_vidmodes;
|
|
} vid_state = { 640, 480 };
|
|
|
|
static void GL_SetupAttributes( ref_safegl_context_t safegl )
|
|
{
|
|
SDL_GL_ResetAttributes();
|
|
|
|
ref.dllFuncs.GL_SetupAttributes( safegl );
|
|
}
|
|
|
|
static void VID_SetWindowIcon( SDL_Window *hWnd )
|
|
{
|
|
char iconpath[MAX_STRING];
|
|
|
|
Q_strncpy( iconpath, GI->iconpath, sizeof( iconpath ));
|
|
COM_ReplaceExtension( iconpath, ".tga", sizeof( iconpath ));
|
|
|
|
rgbdata_t *icon = FS_LoadImage( iconpath, NULL, 0 );
|
|
|
|
if( !icon )
|
|
return;
|
|
|
|
SDL_Surface *surface = SDL_CreateSurfaceFrom( icon->width, icon->height, SDL_PIXELFORMAT_RGBA8888, icon->buffer, 4 * icon->width );
|
|
|
|
FS_FreeImage( icon );
|
|
|
|
if( !surface )
|
|
{
|
|
Con_PrintSDLError( "SDL_CreateSurfaceFrom" );
|
|
return;
|
|
}
|
|
|
|
if( !SDL_SetWindowIcon( hWnd, surface ))
|
|
Con_PrintSDLError( "SDL_SetWindowIcon" );
|
|
|
|
SDL_DestroySurface( surface );
|
|
}
|
|
|
|
static SDL_Window *VID_CreateWindowWithSafeGL( const char *title, SDL_Rect *rect, Uint32 flags )
|
|
{
|
|
for( ; glw_state.safe < SAFE_LAST; glw_state.safe++ )
|
|
{
|
|
if( glw_state.safe == SAFE_NOMSAA && !gl_msaa_samples.value )
|
|
continue;
|
|
|
|
// choose attributes with select safegl level
|
|
GL_SetupAttributes( glw_state.safe );
|
|
|
|
SDL_Window *hWnd = SDL_CreateWindow( title, rect->w, rect->h, flags );
|
|
|
|
// stop if window creation was successful
|
|
if( hWnd )
|
|
return hWnd;
|
|
|
|
Con_Printf( S_ERROR "%s: couldn't create '%s' with safegl level %d: %s\n", __func__, title, glw_state.safe, SDL_GetError( ));
|
|
|
|
glw_state.safe++;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void VID_SaveWindowSize( SDL_Window *hWnd, int width, int height )
|
|
{
|
|
qboolean maximized = FBitSet( SDL_GetWindowFlags( hWnd ), SDL_WINDOW_MAXIMIZED );
|
|
int render_w;
|
|
int render_h;
|
|
|
|
if( !SDL_GetWindowSizeInPixels( hWnd, &render_w, &render_h ))
|
|
{
|
|
render_w = width;
|
|
render_h = height;
|
|
|
|
Con_PrintSDLError( "SDL_GetWindowSizeInPixels" );
|
|
}
|
|
|
|
VID_SetDisplayTransform( &render_w, &render_h );
|
|
R_SaveVideoMode( width, height, render_w, render_h, maximized );
|
|
}
|
|
|
|
static qboolean VID_CreateWindow( const int input_width, const int input_height, window_mode_t window_mode )
|
|
{
|
|
SDL_Rect rect = { SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, input_width, input_height };
|
|
Uint32 flags = SDL_WINDOW_RESIZABLE;
|
|
|
|
if( !glw_state.software )
|
|
SetBits( flags, SDL_WINDOW_OPENGL );
|
|
|
|
// probe true fullscreen first, if it fails, try borderless next
|
|
if( window_mode == WINDOW_MODE_FULLSCREEN )
|
|
{
|
|
SDL_DisplayID display = SDL_GetPrimaryDisplay();
|
|
SDL_DisplayMode dm;
|
|
|
|
if( SDL_GetClosestFullscreenDisplayMode( display, rect.w, rect.h, 0.0f, true, &dm ))
|
|
{
|
|
SetBits( flags, SDL_WINDOW_FULLSCREEN );
|
|
rect.w = dm.w;
|
|
rect.h = dm.h;
|
|
}
|
|
else
|
|
{
|
|
Con_PrintSDLError( "SDL_GetClosestFullscreenDisplayMode" );
|
|
|
|
window_mode = WINDOW_MODE_BORDERLESS;
|
|
}
|
|
}
|
|
|
|
// try borderless mode
|
|
if( window_mode == WINDOW_MODE_BORDERLESS )
|
|
{
|
|
SDL_DisplayID display = SDL_GetPrimaryDisplay();
|
|
const SDL_DisplayMode *dm;
|
|
|
|
dm = SDL_GetDesktopDisplayMode( display );
|
|
|
|
if( dm )
|
|
{
|
|
SetBits( flags, SDL_WINDOW_FULLSCREEN );
|
|
rect.w = dm->w;
|
|
rect.h = dm->h;
|
|
}
|
|
else
|
|
{
|
|
Con_PrintSDLError( "SDL_GetDesktopDisplayMode" );
|
|
window_mode = WINDOW_MODE_WINDOWED;
|
|
}
|
|
}
|
|
|
|
// finally, revert to windowed mode
|
|
if( window_mode == WINDOW_MODE_WINDOWED )
|
|
{
|
|
// no-op
|
|
}
|
|
|
|
host.hWnd = VID_CreateWindowWithSafeGL( GI->title, &rect, flags );
|
|
|
|
if( !host.hWnd )
|
|
return false;
|
|
|
|
VID_SetWindowIcon( host.hWnd );
|
|
|
|
if( glw_state.software )
|
|
{
|
|
// no support yet
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
glw_state.context = SDL_GL_CreateContext( host.hWnd );
|
|
|
|
if( !glw_state.context )
|
|
{
|
|
Con_PrintSDLError( "SDL_GL_CreateContext" );
|
|
return false;
|
|
}
|
|
|
|
if( !SDL_GL_MakeCurrent( host.hWnd, glw_state.context ))
|
|
{
|
|
Con_PrintSDLError( "SDL_GL_MakeCurrent" );
|
|
SDL_GL_DestroyContext( glw_state.context );
|
|
glw_state.context = NULL;
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// update window size
|
|
SDL_GetWindowSize( host.hWnd, &rect.w, &rect.h );
|
|
VID_SaveWindowSize( host.hWnd, rect.w, rect.h );
|
|
|
|
// update the window mode
|
|
if( window_mode != WINDOW_MODE_WINDOWED )
|
|
Cvar_DirectSetValue( &vid_fullscreen, SDL_GetWindowFullscreenMode( host.hWnd ) != NULL ? WINDOW_MODE_FULLSCREEN : WINDOW_MODE_BORDERLESS );
|
|
|
|
return true;
|
|
}
|
|
|
|
static void R_InitVideoModes( void )
|
|
{
|
|
SDL_DisplayID display = SDL_GetDisplayForWindow( host.hWnd );
|
|
int count;
|
|
SDL_DisplayMode **modes = SDL_GetFullscreenDisplayModes( display, &count );
|
|
|
|
if( !modes )
|
|
{
|
|
Con_PrintSDLError( "SDL_GetFullscreenDisplayModes" );
|
|
return;
|
|
}
|
|
|
|
vid_state.num_vidmodes = 0;
|
|
vid_state.vidmodes = Mem_Malloc( host.mempool, count * sizeof( *vid_state.vidmodes ));
|
|
|
|
for( int i = 0; i < count; i++ )
|
|
{
|
|
int w = modes[i]->w;
|
|
int h = modes[i]->h;
|
|
|
|
if( w < VID_MIN_WIDTH || h < VID_MIN_HEIGHT )
|
|
continue;
|
|
|
|
int j;
|
|
|
|
for( j = 0; j < vid_state.num_vidmodes; j++ )
|
|
{
|
|
if( w == vid_state.vidmodes[j].width && h == vid_state.vidmodes[j].height )
|
|
break;
|
|
}
|
|
|
|
if( j != vid_state.num_vidmodes )
|
|
continue;
|
|
|
|
j = vid_state.num_vidmodes++;
|
|
|
|
vid_state.vidmodes[j].width = w;
|
|
vid_state.vidmodes[j].height = h;
|
|
|
|
char buf[MAX_VA_STRING];
|
|
Q_snprintf( buf, sizeof( buf ), "%dx%d", w, h );
|
|
|
|
vid_state.vidmodes[j].desc = copystring( buf );
|
|
}
|
|
|
|
SDL_free( modes );
|
|
}
|
|
|
|
void Platform_Minimize_f( void )
|
|
{
|
|
if( host.hWnd )
|
|
SDL_MinimizeWindow( host.hWnd );
|
|
}
|
|
|
|
void GL_UpdateSwapInterval( void )
|
|
{
|
|
if( FBitSet( gl_vsync.flags, FCVAR_CHANGED ))
|
|
{
|
|
ClearBits( gl_vsync.flags, FCVAR_CHANGED );
|
|
|
|
if( !SDL_GL_SetSwapInterval( gl_vsync.value ))
|
|
Con_PrintSDLError( "SDL_GL_SetSwapInterval" );
|
|
}
|
|
}
|
|
|
|
qboolean R_Init_Video( ref_graphic_apis_t type )
|
|
{
|
|
qboolean retval = false;
|
|
|
|
if( Sys_CheckParm( "-egl" ))
|
|
Con_Printf( S_WARN "%s: -egl option is deprecated\n", __func__ );
|
|
|
|
switch( type )
|
|
{
|
|
case REF_SOFTWARE:
|
|
glw_state.software = true;
|
|
break;
|
|
case REF_GL:
|
|
{
|
|
string safe;
|
|
|
|
if( !glw_state.safe && Sys_GetParmFromCmdLine( "-safegl", safe ))
|
|
glw_state.safe = bound( SAFE_NO, Q_atoi( safe ), SAFE_DONTCARE );
|
|
|
|
if( !SDL_GL_LoadLibrary( NULL ))
|
|
{
|
|
Con_Reportf( S_ERROR "Couldn't initialize OpenGL: %s\n", SDL_GetError( ));
|
|
return false;
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
Host_Error( "Can't initialize unknown context type %d!\n", type );
|
|
break;
|
|
}
|
|
|
|
retval = VID_SetMode();
|
|
if( !retval )
|
|
return false;
|
|
|
|
switch( type )
|
|
{
|
|
case REF_SOFTWARE:
|
|
break;
|
|
case REF_GL:
|
|
ref.dllFuncs.GL_InitExtensions();
|
|
break;
|
|
}
|
|
|
|
R_InitVideoModes();
|
|
|
|
host.renderinfo_changed = false;
|
|
|
|
return true;
|
|
}
|
|
|
|
void R_Free_Video( void )
|
|
{
|
|
SDL_GL_DestroyContext( glw_state.context );
|
|
glw_state.context = NULL;
|
|
|
|
SDL_DestroyWindow( host.hWnd );
|
|
host.hWnd = NULL;
|
|
|
|
refState.window_mode = WINDOW_MODE_WINDOWED;
|
|
|
|
Mem_Free( vid_state.vidmodes );
|
|
vid_state.vidmodes = NULL;
|
|
vid_state.num_vidmodes = 0;
|
|
|
|
ref.dllFuncs.GL_ClearExtensions();
|
|
}
|
|
|
|
int GL_SetAttribute( int attr, int val )
|
|
{
|
|
switch( attr )
|
|
{
|
|
#define MAP_REF_API_ATTRIBUTE_TO_SDL( name ) case REF_##name: return SDL_GL_SetAttribute( SDL_##name, val );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_RED_SIZE );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_GREEN_SIZE );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_BLUE_SIZE );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_ALPHA_SIZE );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_DOUBLEBUFFER );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_DEPTH_SIZE );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_STENCIL_SIZE );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_MULTISAMPLEBUFFERS );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_MULTISAMPLESAMPLES );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_ACCELERATED_VISUAL );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_MAJOR_VERSION );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_MINOR_VERSION );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_FLAGS );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_SHARE_WITH_CURRENT_CONTEXT );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_FRAMEBUFFER_SRGB_CAPABLE );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_PROFILE_MASK );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_RELEASE_BEHAVIOR );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_RESET_NOTIFICATION );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_NO_ERROR );
|
|
#undef MAP_REF_API_ATTRIBUTE_TO_SDL
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int GL_GetAttribute( int attr, int *val )
|
|
{
|
|
switch( attr )
|
|
{
|
|
#define MAP_REF_API_ATTRIBUTE_TO_SDL( name ) case REF_##name: return SDL_GL_GetAttribute( SDL_##name, val );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_RED_SIZE );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_GREEN_SIZE );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_BLUE_SIZE );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_ALPHA_SIZE );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_DOUBLEBUFFER );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_DEPTH_SIZE );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_STENCIL_SIZE );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_MULTISAMPLEBUFFERS );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_MULTISAMPLESAMPLES );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_ACCELERATED_VISUAL );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_MAJOR_VERSION );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_MINOR_VERSION );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_FLAGS );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_SHARE_WITH_CURRENT_CONTEXT );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_FRAMEBUFFER_SRGB_CAPABLE );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_PROFILE_MASK );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_RELEASE_BEHAVIOR );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_RESET_NOTIFICATION );
|
|
MAP_REF_API_ATTRIBUTE_TO_SDL( GL_CONTEXT_NO_ERROR );
|
|
#undef MAP_REF_API_ATTRIBUTE_TO_SDL
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void GL_SwapBuffers( void )
|
|
{
|
|
SDL_GL_SwapWindow( host.hWnd );
|
|
}
|
|
|
|
void *GL_GetProcAddress( const char *name )
|
|
{
|
|
return SDL_GL_GetProcAddress( name );
|
|
}
|
|
|
|
qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *r, uint *g, uint *b )
|
|
{
|
|
// TODO
|
|
return false;
|
|
}
|
|
|
|
void *SW_LockBuffer( void )
|
|
{
|
|
// TODO
|
|
return NULL;
|
|
}
|
|
|
|
void SW_UnlockBuffer( void )
|
|
{
|
|
// TODO
|
|
}
|
|
|
|
ref_window_type_t R_GetWindowHandle( void **handle, ref_window_type_t type )
|
|
{
|
|
if( type == REF_WINDOW_TYPE_SDL3 )
|
|
{
|
|
if( handle )
|
|
*handle = host.hWnd;
|
|
return REF_WINDOW_TYPE_SDL3;
|
|
}
|
|
|
|
if( type == REF_WINDOW_TYPE_SDL2 )
|
|
return REF_WINDOW_TYPE_NULL;
|
|
|
|
const char *driver = SDL_GetCurrentVideoDriver();
|
|
|
|
if( !driver )
|
|
{
|
|
Con_PrintSDLError( "SDL_GetCurrentVideoDriver" );
|
|
return REF_WINDOW_TYPE_NULL;
|
|
}
|
|
|
|
SDL_PropertiesID pid = SDL_GetWindowProperties( host.hWnd );
|
|
|
|
if( !pid )
|
|
{
|
|
Con_PrintSDLError( "SDL_GetWindowProperties" );
|
|
return REF_WINDOW_TYPE_NULL;
|
|
}
|
|
|
|
if( !Q_strcmp( driver, "windows" ))
|
|
{
|
|
if( !type || type == REF_WINDOW_TYPE_WIN32 )
|
|
{
|
|
if( handle )
|
|
*handle = SDL_GetPointerProperty( pid, SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL );
|
|
return REF_WINDOW_TYPE_WIN32;
|
|
}
|
|
}
|
|
else if( !Q_strcmp( driver, "x11" ))
|
|
{
|
|
if( !type || type == REF_WINDOW_TYPE_X11 )
|
|
{
|
|
if( handle )
|
|
*handle = SDL_GetPointerProperty( pid, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, NULL );
|
|
return REF_WINDOW_TYPE_X11;
|
|
}
|
|
}
|
|
else if( !Q_strcmp( driver, "wayland" ))
|
|
{
|
|
if( !type || type == REF_WINDOW_TYPE_WAYLAND )
|
|
{
|
|
if( handle )
|
|
*handle = SDL_GetPointerProperty( pid, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, NULL );
|
|
return REF_WINDOW_TYPE_WAYLAND;
|
|
}
|
|
}
|
|
else if( !Q_strcmp( driver, "cocoa" ))
|
|
{
|
|
if( !type || type == REF_WINDOW_TYPE_MACOS )
|
|
{
|
|
if( handle )
|
|
*handle = SDL_GetPointerProperty( pid, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, NULL );
|
|
return REF_WINDOW_TYPE_MACOS;
|
|
}
|
|
}
|
|
|
|
*handle = NULL;
|
|
return REF_WINDOW_TYPE_NULL;
|
|
}
|
|
|
|
int R_MaxVideoModes( void )
|
|
{
|
|
return vid_state.num_vidmodes;
|
|
}
|
|
|
|
struct vidmode_s *R_GetVideoMode( int num )
|
|
{
|
|
if( !vid_state.vidmodes || num < 0 || num >= R_MaxVideoModes( ))
|
|
return NULL;
|
|
|
|
return &vid_state.vidmodes[num];
|
|
}
|
|
|
|
qboolean VID_SetMode( void )
|
|
{
|
|
window_mode_t window_mode;
|
|
int screen_width = Cvar_VariableInteger( "width" );
|
|
int screen_height = Cvar_VariableInteger( "height" );
|
|
rserr_t err;
|
|
|
|
if( screen_width < VID_MIN_WIDTH || screen_height < VID_MIN_HEIGHT )
|
|
{
|
|
screen_width = vid_state.prev_width;
|
|
screen_width = vid_state.prev_height;
|
|
}
|
|
|
|
#if XASH_MOBILE_PLATFORM
|
|
if( Q_strcmp( vid_fullscreen.string, DEFAULT_FULLSCREEN ))
|
|
{
|
|
Cvar_DirectSet( &vid_fullscreen, DEFAULT_FULLSCREEN );
|
|
Con_Reportf( S_ERROR "%s: windowed unavailable on this platform\n", __func__ );
|
|
}
|
|
#endif
|
|
|
|
window_mode = bound( 0, vid_fullscreen.value, WINDOW_MODE_COUNT - 1 );
|
|
SetBits( gl_vsync.flags, FCVAR_CHANGED );
|
|
|
|
err = R_ChangeDisplaySettings( screen_width, screen_height, window_mode );
|
|
|
|
switch( err )
|
|
{
|
|
case rserr_ok:
|
|
vid_state.prev_width = screen_width;
|
|
vid_state.prev_height = screen_height;
|
|
|
|
return true;
|
|
break;
|
|
case rserr_invalid_fullscreen:
|
|
Cvar_DirectSetValue( &vid_fullscreen, WINDOW_MODE_WINDOWED );
|
|
Sys_Warn( "%s: fullscreen unavailable in this mode!", __func__ );
|
|
|
|
// try same but windowed
|
|
err = R_ChangeDisplaySettings( screen_width, screen_height, WINDOW_MODE_WINDOWED );
|
|
if( err == rserr_ok )
|
|
return true;
|
|
break;
|
|
case rserr_invalid_mode:
|
|
Sys_Warn( "%s: invalid mode, engine will run in %dx%d", __func__, vid_state.prev_width, vid_state.prev_height );
|
|
break;
|
|
}
|
|
|
|
// revert to last successful mode
|
|
err = R_ChangeDisplaySettings( vid_state.prev_width, vid_state.prev_height, WINDOW_MODE_WINDOWED );
|
|
if( err != rserr_ok )
|
|
{
|
|
Sys_Warn( "%s: could not revert to safe mode!", __func__ );
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
rserr_t R_ChangeDisplaySettings( int width, int height, window_mode_t window_mode )
|
|
{
|
|
if( !host.hWnd )
|
|
{
|
|
// create window if not exists
|
|
if( !VID_CreateWindow( width, height, window_mode ))
|
|
return rserr_invalid_mode;
|
|
}
|
|
else
|
|
{
|
|
// TODO: change current window mode
|
|
return rserr_invalid_fullscreen;
|
|
}
|
|
|
|
refState.desktopBitsPixel = 24; // TODO: figure this out
|
|
refState.window_mode = window_mode;
|
|
|
|
return rserr_ok;
|
|
}
|