engine: platform: try to restore SDL1.2 support (only ref_soft is tested, ref_gl doesn't work)

This commit is contained in:
Alibek Omarov
2025-05-05 05:44:31 +03:00
parent aa2e5eb3cc
commit 0cbb62b329
8 changed files with 1438 additions and 0 deletions
+1
View File
@@ -256,6 +256,7 @@ void Platform_SetClipboardText( const char *buffer );
#if XASH_SDL == 1
#define SDL_SetWindowGrab( wnd, state ) SDL_WM_GrabInput( (state) ? SDL_GRAB_ON : SDL_GRAB_OFF )
#define SDL_GetWindowGrab( wnd ) ( SDL_WM_GrabInput( SDL_GRAB_QUERY ) != SDL_GRAB_OFF )
#define SDL_MinimizeWindow( wnd ) SDL_WM_IconifyWindow()
#define SDL_IsTextInputActive() host.textmode
#endif
+354
View File
@@ -0,0 +1,354 @@
/*
host_sdl1.c - SDL event system handlers
Copyright (C) 2015-2025 a1batross
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 <SDL.h>
#include <ctype.h>
#include "common.h"
#include "keydefs.h"
#include "input.h"
#include "client.h"
#include "vgui_draw.h"
#include "platform_sdl1.h"
#include "sound.h"
#include "vid_common.h"
#define SDL_SCANCODE_A SDLK_a
#define SDL_SCANCODE_Z SDLK_z
#define SDL_SCANCODE_1 SDLK_1
#define SDL_SCANCODE_9 SDLK_9
#define SDL_SCANCODE_F1 SDLK_F1
#define SDL_SCANCODE_F12 SDLK_F12
#define SDL_SCANCODE_GRAVE SDLK_BACKQUOTE
#define SDL_SCANCODE_0 SDLK_0
#define SDL_SCANCODE_BACKSLASH SDLK_BACKSLASH
#define SDL_SCANCODE_LEFTBRACKET SDLK_LEFTBRACKET
#define SDL_SCANCODE_RIGHTBRACKET SDLK_RIGHTBRACKET
#define SDL_SCANCODE_EQUALS SDLK_EQUALS
#define SDL_SCANCODE_MINUS SDLK_MINUS
#define SDL_SCANCODE_TAB SDLK_TAB
#define SDL_SCANCODE_RETURN SDLK_RETURN
#define SDL_SCANCODE_ESCAPE SDLK_ESCAPE
#define SDL_SCANCODE_SPACE SDLK_SPACE
#define SDL_SCANCODE_BACKSPACE SDLK_BACKSPACE
#define SDL_SCANCODE_UP SDLK_UP
#define SDL_SCANCODE_LEFT SDLK_LEFT
#define SDL_SCANCODE_DOWN SDLK_DOWN
#define SDL_SCANCODE_RIGHT SDLK_RIGHT
#define SDL_SCANCODE_LALT SDLK_LALT
#define SDL_SCANCODE_RALT SDLK_RALT
#define SDL_SCANCODE_LCTRL SDLK_LCTRL
#define SDL_SCANCODE_RCTRL SDLK_RCTRL
#define SDL_SCANCODE_LSHIFT SDLK_LSHIFT
#define SDL_SCANCODE_RSHIFT SDLK_RSHIFT
#define SDL_SCANCODE_LGUI SDLK_LMETA
#define SDL_SCANCODE_RGUI SDLK_RMETA
#define SDL_SCANCODE_INSERT SDLK_INSERT
#define SDL_SCANCODE_DELETE SDLK_DELETE
#define SDL_SCANCODE_PAGEDOWN SDLK_PAGEDOWN
#define SDL_SCANCODE_PAGEUP SDLK_PAGEUP
#define SDL_SCANCODE_HOME SDLK_HOME
#define SDL_SCANCODE_END SDLK_END
#define SDL_SCANCODE_KP_1 SDLK_KP1
#define SDL_SCANCODE_KP_2 SDLK_KP2
#define SDL_SCANCODE_KP_3 SDLK_KP3
#define SDL_SCANCODE_KP_4 SDLK_KP4
#define SDL_SCANCODE_KP_5 SDLK_KP5
#define SDL_SCANCODE_KP_6 SDLK_KP6
#define SDL_SCANCODE_KP_7 SDLK_KP7
#define SDL_SCANCODE_KP_8 SDLK_KP8
#define SDL_SCANCODE_KP_9 SDLK_KP9
#define SDL_SCANCODE_KP_0 SDLK_KP0
#define SDL_SCANCODE_KP_PERIOD SDLK_KP_PERIOD
#define SDL_SCANCODE_KP_ENTER SDLK_KP_ENTER
#define SDL_SCANCODE_KP_PLUS SDLK_KP_PLUS
#define SDL_SCANCODE_KP_MINUS SDLK_KP_MINUS
#define SDL_SCANCODE_KP_DIVIDE SDLK_KP_DIVIDE
#define SDL_SCANCODE_KP_MULTIPLY SDLK_KP_MULTIPLY
#define SDL_SCANCODE_NUMLOCKCLEAR SDLK_NUMLOCK
#define SDL_SCANCODE_CAPSLOCK SDLK_CAPSLOCK
#define SDL_SCANCODE_SLASH SDLK_SLASH
#define SDL_SCANCODE_PERIOD SDLK_PERIOD
#define SDL_SCANCODE_SEMICOLON SDLK_SEMICOLON
#define SDL_SCANCODE_APOSTROPHE SDLK_QUOTE
#define SDL_SCANCODE_COMMA SDLK_COMMA
#define SDL_SCANCODE_PRINTSCREEN SDLK_PRINT
#define SDL_SCANCODE_UNKNOWN SDLK_UNKNOWN
#define SDL_GetScancodeName( x ) "unknown"
/*
=============
SDLash_KeyEvent
=============
*/
static void SDLash_KeyEvent( SDL_KeyboardEvent key )
{
int down = key.state != SDL_RELEASED;
int keynum = key.keysym.sym;
if( SDL_IsTextInputActive( ) && down )
{
// this is how engine understands ctrl+c, ctrl+v and other hotkeys
if( cls.key_dest != key_game && FBitSet( SDL_GetModState(), KMOD_CTRL ))
{
if( keynum >= SDL_SCANCODE_A && keynum <= SDL_SCANCODE_Z )
{
keynum = keynum - SDL_SCANCODE_A + 1;
CL_CharEvent( keynum );
}
return;
}
if( keynum >= SDLK_KP0 && keynum <= SDLK_KP9 )
keynum -= SDLK_KP0 + '0';
if( isprint( keynum ))
{
if( FBitSet( SDL_GetModState(), KMOD_SHIFT ))
keynum = Key_ToUpper( keynum );
CL_CharEvent( keynum );
}
}
#define DECLARE_KEY_RANGE( min, max, repl ) \
if( keynum >= (min) && keynum <= (max) ) \
{ \
keynum = keynum - (min) + (repl); \
}
DECLARE_KEY_RANGE( SDL_SCANCODE_A, SDL_SCANCODE_Z, 'a' )
else DECLARE_KEY_RANGE( SDL_SCANCODE_1, SDL_SCANCODE_9, '1' )
else DECLARE_KEY_RANGE( SDL_SCANCODE_F1, SDL_SCANCODE_F12, K_F1 )
else
{
qboolean numLock = FBitSet( SDL_GetModState(), KMOD_NUM );
switch( keynum )
{
case SDL_SCANCODE_GRAVE: keynum = '`'; break;
case SDL_SCANCODE_0: keynum = '0'; break;
case SDL_SCANCODE_BACKSLASH: keynum = '\\'; break;
case SDL_SCANCODE_LEFTBRACKET: keynum = '['; break;
case SDL_SCANCODE_RIGHTBRACKET: keynum = ']'; break;
case SDL_SCANCODE_EQUALS: keynum = '='; break;
case SDL_SCANCODE_MINUS: keynum = '-'; break;
case SDL_SCANCODE_TAB: keynum = K_TAB; break;
case SDL_SCANCODE_RETURN: keynum = K_ENTER; break;
case SDL_SCANCODE_ESCAPE: keynum = K_ESCAPE; break;
case SDL_SCANCODE_SPACE: keynum = K_SPACE; break;
case SDL_SCANCODE_BACKSPACE: keynum = K_BACKSPACE; break;
case SDL_SCANCODE_UP: keynum = K_UPARROW; break;
case SDL_SCANCODE_LEFT: keynum = K_LEFTARROW; break;
case SDL_SCANCODE_DOWN: keynum = K_DOWNARROW; break;
case SDL_SCANCODE_RIGHT: keynum = K_RIGHTARROW; break;
case SDL_SCANCODE_LALT:
case SDL_SCANCODE_RALT: keynum = K_ALT; break;
case SDL_SCANCODE_LCTRL:
case SDL_SCANCODE_RCTRL: keynum = K_CTRL; break;
case SDL_SCANCODE_LSHIFT:
case SDL_SCANCODE_RSHIFT: keynum = K_SHIFT; break;
case SDL_SCANCODE_LGUI:
case SDL_SCANCODE_RGUI: keynum = K_WIN; break;
case SDL_SCANCODE_INSERT: keynum = K_INS; break;
case SDL_SCANCODE_DELETE: keynum = K_DEL; break;
case SDL_SCANCODE_PAGEDOWN: keynum = K_PGDN; break;
case SDL_SCANCODE_PAGEUP: keynum = K_PGUP; break;
case SDL_SCANCODE_HOME: keynum = K_HOME; break;
case SDL_SCANCODE_END: keynum = K_END; break;
case SDL_SCANCODE_KP_1: keynum = numLock ? '1' : K_KP_END; break;
case SDL_SCANCODE_KP_2: keynum = numLock ? '2' : K_KP_DOWNARROW; break;
case SDL_SCANCODE_KP_3: keynum = numLock ? '3' : K_KP_PGDN; break;
case SDL_SCANCODE_KP_4: keynum = numLock ? '4' : K_KP_LEFTARROW; break;
case SDL_SCANCODE_KP_5: keynum = numLock ? '5' : K_KP_5; break;
case SDL_SCANCODE_KP_6: keynum = numLock ? '6' : K_KP_RIGHTARROW; break;
case SDL_SCANCODE_KP_7: keynum = numLock ? '7' : K_KP_HOME; break;
case SDL_SCANCODE_KP_8: keynum = numLock ? '8' : K_KP_UPARROW; break;
case SDL_SCANCODE_KP_9: keynum = numLock ? '9' : K_KP_PGUP; break;
case SDL_SCANCODE_KP_0: keynum = numLock ? '0' : K_KP_INS; break;
case SDL_SCANCODE_KP_PERIOD: keynum = K_KP_DEL; break;
case SDL_SCANCODE_KP_ENTER: keynum = K_KP_ENTER; break;
case SDL_SCANCODE_KP_PLUS: keynum = K_KP_PLUS; break;
case SDL_SCANCODE_KP_MINUS: keynum = K_KP_MINUS; break;
case SDL_SCANCODE_KP_DIVIDE: keynum = K_KP_SLASH; break;
case SDL_SCANCODE_KP_MULTIPLY: keynum = '*'; break;
case SDL_SCANCODE_NUMLOCKCLEAR: keynum = K_KP_NUMLOCK; break;
case SDL_SCANCODE_CAPSLOCK: keynum = K_CAPSLOCK; break;
case SDL_SCANCODE_SLASH: keynum = '/'; break;
case SDL_SCANCODE_PERIOD: keynum = '.'; break;
case SDL_SCANCODE_SEMICOLON: keynum = ';'; break;
case SDL_SCANCODE_APOSTROPHE: keynum = '\''; break;
case SDL_SCANCODE_COMMA: keynum = ','; break;
case SDL_SCANCODE_PRINTSCREEN:
{
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
break;
}
case SDL_SCANCODE_UNKNOWN:
{
if( down ) Con_Reportf( "%s: Unknown scancode\n", __func__ );
return;
}
default:
if( down ) Con_Reportf( "%s: Unknown key: %s = %i\n", __func__, SDL_GetScancodeName( keynum ), keynum );
return;
}
}
#undef DECLARE_KEY_RANGE
Key_Event( keynum, down );
}
/*
=============
SDLash_MouseEvent
=============
*/
static void SDLash_MouseEvent( SDL_MouseButtonEvent button )
{
int down;
if( button.state == SDL_RELEASED )
down = 0;
else
down = 1;
switch( button.button )
{
case SDL_BUTTON_LEFT:
IN_MouseEvent( 0, down );
break;
case SDL_BUTTON_RIGHT:
IN_MouseEvent( 1, down );
break;
case SDL_BUTTON_MIDDLE:
IN_MouseEvent( 2, down );
break;
case SDL_BUTTON_X1:
IN_MouseEvent( 3, down );
break;
case SDL_BUTTON_X2:
IN_MouseEvent( 4, down );
break;
case SDL_BUTTON_WHEELUP:
IN_MWheelEvent( -1 );
break;
case SDL_BUTTON_WHEELDOWN:
IN_MWheelEvent( 1 );
break;
default:
Con_Printf( "Unknown mouse button ID: %d\n", button.button );
}
}
static void SDLash_ActiveEvent( int gain )
{
if( gain )
{
host.status = HOST_FRAME;
if( cls.key_dest == key_game )
IN_ActivateMouse( );
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
if( vid_fullscreen.value == WINDOW_MODE_FULLSCREEN )
VID_SetMode();
}
else
{
host.status = HOST_NOFOCUS;
if( cls.key_dest == key_game )
{
Key_ClearStates();
IN_DeactivateMouse();
}
host.force_draw_version_time = host.realtime + 2.0;
VID_RestoreScreenResolution();
}
}
/*
=============
SDLash_EventFilter
=============
*/
static void SDLash_EventHandler( SDL_Event *event )
{
switch ( event->type )
{
/* Mouse events */
case SDL_MOUSEMOTION:
if( host.mouse_visible )
SDL_GetRelativeMouseState( NULL, NULL );
break;
case SDL_MOUSEBUTTONUP:
case SDL_MOUSEBUTTONDOWN:
SDLash_MouseEvent( event->button );
break;
/* Keyboard events */
case SDL_KEYDOWN:
case SDL_KEYUP:
SDLash_KeyEvent( event->key );
break;
case SDL_QUIT:
Sys_Quit( "caught SDL_QUIT" );
break;
case SDL_VIDEORESIZE:
VID_SaveWindowSize( event->resize.w, event->resize.h, false );
break;
case SDL_ACTIVEEVENT:
SDLash_ActiveEvent( event->active.gain );
break;
}
}
/*
=============
SDLash_RunEvents
=============
*/
void Platform_RunEvents( void )
{
SDL_Event event;
while( host.status != HOST_CRASHED && !host.shutdown_issued && SDL_PollEvent( &event ) )
SDLash_EventHandler( &event );
}
/*
========================
Platform_PreCreateMove
this should disable mouse look on client when m_ignore enabled
TODO: kill mouse in win32 clients too
========================
*/
void Platform_PreCreateMove( void )
{
if( m_ignore.value )
{
SDL_GetRelativeMouseState( NULL, NULL );
SDL_ShowCursor( SDL_TRUE );
}
}
+156
View File
@@ -0,0 +1,156 @@
/*
in_sdl1.c - SDL input component
Copyright (C) 2018-2025 a1batross
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 <SDL.h>
#include "common.h"
#include "keydefs.h"
#include "input.h"
#include "client.h"
#include "vgui_draw.h"
#include "platform_sdl1.h"
#include "sound.h"
#include "vid_common.h"
#define SDL_WarpMouseInWindow( win, x, y ) SDL_WarpMouse( ( x ), ( y ) )
/*
=============
Platform_GetMousePos
=============
*/
void GAME_EXPORT Platform_GetMousePos( int *x, int *y )
{
SDL_GetMouseState( x, y );
if( x && window_width.value && window_width.value != refState.width )
{
float factor = refState.width / window_width.value;
*x = *x * factor;
}
if( y && window_height.value && window_height.value != refState.height )
{
float factor = refState.height / window_height.value;
*y = *y * factor;
}
}
/*
=============
Platform_SetMousePos
============
*/
void GAME_EXPORT Platform_SetMousePos( int x, int y )
{
SDL_WarpMouseInWindow( host.hWnd, x, y );
}
/*
========================
Platform_MouseMove
========================
*/
void Platform_MouseMove( float *x, float *y )
{
int m_x, m_y;
SDL_GetRelativeMouseState( &m_x, &m_y );
*x = (float)m_x;
*y = (float)m_y;
}
/*
=============
Platform_GetClipobardText
=============
*/
int Platform_GetClipboardText( char *buffer, size_t size )
{
buffer[0] = 0;
return 0;
}
/*
=============
Platform_SetClipobardText
=============
*/
void Platform_SetClipboardText( const char *buffer )
{
}
/*
=============
Platform_EnableTextInput
=============
*/
void Platform_EnableTextInput( qboolean enable )
{
}
/*
========================
Platform_SetCursorType
========================
*/
void Platform_SetCursorType( VGUI_DefaultCursor type )
{
qboolean visible;
switch( type )
{
case dc_user:
case dc_none:
visible = false;
break;
default:
visible = true;
break;
}
// never disable cursor in touch emulation mode
if( !visible && Touch_WantVisibleCursor( ))
return;
host.mouse_visible = visible;
VGui_UpdateInternalCursorState( type );
if( host.mouse_visible )
{
SDL_ShowCursor( true );
}
else
{
SDL_ShowCursor( false );
}
}
/*
========================
Platform_GetKeyModifiers
========================
*/
key_modifier_t Platform_GetKeyModifiers( void )
{
return KeyModifier_None;
}
+36
View File
@@ -0,0 +1,36 @@
/*
joy_sdl1.c - SDL gamepads
Copyright (C) 2018-2025 a1batross
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 "platform.h"
void Platform_CalibrateGamepadGyro( void )
{
}
void Platform_Vibrate2( float time, int val1, int val2, uint flags )
{
}
void Platform_Vibrate( float time, char flags )
{
}
int Platform_JoyInit( void )
{
return 0;
}
void Platform_JoyShutdown( void )
{
}
+37
View File
@@ -0,0 +1,37 @@
/*
platform_sdl1.h - SDL backend internal header
Copyright (C) 2015-2018 a1batross
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.
*/
#pragma once
#ifndef KEYWRAPPER_H
#define KEYWRAPPER_H
#ifdef XASH_SDL
#include "platform.h"
// window management
void VID_RestoreScreenResolution( void );
qboolean VID_CreateWindow( int width, int height, window_mode_t window_mode );
void VID_DestroyWindow( void );
void GL_InitExtensions( void );
qboolean GL_DeleteContext( void );
void VID_SaveWindowSize( int width, int height, qboolean maximized );
//
// joy_sdl.c
//
void SDLash_HandleGameControllerEvent( SDL_Event *ev );
#endif // XASH_SDL
#endif // KEYWRAPPER_H
+268
View File
@@ -0,0 +1,268 @@
/*
s_sdl1.c - sound hardware output
Copyright (C) 2009 Uncle Mike
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 "common.h"
#include "platform.h"
#if XASH_SOUND == SOUND_SDL
#include "sound.h"
#include "voice.h"
#include <SDL.h>
#include <stdlib.h>
#define SAMPLE_16BIT_SHIFT 1
#define SECONDARY_BUFFER_SIZE 0x10000
#define SDL_GetCurrentAudioDriver() "legacysdl"
#define SDL_OpenAudioDevice( a, b, c, d, e ) SDL_OpenAudio( ( c ), ( d ) )
#define SDL_CloseAudioDevice( a ) SDL_CloseAudio()
#define SDL_PauseAudioDevice( a, b ) SDL_PauseAudio( ( b ) )
#define SDL_LockAudioDevice( x ) SDL_LockAudio()
#define SDL_UnlockAudioDevice( x ) SDL_UnlockAudio()
#define SDLash_IsAudioError( x ) (( x ) != 0)
/*
=======================================================================
Global variables. Must be visible to window-procedure function
so it can unlock and free the data block after it has been played.
=======================================================================
*/
static int sdl_dev;
static char sdl_backend_name[32];
static void SDL_SoundCallback( void *userdata, Uint8 *stream, int len )
{
const int size = dma.samples << 1;
int pos;
int wrapped;
if( !dma.buffer )
{
memset( stream, 0, len );
return;
}
pos = dma.samplepos << 1;
if( pos >= size )
pos = dma.samplepos = 0;
wrapped = pos + len - size;
if( wrapped < 0 )
{
memcpy( stream, dma.buffer + pos, len );
dma.samplepos += len >> 1;
}
else
{
int remaining = size - pos;
memcpy( stream, dma.buffer + pos, remaining );
memcpy( stream + remaining, dma.buffer, wrapped );
dma.samplepos = wrapped >> 1;
}
if( dma.samplepos >= size )
dma.samplepos = 0;
}
/*
==================
SNDDMA_Init
Try to find a sound device to mix for.
Returns false if nothing is found.
==================
*/
qboolean SNDDMA_Init( void )
{
SDL_AudioSpec desired, obtained;
int samplecount;
const char *driver = NULL;
// reinitialize SDL with our driver just in case
if( SDL_WasInit( SDL_INIT_AUDIO ))
SDL_QuitSubSystem( SDL_INIT_AUDIO );
if( SDL_InitSubSystem( SDL_INIT_AUDIO ))
{
Con_Reportf( S_ERROR "Audio: SDL: %s \n", SDL_GetError( ) );
return false;
}
memset( &desired, 0, sizeof( desired ) );
desired.freq = SOUND_DMA_SPEED;
desired.format = AUDIO_S16LSB;
desired.samples = 1024;
desired.channels = 2;
desired.callback = SDL_SoundCallback;
sdl_dev = SDL_OpenAudioDevice( NULL, 0, &desired, &obtained, 0 );
if( SDLash_IsAudioError( sdl_dev ))
{
Con_Printf( "Couldn't open SDL audio: %s\n", SDL_GetError( ) );
return false;
}
if( obtained.format != AUDIO_S16LSB )
{
Con_Printf( "SDL audio format %d unsupported.\n", obtained.format );
goto fail;
}
if( obtained.channels != 1 && obtained.channels != 2 )
{
Con_Printf( "SDL audio channels %d unsupported.\n", obtained.channels );
goto fail;
}
dma.format.speed = obtained.freq;
dma.format.channels = obtained.channels;
dma.format.width = 2;
samplecount = s_samplecount.value;
if( !samplecount )
samplecount = 0x8000;
dma.samples = samplecount * obtained.channels;
dma.buffer = Mem_Calloc( sndpool, dma.samples * 2 );
dma.samplepos = 0;
Con_Printf( "Using SDL audio driver: %s @ %d Hz\n", SDL_GetCurrentAudioDriver( ), obtained.freq );
Q_snprintf( sdl_backend_name, sizeof( sdl_backend_name ), "SDL" );
dma.initialized = true;
dma.backendName = sdl_backend_name;
SNDDMA_Activate( true );
return true;
fail:
SNDDMA_Shutdown( );
return false;
}
/*
==============
SNDDMA_BeginPainting
Makes sure dma.buffer is valid
===============
*/
void SNDDMA_BeginPainting( void )
{
SDL_LockAudioDevice( sdl_dev );
}
/*
==============
SNDDMA_Submit
Send sound to device if buffer isn't really the dma buffer
Also unlocks the dsound buffer
===============
*/
void SNDDMA_Submit( void )
{
SDL_UnlockAudioDevice( sdl_dev );
}
/*
==============
SNDDMA_Shutdown
Reset the sound device for exiting
===============
*/
void SNDDMA_Shutdown( void )
{
Con_Printf( "Shutting down audio.\n" );
dma.initialized = false;
if( sdl_dev )
{
SNDDMA_Activate( false );
SDL_CloseAudioDevice( sdl_dev );
}
if( SDL_WasInit( SDL_INIT_AUDIO ))
SDL_QuitSubSystem( SDL_INIT_AUDIO );
if( dma.buffer )
{
Mem_Free( dma.buffer );
dma.buffer = NULL;
}
}
/*
===========
SNDDMA_Activate
Called when the main window gains or loses focus.
The window have been destroyed and recreated
between a deactivate and an activate.
===========
*/
void SNDDMA_Activate( qboolean active )
{
if( !dma.initialized )
return;
SDL_PauseAudioDevice( sdl_dev, !active );
}
/*
===========
VoiceCapture_Init
===========
*/
qboolean VoiceCapture_Init( void )
{
return false;
}
/*
===========
VoiceCapture_Activate
===========
*/
qboolean VoiceCapture_Activate( qboolean activate )
{
return false;
}
/*
===========
VoiceCapture_Lock
===========
*/
qboolean VoiceCapture_Lock( qboolean lock )
{
return false;
}
/*
==========
VoiceCapture_Shutdown
==========
*/
void VoiceCapture_Shutdown( void )
{
}
#endif // XASH_SOUND == SOUND_SDL
+61
View File
@@ -0,0 +1,61 @@
/*
sys_sdl1.c - SDL1 system utils
Copyright (C) 2018 a1batross
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 <SDL.h>
#include "platform.h"
#include "platform_sdl1.h"
#if XASH_TIMER == TIMER_SDL
double Platform_DoubleTime( void )
{
static Uint64 g_PerformanceFrequency;
static Uint64 g_ClockStart;
Uint64 CurrentTime;
if( !g_PerformanceFrequency )
{
g_PerformanceFrequency = SDL_GetPerformanceFrequency();
g_ClockStart = SDL_GetPerformanceCounter();
}
CurrentTime = SDL_GetPerformanceCounter();
return (double)( CurrentTime - g_ClockStart ) / (double)( g_PerformanceFrequency );
}
void Platform_Sleep( int msec )
{
SDL_Delay( msec );
}
#endif // XASH_TIMER == TIMER_SDL
#if XASH_MESSAGEBOX == MSGBOX_SDL
void Platform_MessageBox( const char *title, const char *message, qboolean parentMainWindow )
{
SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR, title, message, parentMainWindow ? host.hWnd : NULL );
}
#endif // XASH_MESSAGEBOX == MSGBOX_SDL
void SDLash_Init( const char *basedir )
{
if( SDL_Init( SDL_INIT_TIMER | SDL_INIT_VIDEO ))
{
Sys_Warn( "SDL_Init failed: %s", SDL_GetError() );
host.type = HOST_DEDICATED;
}
}
void SDLash_Shutdown( void )
{
SDL_Quit();
}
+525
View File
@@ -0,0 +1,525 @@
/*
vid_sdl1.c - SDL vid component
Copyright (C) 2018 a1batross
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 <SDL.h>
#include "common.h"
#include "client.h"
#include "vid_common.h"
#include "platform_sdl1.h"
static vidmode_t *vidmodes = NULL;
static int num_vidmodes = 0;
static void GL_SetupAttributes( void );
struct
{
int prev_width, prev_height;
} sdlState = { 640, 480 };
struct
{
int width, height;
SDL_Surface *surf;
SDL_Surface *win;
} sw;
qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *r, uint *g, uint *b )
{
sw.width = width;
sw.height = height;
sw.win = SDL_GetVideoSurface();
// sdl will create renderer if hw framebuffer unavailiable, so cannot fallback here
// if it is failed, it is not possible to draw with SDL in REF_SOFTWARE mode
if( !sw.win )
{
Sys_Warn( "failed to initialize software output, try running with -glblit flag" );
return false;
}
*bpp = sw.win->format->BytesPerPixel;
*r = sw.win->format->Rmask;
*g = sw.win->format->Gmask;
*b = sw.win->format->Bmask;
*stride = sw.win->pitch / sw.win->format->BytesPerPixel;
return true;
}
void *SW_LockBuffer( void )
{
sw.win = SDL_GetVideoSurface();
// prevent buffer overrun
if( !sw.win || sw.win->w < sw.width || sw.win->h < sw.height )
return NULL;
// real window pixels (x11 shm region, dma buffer, etc)
// or SDL_Renderer texture if not supported
SDL_LockSurface( sw.win );
return sw.win->pixels;
}
void SW_UnlockBuffer( void )
{
// already blitted
SDL_UnlockSurface( sw.win );
SDL_Flip( host.hWnd );
}
int R_MaxVideoModes( void )
{
return num_vidmodes;
}
vidmode_t *R_GetVideoMode( int num )
{
if( !vidmodes || num < 0 || num >= R_MaxVideoModes() )
{
return NULL;
}
return vidmodes + num;
}
static void R_InitVideoModes( void )
{
char buf[MAX_VA_STRING];
SDL_Rect **modes;
int len = 0, i = 0, j;
modes = SDL_ListModes( NULL, SDL_FULLSCREEN );
if( !modes || modes == (void*)-1 )
return;
for( len = 0; modes[len]; len++ );
vidmodes = Mem_Malloc( host.mempool, len * sizeof( vidmode_t ) );
// from smallest to largest
for( ; i < len; i++ )
{
SDL_Rect *mode = modes[len - i - 1];
for( j = 0; j < num_vidmodes; j++ )
{
if( mode->w == vidmodes[j].width &&
mode->h == vidmodes[j].height )
{
break;
}
}
if( j != num_vidmodes )
continue;
vidmodes[num_vidmodes].width = mode->w;
vidmodes[num_vidmodes].height = mode->h;
Q_snprintf( buf, sizeof( buf ), "%ix%i", mode->w, mode->h );
vidmodes[num_vidmodes].desc = copystring( buf );
num_vidmodes++;
}
}
static void R_FreeVideoModes( void )
{
int i;
if( !vidmodes )
return;
for( i = 0; i < num_vidmodes; i++ )
Mem_Free( (char*)vidmodes[i].desc );
Mem_Free( vidmodes );
vidmodes = NULL;
}
/*
=================
GL_GetProcAddress
=================
*/
void *GL_GetProcAddress( const char *name )
{
void *func = SDL_GL_GetProcAddress( name );
if( !func )
Con_Reportf( S_ERROR "%s failed for %s\n", __func__, name );
return func;
}
/*
===============
GL_UpdateSwapInterval
===============
*/
void GL_UpdateSwapInterval( void )
{
}
/*
=================
GL_DeleteContext
always return false
=================
*/
qboolean GL_DeleteContext( void )
{
return false;
}
/*
=================
GL_CreateContext
=================
*/
static qboolean GL_CreateContext( void )
{
return true;
}
/*
=================
GL_UpdateContext
=================
*/
static qboolean GL_UpdateContext( void )
{
return true;
}
void VID_SaveWindowSize( int width, int height, qboolean maximized )
{
int render_w = width, render_h = height;
VID_SetDisplayTransform( &render_w, &render_h );
R_SaveVideoMode( width, height, render_w, render_h, maximized );
}
static qboolean VID_SetScreenResolution( int width, int height, window_mode_t window_mode )
{
VID_SaveWindowSize( width, height, true );
return true;
}
void VID_RestoreScreenResolution( void )
{
}
static qboolean VID_CreateWindowWithSafeGL( const char *wndname, int xpos, int ypos, int w, int h, uint32_t flags )
{
while( glw_state.safe >= SAFE_NO && glw_state.safe < SAFE_LAST )
{
host.hWnd = sw.surf = SDL_SetVideoMode( w, h, 16, flags );
// we have window, exit loop
if( host.hWnd )
break;
Con_Reportf( S_ERROR "%s: couldn't create '%s' with safegl level %d: %s\n", __func__, wndname, glw_state.safe, SDL_GetError());
glw_state.safe++;
if( !gl_msaa_samples.value && glw_state.safe == SAFE_NOMSAA )
glw_state.safe++; // no need to skip msaa, if we already disabled it
GL_SetupAttributes(); // re-choose attributes
// try again create window
}
// window creation has failed...
if( glw_state.safe >= SAFE_LAST )
return false;
return true;
}
static qboolean RectFitsInDisplay( const SDL_Rect *rect, const SDL_Rect *display )
{
return rect->x >= display->x
&& rect->y >= display->y
&& rect->x + rect->w <= display->x + display->w
&& rect->y + rect->h <= display->y + display->h;
}
// Function to check if the rectangle fits in any display
static qboolean RectFitsInAnyDisplay( const SDL_Rect *rect, const SDL_Rect *display_rects, int num_displays )
{
for( int i = 0; i < num_displays; i++ )
{
if( RectFitsInDisplay( rect, &display_rects[i] ))
return true; // Rectangle fits in this display
}
return false; // Rectangle does not fit in any display
}
/*
=================
VID_CreateWindow
=================
*/
qboolean VID_CreateWindow( int width, int height, window_mode_t window_mode )
{
string wndname;
Uint32 flags = 0;
Q_strncpy( wndname, GI->title, sizeof( wndname ));
if( window_mode != WINDOW_MODE_WINDOWED )
SetBits( flags, SDL_FULLSCREEN|SDL_HWSURFACE );
if( !glw_state.software )
SetBits( flags, SDL_OPENGL );
if( !VID_CreateWindowWithSafeGL( wndname, 0, 0, width, height, flags ))
return false;
VID_SaveWindowSize( width, height, false );
return true;
}
/*
=================
VID_DestroyWindow
=================
*/
void VID_DestroyWindow( void )
{
GL_DeleteContext();
VID_RestoreScreenResolution();
if( host.hWnd )
host.hWnd = NULL;
if( refState.fullScreen )
refState.fullScreen = false;
}
/*
==================
GL_SetupAttributes
==================
*/
static void GL_SetupAttributes( void )
{
ref.dllFuncs.GL_SetupAttributes( glw_state.safe );
}
void GL_SwapBuffers( void )
{
SDL_Flip( host.hWnd );
}
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 );
#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 );
#undef MAP_REF_API_ATTRIBUTE_TO_SDL
}
return 0;
}
/*
==================
R_Init_Video
==================
*/
qboolean R_Init_Video( const int type )
{
string safe;
qboolean retval;
refState.desktopBitsPixel = 16;
switch( type )
{
case REF_SOFTWARE:
glw_state.software = true;
break;
case REF_GL:
if( !glw_state.safe && Sys_GetParmFromCmdLine( "-safegl", safe ) )
glw_state.safe = bound( SAFE_NO, Q_atoi( safe ), SAFE_DONTCARE );
// refdll can request some attributes
GL_SetupAttributes( );
if( SDL_GL_LoadLibrary( NULL ) < 0 )
{
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;
}
if( !(retval = VID_SetMode()) )
{
return retval;
}
switch( type )
{
case REF_GL:
// refdll also can check extensions
ref.dllFuncs.GL_InitExtensions();
break;
case REF_SOFTWARE:
default:
break;
}
R_InitVideoModes();
host.renderinfo_changed = false;
return true;
}
rserr_t R_ChangeDisplaySettings( int width, int height, window_mode_t window_mode )
{
refState.fullScreen = window_mode != WINDOW_MODE_WINDOWED;
Con_Reportf( "%s: Setting video mode to %dx%d %s\n", __func__, width, height, refState.fullScreen ? "fullscreen" : "windowed" );
if( !host.hWnd )
{
if( !VID_CreateWindow( width, height, window_mode ))
return rserr_invalid_mode;
}
else if( refState.fullScreen )
{
if( !VID_SetScreenResolution( width, height, window_mode ))
return rserr_invalid_fullscreen;
}
else
{
VID_RestoreScreenResolution();
VID_SaveWindowSize( width, height, true );
}
return rserr_ok;
}
/*
==================
VID_SetMode
Set the described video mode
==================
*/
qboolean VID_SetMode( void )
{
int iScreenWidth, iScreenHeight;
rserr_t err;
window_mode_t window_mode;
iScreenWidth = Cvar_VariableInteger( "width" );
iScreenHeight = Cvar_VariableInteger( "height" );
if( iScreenWidth < VID_MIN_WIDTH ||
iScreenHeight < VID_MIN_HEIGHT ) // trying to get resolution automatically by default
{
iScreenWidth = 320;
iScreenHeight = 240;
}
window_mode = bound( 0, vid_fullscreen.value, WINDOW_MODE_COUNT - 1 );
SetBits( gl_vsync.flags, FCVAR_CHANGED );
if(( err = R_ChangeDisplaySettings( iScreenWidth, iScreenHeight, window_mode )) == rserr_ok )
{
sdlState.prev_width = iScreenWidth;
sdlState.prev_height = iScreenHeight;
}
else
{
if( err == rserr_invalid_fullscreen )
{
Cvar_DirectSet( &vid_fullscreen, "0" );
Con_Reportf( S_ERROR "%s: fullscreen unavailable in this mode\n", __func__ );
Sys_Warn( "fullscreen unavailable in this mode!" );
if(( err = R_ChangeDisplaySettings( iScreenWidth, iScreenHeight, WINDOW_MODE_WINDOWED )) == rserr_ok )
return true;
}
else if( err == rserr_invalid_mode )
{
Con_Reportf( S_ERROR "%s: invalid mode\n", __func__ );
Sys_Warn( "invalid mode, engine will run in %dx%d", sdlState.prev_width, sdlState.prev_height );
}
// try setting it back to something safe
if(( err = R_ChangeDisplaySettings( sdlState.prev_width, sdlState.prev_height, WINDOW_MODE_WINDOWED )) != rserr_ok )
{
Con_Reportf( S_ERROR "%s: could not revert to safe mode\n", __func__ );
Sys_Warn( "could not revert to safe mode!" );
return false;
}
}
return true;
}
/*
==================
R_Free_Video
==================
*/
void R_Free_Video( void )
{
GL_DeleteContext ();
VID_DestroyWindow ();
R_FreeVideoModes();
ref.dllFuncs.GL_ClearExtensions();
}