Compare commits

...

12 Commits

Author SHA1 Message Date
Alibek Omarov
6c2eb83516 engine: host: add message when native game libraries weren't found but libraries for x86 windows, linux or macos were, telling that the mod probably require custom logic code 2026-04-03 04:29:38 +05:00
Alibek Omarov
b67b261ddb engine: platform: add Platform_LibraryExists and implement it for iOS and generally for everything else with FS_FileExists 2026-04-03 04:28:40 +05:00
Alibek Omarov
8e450d869b engine: common: add host.default_gamedir containing gamedir passed to us from game launcher 2026-04-03 04:09:25 +05:00
Alibek Omarov
e8ef7ad60c engine: server: throw Host_Error when game tries to call precache model with invalid argument, like GoldSrc 2026-04-03 01:43:23 +05:00
Alibek Omarov
216eedcdcd ref: gl: better wording about backface culling goldsrc bug [skip ci] 2026-04-03 01:28:04 +05:00
Alibek Omarov
fd55716633 ref: gl: change backface culling only if it wasn't disabled by mod developer beforehand 2026-04-03 01:23:55 +05:00
Alibek Omarov
0b920be381 engine: client: delay freeing up the sound channel when it becomes inaudible 2026-04-03 00:03:52 +05:00
Alibek Omarov
e6dfccb6ba engine: reorganize common.h header 2026-04-02 20:45:00 +05:00
Alibek Omarov
3129081050 engine: fix a typo USING_ASAN -> USE_ASAN 2026-04-02 02:16:50 +05:00
Alibek Omarov
00dac928c9 ref: replace checking PARM_QUAKE_COMPATIBLE with direct check of feature flag set 2026-04-02 02:13:27 +05:00
Alibek Omarov
3726256514 engine: simplify IsQuakeCompatible by enforcing QUAKE_COMPATIBLE feature flag when Quake demo starts 2026-04-02 02:11:40 +05:00
Alibek Omarov
5eb43505cb engine: platform: try to fix build on 32-bit arm in debug builds (r7 is used by frame pointer, so we push it into stack before using for a syscall) 2026-04-02 02:02:59 +05:00
22 changed files with 320 additions and 163 deletions

View File

@@ -213,6 +213,7 @@ static void CL_ParseQuakeServerInfo( sizebuf_t *msg )
clgame.maxEntities = bound( 600, clgame.maxEntities, MAX_EDICTS );
clgame.maxModels = MAX_MODELS;
Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), sizeof( clgame.maptitle ));
Host_ValidateEngineFeatures( ENGINE_FEATURES_MASK, ENGINE_QUAKE_COMPATIBLE );
// Re-init hud video, especially if we changed game directories
clgame.dllFuncs.pfnVidInit();

View File

