mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-06 12:25:00 +08:00
engine: platform: sdl3: add system and input SDL3 platform implementation
This commit is contained in:
@@ -58,6 +58,7 @@ char *Posix_Input( void );
|
||||
#if XASH_SDL
|
||||
void SDLash_Init( const char *basedir );
|
||||
void SDLash_Shutdown( void );
|
||||
void SDLash_NanoSleep( int nsec );
|
||||
#endif
|
||||
|
||||
#if XASH_ANDROID
|
||||
@@ -171,9 +172,11 @@ static inline void Platform_SetupSigtermHandling( void )
|
||||
|
||||
static inline qboolean Platform_NanoSleep( int nsec )
|
||||
{
|
||||
#if XASH_SDL == 3
|
||||
SDLash_NanoSleep( nsec );
|
||||
return true;
|
||||
// SDL2 doesn't have nanosleep, so use low-level functions here
|
||||
// When this code will be ported to SDL3, use SDL_DelayNS
|
||||
#if XASH_POSIX
|
||||
#elif XASH_POSIX
|
||||
struct timespec ts = {
|
||||
.tv_sec = 0,
|
||||
.tv_nsec = nsec, // just don't put large numbers here
|
||||
|
||||
215
engine/platform/sdl3/in_sdl3.c
Normal file
215
engine/platform/sdl3/in_sdl3.c
Normal file
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
platform_sdl3.h - SDL3 platform definitions
|
||||
Copyright (C) 2025 Er2off
|
||||
Copyright (C) 2025 Alibek Omarov
|
||||
|
||||
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_sdl3.h"
|
||||
#include "eiface.h" // ARRAYSIZE
|
||||
#include "vid_common.h" // window_{width,height}
|
||||
#include "client.h" // refState
|
||||
#include "input.h" // Touch_WantVisibleCursor
|
||||
#include "vgui_draw.h" // VGui_UpdateInternalCursorState
|
||||
|
||||
static struct
|
||||
{
|
||||
qboolean initialized;
|
||||
SDL_Cursor *cursors[dc_last];
|
||||
} cursors;
|
||||
|
||||
static struct
|
||||
{
|
||||
float x, y;
|
||||
qboolean pushed;
|
||||
} in_visible_cursor_pos;
|
||||
|
||||
void SDLash_InitCursors( void )
|
||||
{
|
||||
if( cursors.initialized )
|
||||
SDLash_FreeCursors();
|
||||
|
||||
// load up all default cursors
|
||||
cursors.cursors[dc_none] = NULL;
|
||||
cursors.cursors[dc_arrow] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_DEFAULT );
|
||||
cursors.cursors[dc_ibeam] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_TEXT );
|
||||
cursors.cursors[dc_hourglass] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_WAIT );
|
||||
cursors.cursors[dc_crosshair] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_CROSSHAIR );
|
||||
cursors.cursors[dc_up] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_DEFAULT );
|
||||
cursors.cursors[dc_sizenwse] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_NWSE_RESIZE );
|
||||
cursors.cursors[dc_sizenesw] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_NESW_RESIZE );
|
||||
cursors.cursors[dc_sizewe] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_EW_RESIZE );
|
||||
cursors.cursors[dc_sizens] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_NS_RESIZE );
|
||||
cursors.cursors[dc_sizeall] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_MOVE );
|
||||
cursors.cursors[dc_no] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_NOT_ALLOWED );
|
||||
cursors.cursors[dc_hand] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_POINTER );
|
||||
cursors.initialized = true;
|
||||
}
|
||||
|
||||
void SDLash_FreeCursors( void )
|
||||
{
|
||||
if( !cursors.initialized )
|
||||
return;
|
||||
|
||||
for( int i = 0; i < ARRAYSIZE( cursors.cursors ); i++ )
|
||||
{
|
||||
if( cursors.cursors[i] )
|
||||
{
|
||||
SDL_DestroyCursor( cursors.cursors[i] );
|
||||
cursors.cursors[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
cursors.initialized = false;
|
||||
}
|
||||
|
||||
qboolean Platform_GetMouseGrab( void )
|
||||
{
|
||||
return SDL_GetWindowMouseGrab( host.hWnd );
|
||||
}
|
||||
|
||||
void Platform_SetMouseGrab( qboolean enable )
|
||||
{
|
||||
SDL_SetWindowMouseGrab( host.hWnd, enable );
|
||||
}
|
||||
|
||||
void Platform_MouseMove( float *x, float *y )
|
||||
{
|
||||
SDL_GetRelativeMouseState( x, y );
|
||||
}
|
||||
|
||||
void GAME_EXPORT Platform_SetMousePos( int x, int y )
|
||||
{
|
||||
SDL_WarpMouseInWindow( host.hWnd, x, y );
|
||||
}
|
||||
|
||||
void GAME_EXPORT Platform_GetMousePos( int *x, int *y )
|
||||
{
|
||||
float m_x = 0.0f, m_y = 0.0f;
|
||||
|
||||
SDL_GetMouseState( &m_x, &m_y );
|
||||
|
||||
if( x )
|
||||
{
|
||||
if( window_width.value && window_width.value != refState.width )
|
||||
{
|
||||
float factor = refState.width / window_width.value;
|
||||
*x = m_x * factor;
|
||||
}
|
||||
else *x = m_x;
|
||||
}
|
||||
|
||||
if( y )
|
||||
{
|
||||
if( window_height.value && window_height.value != refState.height )
|
||||
{
|
||||
float factor = refState.height / window_height.value;
|
||||
*y = m_y * factor;
|
||||
}
|
||||
else *y = m_y;
|
||||
}
|
||||
}
|
||||
|
||||
void Platform_SetCursorType( VGUI_DefaultCursor type )
|
||||
{
|
||||
qboolean visible = type != dc_user && type != dc_none;
|
||||
|
||||
// never disable cursor in touch emulation mode
|
||||
if( !visible && Touch_WantVisibleCursor( ))
|
||||
return;
|
||||
|
||||
host.mouse_visible = visible;
|
||||
VGui_UpdateInternalCursorState( type );
|
||||
|
||||
if( visible )
|
||||
{
|
||||
if( cursors.initialized )
|
||||
SDL_SetCursor( cursors.cursors[type] );
|
||||
|
||||
SDL_ShowCursor();
|
||||
|
||||
// restore the last mouse position
|
||||
if( in_visible_cursor_pos.pushed )
|
||||
{
|
||||
SDL_WarpMouseInWindow( host.hWnd, in_visible_cursor_pos.x, in_visible_cursor_pos.y );
|
||||
in_visible_cursor_pos.pushed = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// save last mouse position and warp it to the center
|
||||
if( !in_visible_cursor_pos.pushed )
|
||||
{
|
||||
SDL_GetMouseState( &in_visible_cursor_pos.x, &in_visible_cursor_pos.y );
|
||||
SDL_WarpMouseInWindow( host.hWnd, host.window_center_x, host.window_center_y );
|
||||
in_visible_cursor_pos.pushed = true;
|
||||
}
|
||||
|
||||
SDL_HideCursor();
|
||||
}
|
||||
}
|
||||
|
||||
void Platform_EnableTextInput( qboolean enable )
|
||||
{
|
||||
enable ? SDL_StartTextInput( host.hWnd ) : SDL_StopTextInput( host.hWnd );
|
||||
}
|
||||
|
||||
int Platform_GetClipboardText( char *buffer, size_t size )
|
||||
{
|
||||
int len;
|
||||
char *text = SDL_GetClipboardText();
|
||||
|
||||
if( !text )
|
||||
return 0;
|
||||
|
||||
if( buffer && size > 0 )
|
||||
len = Q_strncpy( buffer, text, size );
|
||||
else
|
||||
len = Q_strlen( text );
|
||||
|
||||
SDL_free( text );
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void Platform_SetClipboardText( const char *buffer )
|
||||
{
|
||||
SDL_SetClipboardText( buffer );
|
||||
}
|
||||
|
||||
key_modifier_t Platform_GetKeyModifiers( void )
|
||||
{
|
||||
SDL_Keymod mod_flags = SDL_GetModState();
|
||||
key_modifier_t result_flags = KeyModifier_None;
|
||||
|
||||
if( FBitSet( mod_flags, SDL_KMOD_LCTRL ))
|
||||
SetBits( result_flags, KeyModifier_LeftCtrl );
|
||||
if( FBitSet( mod_flags, SDL_KMOD_RCTRL ))
|
||||
SetBits( result_flags, KeyModifier_RightCtrl );
|
||||
if( FBitSet( mod_flags, SDL_KMOD_RSHIFT ))
|
||||
SetBits( result_flags, KeyModifier_RightShift );
|
||||
if( FBitSet( mod_flags, SDL_KMOD_LSHIFT ))
|
||||
SetBits( result_flags, KeyModifier_LeftShift );
|
||||
if( FBitSet( mod_flags, SDL_KMOD_LALT ))
|
||||
SetBits( result_flags, KeyModifier_LeftAlt );
|
||||
if( FBitSet( mod_flags, SDL_KMOD_RALT ))
|
||||
SetBits( result_flags, KeyModifier_RightAlt );
|
||||
if( FBitSet( mod_flags, SDL_KMOD_NUM ))
|
||||
SetBits( result_flags, KeyModifier_NumLock );
|
||||
if( FBitSet( mod_flags, SDL_KMOD_CAPS ))
|
||||
SetBits( result_flags, KeyModifier_CapsLock );
|
||||
if( FBitSet( mod_flags, SDL_KMOD_RGUI ))
|
||||
SetBits( result_flags, KeyModifier_RightSuper );
|
||||
if( FBitSet( mod_flags, SDL_KMOD_LGUI ))
|
||||
SetBits( result_flags, KeyModifier_LeftSuper );
|
||||
|
||||
return result_flags;
|
||||
}
|
||||
28
engine/platform/sdl3/platform_sdl3.h
Normal file
28
engine/platform/sdl3/platform_sdl3.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
platform_sdl3.h - SDL3 platform definitions
|
||||
Copyright (C) 2025 Er2off
|
||||
Copyright (C) 2025 Alibek Omarov
|
||||
|
||||
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.
|
||||
*/
|
||||
#ifndef PLATFORM_SDL3_H
|
||||
#define PLATFORM_SDL3_H
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include "platform/platform.h"
|
||||
|
||||
//
|
||||
// in_sdl3.c
|
||||
//
|
||||
void SDLash_InitCursors( void );
|
||||
void SDLash_FreeCursors( void );
|
||||
|
||||
#endif // PLATFORM_SDL3_H
|
||||
121
engine/platform/sdl3/sys_sdl3.c
Normal file
121
engine/platform/sdl3/sys_sdl3.c
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
platform_sdl3.h - SDL3 platform definitions
|
||||
Copyright (C) 2025 Er2off
|
||||
Copyright (C) 2025 Alibek Omarov
|
||||
|
||||
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_sdl3.h"
|
||||
#include "common.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();
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
void SDLash_NanoSleep( int nsec )
|
||||
{
|
||||
SDL_DelayNS( nsec );
|
||||
}
|
||||
|
||||
static const char *SDLash_CategoryToString( int category )
|
||||
{
|
||||
switch( category )
|
||||
{
|
||||
case SDL_LOG_CATEGORY_APPLICATION: return "App";
|
||||
case SDL_LOG_CATEGORY_ERROR: return "Error";
|
||||
case SDL_LOG_CATEGORY_ASSERT: return "Assert";
|
||||
case SDL_LOG_CATEGORY_SYSTEM: return "System";
|
||||
case SDL_LOG_CATEGORY_AUDIO: return "Audio";
|
||||
case SDL_LOG_CATEGORY_VIDEO: return "Video";
|
||||
case SDL_LOG_CATEGORY_RENDER: return "Render";
|
||||
case SDL_LOG_CATEGORY_INPUT: return "Input";
|
||||
case SDL_LOG_CATEGORY_TEST: return "Test";
|
||||
case SDL_LOG_CATEGORY_GPU: return "GPU";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static void SDLCALL SDLash_LogOutputFunction( void *userdata, int category, SDL_LogPriority priority, const char *message )
|
||||
{
|
||||
switch( priority )
|
||||
{
|
||||
case SDL_LOG_PRIORITY_CRITICAL:
|
||||
case SDL_LOG_PRIORITY_ERROR:
|
||||
Con_Printf( S_ERROR S_BLUE "SDL" S_DEFAULT ": [%s] %s\n", SDLash_CategoryToString( category ), message );
|
||||
break;
|
||||
case SDL_LOG_PRIORITY_WARN:
|
||||
Con_DPrintf( S_WARN S_BLUE "SDL" S_DEFAULT ": [%s] %s\n", SDLash_CategoryToString( category ), message );
|
||||
break;
|
||||
case SDL_LOG_PRIORITY_INFO:
|
||||
Con_Reportf( S_NOTE S_BLUE "SDL" S_DEFAULT ": [%s] %s\n", SDLash_CategoryToString( category ), message );
|
||||
break;
|
||||
default:
|
||||
Con_Reportf( S_BLUE "SDL" S_DEFAULT ": [%s] %s\n", SDLash_CategoryToString( category ), message );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SDLash_Init( const char *basedir )
|
||||
{
|
||||
SDL_SetLogOutputFunction( SDLash_LogOutputFunction, NULL );
|
||||
|
||||
if( host_developer.value >= 2 )
|
||||
SDL_SetLogPriorities( SDL_LOG_PRIORITY_VERBOSE );
|
||||
else if( host_developer.value >= 1 )
|
||||
SDL_SetLogPriorities( SDL_LOG_PRIORITY_WARN );
|
||||
else
|
||||
SDL_SetLogPriorities( SDL_LOG_PRIORITY_ERROR );
|
||||
|
||||
if( !SDL_Init( SDL_INIT_VIDEO | SDL_INIT_EVENTS ))
|
||||
{
|
||||
Sys_Warn( "SDL_Init failed: %s", SDL_GetError( ));
|
||||
host.type = HOST_DEDICATED;
|
||||
}
|
||||
|
||||
SDL_SetHint( SDL_HINT_MOUSE_TOUCH_EVENTS, "0" );
|
||||
SDL_SetHint( SDL_HINT_TOUCH_MOUSE_EVENTS, "0" );
|
||||
|
||||
SDLash_InitCursors();
|
||||
}
|
||||
|
||||
void SDLash_Shutdown( void )
|
||||
{
|
||||
SDLash_FreeCursors();
|
||||
SDL_Quit();
|
||||
}
|
||||
Reference in New Issue
Block a user