@@ -521,7 +521,7 @@ static int S_AlterChannel( int entnum, int channel, const sfx_t *sfx, int vol, i
S_SpatializeChannel
=================
*/
static void S_SpatializeChannel( int *left_vol, int *right_vol, int master_vol, float dot, float dist )
static void S_SpatializeChannel( short *left_vol, short *right_vol, int master_vol, float dot, float dist )
{
float scale;

View File

@@ -284,13 +284,20 @@ static int S_MixNormalChannels( portable_samplepair_t *dst, int end, int rate )
// if the sound is unaudible, skip it
// if it's also not looping, free it
if( ch->leftvol < 8 && ch->rightvol < 8 )
{
{
if( !FBitSet( sc->flags, SOUND_LOOPED ) || !ch->use_loop )
S_FreeChannel( ch );
{
if( ch->inauduble_free_time == 0.0f )
ch->inauduble_free_time = host.realtime + MAX_CHANNEL_INAUDIBLE_TIME;
else if( ch->inauduble_free_time > host.realtime )
S_FreeChannel( ch );
}
continue;
}
ch->inauduble_free_time = 0.0f;
if( rate != sc->rate )
continue;

View File

@@ -85,9 +85,9 @@ typedef struct
typedef struct rawchan_s
{
int entnum;
int master_vol;
int leftvol; // 0-255 left volume
int rightvol; // 0-255 right volume
short master_vol;
short leftvol; // 0-255 left volume
short rightvol; // 0-255 right volume
float dist_mult; // distance multiplier (attenuation/clipK)
vec3_t origin; // only use if fixed_origin is set
volatile uint s_rawend;
@@ -101,14 +101,15 @@ typedef struct channel_s
char name[16]; // keep sentence name
sfx_t *sfx; // sfx number
int leftvol; // 0-255 left volume
int rightvol; // 0-255 right volume
vec3_t origin; // only use if fixed_origin is set
float dist_mult; // distance multiplier (attenuation/clipK)
int entnum; // entity soundsource
int entchannel; // sound channel (CHAN_STREAM, CHAN_VOICE, etc.)
vec3_t origin; // only use if fixed_origin is set
float dist_mult; // distance multiplier (attenuation/clipK)
int master_vol; // 0-255 master volume
short master_vol; // 0-255 master volume
short leftvol; // 0-255 left volume
short rightvol; // 0-255 right volume
short basePitch; // base pitch percent (100% is normal pitch playback)
byte use_loop : 1; // don't loop default and local sounds
byte staticsound : 1; // use origin instead of fetching entnum's origin
byte localsound : 1; // it's a local menu sound (not looped, not paused)
@@ -116,11 +117,15 @@ typedef struct channel_s
byte sentence_finished : 1; // if set, finished playing sentence
byte finished : 1; // if set, finished playing single word
byte word_index;
short basePitch; // base pitch percent (100% is normal pitch playback)
voxword_t words[CVOXWORDMAX];
// HACKHACK: count when this channel became inaudible
// to not free it when it could be respatialized soon
#define MAX_CHANNEL_INAUDIBLE_TIME 0.1f
float inauduble_free_time;
double sample;
double forced_end;
wavdata_t *data;
voxword_t words[CVOXWORDMAX];
} channel_t;
typedef struct

View File

@@ -961,7 +961,7 @@ static void Test_LZSS( void )
};
const char decompressed[] = "Do you like what you see?";
#ifdef USING_ASAN
#ifdef USE_ASAN
ASAN_POISON_MEMORY_REGION( poison1, sizeof( poison1 ));
ASAN_POISON_MEMORY_REGION( poison2, sizeof( poison2 ));
ASAN_POISON_MEMORY_REGION( poison3, sizeof( poison3 ));

View File

@@ -16,42 +16,48 @@ GNU General Public License for more details.
#ifndef COMMON_H
#define COMMON_H
#ifdef __cplusplus
extern "C" {
#endif
/*
===================================================================================================================================
Legend:
INTERNAL RESOURCE - function contain hardcoded path to resource that engine required (optional in most cases)
OBSOLETE, UNUSED - this function no longer used and leaved here for keep binary compatibility
TODO - some functionality not impemented but planned
FIXME - code doesn't working properly in some rare cases
HACKHACK - unexpected behavior on some input params (or something like)
BUGBUG - code doesn't working properly in most cases!
TESTTEST - this code may be unstable and needs to be more tested
g-cont: - notes from engine author
XASH SPECIFIC - sort of hack that works only in Xash3D not in GoldSrc
===================================================================================================================================
*/
#include "port.h"
#include "backends.h"
#include "defaults.h"
#include <stdio.h>
#include <stdlib.h> // rand, adbs
#include <stdarg.h> // va
#include "build.h"
#if !XASH_WIN32
#include <stddef.h> // size_t
#else
#include <sys/types.h> // off_t
#endif
#include "port.h"
#include "backends.h"
#include "defaults.h"
#include "library_suffix.h"
#include "enginefeatures.h"
#include "system.h"
#include "com_model.h"
#include "com_strings.h"
#include "crtlib.h"
#include "cvar.h"
#include "con_nprint.h"
#include "crclib.h"
#include "ref_api.h"
#include "com_image.h"
/*
===================================================================================================================================
Legend:
INTERNAL RESOURCE - function contain hardcoded path to resource that engine required (optional in most cases)
OBSOLETE, UNUSED - this function no longer used and leaved here for keep binary compatibility
TODO - some functionality not impemented but planned
FIXME - code doesn't working properly in some rare cases
HACKHACK - unexpected behavior on some input params (or something like)
BUGBUG - code doesn't working properly in most cases!
TESTTEST - this code may be unstable and needs to be more tested
g-cont: - notes from engine author
XASH SPECIFIC - sort of hack that works only in Xash3D not in GoldSrc
===================================================================================================================================
*/
// configuration
@@ -60,21 +66,19 @@ XASH SPECIFIC - sort of hack that works only in Xash3D not in GoldSrc
//
#if XASH_TIMER == TIMER_NULL
#error "Please select timer backend"
#endif
#endif // XASH_TIMER == TIMER_NULL
#if !XASH_DEDICATED
#if XASH_VIDEO == VIDEO_NULL
#error "Please select video backend"
#endif
#endif
#endif // XASH_VIDEO == VIDEO_NULL
#endif // !XASH_DEDICATED
#ifndef XASH_SDL
#if XASH_TIMER == TIMER_SDL || XASH_VIDEO == VIDEO_SDL || XASH_SOUND == SOUND_SDL || XASH_INPUT == INPUT_SDL
#error "SDL backends without XASH_SDL not allowed"
#endif
#endif
#if XASH_TIMER == TIMER_SDL || XASH_VIDEO == VIDEO_SDL || XASH_SOUND == SOUND_SDL || XASH_INPUT == INPUT_SDL
#error "SDL backends without XASH_SDL not allowed"
#endif // XASH_TIMER == TIMER_SDL || XASH_VIDEO == VIDEO_SDL || XASH_SOUND == SOUND_SDL || XASH_INPUT == INPUT_SDL
#endif // XASH_SDL
#define HACKS_RELATED_HLMODS // some HL-mods works differently under Xash and can't be fixed without some hacks at least at current time
@@ -97,19 +101,6 @@ typedef enum instance_e
#define Host_IsDedicated() ( host.type == HOST_DEDICATED )
#endif
#include "system.h"
#include "com_model.h"
#include "com_strings.h"
#include "crtlib.h"
#define FSCALLBACK_OVERRIDE_OPEN
#define FSCALLBACK_OVERRIDE_LOADFILE
#define FSCALLBACK_OVERRIDE_MALLOC_LIKE
#include "fscallback.h"
#include "cvar.h"
#include "con_nprint.h"
#include "crclib.h"
#include "ref_api.h"
// PERFORMANCE INFO
#define MIN_FPS 20.0f // host minimum fps value for maxfps.
#define MAX_FPS_SOFT 200.0f // soft limit for maxfps.
@@ -351,6 +342,9 @@ typedef struct host_parm_s
string gamedll;
string clientlib;
string menulib;
// default game directory, passed to us from game launcher
string default_gamedir;
} host_parm_t;
extern host_parm_t host;
@@ -396,7 +390,7 @@ void Mem_Stats_f( void );
//
// filesystem_engine.c
//
void FS_Init( const char *basedir );
void FS_Init( void );
void FS_Shutdown( void );
void *FS_GetNativeObject( const char *obj );
int FS_Close( file_t *file );
@@ -480,7 +474,6 @@ void Cmd_Escape( char *newCommand, const char *oldCommand, int len );
//
// imagelib
//
#include "com_image.h"
void Image_Setup( void );
void Image_Init( void );
@@ -564,7 +557,11 @@ qboolean Sound_SupportedFileFormat( const char *fileext );
//
typedef void( *pfnChangeGame )( const char *progname );
qboolean Host_IsQuakeCompatible( void );
static inline qboolean Host_IsQuakeCompatible( void )
{
return FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ) ? true : false;
}
void Host_ShutdownWithReason( const char *reason );
int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGame, pfnChangeGame func );
void Host_EndGame( qboolean abort, const char *message, ... ) FORMAT_CHECK( 2 );
@@ -934,7 +931,4 @@ void SoundList_Shutdown( void );
#error "common.h in ref_dll"
#endif
#ifdef __cplusplus
}
#endif
#endif//COMMON_H

View File

@@ -328,7 +328,7 @@ static qboolean FS_DetermineReadOnlyRootDirectory( char *out, size_t size )
FS_Init
================
*/
void FS_Init( const char *basedir )
void FS_Init( void )
{
string gamedir;
char rodir[MAX_OSPATH], rootdir[MAX_OSPATH];
@@ -352,7 +352,7 @@ void FS_Init( const char *basedir )
if( env )
Q_strncpy( gamedir, env, sizeof( gamedir ));
else
Q_strncpy( gamedir, basedir, sizeof( gamedir )); // gamedir == basedir
Q_strncpy( gamedir, host.default_gamedir, sizeof( gamedir )); // gamedir == basedir
}
FS_LoadProgs();
@@ -364,7 +364,7 @@ void FS_Init( const char *basedir )
// and this better be reworked at some point
g_fsapi.SetCurrentDirectory( rootdir );
if( !g_fsapi.InitStdio( true, rootdir, basedir, gamedir, rodir ))
if( !g_fsapi.InitStdio( true, rootdir, host.default_gamedir, gamedir, rodir ))
{
Sys_Error( "Can't init filesystem_stdio!\n" );
return;

View File

@@ -36,6 +36,8 @@ GNU General Public License for more details.
#include "enginefeatures.h"
#include "render_api.h" // decallist_t
#include "tests.h"
#include "library.h"
#include "platform/platform.h"
host_parm_t host; // host parms
static jmp_buf return_from_main_buf;
@@ -296,27 +298,6 @@ void Host_ValidateEngineFeatures( uint32_t mask, uint32_t features )
host.features = features;
}
/*
==============
Host_IsQuakeCompatible
==============
*/
qboolean Host_IsQuakeCompatible( void )
{
// feature set
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
return true;
#if !XASH_DEDICATED
// quake demo playing
if( cls.demoplayback == DEMO_QUAKE1 )
return true;
#endif // XASH_DEDICATED
return false;
}
/*
================
Host_EndGame
@@ -882,6 +863,118 @@ static void Host_DetermineExecutableName( char *out, size_t size )
#endif
}
static qboolean Host_CollectX86Libraries( ECommonLibraryType lib_type,
const char *win_path, const char *lin_path, const char *osx_path,
char *found, size_t found_size )
{
string native_path;
qboolean has_any = false;
found[0] = 0;
COM_GetCommonLibraryPath( lib_type, native_path, sizeof( native_path ));
if( Platform_LibraryExists( native_path, true ))
return 0;
#if !( XASH_WIN32 && XASH_X86 )
if( !COM_StringEmpty( win_path ) && FS_FileExists( win_path, true ))
{
Q_strncat( found, "Windows (x86)", found_size );
has_any = true;
}
#endif
#if !( XASH_LINUX && !XASH_ANDROID && XASH_X86 )
if( !COM_StringEmpty( lin_path ) && FS_FileExists( lin_path, true ))
{
if( has_any )
Q_strncat( found, ", ", found_size );
Q_strncat( found, "GNU/Linux (x86)", found_size );
has_any = true;
}
#endif
#if !( XASH_APPLE && XASH_X86 )
if( !COM_StringEmpty( osx_path ) && FS_FileExists( osx_path, true ))
{
if( has_any )
Q_strncat( found, ", ", found_size );
Q_strncat( found, "macOS (x86)", found_size );
has_any = true;
}
#endif
return has_any;
}
static void Host_CheckGameLibraries( void )
{
// on Android, game libraries are loaded from APKs and are invisible to FS_FileExists,
// so the check cannot work there; iOS is handled via Platform_LibraryExists -> IOS_LibraryExists
#if !defined( XASH_INTERNAL_GAMELIBS ) && !XASH_ANDROID
struct
{
const char *name;
ECommonLibraryType type;
const char *override; // host.gamedll / host.clientlib / host.menulib
} libs[3] = {
{ "client", LIBRARY_CLIENT, host.clientlib },
{ "server", LIBRARY_SERVER, host.gamedll },
{ "menu", LIBRARY_GAMEUI, host.menulib },
};
char details[MAX_VA_STRING];
details[0] = 0;
for( int i = 0; i < ARRAYSIZE( libs ); i++ )
{
string found;
qboolean ret;
// if the user explicitly set a library path, trust them and skip the check
if( !COM_StringEmpty( libs[i].override ))
continue;
if( libs[i].type == LIBRARY_SERVER )
{
// missing server library is only critical when singleplayer is available
// mirrors silent mode in SV_InitGame
if( GI->gamemode != GAME_SINGLEPLAYER_ONLY )
continue;
ret = Host_CollectX86Libraries( libs[i].type,
GI->game_dll, GI->game_dll_linux, GI->game_dll_osx,
found, sizeof( found ));
}
else
{
string win, lin, osx;
Q_snprintf( win, sizeof( win ), "%s/%s.dll", GI->dll_path, libs[i].name );
Q_snprintf( lin, sizeof( lin ), "%s/%s.so", GI->dll_path, libs[i].name );
Q_snprintf( osx, sizeof( osx ), "%s/%s.dylib", GI->dll_path, libs[i].name );
ret = Host_CollectX86Libraries( libs[i].type,
win, lin, osx, found, sizeof( found ));
}
if( ret )
{
size_t len = Q_strlen( details );
Q_snprintf( details + len, sizeof( details ) - len, "- %s: %s\n", libs[i].name, found );
}
}
if( COM_StringEmpty( details ))
return;
Sys_Warn( "No native game libraries found for current platform (%s-%s),\n"
"but found libraries for other platforms:\n"
"%s"
"The game may fail to load or work incorrectly.\n"
"Consider using a mod version built for this platform.",
Q_buildos(), Q_buildarch(), details );
#endif // XASH_INTERNAL_GAMELIBS
}
/*
=================
Host_InitCommon
@@ -913,6 +1006,7 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
host.config_executed = false;
host.status = HOST_INIT; // initialzation started
host.type = HOST_DEDICATED; // predict state
Q_strncpy( host.default_gamedir, basedir, sizeof( host.default_gamedir ));
#ifndef XASH_DEDICATED
if( !Sys_CheckParm( "-dedicated" ))
@@ -985,8 +1079,8 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
#if XASH_DEDICATED
Platform_SetupSigtermHandling();
#endif
Platform_Init( Host_IsDedicated( ) || developer >= DEV_EXTENDED, basedir );
FS_Init( basedir );
Platform_Init( Host_IsDedicated( ) || developer >= DEV_EXTENDED );
FS_Init();
// print current developer level to simplify processing users feedback
if( developer > 0 )
@@ -1018,6 +1112,7 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
#endif
FS_LoadGameInfo();
Host_CheckGameLibraries();
Cvar_PostFSInit();
Image_CheckPaletteQ1 ();

View File

@@ -21,9 +21,6 @@
#include <sys/stat.h>
#include "dlfcn.h"
#ifndef XASH_GAMEDIR
#define XASH_GAMEDIR "valve" // !!! Replace with your default (base) game directory !!!
#endif
#define XASHLIB "@rpath/libxash.dylib"
@@ -331,4 +328,4 @@ int IOS_GetArgs( char ***out )
{
*out = szArgv;
return szArgc;
}
}

View File

@@ -13,63 +13,83 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include <string.h>
#include <unistd.h>
#include <SDL.h>
#include <dlfcn.h>
#include <sys/stat.h>
#include "crtlib.h"
#include "fscallback.h"
#include "library.h"
#include "platform/ios/lib_ios.h"
#include <dlfcn.h>
#include "common.h"
#define EXT_LENGTH 5
const char *g_szLibrarySuffix;
static void *IOS_LoadLibraryInternal( const char *dllname )
{
void *pHandle;
string errorstring = "";
char path[MAX_SYSPATH];
Q_snprintf( path, MAX_SYSPATH, "%s%s", SDL_GetBasePath(), dllname );
Q_snprintf( path, sizeof( path ), "%s%s", SDL_GetBasePath(), dllname );
pHandle = dlopen( path, RTLD_LAZY );
if( !pHandle )
{
COM_PushLibraryError(errorstring);
COM_PushLibraryError(dlerror());
}
COM_PushLibraryError(dlerror( ));
return pHandle;
}
const char *g_szLibrarySuffix;
static qboolean IOS_LibraryExistsInternal( const char *name )
{
struct stat buf;
char path[MAX_SYSPATH];
Q_snprintf( path, sizeof( path ), "%s%s", SDL_GetBasePath(), name );
return stat( path, &buf ) == 0;
}
static const char *IOS_GetLibraryPostfix( void )
{
if( g_szLibrarySuffix )
return g_szLibrarySuffix;
return Q_strcmp( host.default_gamedir, FS_Gamedir( )) ? FS_Gamedir( ) : "";
}
static void IOS_PrepareGameLibraryPath( const char *dllname, char *out, size_t outsize )
{
string strippedname;
Q_strncpy( strippedname, dllname, sizeof( strippedname ));
COM_StripExtension( strippedname );
Q_snprintf( out, outsize, "%s_%s.dylib", strippedname, IOS_GetLibraryPostfix( ));
}
void *IOS_LoadLibrary( const char *dllname )
{
//Immediately load if the library is filesystem_stdio.dylib or we will crash when accessing gamedir
if ( !Q_strcmp( dllname, "filesystem_stdio.dylib" ) )
{
// filesystem_stdio is a special case, as engine won't work correctly without it
// but it's always located at known path
if( !Q_strcmp( dllname, "filesystem_stdio.dylib" ))
return IOS_LoadLibraryInternal( dllname );
}
string name;
string strippedname;
const char *postfix = g_szLibrarySuffix;
char *pHandle;
if( !postfix )
{
if ( Q_strcmp(FS_Gamedir(), "valve" ) )
{
postfix = FS_Gamedir( );
}
else postfix = "";
}
Q_strncpy( strippedname, dllname, sizeof( strippedname ) );
COM_StripExtension(strippedname);
Q_snprintf( name, MAX_STRING, "%s_%s.dylib", strippedname, postfix );
IOS_PrepareGameLibraryPath( dllname, name, sizeof( name ));
pHandle = IOS_LoadLibraryInternal( name );
if( pHandle )
return pHandle;
if( !pHandle )
pHandle = IOS_LoadLibraryInternal( dllname );
return IOS_LoadLibraryInternal( dllname );
return pHandle;
}
qboolean IOS_LibraryExists( const char *dllname )
{
string name;
IOS_PrepareGameLibraryPath( dllname, name, sizeof( name ));
return IOS_LibraryExistsInternal( name ) || IOS_LibraryExistsInternal( dllname );
}

View File

@@ -20,6 +20,7 @@ GNU General Public License for more details.
#define Platform_POSIX_LoadLibrary( x ) IOS_LoadLibrary(( x ))
void *IOS_LoadLibrary( const char *dllname );
qboolean IOS_LibraryExists( const char *name );
#endif // IOS_LIB_H
#endif // TARGET_OS_IPHONE

View File

@@ -66,10 +66,15 @@ qboolean Platform_DebuggerPresent( void )
tracer_pid = (const byte*)Q_strstr( buf, TracerPid );
if( !tracer_pid )
return false;
//printf( "%s\n", tracer_pid );
while( *tracer_pid < '0' || *tracer_pid > '9' )
while(( *tracer_pid < '0' ) || ( *tracer_pid > '9' ))
{
if( *tracer_pid++ == '\n' )
return false;
}
//printf( "%s\n", tracer_pid );
return !!Q_atoi( (const char*)tracer_pid );
}

View File

@@ -18,6 +18,8 @@ GNU General Public License for more details.
#define PLATFORM_H
#include <errno.h>
#define FSCALLBACK_OVERRIDE_MALLOC_LIKE
#include "fscallback.h"
#include "common.h"
#include "system.h"
#include "defaults.h"
@@ -43,6 +45,7 @@ qboolean Platform_DebuggerPresent( void );
int IOS_GetArgs( char ***argv );
const char *IOS_GetDocsDir( void );
void IOS_LaunchDialog( void );
#include "platform/ios/lib_ios.h"
#endif // TARGET_OS_IOS
#if XASH_WIN32 || XASH_LINUX
@@ -58,7 +61,7 @@ char *Posix_Input( void );
#endif
#if XASH_SDL
void SDLash_Init( const char *basedir );
void SDLash_Init( void );
void SDLash_Shutdown( void );
void SDLash_NanoSleep( int nsec );
#endif
@@ -111,7 +114,7 @@ void Linux_SetTimer( float time );
int Linux_GetProcessID( void );
#endif
static inline void Platform_Init( qboolean con_showalways, const char *basedir )
static inline void Platform_Init( qboolean con_showalways )
{
#if XASH_POSIX
// daemonize as early as possible, because we need to close our file descriptors
@@ -119,7 +122,7 @@ static inline void Platform_Init( qboolean con_showalways, const char *basedir )
#endif
#if XASH_SDL
SDLash_Init( basedir );
SDLash_Init( );
#endif
#if XASH_ANDROID
@@ -207,6 +210,18 @@ static inline void Sys_RestoreCrashHandler( void )
}
#endif
static inline qboolean Platform_LibraryExists( const char *name, qboolean gamedironly )
{
#if XASH_IOS
return IOS_LibraryExists( name );
#elif XASH_ANDROID
// sorry, unimplemented
return false;
#else
return g_fsapi.FileExists( name, gamedironly );
#endif
}
/*
==============================================================================
@@ -389,14 +404,16 @@ qboolean VoiceCapture_Lock( qboolean lock );
pid_t raise_tid = Linux_GetProcessID(); \
int raise_sig = (x); \
__asm__ volatile ( \
"push {r7}\n\t" \
"mov r7,#268\n\t" \
"mov r0,%0\n\t" \
"mov r1,%1\n\t" \
"mov r2,%2\n\t" \
"svc 0\n\t" \
"pop {r7}\n\t" \
: \
: "r"(raise_pid), "r"(raise_tid), "r"(raise_sig) \
: "r0", "r1", "r2", "r7", "memory" \
: "r0", "r1", "r2", "memory" \
); \
} while( 0 )
#define INLINE_NANOSLEEP1() do \
@@ -404,13 +421,15 @@ qboolean VoiceCapture_Lock( qboolean lock );
struct timespec ns_t1 = {1, 0}; \
struct timespec ns_t2 = {0, 0}; \
__asm__ volatile ( \
"push {r7}\n\t" \
"mov r7,#162\n\t" \
"mov r0,%0\n\t" \
"mov r1,%1\n\t" \
"svc 0\n\t" \
"pop {r7}\n\t" \
: \
: "r"(&ns_t1), "r"(&ns_t2) \
: "r0", "r1", "r7", "memory" \
: "r0", "r1", "memory" \
); \
} while( 0 )
#elif XASH_LINUX && XASH_ARM && XASH_64BIT

View File

@@ -79,20 +79,23 @@ static void SDLCALL SDLash_LogOutputFunction( void *userdata, int category, SDL_
case SDL_LOG_PRIORITY_INFO:
str = S_NOTE;
break;
default:
str = "";
break;
}
Con_Reportf( "%s" S_BLUE "SDL" S_DEFAULT ": [%s] %s\n", str, SDLash_CategoryToString( category ), message );
}
void SDLash_Init( const char *basedir )
void SDLash_Init( void )
{
#if XASH_APPLE
#if XASH_IOS
char *path = SDL_GetBasePath();
if( path != NULL )
{
char buf[MAX_VA_STRING];
Q_snprintf( buf, sizeof( buf ), "%s%s/extras.pk3", path, basedir );
Q_snprintf( buf, sizeof( buf ), "%s%s/extras.pk3", path, host.default_gamedir );
setenv( "XASH3D_EXTRAS_PAK1", buf, true );
}
#endif

View File

@@ -1284,6 +1284,12 @@ static int GAME_EXPORT pfnPrecacheModel( const char *s )
qboolean optional = false;
int i;
if( COM_StringEmptyOrNULL( s ))
{
Host_Error( "%s: NULL pointer or empty string as model name\n", __func__ );
return 0;
}
if( *s == '!' )
{
optional = true;

View File

@@ -27,9 +27,6 @@ extern fs_globals_t *FI;
#define FS_Gamedir() GI->gamefolder
#define FS_Title() GI->title
#define FS_InitStdio (*g_fsapi.InitStdio)
#define FS_ShutdownStdio (*g_fsapi.ShutdownStdio)
// search path utils
#define FS_Rescan (*g_fsapi.Rescan)
#define FS_ClearSearchPath (*g_fsapi.ClearSearchPath)

View File

@@ -86,7 +86,7 @@ static qboolean Mod_LooksLikeWaterTexture( const char *name )
if(( name[0] == '*' && Q_stricmp( name, REF_DEFAULT_TEXTURE )) || name[0] == '!' )
return true;
if( !ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ))
if( !FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ))
{
if( !Q_strncmp( name, "water", 5 ) || !Q_strnicmp( name, "laser", 5 ))
return true;

View File

@@ -837,7 +837,7 @@ static byte *GL_ApplyFilter( const byte *source, int width, int height )
byte *out = (byte *)source;
int i;
if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ) || glConfig.max_multisamples > 1 )
if( FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ) || glConfig.max_multisamples > 1 )
return in;
for( i = 0; source && i < width * height; i++, in += 4 )

View File

@@ -345,7 +345,7 @@ void R_SetupFrustum( void )
{
const ref_overview_t *ov = gEngfuncs.GetOverviewParms();
if( RP_NORMALPASS() && ( ENGINE_GET_PARM( PARM_WATER_LEVEL ) >= 3 ) && ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ))
if( RP_NORMALPASS() && FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ) && ( ENGINE_GET_PARM( PARM_WATER_LEVEL ) >= 3 ))
{
RI.fov_x = atan( tan( DEG2RAD( RI.fov_x ) / 2 ) * ( 0.97f + sin( gp_cl->time * 1.5f ) * 0.03f )) * 2 / (M_PI_F / 180.0f);
RI.fov_y = atan( tan( DEG2RAD( RI.fov_y ) / 2 ) * ( 1.03f - sin( gp_cl->time * 1.5f ) * 0.03f )) * 2 / (M_PI_F / 180.0f);
@@ -696,7 +696,7 @@ static void R_CheckFog( void )
int i, cnt, count;
// quake global fog
if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ))
if( FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ))
{
if( !tr.movevars->fog_settings )
{
@@ -824,9 +824,7 @@ void R_DrawFog( void )
return;
pglEnable( GL_FOG );
if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ))
pglFogi( GL_FOG_MODE, GL_EXP2 );
else pglFogi( GL_FOG_MODE, GL_EXP );
pglFogi( GL_FOG_MODE, FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ) ? GL_EXP2 : GL_EXP );
pglFogf( GL_FOG_DENSITY, RI.fogDensity );
pglFogfv( GL_FOG_COLOR, RI.fogColor );
pglHint( GL_FOG_HINT, GL_NICEST );

View File

@@ -888,7 +888,7 @@ static void DrawGLPoly( glpoly2_t *p, float xScale, float yScale )
float flRate, flAngle, sy, cy;
gl_texture_t *texture;
if( e == CL_GetEntityByIndex( 0 ) && ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ))
if( e == CL_GetEntityByIndex( 0 ) && FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ))
{
// same as doom speed
flConveyorSpeed = -35.0f;
@@ -1461,7 +1461,7 @@ static void R_DrawTextureChains( void )
continue; // draw translucent water later
}
if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ) && FBitSet( s->flags, SURF_TRANSPARENT ))
if( FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ) && FBitSet( s->flags, SURF_TRANSPARENT ))
{
R_AddToSeparatePass( &draw_alpha_surfaces, i );
continue; // draw transparent surfaces later
@@ -1642,7 +1642,7 @@ static void R_SetRenderMode( cl_entity_t *e )
case kRenderTransAlpha:
pglEnable( GL_ALPHA_TEST );
pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ))
if( FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ))
{
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
pglColor4f( 1.0f, 1.0f, 1.0f, tr.blend );
@@ -1667,7 +1667,7 @@ static void R_SetRenderMode( cl_entity_t *e )
static int R_SortBrushModelSurfaces( cl_entity_t *e, model_t *clmodel, vec3_t mins )
{
qboolean quake_compatible = ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE );
qboolean quake_compatible = FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ) ? true : false;
int num_sorted = 0;
for( int i = 0; i < clmodel->nummodelsurfaces; i++ )
@@ -1766,7 +1766,7 @@ void R_DrawBrushModel( cl_entity_t *e )
VectorSubtract( RI.cullorigin, e->origin, tr.modelorg );
}
if( ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ) && FBitSet( clmodel->flags, MODEL_TRANSPARENT ))
if( FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ) && FBitSet( clmodel->flags, MODEL_TRANSPARENT ))
e->curstate.rendermode = kRenderTransAlpha;
e->visframe = tr.realframecount; // visible

View File

@@ -2340,15 +2340,24 @@ static void R_StudioDrawPoints( void )
pstudionorms = (vec3_t *)((byte *)m_pStudioHeader + m_pSubModel->normindex);
// backface culling for left-handed weapons
if( R_AllowFlipViewModel( RI.currententity ))
//
// there is a bug in GoldSrc that sets backface culling to GL_FRONT
// but doesn't enable OpenGL GL_CULL_FACE. This allows mod developers to disable
// backface culling through TriAPI call
//
// see https://github.com/FWGS/xash3d-fwgs/issues/2517
if( glState.faceCull != GL_NONE )
{
tr.fFlipViewModel = true;
GL_Cull( GL_NONE );
}
else
{
tr.fFlipViewModel = false;
GL_Cull( GL_FRONT );
if( R_AllowFlipViewModel( RI.currententity ))
{
tr.fFlipViewModel = true;
GL_Cull( GL_NONE );
}
else
{
tr.fFlipViewModel = false;
GL_Cull( GL_FRONT );
}
}
for( j = 0; j < m_pSubModel->nummesh; j++ )

View File

@@ -359,7 +359,7 @@ void R_DrawSolidClippedSubmodelPolygons( model_t *pmodel, mnode_t *topnode )
for( i = 0; i < numsurfaces; i++, psurf++ )
{
if( FBitSet( psurf->flags, SURF_DRAWTURB ) && !ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ))
if( FBitSet( psurf->flags, SURF_DRAWTURB ) && !FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ))
{
if( psurf->plane->type != PLANE_Z && !FBitSet( RI.currententity->curstate.effects, EF_WATERSIDES ))
continue;
@@ -441,7 +441,7 @@ void R_DrawSubmodelPolygons( model_t *pmodel, int clipflags, mnode_t *topnode )
for( i = 0; i < numsurfaces; i++, psurf++ )
{
if( FBitSet( psurf->flags, SURF_DRAWTURB ) && !ENGINE_GET_PARM( PARM_QUAKE_COMPATIBLE ))
if( FBitSet( psurf->flags, SURF_DRAWTURB ) && !FBitSet( gp_host->features, ENGINE_QUAKE_COMPATIBLE ))
{
if( psurf->plane->type != PLANE_Z && !FBitSet( RI.currententity->curstate.effects, EF_WATERSIDES ))
continue;