mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-05 19:45:05 +08:00
Compare commits
43 Commits
continuous
...
android-le
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38a3154de0 | ||
|
|
0442af7920 | ||
|
|
42958bc746 | ||
|
|
bd5309b018 | ||
|
|
26cbb1d6bf | ||
|
|
d6cfc65ac0 | ||
|
|
be9dda2a56 | ||
|
|
dbc54fb522 | ||
|
|
ec92d05930 | ||
|
|
892c735c86 | ||
|
|
93e5faa26b | ||
|
|
4953656ee0 | ||
|
|
96c367973a | ||
|
|
ffe1ff326a | ||
|
|
9c097976df | ||
|
|
6fec0398b6 | ||
|
|
abeb267420 | ||
|
|
9484effd4c | ||
|
|
a5f3fce665 | ||
|
|
91d9ca7810 | ||
|
|
0901fd94e2 | ||
|
|
0d18753adb | ||
|
|
7841382fef | ||
|
|
e21d8df1fe | ||
|
|
16aa2e919f | ||
|
|
88f76c6e1e | ||
|
|
1b9af8c515 | ||
|
|
55943ad1ce | ||
|
|
313f2a86b0 | ||
|
|
16eeaef35c | ||
|
|
46c82e89e1 | ||
|
|
bb55de5963 | ||
|
|
d423c437ed | ||
|
|
44b1a8e863 | ||
|
|
06c6371e69 | ||
|
|
7b4fd3bcad | ||
|
|
ea35863c26 | ||
|
|
c2e14eb3a3 | ||
|
|
34aab39f9b | ||
|
|
30c69d3ac8 | ||
|
|
bb9775048b | ||
|
|
eed13cf9f2 | ||
|
|
fbb91e547d |
15
.cirrus.yml
15
.cirrus.yml
@@ -1,3 +1,16 @@
|
||||
task:
|
||||
# Seems packages for it were removed from the mirrors
|
||||
# name: freebsd-12-amd64
|
||||
# freebsd_instance:
|
||||
# image_family: freebsd-12-4
|
||||
# setup_script:
|
||||
# - pkg update
|
||||
# - pkg install -y pkgconf git sdl2 python fontconfig opus
|
||||
# - git submodule update --init --recursive
|
||||
# test_script:
|
||||
# - ./scripts/cirrus/build_freebsd.sh dedicated
|
||||
# - ./scripts/cirrus/build_freebsd.sh full
|
||||
|
||||
task:
|
||||
name: freebsd-13-amd64
|
||||
freebsd_instance:
|
||||
@@ -13,7 +26,7 @@ task:
|
||||
task:
|
||||
name: freebsd-14-amd64
|
||||
freebsd_instance:
|
||||
image_family: freebsd-14-0
|
||||
image_family: freebsd-14-0-snap
|
||||
setup_script:
|
||||
- pkg update
|
||||
- pkg install -y pkgconf git sdl2 python fontconfig opus
|
||||
|
||||
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@@ -1 +0,0 @@
|
||||
custom: https://github.com/FWGS/xash3d-fwgs/blob/master/Documentation/donate.md
|
||||
2
3rdparty/mainui
vendored
2
3rdparty/mainui
vendored
Submodule 3rdparty/mainui updated: f5497ceb04...d75b7f4a57
@@ -1,21 +0,0 @@
|
||||
## Environment variables
|
||||
|
||||
#### Xash3D FWGS
|
||||
|
||||
The engine respects these environment variables:
|
||||
|
||||
| Variable | Type | Description |
|
||||
| --------------------- | ---------- | ----------- |
|
||||
| `XASH3D_GAME` | _string_ | Overrides default game directory. Ignored if `-game` command line argument is set |
|
||||
| `XASH3D_BASEDIR` | _string_ | Sets path to base (root) directory, instead of current working directory |
|
||||
| `XASH3D_RODIR` | _string_ | Sets path to read-only base (root) directory. Ignored if `-rodir` command line argument is set |
|
||||
| `XASH3D_EXTRAS_PAK1` | _string_ | Archive file from specified path will be added to virtual filesystem search path in the lowest possible priority |
|
||||
| `XASH3D_EXTRAS_PAK2` | _string_ | Similar to `XASH3D_EXTRAS_PAK1` but next to it in priority list |
|
||||
|
||||
Environment variables NOT listed in the table above are used internally, and aren't considered as stable interface.
|
||||
|
||||
#### mdldec
|
||||
|
||||
| Variable | Type | Description |
|
||||
| --------------------- | ---------- | ----------- |
|
||||
| `MDLDEC_ACT_PATH` | _string_ | If set, will read activities list from this path |
|
||||
@@ -18,17 +18,20 @@ GNU General Public License for more details.
|
||||
// video backends (XASH_VIDEO)
|
||||
#define VIDEO_NULL 0
|
||||
#define VIDEO_SDL 1
|
||||
#define VIDEO_ANDROID 2
|
||||
#define VIDEO_FBDEV 3
|
||||
#define VIDEO_DOS 4
|
||||
|
||||
// audio backends (XASH_SOUND)
|
||||
#define SOUND_NULL 0
|
||||
#define SOUND_SDL 1
|
||||
#define SOUND_OPENSLES 2
|
||||
#define SOUND_ALSA 3
|
||||
|
||||
// input (XASH_INPUT)
|
||||
#define INPUT_NULL 0
|
||||
#define INPUT_SDL 1
|
||||
#define INPUT_ANDROID 2
|
||||
#define INPUT_EVDEV 3
|
||||
|
||||
// timer (XASH_TIMER)
|
||||
@@ -41,6 +44,7 @@ GNU General Public License for more details.
|
||||
// messageboxes (XASH_MESSAGEBOX)
|
||||
#define MSGBOX_STDERR 0
|
||||
#define MSGBOX_SDL 1
|
||||
#define MSGBOX_ANDROID 2
|
||||
#define MSGBOX_WIN32 3
|
||||
#define MSGBOX_NSWITCH 4
|
||||
|
||||
|
||||
@@ -52,6 +52,25 @@ SETUP BACKENDS DEFINITIONS
|
||||
#endif
|
||||
#endif // XASH_MESSAGEBOX
|
||||
#endif
|
||||
#elif XASH_ANDROID
|
||||
// we are building for Android platform, use Android APIs
|
||||
#ifndef XASH_VIDEO
|
||||
#define XASH_VIDEO VIDEO_ANDROID
|
||||
#endif // XASH_VIDEO
|
||||
|
||||
#ifndef XASH_INPUT
|
||||
#define XASH_INPUT INPUT_ANDROID
|
||||
#endif // XASH_INPUT
|
||||
|
||||
#ifndef XASH_SOUND
|
||||
#define XASH_SOUND SOUND_OPENSLES
|
||||
#endif // XASH_SOUND
|
||||
|
||||
#ifndef XASH_MESSAGEBOX
|
||||
#define XASH_MESSAGEBOX MSGBOX_ANDROID
|
||||
#endif // XASH_MESSAGEBOX
|
||||
|
||||
#define XASH_USE_EVDEV 1
|
||||
#elif XASH_LINUX
|
||||
// we are building for Linux without SDL2, can draw only to framebuffer yet
|
||||
#ifndef XASH_VIDEO
|
||||
@@ -151,8 +170,6 @@ Default build-depended cvar and constant values
|
||||
#define DEFAULT_MODE_WIDTH 960
|
||||
#define DEFAULT_MODE_HEIGHT 544
|
||||
#define DEFAULT_ALLOWCONSOLE 1
|
||||
#elif XASH_ANDROID
|
||||
#define DEFAULT_TOUCH_ENABLE "1"
|
||||
#elif XASH_MOBILE_PLATFORM
|
||||
#define DEFAULT_TOUCH_ENABLE "1"
|
||||
#define DEFAULT_M_IGNORE "1"
|
||||
@@ -164,6 +181,10 @@ Default build-depended cvar and constant values
|
||||
#define XASH_INTERNAL_GAMELIBS
|
||||
#endif // XASH_ANDROID || XASH_IOS || XASH_EMSCRIPTEN
|
||||
|
||||
#if XASH_ANDROID && XASH_SDL
|
||||
#define XASH_ANDROID_ASSETS 1
|
||||
#endif
|
||||
|
||||
// Defaults
|
||||
#ifndef DEFAULT_TOUCH_ENABLE
|
||||
#define DEFAULT_TOUCH_ENABLE "0"
|
||||
|
||||
@@ -1448,7 +1448,7 @@ pfnSPR_Draw
|
||||
*/
|
||||
static void GAME_EXPORT pfnSPR_Draw( int frame, int x, int y, const wrect_t *prc )
|
||||
{
|
||||
ref.dllFuncs.GL_SetRenderMode( kRenderTransAlpha );
|
||||
ref.dllFuncs.GL_SetRenderMode( kRenderNormal );
|
||||
SPR_DrawGeneric( frame, x, y, -1, -1, prc );
|
||||
}
|
||||
|
||||
@@ -1713,8 +1713,7 @@ pfnCvar_RegisterVariable
|
||||
static cvar_t *GAME_EXPORT pfnCvar_RegisterClientVariable( const char *szName, const char *szValue, int flags )
|
||||
{
|
||||
// a1ba: try to mitigate outdated client.dll vulnerabilities
|
||||
if( !Q_stricmp( szName, "motdfile" )
|
||||
|| !Q_stricmp( szName, "sensitivity" ))
|
||||
if( !Q_stricmp( szName, "motdfile" ))
|
||||
flags |= FCVAR_PRIVILEGED;
|
||||
|
||||
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_CLIENTDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_CLIENTDLL ));
|
||||
|
||||
@@ -1125,7 +1125,7 @@ Con_ClearField
|
||||
*/
|
||||
static void Con_ClearField( field_t *edit )
|
||||
{
|
||||
memset( edit->buffer, 0, sizeof( edit->buffer ));
|
||||
memset( edit->buffer, 0, MAX_STRING );
|
||||
edit->cursor = 0;
|
||||
edit->scroll = 0;
|
||||
}
|
||||
@@ -1444,49 +1444,36 @@ static void Con_HistoryAppend( con_history_t *self, field_t *from )
|
||||
|
||||
static void Con_LoadHistory( con_history_t *self )
|
||||
{
|
||||
const byte *aFile = FS_LoadFile( "console_history.txt", NULL, true );
|
||||
const char *pLine, *pFile;
|
||||
int i, len;
|
||||
field_t *f;
|
||||
file_t *fd;
|
||||
int i;
|
||||
|
||||
fd = FS_Open( "console_history.txt", "rb", true );
|
||||
|
||||
if( !fd )
|
||||
if( !aFile )
|
||||
return;
|
||||
|
||||
while( !FS_Eof( fd ))
|
||||
for( pFile = pLine = (char *)aFile; *pFile; pFile++ )
|
||||
{
|
||||
f = &self->lines[self->next % CON_HISTORY];
|
||||
|
||||
Con_ClearField( f );
|
||||
f->widthInChars = con.linewidth;
|
||||
|
||||
FS_Gets( fd, f->buffer, sizeof( f->buffer ));
|
||||
f->cursor = Q_strlen( f->buffer );
|
||||
|
||||
// skip empty lines
|
||||
if( f->cursor == 0 )
|
||||
if( *pFile != '\n' )
|
||||
continue;
|
||||
|
||||
// skip repeating lines
|
||||
if( self->next > 0 )
|
||||
{
|
||||
field_t *prev;
|
||||
prev = &self->lines[(self->next - 1) % CON_HISTORY];
|
||||
if( !Q_stricmp( prev->buffer, f->buffer ))
|
||||
continue;
|
||||
}
|
||||
Con_ClearField( &self->lines[self->next] );
|
||||
|
||||
len = Q_min( pFile - pLine + 1, sizeof( f->buffer ));
|
||||
f = &self->lines[self->next % CON_HISTORY];
|
||||
f->widthInChars = con.linewidth;
|
||||
f->cursor = len - 1;
|
||||
Q_strncpy( f->buffer, pLine, len);
|
||||
|
||||
self->next++;
|
||||
}
|
||||
|
||||
FS_Close( fd );
|
||||
pLine = pFile + 1;
|
||||
}
|
||||
|
||||
for( i = self->next; i < CON_HISTORY; i++ )
|
||||
{
|
||||
f = &self->lines[i];
|
||||
|
||||
Con_ClearField( f );
|
||||
f->widthInChars = con.linewidth;
|
||||
Con_ClearField( &self->lines[i] );
|
||||
self->lines[i].widthInChars = con.linewidth;
|
||||
}
|
||||
|
||||
self->line = self->next;
|
||||
@@ -1504,7 +1491,7 @@ static void Con_SaveHistory( con_history_t *self )
|
||||
if( historyStart < 0 )
|
||||
historyStart = 0;
|
||||
|
||||
f = FS_Open( "console_history.txt", "wb", true );
|
||||
f = FS_Open( "console_history.txt", "w", true );
|
||||
|
||||
for( i = historyStart; i < self->next; i++ )
|
||||
FS_Printf( f, "%s\n", self->lines[i % CON_HISTORY].buffer );
|
||||
|
||||
@@ -565,7 +565,7 @@ static void R_CollectRendererNames( void )
|
||||
"GL4ES",
|
||||
#endif
|
||||
#if XASH_REF_GLES3COMPAT_ENABLED
|
||||
"GLES3 (gl2_shim)",
|
||||
"GLES3 (gl2_shim)"
|
||||
#endif
|
||||
#if XASH_REF_SOFT_ENABLED
|
||||
"Software",
|
||||
|
||||
@@ -43,7 +43,7 @@ CVAR_DEFINE_AUTO( s_lerping, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "apply interpo
|
||||
static CVAR_DEFINE( s_ambient_level, "ambient_level", "0.3", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "volume of environment noises (water and wind)" );
|
||||
static CVAR_DEFINE( s_ambient_fade, "ambient_fade", "1000", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "rate of volume fading when client is moving" );
|
||||
static CVAR_DEFINE_AUTO( s_combine_sounds, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "combine channels with same sounds" );
|
||||
static CVAR_DEFINE_AUTO( snd_mute_losefocus, "1", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "silence the audio when game window loses focus" );
|
||||
CVAR_DEFINE_AUTO( snd_mute_losefocus, "1", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "silence the audio when game window loses focus" );
|
||||
CVAR_DEFINE_AUTO( s_test, "0", 0, "engine developer cvar for quick testing new features" );
|
||||
CVAR_DEFINE_AUTO( s_samplecount, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "sample count (0 for default value)" );
|
||||
CVAR_DEFINE_AUTO( s_warn_late_precache, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "warn about late precached sounds on client-side" );
|
||||
@@ -64,12 +64,6 @@ float S_GetMasterVolume( void )
|
||||
{
|
||||
float scale = 1.0f;
|
||||
|
||||
if( host.status == HOST_NOFOCUS && snd_mute_losefocus.value != 0.0f )
|
||||
{
|
||||
// we return zero volume to keep sounds running
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if( !s_listener.inmenu && soundfade.percent != 0 )
|
||||
{
|
||||
scale = bound( 0.0f, soundfade.percent / 100.0f, 1.0f );
|
||||
|
||||
@@ -221,6 +221,7 @@ extern convar_t s_musicvolume;
|
||||
extern convar_t s_lerping;
|
||||
extern convar_t s_test; // cvar to testify new effects
|
||||
extern convar_t s_samplecount;
|
||||
extern convar_t snd_mute_losefocus;
|
||||
extern convar_t s_warn_late_precache;
|
||||
|
||||
void S_InitScaletable( void );
|
||||
|
||||
@@ -25,12 +25,11 @@ voice_state_t voice = { 0 };
|
||||
CVAR_DEFINE_AUTO( voice_enable, "1", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "enable voice chat" );
|
||||
CVAR_DEFINE_AUTO( voice_loopback, "0", FCVAR_PRIVILEGED, "loopback voice back to the speaker" );
|
||||
CVAR_DEFINE_AUTO( voice_scale, "1.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "incoming voice volume scale" );
|
||||
CVAR_DEFINE_AUTO( voice_transmit_scale, "1.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "outcoming voice volume scale" );
|
||||
CVAR_DEFINE_AUTO( voice_avggain, "0.5", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "automatic voice gain control (average)" );
|
||||
CVAR_DEFINE_AUTO( voice_maxgain, "5.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "automatic voice gain control (maximum)" );
|
||||
CVAR_DEFINE_AUTO( voice_inputfromfile, "0", FCVAR_PRIVILEGED, "input voice from voice_input.wav" );
|
||||
|
||||
static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale );
|
||||
static void Voice_ApplyGainAdjust( int16_t *samples, int count );
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
@@ -40,25 +39,6 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale );
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
static qboolean Voice_InitCustomMode( void )
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
voice.width = sizeof( opus_int16 );
|
||||
voice.samplerate = VOICE_OPUS_CUSTOM_SAMPLERATE;
|
||||
voice.frame_size = VOICE_OPUS_CUSTOM_FRAME_SIZE;
|
||||
|
||||
voice.custom_mode = opus_custom_mode_create( SOUND_44k, voice.frame_size, &err );
|
||||
|
||||
if( !voice.custom_mode )
|
||||
{
|
||||
Con_Printf( S_ERROR "Can't create Opus Custom mode: %s\n", opus_strerror( err ));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
Voice_InitOpusDecoder
|
||||
@@ -67,17 +47,24 @@ Voice_InitOpusDecoder
|
||||
*/
|
||||
static qboolean Voice_InitOpusDecoder( void )
|
||||
{
|
||||
int err = 0;
|
||||
int err;
|
||||
|
||||
for( int i = 0; i < cl.maxclients; i++ )
|
||||
voice.width = sizeof( opus_int16 );
|
||||
voice.samplerate = VOICE_OPUS_CUSTOM_SAMPLERATE;
|
||||
voice.frame_size = VOICE_OPUS_CUSTOM_FRAME_SIZE;
|
||||
|
||||
voice.custom_mode = opus_custom_mode_create( SOUND_44k, voice.frame_size, &err );
|
||||
if( !voice.custom_mode )
|
||||
{
|
||||
voice.decoders[i] = opus_custom_decoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
||||
Con_Printf( S_ERROR "Can't create Opus Custom mode: %s\n", opus_strerror( err ));
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !voice.decoders[i] )
|
||||
{
|
||||
Con_Printf( S_ERROR "Can't create Opus decoder for %i: %s\n", i, opus_strerror( err ));
|
||||
return false;
|
||||
}
|
||||
voice.decoder = opus_custom_decoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
||||
if( !voice.decoder )
|
||||
{
|
||||
Con_Printf( S_ERROR "Can't create Opus encoder: %s\n", opus_strerror( err ));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -91,7 +78,7 @@ Voice_InitOpusEncoder
|
||||
*/
|
||||
static qboolean Voice_InitOpusEncoder( int quality )
|
||||
{
|
||||
int err = 0;
|
||||
int err;
|
||||
|
||||
voice.encoder = opus_custom_encoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
||||
if( !voice.encoder )
|
||||
@@ -130,13 +117,10 @@ Voice_ShutdownOpusDecoder
|
||||
*/
|
||||
static void Voice_ShutdownOpusDecoder( void )
|
||||
{
|
||||
for( int i = 0; i < MAX_CLIENTS; i++ )
|
||||
if( voice.decoder )
|
||||
{
|
||||
if( !voice.decoders[i] )
|
||||
continue;
|
||||
|
||||
opus_custom_decoder_destroy( voice.decoders[i] );
|
||||
voice.decoders[i] = NULL;
|
||||
opus_custom_decoder_destroy( voice.decoder );
|
||||
voice.decoder = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,10 +137,7 @@ static void Voice_ShutdownOpusEncoder( void )
|
||||
opus_custom_encoder_destroy( voice.encoder );
|
||||
voice.encoder = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void Voice_ShutdownCustomMode( void )
|
||||
{
|
||||
if( voice.custom_mode )
|
||||
{
|
||||
opus_custom_mode_destroy( voice.custom_mode );
|
||||
@@ -203,7 +184,7 @@ static uint Voice_GetOpusCompressedData( byte *out, uint maxsize, uint *frames )
|
||||
if( !voice.input_file )
|
||||
{
|
||||
// adjust gain before encoding, but only for input from voice
|
||||
Voice_ApplyGainAdjust((opus_int16*)(voice.input_buffer + ofs), voice.frame_size, voice_transmit_scale.value);
|
||||
Voice_ApplyGainAdjust((opus_int16*)(voice.input_buffer + ofs), voice.frame_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -257,10 +238,10 @@ Voice_ApplyGainAdjust
|
||||
|
||||
=========================
|
||||
*/
|
||||
static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale )
|
||||
static void Voice_ApplyGainAdjust( int16_t *samples, int count )
|
||||
{
|
||||
float gain, modifiedMax;
|
||||
int average, blockOffset = 0;
|
||||
int average, adjustedSample, blockOffset = 0;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
@@ -279,8 +260,10 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale )
|
||||
localMax = absSample;
|
||||
|
||||
localSum += absSample;
|
||||
|
||||
gain = voice.autogain.current_gain + i * voice.autogain.gain_multiplier;
|
||||
samples[blockOffset + i] = bound( SHRT_MIN, (int)( sample * gain ), SHRT_MAX );
|
||||
adjustedSample = Q_min( SHRT_MAX, Q_max(( int )( sample * gain ), SHRT_MIN ));
|
||||
samples[blockOffset + i] = adjustedSample;
|
||||
}
|
||||
|
||||
if( blockOffset % voice.autogain.block_size == 0 )
|
||||
@@ -288,9 +271,9 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale )
|
||||
average = localSum / blockSize;
|
||||
modifiedMax = average + ( localMax - average ) * voice_avggain.value;
|
||||
|
||||
voice.autogain.current_gain = voice.autogain.next_gain * scale;
|
||||
voice.autogain.next_gain = Q_min( (float)SHRT_MAX / modifiedMax, voice_maxgain.value ) * scale;
|
||||
voice.autogain.gain_multiplier = ( voice.autogain.next_gain - voice.autogain.current_gain ) / ( blockSize - 1 );
|
||||
voice.autogain.current_gain = voice.autogain.next_gain * voice_scale.value;
|
||||
voice.autogain.next_gain = Q_min( (float)SHRT_MAX / modifiedMax, voice_maxgain.value ) * voice_scale.value;
|
||||
voice.autogain.gain_multiplier = ( voice.autogain.next_gain - voice.autogain.current_gain ) / ( voice.autogain.block_size - 1 );
|
||||
}
|
||||
blockOffset += blockSize;
|
||||
}
|
||||
@@ -460,7 +443,7 @@ Feed the decoded data to engine sound subsystem
|
||||
static void Voice_StartChannel( uint samples, byte *data, int entnum )
|
||||
{
|
||||
SND_ForceInitMouth( entnum );
|
||||
S_RawEntSamples( entnum, samples, voice.samplerate, voice.width, VOICE_PCM_CHANNELS, data, bound( 0, 255 * voice_scale.value, 255 ));
|
||||
S_RawEntSamples( entnum, samples, voice.samplerate, voice.width, VOICE_PCM_CHANNELS, data, 255 );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -472,11 +455,10 @@ Received encoded voice data, decode it
|
||||
*/
|
||||
void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames )
|
||||
{
|
||||
const int playernum = ent - 1;
|
||||
int samples = 0;
|
||||
int ofs = 0;
|
||||
|
||||
if( playernum < 0 || playernum >= cl.maxclients || !voice.decoders[playernum] )
|
||||
if( !voice.decoder )
|
||||
return;
|
||||
|
||||
// decode frame by frame
|
||||
@@ -496,7 +478,7 @@ void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames )
|
||||
if( ofs + compressed_size > size )
|
||||
break;
|
||||
|
||||
frame_samples = opus_custom_decode( voice.decoders[playernum], data + ofs, compressed_size,
|
||||
frame_samples = opus_custom_decode( voice.decoder, data + ofs, compressed_size,
|
||||
(opus_int16*)voice.decompress_buffer + samples, voice.frame_size );
|
||||
|
||||
ofs += compressed_size;
|
||||
@@ -520,8 +502,8 @@ void CL_AddVoiceToDatagram( void )
|
||||
|
||||
if( cls.state != ca_active || !Voice_IsRecording() || !voice.encoder )
|
||||
return;
|
||||
|
||||
size = Voice_GetOpusCompressedData( voice.compress_buffer, sizeof( voice.compress_buffer ), &frames );
|
||||
|
||||
size = Voice_GetOpusCompressedData( voice.output_buffer, sizeof( voice.output_buffer ), &frames );
|
||||
|
||||
if( size > 0 && MSG_GetNumBytesLeft( &cls.datagram ) >= size + 32 )
|
||||
{
|
||||
@@ -529,7 +511,7 @@ void CL_AddVoiceToDatagram( void )
|
||||
MSG_WriteByte( &cls.datagram, voice_loopback.value != 0 );
|
||||
MSG_WriteByte( &cls.datagram, frames );
|
||||
MSG_WriteShort( &cls.datagram, size );
|
||||
MSG_WriteBytes( &cls.datagram, voice.compress_buffer, size );
|
||||
MSG_WriteBytes( &cls.datagram, voice.output_buffer, size );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -545,7 +527,6 @@ void Voice_RegisterCvars( void )
|
||||
Cvar_RegisterVariable( &voice_enable );
|
||||
Cvar_RegisterVariable( &voice_loopback );
|
||||
Cvar_RegisterVariable( &voice_scale );
|
||||
Cvar_RegisterVariable( &voice_transmit_scale );
|
||||
Cvar_RegisterVariable( &voice_avggain );
|
||||
Cvar_RegisterVariable( &voice_maxgain );
|
||||
Cvar_RegisterVariable( &voice_inputfromfile );
|
||||
@@ -563,9 +544,8 @@ static void Voice_Shutdown( void )
|
||||
int i;
|
||||
|
||||
Voice_RecordStop();
|
||||
Voice_ShutdownOpusDecoder();
|
||||
Voice_ShutdownOpusEncoder();
|
||||
Voice_ShutdownCustomMode();
|
||||
Voice_ShutdownOpusDecoder();
|
||||
VoiceCapture_Shutdown();
|
||||
|
||||
if( voice.local.talking_ack )
|
||||
@@ -629,10 +609,11 @@ qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit )
|
||||
|
||||
voice.autogain.block_size = 128;
|
||||
|
||||
if( !Voice_InitCustomMode( ))
|
||||
if( !Voice_InitOpusDecoder( ))
|
||||
{
|
||||
// no reason to init encoder and open audio device
|
||||
// if we can't hear other players
|
||||
Con_Printf( S_ERROR "Voice chat disabled.\n" );
|
||||
Voice_Shutdown();
|
||||
return false;
|
||||
}
|
||||
@@ -652,16 +633,6 @@ qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit )
|
||||
|
||||
if( !preinit )
|
||||
{
|
||||
Voice_ShutdownOpusDecoder();
|
||||
if( !Voice_InitOpusDecoder())
|
||||
{
|
||||
// no reason to init encoder and open audio device
|
||||
// if we can't hear other players
|
||||
Con_Printf( S_ERROR "Can't create decoders, voice chat is disabled.\n" );
|
||||
Voice_Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
voice.device_opened = VoiceCapture_Init();
|
||||
|
||||
if( !voice.device_opened )
|
||||
|
||||
@@ -62,7 +62,7 @@ typedef struct voice_state_s
|
||||
// opus stuff
|
||||
OpusCustomMode *custom_mode;
|
||||
OpusCustomEncoder *encoder;
|
||||
OpusCustomDecoder *decoders[MAX_CLIENTS];
|
||||
OpusCustomDecoder *decoder;
|
||||
|
||||
// audio info
|
||||
uint width;
|
||||
@@ -71,7 +71,7 @@ typedef struct voice_state_s
|
||||
|
||||
// buffers
|
||||
byte input_buffer[MAX_RAW_SAMPLES];
|
||||
byte compress_buffer[MAX_RAW_SAMPLES];
|
||||
byte output_buffer[MAX_RAW_SAMPLES];
|
||||
byte decompress_buffer[MAX_RAW_SAMPLES];
|
||||
fs_offset_t input_buffer_pos; // in bytes
|
||||
|
||||
|
||||
@@ -949,7 +949,7 @@ static void Cmd_Else_f( void )
|
||||
|
||||
static qboolean Cmd_ShouldAllowCommand( cmd_t *cmd, qboolean isPrivileged )
|
||||
{
|
||||
const char *prefixes[] = { "cl_", "gl_", "r_", "m_", "hud_", "joy_" };
|
||||
const char *prefixes[] = { "cl_", "gl_", "r_", "m_", "hud_" };
|
||||
int i;
|
||||
|
||||
// always allow local commands
|
||||
|
||||
@@ -74,7 +74,6 @@ GNU General Public License for more details.
|
||||
#define DEFAULT_UPDATE_PAGE "https://github.com/FWGS/xash3d-fwgs/releases/latest"
|
||||
|
||||
#define XASH_ENGINE_NAME "Xash3D FWGS"
|
||||
#define XASH_DEDICATED_SERVER_NAME "XashDS"
|
||||
#define XASH_VERSION "0.20" // engine current version
|
||||
#define XASH_COMPAT_VERSION "0.99" // version we are based on
|
||||
|
||||
|
||||
@@ -390,9 +390,6 @@ byte *LZSS_Compress( byte *pInput, int inputLength, uint *pOutputSize )
|
||||
byte *pFinal = NULL;
|
||||
lzss_state_t state;
|
||||
|
||||
if( !pStart )
|
||||
return NULL;
|
||||
|
||||
memset( &state, 0, sizeof( state ));
|
||||
state.window_size = LZSS_WINDOW_SIZE;
|
||||
|
||||
|
||||
@@ -866,7 +866,7 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
||||
return true; // exist
|
||||
|
||||
// setup mpfilter
|
||||
Q_snprintf( mpfilter, sizeof( mpfilter ), "maps/%s", GI->mp_filter );
|
||||
size = Q_snprintf( mpfilter, sizeof( mpfilter ), "maps/%s", GI->mp_filter );
|
||||
t = FS_Search( "maps/*.bsp", false, onlyingamedir );
|
||||
|
||||
if( !t )
|
||||
@@ -900,9 +900,9 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
||||
|
||||
if( f )
|
||||
{
|
||||
qboolean have_spawnpoints = false;
|
||||
dheader_t *header;
|
||||
dlump_t entities;
|
||||
int num_spawnpoints = 0;
|
||||
dheader_t *header;
|
||||
dlump_t entities;
|
||||
|
||||
memset( buf, 0, MAX_SYSPATH );
|
||||
FS_Read( f, buf, MAX_SYSPATH );
|
||||
@@ -943,18 +943,7 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
||||
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
|
||||
{
|
||||
if( token[0] == '}' && worldspawn )
|
||||
{
|
||||
worldspawn = false;
|
||||
|
||||
// if mod has mp_filter set up, then it's a mod that
|
||||
// might not have valid mp_entity set in GI
|
||||
// if mod is multiplayer only, assume all maps are valid
|
||||
if( use_filter || GI->gamemode == GAME_MULTIPLAYER_ONLY )
|
||||
{
|
||||
have_spawnpoints = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( !Q_strcmp( token, "message" ) && worldspawn )
|
||||
{
|
||||
// get the message contents
|
||||
@@ -963,23 +952,17 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
||||
else if( !Q_strcmp( token, "classname" ))
|
||||
{
|
||||
pfile = COM_ParseFile( pfile, token, sizeof( token ));
|
||||
|
||||
if( !Q_strcmp( token, GI->mp_entity ))
|
||||
{
|
||||
have_spawnpoints = true;
|
||||
break;
|
||||
}
|
||||
if( !Q_strcmp( token, GI->mp_entity ) || use_filter )
|
||||
num_spawnpoints++;
|
||||
}
|
||||
|
||||
if( have_spawnpoints )
|
||||
break; // valid map
|
||||
if( num_spawnpoints ) break; // valid map
|
||||
}
|
||||
Mem_Free( ents );
|
||||
}
|
||||
|
||||
if( f ) FS_Close( f );
|
||||
|
||||
if( have_spawnpoints )
|
||||
if( num_spawnpoints )
|
||||
{
|
||||
// format: mapname "maptitle"\n
|
||||
Q_snprintf( result, sizeof( result ), "%s \"%s\"\n", mapname, message );
|
||||
|
||||
@@ -152,10 +152,8 @@ static qboolean Cvar_UpdateInfo( convar_t *var, const char *value, qboolean noti
|
||||
if ( Host_IsDedicated() )
|
||||
{
|
||||
// g-cont. this is a very strange behavior...
|
||||
char *info = SV_Serverinfo();
|
||||
|
||||
Info_SetValueForKey( info, var->name, value, MAX_SERVERINFO_STRING ),
|
||||
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", info );
|
||||
Info_SetValueForKey( SV_Serverinfo(), var->name, value, MAX_SERVERINFO_STRING ),
|
||||
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", SV_Serverinfo( ));
|
||||
}
|
||||
#if !XASH_DEDICATED
|
||||
else
|
||||
@@ -955,7 +953,7 @@ static void Cvar_SetGL( const char *name, const char *value )
|
||||
|
||||
static qboolean Cvar_ShouldSetCvar( convar_t *v, qboolean isPrivileged )
|
||||
{
|
||||
const char *prefixes[] = { "cl_", "gl_", "m_", "r_", "hud_", "joy_" };
|
||||
const char *prefixes[] = { "cl_", "gl_", "m_", "r_", "hud_" };
|
||||
int i;
|
||||
|
||||
if( isPrivileged )
|
||||
|
||||
@@ -92,9 +92,8 @@ static void Sys_PrintUsage( void )
|
||||
O("-minidumps ", "enable writing minidumps when game is crashed")
|
||||
#endif
|
||||
O("-rodir <path> ", "set read-only base directory")
|
||||
O("-bugcomp ", "enable precise bug compatibility")
|
||||
O(" ", "will break games that don't require it")
|
||||
O(" ", "refer to engine documentation for more info")
|
||||
O("-bugcomp ", "enable precise bug compatibility. Will break games that don't require it")
|
||||
O(" ", "Refer to engine documentation for more info")
|
||||
O("-disablehelp ", "disable this message")
|
||||
#if !XASH_DEDICATED
|
||||
O("-dedicated ", "run engine in dedicated mode")
|
||||
@@ -107,8 +106,7 @@ static void Sys_PrintUsage( void )
|
||||
O("-noip6 ", "disable IPv6")
|
||||
O("-ip6 <ip> ", "set IPv6 address")
|
||||
O("-port6 <port> ", "set IPv6 port")
|
||||
O("-clockwindow <cw>", "adjust clockwindow used to ignore client commands")
|
||||
O(" ", "to prevent speed hacks")
|
||||
O("-clockwindow <cw>", "adjust clockwindow used to ignore client commands to prevent speed hacks")
|
||||
|
||||
"\nGame options:\n"
|
||||
O("-game <directory>", "set game directory to start engine with")
|
||||
@@ -941,7 +939,6 @@ static void Host_RunTests( int stage )
|
||||
TEST_LIST_1_CLIENT;
|
||||
#endif
|
||||
Msg( "Done! %d passed, %d failed\n", tests_stats.passed, tests_stats.failed );
|
||||
error_on_exit = tests_stats.failed > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
Sys_Quit();
|
||||
}
|
||||
}
|
||||
@@ -1190,11 +1187,6 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
|
||||
Con_Printf( "^3BUGCOMP^7: GoldSrc bug-compatibility enabled\n" );
|
||||
}
|
||||
|
||||
// print current developer level to simplify processing users feedback
|
||||
if( developer > 0 ) {
|
||||
Con_Printf( "Developer level: ^3%i\n", developer );
|
||||
}
|
||||
|
||||
Cmd_AddCommand( "exec", Host_Exec_f, "execute a script file" );
|
||||
Cmd_AddCommand( "memlist", Host_MemStats_f, "prints memory pool information" );
|
||||
Cmd_AddRestrictedCommand( "userconfigd", Host_Userconfigd_f, "execute all scripts from userconfig.d" );
|
||||
@@ -1377,11 +1369,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||
host.status = HOST_FRAME;
|
||||
|
||||
if( GameState->nextstate == STATE_RUNFRAME )
|
||||
#if XASH_WIN32 // FIXME: implement autocomplete on *nix
|
||||
Con_Printf( "Type 'map <mapname>' to start game... (TAB-autocomplete is working too)\n" );
|
||||
#else // !XASH_WIN32
|
||||
Con_Printf( "Type 'map <mapname>' to start game...\n" );
|
||||
#endif // !XASH_WIN32
|
||||
|
||||
// execute server.cfg after commandline
|
||||
// so we have a chance to set servercfgfile
|
||||
|
||||
@@ -390,7 +390,7 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
if( Q_strrchr( name, '{' ))
|
||||
{
|
||||
// NOTE: decals with 'blue base' can be interpret as colored decals
|
||||
if( !Image_CheckFlag( IL_LOAD_DECAL ) || ( pal && pal[765] == 0 && pal[766] == 0 && pal[767] == 255 ))
|
||||
if( !Image_CheckFlag( IL_LOAD_DECAL ) || ( pal[765] == 0 && pal[766] == 0 && pal[767] == 255 ))
|
||||
{
|
||||
SetBits( image.flags, IMAGE_ONEBIT_ALPHA );
|
||||
rendermode = LUMP_MASKED;
|
||||
@@ -488,40 +488,37 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
}
|
||||
|
||||
// check for half-life water texture
|
||||
if( pal != NULL )
|
||||
if( hl_texture && ( mip.name[0] == '!' || !Q_strnicmp( mip.name, "water", 5 )))
|
||||
{
|
||||
if( hl_texture && ( mip.name[0] == '!' || !Q_strnicmp( mip.name, "water", 5 )))
|
||||
{
|
||||
// grab the fog color
|
||||
image.fogParams[0] = pal[3*3+0];
|
||||
image.fogParams[1] = pal[3*3+1];
|
||||
image.fogParams[2] = pal[3*3+2];
|
||||
// grab the fog color
|
||||
image.fogParams[0] = pal[3*3+0];
|
||||
image.fogParams[1] = pal[3*3+1];
|
||||
image.fogParams[2] = pal[3*3+2];
|
||||
|
||||
// grab the fog density
|
||||
image.fogParams[3] = pal[4*3+0];
|
||||
}
|
||||
else if( hl_texture && ( rendermode == LUMP_GRADIENT ))
|
||||
{
|
||||
// grab the decal color
|
||||
image.fogParams[0] = pal[255*3+0];
|
||||
image.fogParams[1] = pal[255*3+1];
|
||||
image.fogParams[2] = pal[255*3+2];
|
||||
// grab the fog density
|
||||
image.fogParams[3] = pal[4*3+0];
|
||||
}
|
||||
else if( hl_texture && ( rendermode == LUMP_GRADIENT ))
|
||||
{
|
||||
// grab the decal color
|
||||
image.fogParams[0] = pal[255*3+0];
|
||||
image.fogParams[1] = pal[255*3+1];
|
||||
image.fogParams[2] = pal[255*3+2];
|
||||
|
||||
// calc the decal reflectivity
|
||||
image.fogParams[3] = VectorAvg( image.fogParams );
|
||||
}
|
||||
else
|
||||
// calc the decal reflectivity
|
||||
image.fogParams[3] = VectorAvg( image.fogParams );
|
||||
}
|
||||
else if( pal != NULL )
|
||||
{
|
||||
// calc texture reflectivity
|
||||
for( i = 0; i < 256; i++ )
|
||||
{
|
||||
// calc texture reflectivity
|
||||
for( i = 0; i < 256; i++ )
|
||||
{
|
||||
reflectivity[0] += pal[i*3+0];
|
||||
reflectivity[1] += pal[i*3+1];
|
||||
reflectivity[2] += pal[i*3+2];
|
||||
}
|
||||
|
||||
VectorDivide( reflectivity, 256, image.fogParams );
|
||||
reflectivity[0] += pal[i*3+0];
|
||||
reflectivity[1] += pal[i*3+1];
|
||||
reflectivity[2] += pal[i*3+2];
|
||||
}
|
||||
|
||||
VectorDivide( reflectivity, 256, image.fogParams );
|
||||
}
|
||||
|
||||
image.type = PF_INDEXED_32; // 32-bit palete
|
||||
|
||||
@@ -118,7 +118,7 @@ static void NET_AnnounceToMaster( master_t *m )
|
||||
MSG_WriteBytes( &msg, "q\xFF", 2 );
|
||||
MSG_WriteDword( &msg, m->heartbeat_challenge );
|
||||
|
||||
NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &msg ), MSG_GetData( &msg ), m->adr );
|
||||
NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &msg ), MSG_GetBuf( &msg ), m->adr );
|
||||
|
||||
if( sv_verbose_heartbeats.value )
|
||||
{
|
||||
|
||||
@@ -109,6 +109,85 @@ void MSG_InitMasks( void )
|
||||
ExtraMasks[maskBit] = (uint)BIT( maskBit ) - 1;
|
||||
}
|
||||
|
||||
void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits )
|
||||
{
|
||||
MSG_StartWriting( sb, pData, nBytes, 0, nMaxBits );
|
||||
|
||||
sb->pDebugName = pDebugName;
|
||||
}
|
||||
|
||||
void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits )
|
||||
{
|
||||
// make sure it's dword aligned and padded.
|
||||
Assert(((uint32_t)pData & 3 ) == 0 );
|
||||
|
||||
sb->pDebugName = "Unnamed";
|
||||
sb->pData = (byte *)pData;
|
||||
|
||||
if( nBits == -1 )
|
||||
{
|
||||
sb->nDataBits = nBytes << 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert( nBits <= nBytes * 8 );
|
||||
sb->nDataBits = nBits;
|
||||
}
|
||||
|
||||
sb->iCurBit = iStartBit;
|
||||
sb->bOverflow = false;
|
||||
}
|
||||
|
||||
/*
|
||||
=======================
|
||||
MSG_Clear
|
||||
|
||||
for clearing overflowed buffer
|
||||
=======================
|
||||
*/
|
||||
void MSG_Clear( sizebuf_t *sb )
|
||||
{
|
||||
sb->iCurBit = 0;
|
||||
sb->bOverflow = false;
|
||||
}
|
||||
|
||||
static qboolean MSG_Overflow( sizebuf_t *sb, int nBits )
|
||||
{
|
||||
if( sb->iCurBit + nBits > sb->nDataBits )
|
||||
sb->bOverflow = true;
|
||||
return sb->bOverflow;
|
||||
}
|
||||
|
||||
qboolean MSG_CheckOverflow( sizebuf_t *sb )
|
||||
{
|
||||
return MSG_Overflow( sb, 0 );
|
||||
}
|
||||
|
||||
int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence )
|
||||
{
|
||||
// compute the file offset
|
||||
switch( whence )
|
||||
{
|
||||
case SEEK_CUR:
|
||||
bitPos += sb->iCurBit;
|
||||
break;
|
||||
case SEEK_SET:
|
||||
break;
|
||||
case SEEK_END:
|
||||
bitPos += sb->nDataBits;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( bitPos < 0 || bitPos > sb->nDataBits )
|
||||
return -1;
|
||||
|
||||
sb->iCurBit = bitPos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MSG_WriteOneBit( sizebuf_t *sb, int nValue )
|
||||
{
|
||||
if( !MSG_Overflow( sb, 1 ))
|
||||
@@ -590,7 +669,7 @@ qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes )
|
||||
return MSG_ReadBits( sb, pOut, nBytes << 3 );
|
||||
}
|
||||
|
||||
static char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
|
||||
char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
|
||||
{
|
||||
static char string[4096];
|
||||
int l = 0, c;
|
||||
@@ -616,16 +695,6 @@ static char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
|
||||
return string;
|
||||
}
|
||||
|
||||
char *MSG_ReadString( sizebuf_t *sb )
|
||||
{
|
||||
return MSG_ReadStringExt( sb, false );
|
||||
}
|
||||
|
||||
char *MSG_ReadStringLine( sizebuf_t *sb )
|
||||
{
|
||||
return MSG_ReadStringExt( sb, true );
|
||||
}
|
||||
|
||||
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove )
|
||||
{
|
||||
int i, endbit = startbit + bitstoremove;
|
||||
|
||||
@@ -30,128 +30,39 @@ GNU General Public License for more details.
|
||||
// So PAD_NUMBER(0,4) is 0 and PAD_NUMBER(1,4) is 4
|
||||
#define PAD_NUMBER( num, boundary ) ((( num ) + (( boundary ) - 1 )) / ( boundary )) * ( boundary )
|
||||
|
||||
static inline int BitByte( int bits )
|
||||
_inline int BitByte( int bits )
|
||||
{
|
||||
return PAD_NUMBER( bits, 8 ) >> 3;
|
||||
}
|
||||
|
||||
struct sizebuf_s
|
||||
{
|
||||
byte *pData;
|
||||
qboolean bOverflow; // overflow reading or writing
|
||||
int iCurBit;
|
||||
int nDataBits;
|
||||
const char *pDebugName; // buffer name (pointer to const name)
|
||||
qboolean bOverflow; // overflow reading or writing
|
||||
const char *pDebugName; // buffer name (pointer to const name)
|
||||
|
||||
byte *pData;
|
||||
int iCurBit;
|
||||
int nDataBits;
|
||||
};
|
||||
|
||||
#define MSG_StartReading MSG_StartWriting
|
||||
#define MSG_GetNumBytesRead MSG_GetNumBytesWritten
|
||||
#define MSG_GetRealBytesRead MSG_GetRealBytesWritten
|
||||
#define MSG_GetNumBitsRead MSG_GetNumBitsWritten
|
||||
#define MSG_ReadBitAngles MSG_ReadBitVec3Coord
|
||||
#define MSG_ReadAngle( sb ) (float)( MSG_ReadChar( sb ) * ( 360.0f / 256.0f ))
|
||||
#define MSG_Init( sb, name, data, bytes ) MSG_InitExt( sb, name, data, bytes, -1 )
|
||||
#define MSG_CheckOverflow( sb ) MSG_Overflow( sb, 0 )
|
||||
#define MSG_StartReading MSG_StartWriting
|
||||
#define MSG_GetNumBytesRead MSG_GetNumBytesWritten
|
||||
#define MSG_GetRealBytesRead MSG_GetRealBytesWritten
|
||||
#define MSG_GetNumBitsRead MSG_GetNumBitsWritten
|
||||
#define MSG_ReadBitAngles MSG_ReadBitVec3Coord
|
||||
#define MSG_ReadString( sb ) MSG_ReadStringExt( sb, false )
|
||||
#define MSG_ReadStringLine( sb ) MSG_ReadStringExt( sb, true )
|
||||
#define MSG_ReadAngle( sb ) (float)(MSG_ReadChar( sb ) * ( 360.0f / 256.0f ))
|
||||
#define MSG_Init( sb, name, data, bytes ) MSG_InitExt( sb, name, data, bytes, -1 )
|
||||
|
||||
// common functions
|
||||
static inline void MSG_Clear( sizebuf_t *sb )
|
||||
{
|
||||
sb->bOverflow = false;
|
||||
sb->iCurBit = 0;
|
||||
}
|
||||
|
||||
static inline void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nBits )
|
||||
{
|
||||
sb->pData = pData;
|
||||
MSG_Clear( sb );
|
||||
|
||||
if( nBits < 0 )
|
||||
sb->nDataBits = nBytes << 3;
|
||||
else
|
||||
sb->nDataBits = nBits;
|
||||
|
||||
sb->pDebugName = pDebugName;
|
||||
}
|
||||
|
||||
static inline void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits )
|
||||
{
|
||||
MSG_InitExt( sb, "Unnamed", pData, nBytes, nBits );
|
||||
sb->iCurBit = iStartBit;
|
||||
}
|
||||
|
||||
static inline int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence )
|
||||
{
|
||||
// compute the file offset
|
||||
switch( whence )
|
||||
{
|
||||
case SEEK_CUR:
|
||||
bitPos += sb->iCurBit;
|
||||
break;
|
||||
case SEEK_SET:
|
||||
break;
|
||||
case SEEK_END:
|
||||
bitPos += sb->nDataBits;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( unlikely( bitPos < 0 || bitPos > sb->nDataBits ))
|
||||
return -1;
|
||||
|
||||
sb->iCurBit = bitPos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int MSG_TellBit( sizebuf_t *sb )
|
||||
{
|
||||
return sb->iCurBit;
|
||||
}
|
||||
|
||||
static inline const char *MSG_GetName( sizebuf_t *sb )
|
||||
{
|
||||
return sb->pDebugName;
|
||||
}
|
||||
|
||||
static inline int MSG_GetNumBytesWritten( sizebuf_t *sb )
|
||||
{
|
||||
return BitByte( sb->iCurBit );
|
||||
}
|
||||
|
||||
static inline int MSG_GetRealBytesWritten( sizebuf_t *sb )
|
||||
{
|
||||
return sb->iCurBit >> 3; // unpadded
|
||||
}
|
||||
static inline int MSG_GetNumBitsWritten( sizebuf_t *sb )
|
||||
{
|
||||
return sb->iCurBit;
|
||||
}
|
||||
|
||||
static inline int MSG_GetMaxBits( sizebuf_t *sb )
|
||||
{
|
||||
return sb->nDataBits;
|
||||
}
|
||||
|
||||
static inline int MSG_GetMaxBytes( sizebuf_t *sb )
|
||||
{
|
||||
return sb->nDataBits >> 3;
|
||||
}
|
||||
|
||||
static inline int MSG_GetNumBitsLeft( sizebuf_t *sb )
|
||||
{
|
||||
return sb->nDataBits - sb->iCurBit;
|
||||
}
|
||||
|
||||
static inline int MSG_GetNumBytesLeft( sizebuf_t *sb )
|
||||
{
|
||||
return MSG_GetNumBitsLeft( sb ) >> 3;
|
||||
}
|
||||
|
||||
static inline byte *MSG_GetData( sizebuf_t *sb )
|
||||
{
|
||||
return sb->pData;
|
||||
}
|
||||
void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits );
|
||||
void MSG_InitMasks( void ); // called once at startup engine
|
||||
int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence );
|
||||
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
|
||||
_inline int MSG_TellBit( sizebuf_t *sb ) { return sb->iCurBit; }
|
||||
_inline const char *MSG_GetName( sizebuf_t *sb ) { return sb->pDebugName; }
|
||||
qboolean MSG_CheckOverflow( sizebuf_t *sb );
|
||||
|
||||
#if XASH_BIG_ENDIAN
|
||||
#define MSG_BigShort( x ) ( x )
|
||||
@@ -162,15 +73,9 @@ static inline uint16_t MSG_BigShort( const uint16_t x )
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline qboolean MSG_Overflow( sizebuf_t *sb, int nBits )
|
||||
{
|
||||
if( sb->iCurBit + nBits > sb->nDataBits )
|
||||
sb->bOverflow = true;
|
||||
return sb->bOverflow;
|
||||
}
|
||||
|
||||
void MSG_InitMasks( void ); // called once at startup engine
|
||||
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
|
||||
// init writing
|
||||
void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits );
|
||||
void MSG_Clear( sizebuf_t *sb );
|
||||
|
||||
// Bit-write functions
|
||||
void MSG_WriteOneBit( sizebuf_t *sb, int nValue );
|
||||
@@ -194,11 +99,20 @@ void MSG_WriteCoord( sizebuf_t *sb, float val );
|
||||
void MSG_WriteFloat( sizebuf_t *sb, float val );
|
||||
void MSG_WriteVec3Coord( sizebuf_t *sb, const float *fa );
|
||||
void MSG_WriteVec3Angles( sizebuf_t *sb, const float *fa );
|
||||
qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes ); // same as MSG_WriteData
|
||||
qboolean MSG_WriteString( sizebuf_t *sb, const char *pStr ); // returns false if it overflows the buffer.
|
||||
qboolean MSG_WriteStringf( sizebuf_t *sb, const char *format, ... ) _format( 2 );
|
||||
qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes );
|
||||
|
||||
// helper functions
|
||||
_inline int MSG_GetNumBytesWritten( sizebuf_t *sb ) { return BitByte( sb->iCurBit ); }
|
||||
_inline int MSG_GetRealBytesWritten( sizebuf_t *sb ) { return sb->iCurBit >> 3; } // unpadded
|
||||
_inline int MSG_GetNumBitsWritten( sizebuf_t *sb ) { return sb->iCurBit; }
|
||||
_inline int MSG_GetMaxBits( sizebuf_t *sb ) { return sb->nDataBits; }
|
||||
_inline int MSG_GetMaxBytes( sizebuf_t *sb ) { return sb->nDataBits >> 3; }
|
||||
_inline int MSG_GetNumBitsLeft( sizebuf_t *sb ) { return sb->nDataBits - sb->iCurBit; }
|
||||
_inline int MSG_GetNumBytesLeft( sizebuf_t *sb ) { return MSG_GetNumBitsLeft( sb ) >> 3; }
|
||||
_inline byte *MSG_GetData( sizebuf_t *sb ) { return sb->pData; }
|
||||
_inline byte *MSG_GetBuf( sizebuf_t *sb ) { return sb->pData; } // just an alias
|
||||
|
||||
// Bit-read functions
|
||||
int MSG_ReadOneBit( sizebuf_t *sb );
|
||||
@@ -222,8 +136,7 @@ float MSG_ReadCoord( sizebuf_t *sb );
|
||||
float MSG_ReadFloat( sizebuf_t *sb );
|
||||
void MSG_ReadVec3Coord( sizebuf_t *sb, vec3_t fa );
|
||||
void MSG_ReadVec3Angles( sizebuf_t *sb, vec3_t fa );
|
||||
char *MSG_ReadString( sizebuf_t *sb );
|
||||
char *MSG_ReadStringLine( sizebuf_t *sb );
|
||||
qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes );
|
||||
char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine );
|
||||
|
||||
#endif//NET_BUFFER_H
|
||||
|
||||
@@ -315,43 +315,6 @@ static const delta_field_t ent_fields[] =
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
#if XASH_ENGINE_TESTS
|
||||
typedef struct delta_test_struct_t
|
||||
{
|
||||
char dt_string[128]; // always signed
|
||||
float dt_timewindow_big; // always signed
|
||||
float dt_timewindow_8; // always signed
|
||||
float dt_angle; // always_signed
|
||||
float dt_float_signed;
|
||||
float dt_float_unsigned;
|
||||
int32_t dt_integer_signed;
|
||||
uint32_t dt_integer_unsigned;
|
||||
int16_t dt_short_signed;
|
||||
uint16_t dt_short_unsigned;
|
||||
int8_t dt_byte_signed;
|
||||
uint8_t dt_byte_unsigned;
|
||||
} delta_test_struct_t;
|
||||
|
||||
#define TEST_DEF( x ) #x, offsetof( delta_test_struct_t, x ), sizeof( ((delta_test_struct_t *)0)->x )
|
||||
|
||||
static const delta_field_t test_fields[] =
|
||||
{
|
||||
{ TEST_DEF( dt_string ) },
|
||||
{ TEST_DEF( dt_timewindow_big )},
|
||||
{ TEST_DEF( dt_timewindow_8 )},
|
||||
{ TEST_DEF( dt_angle ) },
|
||||
{ TEST_DEF( dt_float_signed ) },
|
||||
{ TEST_DEF( dt_float_unsigned ) },
|
||||
{ TEST_DEF( dt_integer_signed ) },
|
||||
{ TEST_DEF( dt_integer_unsigned ) },
|
||||
{ TEST_DEF( dt_short_signed ) },
|
||||
{ TEST_DEF( dt_short_unsigned ) },
|
||||
{ TEST_DEF( dt_byte_signed ) },
|
||||
{ TEST_DEF( dt_byte_unsigned ) },
|
||||
{ NULL },
|
||||
};
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
DT_EVENT_T = 0,
|
||||
@@ -362,10 +325,6 @@ enum
|
||||
DT_ENTITY_STATE_T,
|
||||
DT_ENTITY_STATE_PLAYER_T,
|
||||
DT_CUSTOM_ENTITY_STATE_T,
|
||||
#if XASH_ENGINE_TESTS
|
||||
DT_DELTA_TEST_STRUCT_T,
|
||||
#endif
|
||||
DT_STRUCT_COUNT
|
||||
};
|
||||
|
||||
static delta_info_t dt_info[] =
|
||||
@@ -378,10 +337,7 @@ static delta_info_t dt_info[] =
|
||||
[DT_ENTITY_STATE_T] = { "entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||
[DT_ENTITY_STATE_PLAYER_T] = { "entity_state_player_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||
[DT_CUSTOM_ENTITY_STATE_T] = { "custom_entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||
#if XASH_ENGINE_TESTS
|
||||
[DT_DELTA_TEST_STRUCT_T] = { "delta_test_struct_t", test_fields, NUM_FIELDS( test_fields ) },
|
||||
#endif
|
||||
[DT_STRUCT_COUNT] = { NULL },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static delta_info_t *Delta_FindStruct( const char *name )
|
||||
@@ -455,7 +411,9 @@ static void Delta_CustomEncode( delta_info_t *dt, const void *from, const void *
|
||||
dt->pFields[i].bInactive = false;
|
||||
|
||||
if( dt->userCallback )
|
||||
{
|
||||
dt->userCallback( dt->pFields, from, to );
|
||||
}
|
||||
}
|
||||
|
||||
static delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName )
|
||||
@@ -1016,14 +974,14 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
|
||||
toF = *(uint8_t *)((int8_t *)to + pField->offset );
|
||||
}
|
||||
|
||||
if( !Q_equal(pField->multiplier, 1.0f ))
|
||||
{
|
||||
fromF *= pField->multiplier;
|
||||
toF *= pField->multiplier;
|
||||
}
|
||||
|
||||
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
||||
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
|
||||
|
||||
if( !Q_equal(pField->multiplier, 1.0f ))
|
||||
fromF *= pField->multiplier;
|
||||
|
||||
if( !Q_equal( pField->multiplier, 1.0f ))
|
||||
toF *= pField->multiplier;
|
||||
}
|
||||
else if( pField->flags & DT_SHORT )
|
||||
{
|
||||
@@ -1038,14 +996,14 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
|
||||
toF = *(uint16_t *)((int8_t *)to + pField->offset );
|
||||
}
|
||||
|
||||
if( !Q_equal(pField->multiplier, 1.0f ))
|
||||
{
|
||||
fromF *= pField->multiplier;
|
||||
toF *= pField->multiplier;
|
||||
}
|
||||
|
||||
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
||||
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
|
||||
|
||||
if( !Q_equal(pField->multiplier, 1.0f ))
|
||||
fromF *= pField->multiplier;
|
||||
|
||||
if( !Q_equal( pField->multiplier, 1.0f ))
|
||||
toF *= pField->multiplier;
|
||||
}
|
||||
else if( pField->flags & DT_INTEGER )
|
||||
{
|
||||
@@ -1059,15 +1017,14 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
|
||||
fromF = *(uint32_t *)((int8_t *)from + pField->offset );
|
||||
toF = *(uint32_t *)((int8_t *)to + pField->offset );
|
||||
}
|
||||
|
||||
if( !Q_equal(pField->multiplier, 1.0f ))
|
||||
{
|
||||
fromF *= pField->multiplier;
|
||||
toF *= pField->multiplier;
|
||||
}
|
||||
|
||||
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
||||
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
|
||||
|
||||
if( !Q_equal(pField->multiplier, 1.0f ))
|
||||
fromF *= pField->multiplier;
|
||||
|
||||
if( !Q_equal( pField->multiplier, 1.0f ))
|
||||
toF *= pField->multiplier;
|
||||
}
|
||||
else if( pField->flags & ( DT_ANGLE|DT_FLOAT ))
|
||||
{
|
||||
@@ -1077,17 +1034,33 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
|
||||
}
|
||||
else if( pField->flags & DT_TIMEWINDOW_8 )
|
||||
{
|
||||
val_a = *(float *)((byte *)from + pField->offset );
|
||||
val_b = *(float *)((byte *)to + pField->offset );
|
||||
fromF = Q_rint(( timebase - val_a ) * 100.0 );
|
||||
toF = Q_rint(( timebase - val_b ) * 100.0 );
|
||||
val_a = Q_rint((*(float *)((byte *)from + pField->offset )) * 100.0f );
|
||||
val_b = Q_rint((*(float *)((byte *)to + pField->offset )) * 100.0f );
|
||||
val_a -= Q_rint(timebase * 100.0);
|
||||
val_b -= Q_rint(timebase * 100.0);
|
||||
fromF = FloatAsInt( val_a );
|
||||
toF = FloatAsInt( val_b );
|
||||
}
|
||||
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
||||
{
|
||||
val_a = *(float *)((byte *)from + pField->offset );
|
||||
val_b = *(float *)((byte *)to + pField->offset );
|
||||
fromF = Q_rint(( timebase - val_a ) * pField->multiplier );
|
||||
toF = Q_rint(( timebase - val_b ) * pField->multiplier );
|
||||
val_a = (*(float *)((byte *)from + pField->offset ));
|
||||
val_b = (*(float *)((byte *)to + pField->offset ));
|
||||
|
||||
if( !Q_equal( pField->multiplier, 1.0f ))
|
||||
{
|
||||
val_a *= pField->multiplier;
|
||||
val_b *= pField->multiplier;
|
||||
val_a = (timebase * pField->multiplier) - val_a;
|
||||
val_b = (timebase * pField->multiplier) - val_b;
|
||||
}
|
||||
else
|
||||
{
|
||||
val_a = timebase - val_a;
|
||||
val_b = timebase - val_b;
|
||||
}
|
||||
|
||||
fromF = FloatAsInt( val_a );
|
||||
toF = FloatAsInt( val_b );
|
||||
}
|
||||
else if( pField->flags & DT_STRING )
|
||||
{
|
||||
@@ -1171,7 +1144,6 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
|
||||
int signbit = FBitSet( pField->flags, DT_SIGNED ) ? 1 : 0;
|
||||
float flValue, flAngle;
|
||||
uint iValue;
|
||||
int dt;
|
||||
const char *pStr;
|
||||
|
||||
if( Delta_CompareField( pField, from, to, timebase ))
|
||||
@@ -1188,11 +1160,11 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
|
||||
iValue = *(int8_t *)((int8_t *)to + pField->offset );
|
||||
else
|
||||
iValue = *(uint8_t *)((int8_t *)to + pField->offset );
|
||||
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
||||
|
||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
||||
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||
iValue *= pField->multiplier;
|
||||
|
||||
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
||||
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||
}
|
||||
else if( pField->flags & DT_SHORT )
|
||||
@@ -1201,11 +1173,11 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
|
||||
iValue = *(int16_t *)((int8_t *)to + pField->offset );
|
||||
else
|
||||
iValue = *(uint16_t *)((int8_t *)to + pField->offset );
|
||||
|
||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
||||
iValue *= pField->multiplier;
|
||||
|
||||
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
||||
|
||||
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||
iValue *= pField->multiplier;
|
||||
|
||||
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||
}
|
||||
else if( pField->flags & DT_INTEGER )
|
||||
@@ -1214,11 +1186,11 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
|
||||
iValue = *(int32_t *)((int8_t *)to + pField->offset );
|
||||
else
|
||||
iValue = *(uint32_t *)((int8_t *)to + pField->offset );
|
||||
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
||||
|
||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
||||
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||
iValue *= pField->multiplier;
|
||||
|
||||
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
||||
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||
}
|
||||
else if( pField->flags & DT_FLOAT )
|
||||
@@ -1238,17 +1210,19 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
|
||||
}
|
||||
else if( pField->flags & DT_TIMEWINDOW_8 )
|
||||
{
|
||||
signbit = 1; // timewindow is always signed
|
||||
flValue = *(float *)((byte *)to + pField->offset );
|
||||
dt = Q_rint(( timebase - flValue ) * 100.0 );
|
||||
dt = Delta_ClampIntegerField( pField, dt, 1, pField->bits );
|
||||
MSG_WriteSBitLong( msg, dt, pField->bits );
|
||||
iValue = (int)Q_rint( timebase * 100.0 ) - (int)Q_rint( flValue * 100.0 );
|
||||
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
||||
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||
}
|
||||
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
||||
{
|
||||
signbit = 1; // timewindow is always signed
|
||||
flValue = *(float *)((byte *)to + pField->offset );
|
||||
dt = Q_rint(( timebase - flValue ) * pField->multiplier );
|
||||
dt = Delta_ClampIntegerField( pField, dt, 1, pField->bits );
|
||||
MSG_WriteSBitLong( msg, dt, pField->bits );
|
||||
iValue = (int)Q_rint( timebase * pField->multiplier ) - (int)Q_rint( flValue * pField->multiplier );
|
||||
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
||||
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||
}
|
||||
else if( pField->flags & DT_STRING )
|
||||
{
|
||||
@@ -1332,12 +1306,9 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
||||
if( pField->flags & DT_BYTE )
|
||||
{
|
||||
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
||||
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||
iValue /= pField->multiplier;
|
||||
|
||||
if( !Q_equal( pField->post_multiplier, 1.0 ))
|
||||
iValue *= pField->post_multiplier;
|
||||
|
||||
if( bSigned )
|
||||
*(int8_t *)((uint8_t *)to + pField->offset ) = iValue;
|
||||
else
|
||||
@@ -1346,12 +1317,9 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
||||
else if( pField->flags & DT_SHORT )
|
||||
{
|
||||
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
||||
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||
iValue /= pField->multiplier;
|
||||
|
||||
if( !Q_equal( pField->post_multiplier, 1.0 ))
|
||||
iValue *= pField->post_multiplier;
|
||||
|
||||
if( bSigned )
|
||||
*(int16_t *)((uint8_t *)to + pField->offset ) = iValue;
|
||||
else
|
||||
@@ -1360,12 +1328,9 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
||||
else if( pField->flags & DT_INTEGER )
|
||||
{
|
||||
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
||||
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||
iValue /= pField->multiplier;
|
||||
|
||||
if( !Q_equal( pField->post_multiplier, 1.0 ))
|
||||
iValue *= pField->post_multiplier;
|
||||
|
||||
if( bSigned )
|
||||
*(int32_t *)((uint8_t *)to + pField->offset ) = iValue;
|
||||
else
|
||||
@@ -1379,11 +1344,11 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
||||
else
|
||||
flValue = iValue;
|
||||
|
||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
||||
flValue /= pField->multiplier;
|
||||
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||
flValue = flValue / pField->multiplier;
|
||||
|
||||
if( !Q_equal( pField->post_multiplier, 1.0 ))
|
||||
flValue *= pField->post_multiplier;
|
||||
if( !Q_equal( pField->post_multiplier, 1.0 ) )
|
||||
flValue = flValue * pField->post_multiplier;
|
||||
|
||||
*(float *)((byte *)to + pField->offset ) = flValue;
|
||||
}
|
||||
@@ -1405,7 +1370,7 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
||||
bSigned = true; // timewindow is always signed
|
||||
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
||||
|
||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
||||
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||
flTime = ( timebase * pField->multiplier - (int)iValue ) / pField->multiplier;
|
||||
else
|
||||
flTime = timebase - (int)iValue;
|
||||
@@ -2104,103 +2069,3 @@ void GAME_EXPORT Delta_UnsetFieldByIndex( delta_t *pFields, int fieldNumber )
|
||||
|
||||
dt->pFields[fieldNumber].bInactive = true;
|
||||
}
|
||||
|
||||
#if XASH_ENGINE_TESTS
|
||||
#include "tests.h"
|
||||
|
||||
void Test_RunDelta( void )
|
||||
{
|
||||
delta_info_t *dt = &dt_info[DT_DELTA_TEST_STRUCT_T];
|
||||
delta_test_struct_t from, to = { 0 };
|
||||
delta_test_struct_t null = { 0 };
|
||||
sizebuf_t msg;
|
||||
int i;
|
||||
char buffer[4096] = { 0 };
|
||||
const double timebase = 123.123;
|
||||
|
||||
// a1ba: netbuffer bitmasks are initialized in netchan for some reason
|
||||
// initialize it ourselves just in case
|
||||
MSG_InitMasks(); // initialize bit-masks
|
||||
|
||||
Delta_AddField( dt, "dt_string", DT_STRING, 1, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "dt_timewindow_big", DT_TIMEWINDOW_BIG, 24, 1000.f, 1.0f );
|
||||
Delta_AddField( dt, "dt_timewindow_8", DT_TIMEWINDOW_8, 8, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "dt_angle", DT_ANGLE, 16, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "dt_float_signed", DT_FLOAT | DT_SIGNED, 22, 100.0f, 1.0f );
|
||||
Delta_AddField( dt, "dt_float_unsigned", DT_FLOAT, 24, 10000.0f, 0.1f );
|
||||
Delta_AddField( dt, "dt_integer_signed", DT_INTEGER | DT_SIGNED, 24, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "dt_integer_unsigned", DT_INTEGER, 24, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "dt_short_signed", DT_SHORT | DT_SIGNED, 16, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "dt_short_unsigned", DT_SHORT, 15, 0.125f, 1.0f );
|
||||
Delta_AddField( dt, "dt_byte_signed", DT_BYTE | DT_SIGNED, 6, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "dt_byte_unsigned", DT_BYTE, 8, 1.0f, 1.0f );
|
||||
|
||||
Q_strncpy( from.dt_string, "test data check it's the same", sizeof( from.dt_string ));
|
||||
from.dt_timewindow_big = timebase + 2.3456;
|
||||
from.dt_timewindow_8 = timebase + 0.0234;
|
||||
from.dt_angle = 160.245f;
|
||||
from.dt_float_signed = -15.123f;
|
||||
from.dt_float_unsigned = 1235.321f;
|
||||
from.dt_integer_signed = -412784;
|
||||
from.dt_integer_unsigned = 123453;
|
||||
from.dt_short_signed = -12343;
|
||||
from.dt_short_unsigned = 32131;
|
||||
from.dt_byte_signed = 16;
|
||||
from.dt_byte_unsigned = 218;
|
||||
|
||||
MSG_Init( &msg, "test message", buffer, sizeof( buffer ));
|
||||
|
||||
for( i = 0; i < dt->numFields; i++ )
|
||||
Delta_WriteField( &msg, &dt->pFields[i], &null, &from, timebase );
|
||||
|
||||
MSG_SeekToBit( &msg, 0, SEEK_SET );
|
||||
|
||||
for( i = 0; i < dt->numFields; i++ )
|
||||
Delta_ReadField( &msg, &dt->pFields[i], &null, &to, timebase );
|
||||
|
||||
Con_Printf( "struct as encoded to delta:\n" );
|
||||
TASSERT_STR( from.dt_string, to.dt_string );
|
||||
|
||||
// the epsilon value is derived from multiplier value
|
||||
TASSERT( Q_equal_e( from.dt_timewindow_big, to.dt_timewindow_big, 0.001f ));
|
||||
|
||||
// dt_timewindow_8 type has multiplier locked at 100.0f
|
||||
TASSERT( Q_equal_e( from.dt_timewindow_8, to.dt_timewindow_8, 0.01f ));
|
||||
TASSERT( Q_equal_e( from.dt_angle, to.dt_angle, 0.1f ));
|
||||
TASSERT( Q_equal_e( from.dt_float_signed, to.dt_float_signed, 0.01f ));
|
||||
|
||||
// dt_float_unsigned has post-multiplier that doesn't affect network data
|
||||
// and therefore should be reverted back when comparing
|
||||
TASSERT( Q_equal_e( from.dt_float_unsigned, to.dt_float_unsigned * 10.f , 0.01f ));
|
||||
|
||||
TASSERT_EQi( from.dt_integer_signed, to.dt_integer_signed );
|
||||
TASSERT_EQi( from.dt_integer_unsigned, to.dt_integer_unsigned );
|
||||
TASSERT_EQi( from.dt_short_signed, to.dt_short_signed );
|
||||
TASSERT(( from.dt_short_unsigned & ( 0xffff << 3 )) == to.dt_short_unsigned );
|
||||
TASSERT_EQi( from.dt_byte_signed, to.dt_byte_signed );
|
||||
TASSERT_EQi( from.dt_byte_unsigned, to.dt_byte_unsigned );
|
||||
|
||||
Con_Printf( "from.dt_timewindow_big = %f\n", from.dt_timewindow_big );
|
||||
Con_Printf( "to.dt_timewindow_big = %f\n", to.dt_timewindow_big );
|
||||
Con_Printf( "from.dt_timewindow_8 = %f\n", from.dt_timewindow_8 );
|
||||
Con_Printf( "to.dt_timewindow_8 = %f\n", to.dt_timewindow_8 );
|
||||
Con_Printf( "from.dt_angle = %f\n", from.dt_angle );
|
||||
Con_Printf( "to.dt_angle = %f\n", to.dt_angle );
|
||||
Con_Printf( "from.dt_float_signed = %f\n", from.dt_float_signed );
|
||||
Con_Printf( "to.dt_float_signed = %f\n", to.dt_float_signed );
|
||||
Con_Printf( "from.dt_float_unsigned = %f\n", from.dt_float_unsigned );
|
||||
Con_Printf( "to.dt_float_unsigned = %f\n", to.dt_float_unsigned );
|
||||
Con_Printf( "from.dt_integer_signed = %i\n", from.dt_integer_signed );
|
||||
Con_Printf( "to.dt_integer_signed = %i\n", to.dt_integer_signed );
|
||||
Con_Printf( "from.dt_integer_unsigned = %i\n", from.dt_integer_unsigned );
|
||||
Con_Printf( "to.dt_integer_unsigned = %i\n", to.dt_integer_unsigned );
|
||||
Con_Printf( "from.dt_short_signed = %i\n", from.dt_short_signed );
|
||||
Con_Printf( "to.dt_short_signed = %i\n", to.dt_short_signed );
|
||||
Con_Printf( "from.dt_short_unsigned = %i\n", from.dt_short_unsigned );
|
||||
Con_Printf( "to.dt_short_unsigned = %i\n", to.dt_short_unsigned );
|
||||
Con_Printf( "from.dt_byte_signed = %i\n", from.dt_byte_signed );
|
||||
Con_Printf( "to.dt_byte_signed = %i\n", to.dt_byte_signed );
|
||||
Con_Printf( "from.dt_byte_unsigned = %i\n", from.dt_byte_unsigned );
|
||||
Con_Printf( "to.dt_byte_unsigned = %i\n", to.dt_byte_unsigned );
|
||||
}
|
||||
#endif // XASH_ENGINE_TESTS
|
||||
|
||||
@@ -135,10 +135,6 @@ void Sys_InitLog( void )
|
||||
mode = "a";
|
||||
else mode = "w";
|
||||
|
||||
if( Host_IsDedicated( ))
|
||||
Q_strncpy( s_ld.title, XASH_DEDICATED_SERVER_NAME " " XASH_VERSION, sizeof( s_ld.title ));
|
||||
else Q_strncpy( s_ld.title, XASH_ENGINE_NAME " " XASH_VERSION, sizeof( s_ld.title ));
|
||||
|
||||
// create log if needed
|
||||
if( s_ld.log_active )
|
||||
{
|
||||
@@ -146,18 +142,15 @@ void Sys_InitLog( void )
|
||||
|
||||
if ( !s_ld.logfile )
|
||||
{
|
||||
Con_Reportf( S_ERROR "Sys_InitLog: can't create log file %s: %s\n", s_ld.log_path, strerror( errno ));
|
||||
Con_Reportf( S_ERROR "Sys_InitLog: can't create log file %s: %s\n", s_ld.log_path, strerror( errno ) );
|
||||
return;
|
||||
}
|
||||
|
||||
s_ld.logfileno = fileno( s_ld.logfile );
|
||||
|
||||
// fit to 80 columns for easier read on standard terminal
|
||||
fputs( "================================================================================\n", s_ld.logfile );
|
||||
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
fprintf( s_ld.logfile, "Game started at %s\n", Q_timestamp( TIME_FULL ));
|
||||
fputs( "================================================================================\n", s_ld.logfile );
|
||||
fflush( s_ld.logfile );
|
||||
fprintf( s_ld.logfile, "=================================================================================\n" );
|
||||
fprintf( s_ld.logfile, "\t%s (build %i commit %s (%s-%s)) started at %s\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch(), Q_timestamp( TIME_FULL ) );
|
||||
fprintf( s_ld.logfile, "=================================================================================\n" );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,11 +177,12 @@ void Sys_CloseLog( void )
|
||||
|
||||
if( s_ld.logfile )
|
||||
{
|
||||
fputc( '\n', s_ld.logfile );
|
||||
fputs( "================================================================================\n", s_ld.logfile );
|
||||
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
fprintf( s_ld.logfile, "Stopped with reason \"%s\" at %s\n", event_name, Q_timestamp( TIME_FULL ));
|
||||
fputs( "================================================================================\n", s_ld.logfile );
|
||||
fprintf( s_ld.logfile, "\n");
|
||||
fprintf( s_ld.logfile, "=================================================================================");
|
||||
if( host.change_game ) fprintf( s_ld.logfile, "\n\t%s (build %i) %s\n", s_ld.title, Q_buildnum(), event_name );
|
||||
else fprintf( s_ld.logfile, "\n\t%s (build %i) %s at %s\n", s_ld.title, Q_buildnum(), event_name, Q_timestamp( TIME_FULL ));
|
||||
fprintf( s_ld.logfile, "=================================================================================\n");
|
||||
|
||||
fclose( s_ld.logfile );
|
||||
s_ld.logfile = NULL;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ GNU General Public License for more details.
|
||||
#include "library.h"
|
||||
#include "whereami.h"
|
||||
|
||||
int error_on_exit = 0; // arg for exit();
|
||||
qboolean error_on_exit = false; // arg for exit();
|
||||
|
||||
/*
|
||||
================
|
||||
@@ -404,7 +404,7 @@ void Sys_Warn( const char *format, ... )
|
||||
Msg( "Sys_Warn: %s\n", text );
|
||||
|
||||
if( !Host_IsDedicated() ) // dedicated server should not hang on messagebox
|
||||
Platform_MessageBox( "Xash Warning", text, true );
|
||||
Platform_MessageBox( "Xash Warning", text, false );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -430,7 +430,7 @@ void Sys_Error( const char *error, ... )
|
||||
// make sure that console received last message
|
||||
if( host.change_game ) Sys_Sleep( 200 );
|
||||
|
||||
error_on_exit = 1;
|
||||
error_on_exit = true;
|
||||
host.status = HOST_ERR_FATAL;
|
||||
va_start( argptr, error );
|
||||
Q_vsnprintf( text, MAX_PRINT_MSG, error, argptr );
|
||||
@@ -449,7 +449,7 @@ void Sys_Error( const char *error, ... )
|
||||
Wcon_ShowConsole( false );
|
||||
#endif
|
||||
Sys_Print( text );
|
||||
Platform_MessageBox( "Xash Error", text, true );
|
||||
Platform_MessageBox( "Xash Error", text, false );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -41,7 +41,7 @@ NOTE: never change this structure because all dll descriptions in xash code
|
||||
writes into struct by offsets not names
|
||||
========================================================================
|
||||
*/
|
||||
extern int error_on_exit;
|
||||
|
||||
void Sys_Sleep( int msec );
|
||||
double Sys_DoubleTime( void );
|
||||
char *Sys_GetClipboardData( void );
|
||||
|
||||
@@ -39,15 +39,13 @@ void Test_RunCon( void );
|
||||
void Test_RunVOX( void );
|
||||
void Test_RunIPFilter( void );
|
||||
void Test_RunGamma( void );
|
||||
void Test_RunDelta( void );
|
||||
|
||||
#define TEST_LIST_0 \
|
||||
Test_RunLibCommon(); \
|
||||
Test_RunCommon(); \
|
||||
Test_RunCmd(); \
|
||||
Test_RunCvar(); \
|
||||
Test_RunIPFilter(); \
|
||||
Test_RunDelta();
|
||||
Test_RunIPFilter();
|
||||
|
||||
#define TEST_LIST_0_CLIENT \
|
||||
Test_RunCon(); \
|
||||
|
||||
@@ -14,7 +14,7 @@ GNU General Public License for more details.
|
||||
*/
|
||||
#include "platform/platform.h"
|
||||
|
||||
#if !defined(XASH_DEDICATED)
|
||||
#if !defined(XASH_DEDICATED) && XASH_SDL
|
||||
|
||||
#include "input.h"
|
||||
#include "client.h"
|
||||
|
||||
1064
engine/platform/android/android_nosdl.c
Normal file
1064
engine/platform/android/android_nosdl.c
Normal file
File diff suppressed because it is too large
Load Diff
55
engine/platform/android/android_priv.h
Normal file
55
engine/platform/android/android_priv.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
#ifndef ANDROID_PRIV_H
|
||||
#define ANDROID_PRIV_H
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <android/log.h>
|
||||
#include <jni.h>
|
||||
|
||||
extern struct jnimethods_s
|
||||
{
|
||||
jclass actcls;
|
||||
jclass bindcls;
|
||||
JavaVM *vm;
|
||||
JNIEnv *env;
|
||||
jmethodID enableTextInput;
|
||||
jmethodID vibrate;
|
||||
jmethodID messageBox;
|
||||
jmethodID notify;
|
||||
jmethodID setTitle;
|
||||
jmethodID setIcon;
|
||||
jmethodID getAndroidId;
|
||||
jmethodID saveID;
|
||||
jmethodID loadID;
|
||||
jmethodID showMouse;
|
||||
jmethodID shellExecute;
|
||||
jmethodID swapBuffers;
|
||||
jmethodID toggleEGL;
|
||||
jmethodID createGLContext;
|
||||
jmethodID getGLAttribute;
|
||||
jmethodID deleteGLContext;
|
||||
jmethodID getSurface;
|
||||
jmethodID preShutdown;
|
||||
int width, height;
|
||||
} jni;
|
||||
|
||||
typedef enum surfacestate_e
|
||||
{
|
||||
surface_pause,
|
||||
surface_active,
|
||||
surface_dummy,
|
||||
|
||||
} surfacestate_t;
|
||||
|
||||
|
||||
extern struct jnimouse_s
|
||||
{
|
||||
float x, y;
|
||||
} jnimouse;
|
||||
|
||||
//
|
||||
// vid_android.c
|
||||
//
|
||||
void Android_UpdateSurface( surfacestate_t state );
|
||||
|
||||
#endif // ANDROID_PRIV_H
|
||||
@@ -25,30 +25,36 @@
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#if defined __ANDROID__ && !defined XASH_64BIT
|
||||
#include "build.h"
|
||||
#if !XASH_64BIT
|
||||
#include <string.h>
|
||||
#include <android/log.h>
|
||||
#include <dlfcn.h>
|
||||
#include "linker.h"
|
||||
extern "C" {
|
||||
#include "lib_android.h"
|
||||
}
|
||||
|
||||
static Elf_Sym* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
|
||||
static Elf_Sym* soinfo_elf_lookup( soinfo* si, unsigned hash, const char* name )
|
||||
{
|
||||
Elf_Sym* symtab = si->symtab;
|
||||
const char* strtab = si->strtab;
|
||||
|
||||
if( si->nbucket == 0 )
|
||||
return NULL;
|
||||
|
||||
for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) {
|
||||
for( unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n] )
|
||||
{
|
||||
Elf_Sym* s = symtab + n;
|
||||
if (strcmp(strtab + s->st_name, name)) continue;
|
||||
if( strcmp( strtab + s->st_name, name )) continue;
|
||||
|
||||
/* only concern ourselves with global and weak symbol definitions */
|
||||
switch (ELF_ST_BIND(s->st_info)) {
|
||||
switch( ELF_ST_BIND( s->st_info ))
|
||||
{
|
||||
case STB_GLOBAL:
|
||||
case STB_WEAK:
|
||||
if (s->st_shndx == SHN_UNDEF) {
|
||||
if( s->st_shndx == SHN_UNDEF )
|
||||
continue;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -56,11 +62,44 @@ static Elf_Sym* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned elfhash(const char* _name) {
|
||||
const unsigned char* name = (const unsigned char*) _name;
|
||||
static Elf_Sym* soinfo_elf_lookup_reverse(soinfo* si, size_t addr)
|
||||
{
|
||||
Elf_Sym* symtab = si->symtab;
|
||||
|
||||
if( si->nbucket == 0 )
|
||||
return NULL;
|
||||
|
||||
for( int j = 0; j < si->nbucket; j++ )
|
||||
{
|
||||
for( unsigned n = si->bucket[j]; n != 0; n = si->chain[n] )
|
||||
{
|
||||
Elf_Sym* s = symtab + n;
|
||||
if( s->st_value != addr )continue;
|
||||
|
||||
/* only concern ourselves with global and weak symbol definitions */
|
||||
switch( ELF_ST_BIND( s->st_info ))
|
||||
{
|
||||
case STB_GLOBAL:
|
||||
case STB_LOCAL:
|
||||
case STB_WEAK:
|
||||
if (s->st_shndx == SHN_UNDEF)
|
||||
continue;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static unsigned elfhash( const char* _name )
|
||||
{
|
||||
const unsigned char* name = ( const unsigned char* ) _name;
|
||||
unsigned h = 0, g;
|
||||
|
||||
while(*name) {
|
||||
while(*name)
|
||||
{
|
||||
h = (h << 4) + *name++;
|
||||
g = h & 0xf0000000;
|
||||
h ^= g;
|
||||
@@ -78,21 +117,73 @@ static unsigned elfhash(const char* _name) {
|
||||
Binary Interface) where in Chapter 5 it discuss resolving "Shared
|
||||
Object Dependencies" in breadth first search order.
|
||||
*/
|
||||
static Elf_Sym* dlsym_handle_lookup(soinfo* si, const char* name) {
|
||||
return soinfo_elf_lookup(si, elfhash(name), name);
|
||||
static Elf_Sym* dlsym_handle_lookup( soinfo* si, const char* name )
|
||||
{
|
||||
return soinfo_elf_lookup( si, elfhash( name ), name );
|
||||
}
|
||||
|
||||
extern "C" void* dlsym_weak(void* handle, const char* symbol) {
|
||||
static int dladdr_fallback( const void *addr, Dl_info *info )
|
||||
{
|
||||
static soinfo *server_info;
|
||||
Elf_Sym *sym;
|
||||
|
||||
if( !server_info )
|
||||
server_info = ( soinfo* )ANDROID_GetServerLibrary();
|
||||
if( !server_info )
|
||||
return 0;
|
||||
//__android_log_print( ANDROID_LOG_ERROR, "dladdr_fb", "%p %p\n", addr, server_info );
|
||||
|
||||
sym = soinfo_elf_lookup_reverse( server_info, ((char*)addr) - ((char*)server_info->base ));
|
||||
//__android_log_print( ANDROID_LOG_ERROR, "dladdr_fb", "sym %p %p\n", addr, sym );
|
||||
if( sym )
|
||||
{
|
||||
info->dli_sname = server_info->strtab + sym->st_name;
|
||||
info->dli_fname = "server";
|
||||
info->dli_fbase = (void*)server_info->base;
|
||||
info->dli_saddr = (void*)addr;
|
||||
//__android_log_print( ANDROID_LOG_ERROR, "dladdr_fb", "name %p %s\n", addr, info->dli_sname );
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern "C" int __attribute__((visibility("hidden"))) dladdr( const void *addr, Dl_info *info )
|
||||
{
|
||||
typedef int (*PFNDLADDR)( const void *addr, Dl_info *info );
|
||||
PFNDLADDR pfn_dladdr;
|
||||
|
||||
if( !pfn_dladdr )
|
||||
{
|
||||
/* android does not have libdl, but have soinfo record for it from linker
|
||||
* use dlopen to get this record directly */
|
||||
void *lib = dlopen( "libdl.so", RTLD_NOW );
|
||||
|
||||
if( lib )
|
||||
pfn_dladdr = (PFNDLADDR)dlsym( lib, "dladdr" );
|
||||
if( pfn_dladdr == (PFNDLADDR)dladdr )
|
||||
pfn_dladdr = 0;
|
||||
if( !pfn_dladdr )
|
||||
pfn_dladdr = (PFNDLADDR)dladdr_fallback;
|
||||
}
|
||||
|
||||
return pfn_dladdr( addr, info );
|
||||
}
|
||||
|
||||
|
||||
extern "C" void* dlsym_weak( void* handle, const char* symbol ) {
|
||||
|
||||
soinfo* found = NULL;
|
||||
Elf_Sym* sym = NULL;
|
||||
found = reinterpret_cast<soinfo*>(handle);
|
||||
sym = dlsym_handle_lookup(found, symbol);
|
||||
found = reinterpret_cast<soinfo*>( handle );
|
||||
sym = dlsym_handle_lookup( found, symbol );
|
||||
|
||||
if (sym != NULL) {
|
||||
return reinterpret_cast<void*>(sym->st_value + found->base/*load_bias*/);
|
||||
if ( sym != NULL ) {
|
||||
return reinterpret_cast<void*>( sym->st_value + found->base /*load_bias*/ );
|
||||
}
|
||||
__android_log_print(ANDROID_LOG_ERROR, "dlsym-weak", "Failed when looking up %s\n", symbol);
|
||||
__android_log_print( ANDROID_LOG_ERROR, "dlsym-weak", "Failed when looking up %s\n", symbol );
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
453
engine/platform/android/eglutil.c
Normal file
453
engine/platform/android/eglutil.c
Normal file
@@ -0,0 +1,453 @@
|
||||
/*
|
||||
eglutil.c - EGL context utility
|
||||
Copyright (C) 2023 mittorn
|
||||
|
||||
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/platform.h"
|
||||
#if !defined(XASH_DEDICATED) && !XASH_SDL
|
||||
#include "eglutil.h"
|
||||
#include "client.h"
|
||||
#include "vid_common.h"
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
struct eglapi_s egl;
|
||||
|
||||
#undef GetProcAddress // windows.h?
|
||||
#define EGL_FF(x) {"egl"#x, (void*)&egl.x}
|
||||
static dllfunc_t egl_funcs[] =
|
||||
{
|
||||
EGL_FF(SwapInterval),
|
||||
EGL_FF(SwapBuffers),
|
||||
EGL_FF(GetError),
|
||||
EGL_FF(GetCurrentDisplay),
|
||||
EGL_FF(GetCurrentSurface),
|
||||
EGL_FF(GetProcAddress),
|
||||
EGL_FF(GetConfigAttrib),
|
||||
EGL_FF(GetDisplay),
|
||||
EGL_FF(Initialize),
|
||||
EGL_FF(Terminate),
|
||||
EGL_FF(QueryString),
|
||||
EGL_FF(ChooseConfig),
|
||||
EGL_FF(CreateWindowSurface),
|
||||
EGL_FF(CreateContext),
|
||||
EGL_FF(DestroyContext),
|
||||
EGL_FF(MakeCurrent),
|
||||
EGL_FF(BindAPI),
|
||||
EGL_FF(DestroySurface),
|
||||
{ NULL, NULL }
|
||||
};
|
||||
#undef EGL_FF
|
||||
static dll_info_t egl_info = { "libEGL.so", egl_funcs, false };
|
||||
|
||||
struct eglstate_s eglstate;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
|
||||
refapi/egl wrappers
|
||||
|
||||
===================
|
||||
*/
|
||||
|
||||
int EGL_SetAttribute( int attr, int val )
|
||||
{
|
||||
if( attr < 0 || attr >= REF_GL_ATTRIBUTES_COUNT )
|
||||
return -1;
|
||||
|
||||
eglstate.gl_attribs[attr] = val;
|
||||
eglstate.gl_attribs_set[attr] = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define COPY_ATTR_IF_SET( refattr, attr ) \
|
||||
if( eglstate.gl_attribs_set[refattr] ) \
|
||||
{ \
|
||||
attribs[i++] = attr; \
|
||||
attribs[i++] = eglstate.gl_attribs[refattr]; \
|
||||
}
|
||||
|
||||
size_t EGL_GenerateConfig( EGLint *attribs, size_t size )
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
memset( attribs, 0, size * sizeof( EGLint ) );
|
||||
eglstate.gles1 = false;
|
||||
memset( eglstate.gl_attribs, 0, sizeof( eglstate.gl_attribs ));
|
||||
memset( eglstate.gl_attribs_set, 0, sizeof( eglstate.gl_attribs_set ));
|
||||
|
||||
// refdll can request some attributes
|
||||
ref.dllFuncs.GL_SetupAttributes( glw_state.safe );
|
||||
|
||||
COPY_ATTR_IF_SET( REF_GL_RED_SIZE, EGL_RED_SIZE );
|
||||
COPY_ATTR_IF_SET( REF_GL_GREEN_SIZE, EGL_GREEN_SIZE );
|
||||
COPY_ATTR_IF_SET( REF_GL_BLUE_SIZE, EGL_BLUE_SIZE );
|
||||
COPY_ATTR_IF_SET( REF_GL_ALPHA_SIZE, EGL_ALPHA_SIZE );
|
||||
COPY_ATTR_IF_SET( REF_GL_DEPTH_SIZE, EGL_DEPTH_SIZE );
|
||||
COPY_ATTR_IF_SET( REF_GL_STENCIL_SIZE, EGL_STENCIL_SIZE );
|
||||
COPY_ATTR_IF_SET( REF_GL_MULTISAMPLEBUFFERS, EGL_SAMPLE_BUFFERS );
|
||||
COPY_ATTR_IF_SET( REF_GL_MULTISAMPLESAMPLES, EGL_SAMPLES );
|
||||
|
||||
if( eglstate.gl_attribs_set[REF_GL_ACCELERATED_VISUAL] )
|
||||
{
|
||||
attribs[i++] = EGL_CONFIG_CAVEAT;
|
||||
attribs[i++] = eglstate.gl_attribs[REF_GL_ACCELERATED_VISUAL] ? EGL_NONE : EGL_DONT_CARE;
|
||||
}
|
||||
|
||||
// BigGL support
|
||||
attribs[i++] = EGL_RENDERABLE_TYPE;
|
||||
eglstate.gl_api = EGL_OPENGL_ES_API;
|
||||
|
||||
if( eglstate.gl_attribs_set[REF_GL_CONTEXT_PROFILE_MASK] &&
|
||||
!( eglstate.gl_attribs[REF_GL_CONTEXT_PROFILE_MASK] & REF_GL_CONTEXT_PROFILE_ES ))
|
||||
{
|
||||
attribs[i++] = EGL_OPENGL_BIT;
|
||||
eglstate.gl_api = EGL_OPENGL_API;
|
||||
}
|
||||
else if( eglstate.gl_attribs_set[REF_GL_CONTEXT_MAJOR_VERSION] &&
|
||||
eglstate.gl_attribs[REF_GL_CONTEXT_MAJOR_VERSION] >= 2 )
|
||||
{
|
||||
attribs[i++] = EGL_OPENGL_ES2_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
i--; // erase EGL_RENDERABLE_TYPE
|
||||
eglstate.gles1 = true;
|
||||
}
|
||||
|
||||
attribs[i++] = EGL_NONE;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
size_t EGL_GenerateContextConfig( EGLint *attribs, size_t size )
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
memset( attribs, 0, size * sizeof( EGLint ));
|
||||
|
||||
if( Q_strstr( eglstate.extensions, "EGL_KHR_create_context") )
|
||||
{
|
||||
Con_DPrintf( S_NOTE "EGL_KHR_create_context found, setting additional context flags\n");
|
||||
|
||||
if( eglstate.gl_attribs_set[REF_GL_CONTEXT_FLAGS] )
|
||||
{
|
||||
attribs[i++] = 0x30FC; // EGL_CONTEXT_FLAGS_KHR
|
||||
attribs[i++] = eglstate.gl_attribs[REF_GL_CONTEXT_FLAGS] & ((REF_GL_CONTEXT_ROBUST_ACCESS_FLAG << 1) - 1);
|
||||
}
|
||||
|
||||
if( eglstate.gl_attribs_set[REF_GL_CONTEXT_PROFILE_MASK] )
|
||||
{
|
||||
int val = eglstate.gl_attribs[REF_GL_CONTEXT_PROFILE_MASK];
|
||||
|
||||
if( val & ( (REF_GL_CONTEXT_PROFILE_COMPATIBILITY << 1) - 1 ) )
|
||||
{
|
||||
attribs[i++] = 0x30FD; // EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
|
||||
attribs[i++] = val;
|
||||
}
|
||||
}
|
||||
|
||||
COPY_ATTR_IF_SET( REF_GL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_CLIENT_VERSION );
|
||||
COPY_ATTR_IF_SET( REF_GL_CONTEXT_MINOR_VERSION, 0x30FB );
|
||||
}
|
||||
else
|
||||
{
|
||||
// without extension we can set only major version
|
||||
COPY_ATTR_IF_SET( REF_GL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_CLIENT_VERSION );
|
||||
if( eglstate.gl_attribs_set[REF_GL_CONTEXT_FLAGS] && (eglstate.gl_attribs[REF_GL_CONTEXT_FLAGS] & REF_GL_CONTEXT_DEBUG_FLAG ))
|
||||
{
|
||||
attribs[i++] = 0x31B0; // EGL_CONTEXT_OPENGL_DEBUG;
|
||||
attribs[i++] = EGL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
attribs[i++] = EGL_NONE;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=========================
|
||||
EGL_GetAttribute
|
||||
|
||||
query
|
||||
=========================
|
||||
*/
|
||||
int EGL_GetAttribute( int attr, int *val )
|
||||
{
|
||||
EGLBoolean ret;
|
||||
|
||||
if( attr < 0 || attr >= REF_GL_ATTRIBUTES_COUNT )
|
||||
return -1;
|
||||
|
||||
if( !val )
|
||||
return -1;
|
||||
|
||||
switch( attr )
|
||||
{
|
||||
case REF_GL_RED_SIZE:
|
||||
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_RED_SIZE, val );
|
||||
return 0;
|
||||
case REF_GL_GREEN_SIZE:
|
||||
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_GREEN_SIZE, val );
|
||||
return 0;
|
||||
case REF_GL_BLUE_SIZE:
|
||||
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_BLUE_SIZE, val );
|
||||
return 0;
|
||||
case REF_GL_ALPHA_SIZE:
|
||||
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_ALPHA_SIZE, val );
|
||||
return 0;
|
||||
case REF_GL_DEPTH_SIZE:
|
||||
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_DEPTH_SIZE, val );
|
||||
return 0;
|
||||
case REF_GL_STENCIL_SIZE:
|
||||
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_STENCIL_SIZE, val );
|
||||
return 0;
|
||||
case REF_GL_MULTISAMPLESAMPLES:
|
||||
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_SAMPLES, val );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=========================
|
||||
EGL_UpdateSurface
|
||||
|
||||
destroy old surface, recreate and make context current
|
||||
must be called with valid context
|
||||
=========================
|
||||
*/
|
||||
qboolean EGL_UpdateSurface( void *window, qboolean dummy )
|
||||
{
|
||||
if( !eglstate.valid )
|
||||
return false;
|
||||
|
||||
egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
|
||||
host.status = HOST_SLEEP;
|
||||
|
||||
if( eglstate.surface )
|
||||
{
|
||||
egl.DestroySurface( eglstate.dpy, eglstate.surface );
|
||||
eglstate.surface = EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
if( !window )
|
||||
{
|
||||
|
||||
if( dummy && eglstate.support_surfaceless_context )
|
||||
{
|
||||
if( egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, eglstate.context ))
|
||||
{
|
||||
Con_Reportf( S_NOTE "EGL_UpdateSurface: using surfaceless mode\n" );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
|
||||
eglstate.support_surfaceless_context = false;
|
||||
}
|
||||
Con_Reportf( S_NOTE "EGL_UpdateSurface: missing native window, detaching context\n" );
|
||||
}
|
||||
|
||||
return false; // let platform fallback to dummy surface or pause engine
|
||||
}
|
||||
|
||||
if(( eglstate.surface = egl.CreateWindowSurface( eglstate.dpy, eglstate.cfg, window, NULL )) == EGL_NO_SURFACE )
|
||||
{
|
||||
Con_Reportf( S_ERROR "eglCreateWindowSurface returned error: 0x%x\n", egl.GetError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !egl.MakeCurrent( eglstate.dpy, eglstate.surface, eglstate.surface, eglstate.context ))
|
||||
{
|
||||
Con_Reportf( S_ERROR "eglMakeCurrent returned error: 0x%x\n", egl.GetError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
Con_DPrintf( S_NOTE "restored current context\n" );
|
||||
if( !dummy)
|
||||
host.status = HOST_FRAME;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=========================
|
||||
EGL_CreateContext
|
||||
|
||||
query attributes for ref and create context
|
||||
=========================
|
||||
*/
|
||||
qboolean EGL_CreateContext( void )
|
||||
{
|
||||
EGLint attribs[32+1], contextAttribs[32+1];
|
||||
const size_t attribsSize = ARRAYSIZE( attribs );
|
||||
size_t s1, s2;
|
||||
|
||||
if( !eglstate.dpy && ( eglstate.dpy = egl.GetDisplay( EGL_DEFAULT_DISPLAY )) == EGL_NO_DISPLAY )
|
||||
{
|
||||
Con_Reportf( S_ERROR "eglGetDisplay returned error: 0x%x\n", egl.GetError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
eglstate.extensions = egl.QueryString( eglstate.dpy, EGL_EXTENSIONS );
|
||||
|
||||
s1 = EGL_GenerateConfig(attribs, attribsSize);
|
||||
s2 = EGL_GenerateContextConfig(contextAttribs, attribsSize);
|
||||
|
||||
|
||||
if( !egl.BindAPI( eglstate.gl_api ))
|
||||
{
|
||||
Con_Reportf( S_ERROR "eglBindAPI returned error: 0x%x\n", egl.GetError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !egl.Initialize( eglstate.dpy, NULL, NULL ))
|
||||
{
|
||||
Con_Reportf( S_ERROR "eglInitialize returned error: 0x%x\n", egl.GetError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !egl.ChooseConfig( eglstate.dpy, attribs, &eglstate.cfg, 1, &eglstate.numCfg ))
|
||||
{
|
||||
Con_Reportf( S_ERROR "eglChooseConfig returned error: 0x%x\n", egl.GetError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if(( eglstate.context = egl.CreateContext( eglstate.dpy, eglstate.cfg, NULL, contextAttribs )) == EGL_NO_CONTEXT )
|
||||
{
|
||||
Con_Reportf( S_ERROR "eglCreateContext returned error: 0x%x\n", egl.GetError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
eglstate.valid = true;
|
||||
eglstate.imported = false;
|
||||
|
||||
// now check if it's safe to use surfaceless context here without surface fallback
|
||||
if( eglstate.extensions && Q_strstr( eglstate.extensions, "EGL_KHR_surfaceless_context" ))
|
||||
eglstate.support_surfaceless_context = true;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
===========================
|
||||
EGL_ImportContext
|
||||
|
||||
import current egl context to use EGL functions
|
||||
===========================
|
||||
*/
|
||||
qboolean EGL_ImportContext( void )
|
||||
{
|
||||
if( !egl.GetCurrentDisplay )
|
||||
return false;
|
||||
|
||||
eglstate.dpy = egl.GetCurrentDisplay();
|
||||
|
||||
if( eglstate.dpy == EGL_NO_DISPLAY )
|
||||
return false;
|
||||
|
||||
eglstate.surface = egl.GetCurrentSurface( EGL_DRAW );
|
||||
|
||||
if( eglstate.surface == EGL_NO_SURFACE )
|
||||
return false;
|
||||
|
||||
// now check if swapBuffers does not give error
|
||||
if( egl.SwapBuffers( eglstate.dpy, eglstate.surface ) == EGL_FALSE )
|
||||
return false;
|
||||
|
||||
// double check
|
||||
if( egl.GetError() != EGL_SUCCESS )
|
||||
return false;
|
||||
|
||||
eglstate.extensions = egl.QueryString( eglstate.dpy, EGL_EXTENSIONS );
|
||||
|
||||
eglstate.valid = eglstate.imported = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
EGL_Terminate
|
||||
=========================
|
||||
*/
|
||||
void EGL_Terminate( void )
|
||||
{
|
||||
egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
|
||||
|
||||
egl.DestroyContext( eglstate.dpy, eglstate.context );
|
||||
|
||||
egl.DestroySurface( eglstate.dpy, eglstate.surface );
|
||||
|
||||
egl.Terminate( eglstate.dpy );
|
||||
|
||||
Sys_FreeLibrary( &egl_info );
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
EGL_GetProcAddress
|
||||
|
||||
eglGetProcAddress/dlsym wrapper
|
||||
=========================
|
||||
*/
|
||||
void *EGL_GetProcAddress( const char *name )
|
||||
{
|
||||
void *gles;
|
||||
void *addr;
|
||||
|
||||
// TODO: cross-platform loading
|
||||
if( eglstate.gles1 )
|
||||
{
|
||||
if( !eglstate.libgles1 )
|
||||
eglstate.libgles1 = dlopen( "libGLESv1_CM.so", RTLD_NOW );
|
||||
gles = eglstate.libgles1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !eglstate.libgles2 )
|
||||
eglstate.libgles2 = dlopen( "libGLESv2.so", RTLD_NOW );
|
||||
gles = eglstate.libgles2;
|
||||
}
|
||||
|
||||
if( gles && ( addr = dlsym( gles, name )))
|
||||
return addr;
|
||||
|
||||
if( !egl.GetProcAddress )
|
||||
return NULL;
|
||||
|
||||
return egl.GetProcAddress( name );
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
EGL_LoadLibrary
|
||||
=========================
|
||||
*/
|
||||
void EGL_LoadLibrary( void )
|
||||
{
|
||||
Sys_LoadLibrary( &egl_info );
|
||||
}
|
||||
#endif
|
||||
73
engine/platform/android/eglutil.h
Normal file
73
engine/platform/android/eglutil.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
eglutil.h - EGL context utility
|
||||
Copyright (C) 2023 mittorn
|
||||
|
||||
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 EGLUTIL_H
|
||||
#define EGLUTIL_H
|
||||
#include "platform/platform.h"
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
extern struct eglstate_s
|
||||
{
|
||||
qboolean valid, imported;
|
||||
EGLDisplay dpy;
|
||||
EGLSurface surface;
|
||||
EGLContext context;
|
||||
EGLConfig cfg;
|
||||
EGLint numCfg;
|
||||
qboolean support_surfaceless_context;
|
||||
|
||||
const char *extensions;
|
||||
int gl_attribs[REF_GL_ATTRIBUTES_COUNT];
|
||||
qboolean gl_attribs_set[REF_GL_ATTRIBUTES_COUNT];
|
||||
EGLint gl_api;
|
||||
qboolean gles1;
|
||||
void *libgles1, *libgles2;
|
||||
} eglstate;
|
||||
|
||||
extern struct eglapi_s
|
||||
{
|
||||
EGLSurface (*GetCurrentSurface)( EGLint readdraw );
|
||||
EGLDisplay (*GetCurrentDisplay)( void );
|
||||
EGLint (*GetError)( void );
|
||||
EGLBoolean (*SwapBuffers)( EGLDisplay dpy, EGLSurface surface );
|
||||
EGLBoolean (*SwapInterval)( EGLDisplay dpy, EGLint interval );
|
||||
void *(*GetProcAddress)( const char *procname );
|
||||
EGLBoolean (*GetConfigAttrib)( EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value );
|
||||
EGLDisplay (*GetDisplay)( NativeDisplayType display );
|
||||
EGLBoolean (*Initialize)( EGLDisplay dpy, EGLint *major, EGLint *minor );
|
||||
EGLBoolean (*Terminate)( EGLDisplay dpy );
|
||||
const char *(*QueryString)( EGLDisplay dpy, EGLint name );
|
||||
EGLBoolean (*ChooseConfig)( EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config );
|
||||
EGLSurface (*CreateWindowSurface)( EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list );
|
||||
EGLContext (*CreateContext)( EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list );
|
||||
EGLBoolean (*DestroyContext)( EGLDisplay dpy, EGLContext ctx );
|
||||
EGLBoolean (*MakeCurrent)( EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx );
|
||||
EGLBoolean (*BindAPI)( EGLenum api );
|
||||
EGLBoolean (*DestroySurface)( EGLDisplay dpy, EGLSurface surface );
|
||||
|
||||
} egl;
|
||||
|
||||
void EGL_LoadLibrary( void );
|
||||
void * EGL_GetProcAddress( const char *name );
|
||||
void EGL_Terminate( void );
|
||||
qboolean EGL_ImportContext( void );
|
||||
qboolean EGL_CreateContext( void );
|
||||
qboolean EGL_UpdateSurface( void *window, qboolean dummy );
|
||||
int EGL_GetAttribute( int attr, int *val );
|
||||
size_t EGL_GenerateContextConfig( EGLint *attribs, size_t size );
|
||||
size_t EGL_GenerateConfig( EGLint *attribs, size_t size );
|
||||
int EGL_SetAttribute( int attr, int val );
|
||||
|
||||
#endif // EGLUTIL_H
|
||||
@@ -19,6 +19,12 @@ GNU General Public License for more details.
|
||||
#include "platform/android/lib_android.h"
|
||||
#include "platform/android/dlsym-weak.h" // Android < 5.0
|
||||
|
||||
void *ANDROID_GetServerLibrary( void )
|
||||
{
|
||||
return svgame.hInstance;
|
||||
}
|
||||
|
||||
|
||||
void *ANDROID_LoadLibrary( const char *dllname )
|
||||
{
|
||||
char path[MAX_SYSPATH];
|
||||
|
||||
@@ -20,6 +20,7 @@ GNU General Public License for more details.
|
||||
#define Platform_POSIX_LoadLibrary( x ) ANDROID_LoadLibrary(( x ))
|
||||
#define Platform_POSIX_GetProcAddress( x, y ) ANDROID_GetProcAddress(( x ), ( y ))
|
||||
|
||||
void *ANDROID_GetServerLibrary( void );
|
||||
void *ANDROID_LoadLibrary( const char *dllname );
|
||||
void *ANDROID_GetProcAddress( void *hInstance, const char *name );
|
||||
|
||||
|
||||
277
engine/platform/android/snd_opensles.c
Normal file
277
engine/platform/android/snd_opensles.c
Normal file
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
Copyright (C) 2015 SiPlus, Chasseur de bots
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "platform/platform.h"
|
||||
#if XASH_SOUND == SOUND_OPENSLES
|
||||
#include <SLES/OpenSLES.h>
|
||||
#include "pthread.h"
|
||||
#include "sound.h"
|
||||
|
||||
extern dma_t dma;
|
||||
|
||||
static SLObjectItf snddma_android_engine = NULL;
|
||||
static SLObjectItf snddma_android_outputMix = NULL;
|
||||
static SLObjectItf snddma_android_player = NULL;
|
||||
static SLBufferQueueItf snddma_android_bufferQueue;
|
||||
static SLPlayItf snddma_android_play;
|
||||
|
||||
static pthread_mutex_t snddma_android_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static int snddma_android_size;
|
||||
|
||||
static const SLInterfaceID *pSL_IID_ENGINE;
|
||||
static const SLInterfaceID *pSL_IID_BUFFERQUEUE;
|
||||
static const SLInterfaceID *pSL_IID_PLAY;
|
||||
static SLresult SLAPIENTRY (*pslCreateEngine)(
|
||||
SLObjectItf *pEngine,
|
||||
SLuint32 numOptions,
|
||||
const SLEngineOption *pEngineOptions,
|
||||
SLuint32 numInterfaces,
|
||||
const SLInterfaceID *pInterfaceIds,
|
||||
const SLboolean * pInterfaceRequired
|
||||
);
|
||||
|
||||
void SNDDMA_Activate( qboolean active )
|
||||
{
|
||||
if( !dma.initialized )
|
||||
return;
|
||||
|
||||
if( active )
|
||||
{
|
||||
memset( dma.buffer, 0, snddma_android_size * 2 );
|
||||
(*snddma_android_bufferQueue)->Enqueue( snddma_android_bufferQueue, dma.buffer, snddma_android_size );
|
||||
(*snddma_android_play)->SetPlayState( snddma_android_play, SL_PLAYSTATE_PLAYING );
|
||||
}
|
||||
else
|
||||
{
|
||||
(*snddma_android_play)->SetPlayState( snddma_android_play, SL_PLAYSTATE_STOPPED );
|
||||
(*snddma_android_bufferQueue)->Clear( snddma_android_bufferQueue );
|
||||
}
|
||||
}
|
||||
|
||||
static void SNDDMA_Android_Callback( SLBufferQueueItf bq, void *context )
|
||||
{
|
||||
uint8_t *buffer2;
|
||||
|
||||
pthread_mutex_lock( &snddma_android_mutex );
|
||||
|
||||
buffer2 = ( uint8_t * )dma.buffer + snddma_android_size;
|
||||
(*bq)->Enqueue( bq, buffer2, snddma_android_size );
|
||||
memcpy( buffer2, dma.buffer, snddma_android_size );
|
||||
memset( dma.buffer, 0, snddma_android_size );
|
||||
dma.samplepos += dma.samples;
|
||||
|
||||
pthread_mutex_unlock( &snddma_android_mutex );
|
||||
}
|
||||
|
||||
static const char *SNDDMA_Android_Init( void )
|
||||
{
|
||||
SLresult result;
|
||||
|
||||
SLEngineItf engine;
|
||||
|
||||
int freq;
|
||||
|
||||
SLDataLocator_BufferQueue sourceLocator;
|
||||
SLDataFormat_PCM sourceFormat;
|
||||
SLDataSource source;
|
||||
|
||||
SLDataLocator_OutputMix sinkLocator;
|
||||
SLDataSink sink;
|
||||
|
||||
SLInterfaceID interfaceID;
|
||||
SLboolean interfaceRequired;
|
||||
|
||||
int samples;
|
||||
void *handle = dlopen( "libOpenSLES.so", RTLD_LAZY );
|
||||
|
||||
if( !handle )
|
||||
return "dlopen for libOpenSLES.so";
|
||||
|
||||
pslCreateEngine = dlsym( handle, "slCreateEngine" );
|
||||
|
||||
if( !pslCreateEngine )
|
||||
return "resolve slCreateEngine";
|
||||
|
||||
pSL_IID_ENGINE = dlsym( handle, "SL_IID_ENGINE" );
|
||||
|
||||
if( !pSL_IID_ENGINE )
|
||||
return "resolve SL_IID_ENGINE";
|
||||
|
||||
pSL_IID_PLAY = dlsym( handle, "SL_IID_PLAY" );
|
||||
|
||||
if( !pSL_IID_PLAY )
|
||||
return "resolve SL_IID_PLAY";
|
||||
|
||||
pSL_IID_BUFFERQUEUE = dlsym( handle, "SL_IID_BUFFERQUEUE" );
|
||||
|
||||
if( !pSL_IID_BUFFERQUEUE )
|
||||
return "resolve SL_IID_BUFFERQUEUE";
|
||||
|
||||
|
||||
result = pslCreateEngine( &snddma_android_engine, 0, NULL, 0, NULL, NULL );
|
||||
if( result != SL_RESULT_SUCCESS ) return "slCreateEngine";
|
||||
result = (*snddma_android_engine)->Realize( snddma_android_engine, SL_BOOLEAN_FALSE );
|
||||
if( result != SL_RESULT_SUCCESS ) return "engine->Realize";
|
||||
result = (*snddma_android_engine)->GetInterface( snddma_android_engine, *pSL_IID_ENGINE, &engine );
|
||||
if( result != SL_RESULT_SUCCESS ) return "engine->GetInterface(ENGINE)";
|
||||
|
||||
result = (*engine)->CreateOutputMix( engine, &snddma_android_outputMix, 0, NULL, NULL );
|
||||
if( result != SL_RESULT_SUCCESS ) return "engine->CreateOutputMix";
|
||||
result = (*snddma_android_outputMix)->Realize( snddma_android_outputMix, SL_BOOLEAN_FALSE );
|
||||
if( result != SL_RESULT_SUCCESS ) return "outputMix->Realize";
|
||||
|
||||
freq = SOUND_DMA_SPEED;
|
||||
sourceLocator.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
|
||||
sourceLocator.numBuffers = 2;
|
||||
sourceFormat.formatType = SL_DATAFORMAT_PCM;
|
||||
sourceFormat.numChannels = 2; // always stereo, because engine supports only stereo
|
||||
sourceFormat.samplesPerSec = freq * 1000;
|
||||
sourceFormat.bitsPerSample = 16; // always 16 bit audio
|
||||
sourceFormat.containerSize = sourceFormat.bitsPerSample;
|
||||
sourceFormat.channelMask = SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT;
|
||||
sourceFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
||||
source.pLocator = &sourceLocator;
|
||||
source.pFormat = &sourceFormat;
|
||||
|
||||
sinkLocator.locatorType = SL_DATALOCATOR_OUTPUTMIX;
|
||||
sinkLocator.outputMix = snddma_android_outputMix;
|
||||
sink.pLocator = &sinkLocator;
|
||||
sink.pFormat = NULL;
|
||||
|
||||
interfaceID = *pSL_IID_BUFFERQUEUE;
|
||||
interfaceRequired = SL_BOOLEAN_TRUE;
|
||||
|
||||
result = (*engine)->CreateAudioPlayer( engine, &snddma_android_player, &source, &sink, 1, &interfaceID, &interfaceRequired );
|
||||
if( result != SL_RESULT_SUCCESS ) return "engine->CreateAudioPlayer";
|
||||
result = (*snddma_android_player)->Realize( snddma_android_player, SL_BOOLEAN_FALSE );
|
||||
if( result != SL_RESULT_SUCCESS ) return "player->Realize";
|
||||
result = (*snddma_android_player)->GetInterface( snddma_android_player, *pSL_IID_BUFFERQUEUE, &snddma_android_bufferQueue );
|
||||
if( result != SL_RESULT_SUCCESS ) return "player->GetInterface(BUFFERQUEUE)";
|
||||
result = (*snddma_android_player)->GetInterface( snddma_android_player, *pSL_IID_PLAY, &snddma_android_play );
|
||||
if( result != SL_RESULT_SUCCESS ) return "player->GetInterface(PLAY)";
|
||||
result = (*snddma_android_bufferQueue)->RegisterCallback( snddma_android_bufferQueue, SNDDMA_Android_Callback, NULL );
|
||||
if( result != SL_RESULT_SUCCESS ) return "bufferQueue->RegisterCallback";
|
||||
|
||||
samples = s_samplecount.value;
|
||||
if( !samples )
|
||||
samples = 4096;
|
||||
|
||||
dma.format.channels = sourceFormat.numChannels;
|
||||
dma.samples = samples * sourceFormat.numChannels;
|
||||
dma.format.speed = freq;
|
||||
snddma_android_size = dma.samples * ( sourceFormat.bitsPerSample >> 3 );
|
||||
dma.buffer = Z_Malloc( snddma_android_size * 2 );
|
||||
dma.samplepos = 0;
|
||||
// dma.sampleframes = dma.samples / dma.format.channels;
|
||||
dma.format.width = 2;
|
||||
if( !dma.buffer ) return "malloc";
|
||||
|
||||
//snddma_android_mutex = trap_Mutex_Create();
|
||||
|
||||
dma.initialized = true;
|
||||
|
||||
SNDDMA_Activate( true );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qboolean SNDDMA_Init( void )
|
||||
{
|
||||
const char *initError;
|
||||
|
||||
Msg( "OpenSL ES audio device initializing...\n" );
|
||||
|
||||
initError = SNDDMA_Android_Init();
|
||||
if( initError )
|
||||
{
|
||||
Msg( S_ERROR "SNDDMA_Init: %s failed.\n", initError );
|
||||
SNDDMA_Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
Msg( "OpenSL ES audio initialized.\n" );
|
||||
dma.backendName = "OpenSL ES";
|
||||
return true;
|
||||
}
|
||||
|
||||
void SNDDMA_Shutdown( void )
|
||||
{
|
||||
Msg( "Closing OpenSL ES audio device...\n" );
|
||||
|
||||
if( snddma_android_player )
|
||||
{
|
||||
(*snddma_android_player)->Destroy( snddma_android_player );
|
||||
snddma_android_player = NULL;
|
||||
}
|
||||
if( snddma_android_outputMix )
|
||||
{
|
||||
(*snddma_android_outputMix)->Destroy( snddma_android_outputMix );
|
||||
snddma_android_outputMix = NULL;
|
||||
}
|
||||
if( snddma_android_engine )
|
||||
{
|
||||
(*snddma_android_engine)->Destroy( snddma_android_engine );
|
||||
snddma_android_engine = NULL;
|
||||
}
|
||||
|
||||
if( dma.buffer )
|
||||
{
|
||||
Z_Free( dma.buffer );
|
||||
dma.buffer = NULL;
|
||||
}
|
||||
|
||||
//if( snddma_android_mutex )
|
||||
//trap_Mutex_Destroy( &snddma_android_mutex );
|
||||
|
||||
Msg( "OpenSL ES audio device shut down.\n" );
|
||||
}
|
||||
|
||||
void SNDDMA_Submit( void )
|
||||
{
|
||||
pthread_mutex_unlock( &snddma_android_mutex );
|
||||
}
|
||||
|
||||
void SNDDMA_BeginPainting( void )
|
||||
{
|
||||
pthread_mutex_lock( &snddma_android_mutex );
|
||||
}
|
||||
|
||||
qboolean VoiceCapture_Init( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean VoiceCapture_Activate( qboolean activate )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean VoiceCapture_Lock( qboolean lock )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void VoiceCapture_Shutdown( void )
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
513
engine/platform/android/vid_android.c
Normal file
513
engine/platform/android/vid_android.c
Normal file
@@ -0,0 +1,513 @@
|
||||
#include "platform/platform.h"
|
||||
#if !XASH_SDL
|
||||
#include "input.h"
|
||||
#include "client.h"
|
||||
#include "filesystem.h"
|
||||
#include "platform/android/android_priv.h"
|
||||
#include "vid_common.h"
|
||||
#include <android/native_window.h>
|
||||
#include <android/native_window_jni.h>
|
||||
#include "eglutil.h"
|
||||
|
||||
|
||||
static struct vid_android_s
|
||||
{
|
||||
qboolean has_context;
|
||||
ANativeWindow* window;
|
||||
qboolean nativeegl;
|
||||
} vid_android;
|
||||
|
||||
static struct nw_s
|
||||
{
|
||||
void (*release)(ANativeWindow* window);
|
||||
int32_t (*getWidth)(ANativeWindow* window);
|
||||
int32_t (*getHeight)(ANativeWindow* window);
|
||||
int32_t (*getFormat)(ANativeWindow* window);
|
||||
int32_t (*setBuffersGeometry)(ANativeWindow* window, int32_t width, int32_t height, int32_t format);
|
||||
int32_t (*lock)(ANativeWindow* window, ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
|
||||
int32_t (*unlockAndPost)(ANativeWindow* window);
|
||||
ANativeWindow* (*fromSurface)(JNIEnv* env, jobject surface);
|
||||
} nw;
|
||||
|
||||
#define NW_FF(x) {"ANativeWindow_"#x, (void*)&nw.x}
|
||||
|
||||
|
||||
static dllfunc_t android_funcs[] =
|
||||
{
|
||||
NW_FF(release),
|
||||
NW_FF(getWidth),
|
||||
NW_FF(getHeight),
|
||||
NW_FF(getFormat),
|
||||
NW_FF(setBuffersGeometry),
|
||||
NW_FF(lock),
|
||||
NW_FF(unlockAndPost),
|
||||
NW_FF(fromSurface),
|
||||
{ NULL, NULL }
|
||||
};
|
||||
#undef NW_FF
|
||||
static dll_info_t android_info = { "libandroid.so", android_funcs, false };
|
||||
|
||||
/*
|
||||
========================
|
||||
Android_SwapInterval
|
||||
========================
|
||||
*/
|
||||
static void Android_SwapInterval( int interval )
|
||||
{
|
||||
if( vid_android.nativeegl && eglstate.valid )
|
||||
egl.SwapInterval( eglstate.dpy, interval );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
Android_SetTitle
|
||||
========================
|
||||
*/
|
||||
static void Android_SetTitle( const char *title )
|
||||
{
|
||||
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.setTitle, (*jni.env)->NewStringUTF( jni.env, title ) );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
Android_SetIcon
|
||||
========================
|
||||
*/
|
||||
static void Android_SetIcon( const char *path )
|
||||
{
|
||||
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.setIcon, (*jni.env)->NewStringUTF( jni.env, path ) );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
Android_GetScreenRes
|
||||
|
||||
Resolution got from last resize event
|
||||
========================
|
||||
*/
|
||||
static void Android_GetScreenRes( int *width, int *height )
|
||||
{
|
||||
*width = jni.width;
|
||||
*height = jni.height;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
Android_SwapBuffers
|
||||
|
||||
Update screen. Use native EGL if possible
|
||||
========================
|
||||
*/
|
||||
void GL_SwapBuffers( void )
|
||||
{
|
||||
if( vid_android.nativeegl && eglstate.valid )
|
||||
{
|
||||
egl.SwapBuffers( eglstate.dpy, eglstate.surface );
|
||||
}
|
||||
else
|
||||
{
|
||||
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.swapBuffers );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
Android_UpdateSurface
|
||||
|
||||
Check if we may use native EGL without jni calls
|
||||
========================
|
||||
*/
|
||||
void Android_UpdateSurface( surfacestate_t state )
|
||||
{
|
||||
qboolean active = state == surface_active;
|
||||
vid_android.nativeegl = false;
|
||||
|
||||
if( glw_state.software || ( eglstate.valid && !eglstate.imported ))
|
||||
{
|
||||
if( vid_android.window )
|
||||
{
|
||||
EGL_UpdateSurface( NULL, false );
|
||||
nw.release( vid_android.window );
|
||||
vid_android.window = NULL;
|
||||
}
|
||||
if( state == surface_dummy && glw_state.software )
|
||||
return;
|
||||
// first, ask EGL for surfaceless mode
|
||||
if( state == surface_dummy && EGL_UpdateSurface( NULL, true ))
|
||||
{
|
||||
vid_android.nativeegl = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if( state != surface_pause )
|
||||
{
|
||||
EGLint format = WINDOW_FORMAT_RGB_565;
|
||||
jobject surf;
|
||||
if( vid_android.window )
|
||||
nw.release( vid_android.window );
|
||||
surf = (*jni.env)->CallStaticObjectMethod( jni.env, jni.bindcls, jni.getSurface, state );
|
||||
Con_DPrintf("Surface handle %p\n", surf);
|
||||
if( surf )
|
||||
{
|
||||
vid_android.window = nw.fromSurface(jni.env, surf);
|
||||
Con_DPrintf("NativeWindow %p\n", vid_android.window);
|
||||
|
||||
if( eglstate.valid )
|
||||
egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_NATIVE_VISUAL_ID, &format );
|
||||
|
||||
nw.setBuffersGeometry(vid_android.window, 0, 0, format );
|
||||
|
||||
(*jni.env)->DeleteLocalRef( jni.env, surf );
|
||||
}
|
||||
}
|
||||
|
||||
if( eglstate.valid && !eglstate.imported )
|
||||
{
|
||||
EGL_UpdateSurface( vid_android.window, state == surface_dummy );
|
||||
vid_android.nativeegl = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if( !vid_android.has_context )
|
||||
return;
|
||||
|
||||
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.toggleEGL, (int)state );
|
||||
host.status = HOST_FRAME; // active ? HOST_FRAME : HOST_SLEEP;
|
||||
|
||||
// todo: check opengl context here and set HOST_SLEEP if not
|
||||
|
||||
if( !Sys_CheckParm("-nativeegl") || !active )
|
||||
return; // enabled by user
|
||||
|
||||
vid_android.nativeegl = EGL_ImportContext();
|
||||
if( vid_android.nativeegl )
|
||||
Con_DPrintf( "nativeEGL success\n");
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
Android_GetGLAttribute
|
||||
========================
|
||||
*/
|
||||
static int Android_GetGLAttribute( int eglAttr )
|
||||
{
|
||||
int ret = (*jni.env)->CallStaticIntMethod( jni.env, jni.bindcls, jni.getGLAttribute, eglAttr );
|
||||
// Con_Reportf( "Android_GetGLAttribute( %i ) => %i\n", eglAttr, ret );
|
||||
return ret;
|
||||
}
|
||||
|
||||
qboolean R_Init_Video( const int type )
|
||||
{
|
||||
qboolean retval;
|
||||
char buf[10]; // Sys_GetParmFromCmdLine
|
||||
|
||||
if( FS_FileExists( GI->iconpath, true ) )
|
||||
{
|
||||
// TODO: convert icon to some android-readable format and place
|
||||
Android_SetIcon( FS_GetDiskPath( GI->iconpath, false ));
|
||||
}
|
||||
|
||||
Android_SetTitle( GI->title );
|
||||
|
||||
VID_StartupGamma();
|
||||
|
||||
Sys_LoadLibrary( &android_info );
|
||||
|
||||
switch( type )
|
||||
{
|
||||
case REF_SOFTWARE:
|
||||
glw_state.software = true;
|
||||
break;
|
||||
case REF_GL:
|
||||
glw_state.software = false;
|
||||
EGL_LoadLibrary();
|
||||
|
||||
if( !glw_state.safe && Sys_GetParmFromCmdLine( "-safegl", buf ) )
|
||||
glw_state.safe = bound( SAFE_NO, Q_atoi( buf ), SAFE_DONTCARE );
|
||||
|
||||
break;
|
||||
default:
|
||||
Host_Error( "Can't initialize unknown context type %d!\n", type );
|
||||
break;
|
||||
}
|
||||
|
||||
if( glw_state.software )
|
||||
{
|
||||
uint arg;
|
||||
|
||||
if( !nw.release )
|
||||
{
|
||||
Con_Reportf( S_ERROR "Native software mode unavailiable\n" );
|
||||
return false;
|
||||
}
|
||||
Android_UpdateSurface( surface_active );
|
||||
if( !SW_CreateBuffer( jni.width, jni.height, &arg, &arg, &arg, &arg, &arg ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
while( !(retval = VID_SetMode()) )
|
||||
{
|
||||
glw_state.safe++;
|
||||
if( glw_state.safe > SAFE_LAST )
|
||||
return false;
|
||||
}
|
||||
|
||||
switch( type )
|
||||
{
|
||||
case REF_GL:
|
||||
// refdll also can check extensions
|
||||
ref.dllFuncs.GL_InitExtensions();
|
||||
break;
|
||||
case REF_SOFTWARE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
host.renderinfo_changed = false;
|
||||
|
||||
host.status = HOST_FRAME; // where it should we done? We have broken host.status on all non-SDL platforms!
|
||||
return true;
|
||||
}
|
||||
|
||||
void R_Free_Video( void )
|
||||
{
|
||||
// (*jni.env)->CallStaticBooleanMethod( jni.env, jni.bindcls, jni.deleteGLContext );
|
||||
|
||||
// VID_DestroyWindow ();
|
||||
|
||||
// R_FreeVideoModes();
|
||||
Sys_FreeLibrary( &android_info );
|
||||
vid_android.has_context = false;
|
||||
ref.dllFuncs.GL_ClearExtensions();
|
||||
}
|
||||
|
||||
void *Android_GetWindow( void )
|
||||
{
|
||||
EGLint format;
|
||||
|
||||
if( !vid_android.window )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( !egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_NATIVE_VISUAL_ID, &format) )
|
||||
{
|
||||
Con_Reportf( S_ERROR "eglGetConfigAttrib(VISUAL_ID) returned error: 0x%x\n", egl.GetError() );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( nw.setBuffersGeometry( vid_android.window, 0, 0, format ) )
|
||||
{
|
||||
Con_Reportf( S_ERROR "ANativeWindow_setBuffersGeometry returned error\n" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return vid_android.window;
|
||||
}
|
||||
|
||||
|
||||
qboolean VID_SetMode( void )
|
||||
{
|
||||
EGLint format;
|
||||
jintArray attribs, contextAttribs;
|
||||
static EGLint nAttribs[32+1], nContextAttribs[32+1];
|
||||
const size_t attribsSize = ARRAYSIZE( nAttribs );
|
||||
size_t s1, s2;
|
||||
|
||||
// create context on egl side by user request
|
||||
if( !vid_android.has_context && Sys_CheckParm("-egl") )
|
||||
{
|
||||
vid_android.has_context = vid_android.nativeegl = EGL_CreateContext();
|
||||
|
||||
if( vid_android.has_context )
|
||||
Android_UpdateSurface( surface_active );
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if( vid_android.has_context || glw_state.software )
|
||||
{
|
||||
R_ChangeDisplaySettings( 0, 0, WINDOW_MODE_WINDOWED ); // width and height are ignored anyway
|
||||
return true;
|
||||
}
|
||||
|
||||
s1 = EGL_GenerateConfig(nAttribs, attribsSize);
|
||||
s2 = EGL_GenerateContextConfig(nContextAttribs, attribsSize);
|
||||
|
||||
attribs = (*jni.env)->NewIntArray( jni.env, s1 );
|
||||
contextAttribs = (*jni.env)->NewIntArray( jni.env, s2 );
|
||||
|
||||
(*jni.env)->SetIntArrayRegion( jni.env, attribs, 0, s1, nAttribs );
|
||||
(*jni.env)->SetIntArrayRegion( jni.env, contextAttribs, 0, s2, nContextAttribs );
|
||||
|
||||
R_ChangeDisplaySettings( 0, 0, WINDOW_MODE_WINDOWED ); // width and height are ignored anyway
|
||||
|
||||
|
||||
if( (*jni.env)->CallStaticBooleanMethod( jni.env, jni.bindcls, jni.createGLContext, attribs, contextAttribs ) )
|
||||
{
|
||||
vid_android.has_context = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
rserr_t R_ChangeDisplaySettings( int width, int height, window_mode_t window_mode )
|
||||
{
|
||||
int render_w, render_h;
|
||||
|
||||
Android_GetScreenRes(&width, &height);
|
||||
|
||||
render_w = width;
|
||||
render_h = height;
|
||||
|
||||
Con_Reportf( "R_ChangeDisplaySettings: forced resolution to %dx%d)\n", width, height);
|
||||
|
||||
VID_SetDisplayTransform( &render_w, &render_h );
|
||||
|
||||
R_SaveVideoMode( width, height, render_w, render_h, true );
|
||||
|
||||
refState.wideScreen = true; // V_AdjustFov will check for widescreen
|
||||
|
||||
return rserr_ok;
|
||||
}
|
||||
|
||||
int GL_SetAttribute( int attr, int val )
|
||||
{
|
||||
return EGL_SetAttribute( attr, val );
|
||||
}
|
||||
|
||||
int GL_GetAttribute( int attr, int *val )
|
||||
{
|
||||
EGLBoolean ret;
|
||||
|
||||
if( eglstate.valid )
|
||||
return EGL_GetAttribute( attr, val );
|
||||
|
||||
if( attr < 0 || attr >= REF_GL_ATTRIBUTES_COUNT )
|
||||
return -1;
|
||||
|
||||
if( !val )
|
||||
return -1;
|
||||
|
||||
switch( attr )
|
||||
{
|
||||
case REF_GL_RED_SIZE:
|
||||
*val = Android_GetGLAttribute( EGL_RED_SIZE );
|
||||
return 0;
|
||||
case REF_GL_GREEN_SIZE:
|
||||
*val = Android_GetGLAttribute( EGL_GREEN_SIZE );
|
||||
return 0;
|
||||
case REF_GL_BLUE_SIZE:
|
||||
*val = Android_GetGLAttribute( EGL_BLUE_SIZE );
|
||||
return 0;
|
||||
case REF_GL_ALPHA_SIZE:
|
||||
*val = Android_GetGLAttribute( EGL_ALPHA_SIZE );
|
||||
return 0;
|
||||
case REF_GL_DEPTH_SIZE:
|
||||
*val = Android_GetGLAttribute( EGL_DEPTH_SIZE );
|
||||
return 0;
|
||||
case REF_GL_STENCIL_SIZE:
|
||||
*val = Android_GetGLAttribute( EGL_STENCIL_SIZE );
|
||||
return 0;
|
||||
case REF_GL_MULTISAMPLESAMPLES:
|
||||
*val = Android_GetGLAttribute( EGL_SAMPLES );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int R_MaxVideoModes( void )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
vidmode_t* R_GetVideoMode( int num )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* GL_GetProcAddress( const char *name ) // RenderAPI requirement
|
||||
{
|
||||
return EGL_GetProcAddress( name );
|
||||
}
|
||||
|
||||
void GL_UpdateSwapInterval( void )
|
||||
{
|
||||
// disable VSync while level is loading
|
||||
if( cls.state < ca_active )
|
||||
{
|
||||
Android_SwapInterval( 0 );
|
||||
SetBits( gl_vsync.flags, FCVAR_CHANGED );
|
||||
}
|
||||
else if( FBitSet( gl_vsync.flags, FCVAR_CHANGED ))
|
||||
{
|
||||
ClearBits( gl_vsync.flags, FCVAR_CHANGED );
|
||||
Android_SwapInterval( gl_vsync.value );
|
||||
}
|
||||
}
|
||||
|
||||
void *SW_LockBuffer( void )
|
||||
{
|
||||
ANativeWindow_Buffer buffer;
|
||||
if( !nw.lock || !vid_android.window )
|
||||
return NULL;
|
||||
if( nw.lock( vid_android.window, &buffer, NULL ) )
|
||||
return NULL;
|
||||
if( buffer.width < refState.width || buffer.height < refState.height )
|
||||
return NULL;
|
||||
return buffer.bits;
|
||||
}
|
||||
|
||||
void SW_UnlockBuffer( void )
|
||||
{
|
||||
if( nw.unlockAndPost )
|
||||
nw.unlockAndPost( vid_android.window );
|
||||
}
|
||||
|
||||
qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *r, uint *g, uint *b )
|
||||
{
|
||||
ANativeWindow_Buffer buffer;
|
||||
int lock;
|
||||
if( !nw.lock || !vid_android.window )
|
||||
return false;
|
||||
nw.unlockAndPost( vid_android.window );
|
||||
|
||||
if( ( lock = nw.lock( vid_android.window, &buffer, NULL ) ) )
|
||||
{
|
||||
Con_Printf( "SW_CreateBuffer: lock %d\n", lock );
|
||||
return false;
|
||||
}
|
||||
nw.unlockAndPost( vid_android.window );
|
||||
Con_Printf( "SW_CreateBuffer: buffer %d %d %x %d %p\n", buffer.width, buffer.height, buffer.format, buffer.stride, buffer.bits );
|
||||
if( width > buffer.width || height > buffer.height )
|
||||
{
|
||||
// resize event missed? do not resize now, wait for REAL resize event or when java code will be fixed
|
||||
Con_Printf( S_ERROR "SW_CreateBuffer: buffer too small, need %dx%d, got %dx%d, java part probably sucks\n", width, height, buffer.width, buffer.height );
|
||||
#if 0
|
||||
if( jni.width < buffer.width )
|
||||
jni.width = buffer.width;
|
||||
if( jni.height < buffer.height )
|
||||
jni.width = buffer.height;
|
||||
VID_SetMode();
|
||||
Android_UpdateSurface( true );
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
if( buffer.format != WINDOW_FORMAT_RGB_565 )
|
||||
{
|
||||
Con_Printf( "SW_CreateBuffer: wrong format %d\n", buffer.format );
|
||||
return false;
|
||||
}
|
||||
Con_Printf( "SW_CreateBuffer: ok\n" );
|
||||
*stride = buffer.stride;
|
||||
|
||||
*bpp = 2;
|
||||
*r = (((1 << 5) - 1) << (5+6));
|
||||
*g = (((1 << 6) - 1) << (5));
|
||||
*b = (((1 << 5) - 1) << (0));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -52,7 +52,7 @@ static pid_t gettid( void )
|
||||
static void *g_hsystemd;
|
||||
static int (*g_pfn_sd_notify)( int unset_environment, const char *state );
|
||||
|
||||
qboolean Platform_DebuggerPresent( void )
|
||||
qboolean Sys_DebuggerPresent( void )
|
||||
{
|
||||
char buf[4096];
|
||||
ssize_t num_read;
|
||||
@@ -111,11 +111,6 @@ void Linux_Init( void )
|
||||
if( !Host_IsDedicated( ))
|
||||
return;
|
||||
|
||||
// manpage says sd_notify will send messages to socket in NOTIFY_SOCKET
|
||||
// environment variable. Check if it's available.
|
||||
if( getenv( "NOTIFY_SOCKET" ) == NULL )
|
||||
return;
|
||||
|
||||
if(( g_hsystemd = dlopen( "libsystemd.so.0", RTLD_LAZY )) == NULL )
|
||||
return;
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ double Platform_DoubleTime( void );
|
||||
void Platform_Sleep( int msec );
|
||||
void Platform_ShellExecute( const char *path, const char *parms );
|
||||
void Platform_MessageBox( const char *title, const char *message, qboolean parentMainWindow );
|
||||
qboolean Sys_DebuggerPresent( void ); // optional, see Sys_DebugBreak
|
||||
void Platform_SetStatus( const char *status );
|
||||
qboolean Platform_DebuggerPresent( void );
|
||||
|
||||
// legacy iOS port functions
|
||||
#if TARGET_OS_IOS
|
||||
@@ -139,15 +139,8 @@ static inline void Platform_Shutdown( void )
|
||||
|
||||
#if XASH_SDL
|
||||
SDLash_Shutdown( );
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline qboolean Sys_DebuggerPresent( void )
|
||||
{
|
||||
#if XASH_LINUX || XASH_WIN32
|
||||
return Platform_DebuggerPresent();
|
||||
#else
|
||||
return false;
|
||||
#elif XASH_ANDROID
|
||||
Android_Shutdown();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -374,8 +374,14 @@ static void SDLash_ActiveEvent( int gain )
|
||||
{
|
||||
host.status = HOST_FRAME;
|
||||
if( cls.key_dest == key_game )
|
||||
{
|
||||
IN_ActivateMouse( );
|
||||
}
|
||||
|
||||
if( dma.initialized && snd_mute_losefocus.value )
|
||||
{
|
||||
SNDDMA_Activate( true );
|
||||
}
|
||||
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
|
||||
if( vid_fullscreen.value == WINDOW_MODE_FULLSCREEN )
|
||||
VID_SetMode();
|
||||
@@ -391,8 +397,14 @@ static void SDLash_ActiveEvent( int gain )
|
||||
#endif
|
||||
host.status = HOST_NOFOCUS;
|
||||
if( cls.key_dest == key_game )
|
||||
{
|
||||
IN_DeactivateMouse();
|
||||
}
|
||||
|
||||
if( dma.initialized && snd_mute_losefocus.value )
|
||||
{
|
||||
SNDDMA_Activate( false );
|
||||
}
|
||||
host.force_draw_version_time = host.realtime + 2.0;
|
||||
VID_RestoreScreenResolution();
|
||||
}
|
||||
|
||||
@@ -504,12 +504,12 @@ void Wcon_CreateConsole( void )
|
||||
|
||||
if( host.type == HOST_NORMAL )
|
||||
{
|
||||
Q_strncpy( s_wcd.title, XASH_ENGINE_NAME " " XASH_VERSION, sizeof( s_wcd.title ));
|
||||
Q_strncpy( s_wcd.title, "Xash3D " XASH_VERSION, sizeof( s_wcd.title ));
|
||||
Q_strncpy( s_wcd.log_path, "engine.log", sizeof( s_wcd.log_path ));
|
||||
}
|
||||
else // dedicated console
|
||||
{
|
||||
Q_strncpy( s_wcd.title, XASH_DEDICATED_SERVER_NAME " " XASH_VERSION, sizeof( s_wcd.title ));
|
||||
Q_strncpy( s_wcd.title, "XashDS " XASH_VERSION, sizeof( s_wcd.title ));
|
||||
Q_strncpy( s_wcd.log_path, "dedicated.log", sizeof( s_wcd.log_path ));
|
||||
s_wcd.log_active = true; // always make log
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ void Platform_Sleep( int msec )
|
||||
}
|
||||
#endif // XASH_TIMER == TIMER_WIN32
|
||||
|
||||
qboolean Platform_DebuggerPresent( void )
|
||||
qboolean Sys_DebuggerPresent( void )
|
||||
{
|
||||
return IsDebuggerPresent();
|
||||
}
|
||||
|
||||
@@ -43,9 +43,10 @@ extern int SV_UPDATE_BACKUP;
|
||||
#define SVF_MERGE_VISIBILITY BIT( 1 ) // we are do portal pass
|
||||
|
||||
// mapvalid flags
|
||||
#define MAP_IS_EXIST BIT( 0 )
|
||||
#define MAP_HAS_LANDMARK BIT( 2 )
|
||||
#define MAP_INVALID_VERSION BIT( 3 )
|
||||
#define MAP_IS_EXIST BIT( 0 )
|
||||
#define MAP_HAS_SPAWNPOINT BIT( 1 )
|
||||
#define MAP_HAS_LANDMARK BIT( 2 )
|
||||
#define MAP_INVALID_VERSION BIT( 3 )
|
||||
|
||||
#define SV_SPAWN_TIME 0.1
|
||||
|
||||
@@ -612,9 +613,11 @@ string_t SV_MakeString( const char *szValue );
|
||||
const char *SV_GetString( string_t iString );
|
||||
void SV_SetStringArrayMode( qboolean dynamic );
|
||||
void SV_EmptyStringPool( void );
|
||||
#ifdef XASH_64BIT
|
||||
void SV_PrintStr64Stats_f( void );
|
||||
#endif
|
||||
sv_client_t *SV_ClientFromEdict( const edict_t *pEdict, qboolean spawned_only );
|
||||
uint SV_MapIsValid( const char *filename, const char *landmark_name );
|
||||
uint SV_MapIsValid( const char *filename, const char *spawn_entity, const char *landmark_name );
|
||||
void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch );
|
||||
edict_t *SV_FindGlobalEntity( string_t classname, string_t globalname );
|
||||
qboolean SV_CreateStaticEntity( struct sizebuf_s *msg, int index );
|
||||
@@ -625,18 +628,12 @@ void SV_RestartAmbientSounds( void );
|
||||
void SV_RestartDecals( void );
|
||||
void SV_RestartStaticEnts( void );
|
||||
int pfnDropToFloor( edict_t* e );
|
||||
edict_t *SV_EdictNum( int n );
|
||||
void SV_SetModel( edict_t *ent, const char *name );
|
||||
int pfnDecalIndex( const char *m );
|
||||
void SV_CreateDecal( sizebuf_t *msg, const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags, float scale );
|
||||
qboolean SV_RestoreCustomDecal( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent );
|
||||
|
||||
static inline edict_t *SV_EdictNum( int n )
|
||||
{
|
||||
if( likely( n >= 0 && n < GI->max_edicts ))
|
||||
return &svgame.edicts[n];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// sv_log.c
|
||||
//
|
||||
|
||||
@@ -1690,7 +1690,7 @@ static qboolean SV_New_f( sv_client_t *cl )
|
||||
|
||||
// server info string
|
||||
MSG_BeginServerCmd( &msg, svc_stufftext );
|
||||
MSG_WriteStringf( &msg, "fullserverinfo \"%s\"\n", svs.serverinfo );
|
||||
MSG_WriteStringf( &msg, "fullserverinfo \"%s\"\n", SV_Serverinfo( ));
|
||||
|
||||
// collect the info about all the players and send to me
|
||||
for( i = 0, cur = svs.clients; i < svs.maxclients; i++, cur++ )
|
||||
|
||||
@@ -169,11 +169,17 @@ SV_ValidateMap
|
||||
check map for typically errors
|
||||
==================
|
||||
*/
|
||||
static qboolean SV_ValidateMap( const char *pMapName )
|
||||
static qboolean SV_ValidateMap( const char *pMapName, qboolean check_spawn )
|
||||
{
|
||||
char *spawn_entity;
|
||||
int flags;
|
||||
|
||||
flags = SV_MapIsValid( pMapName, NULL );
|
||||
// determine spawn entity classname
|
||||
if( !check_spawn || (int)sv_maxclients.value <= 1 )
|
||||
spawn_entity = GI->sp_entity;
|
||||
else spawn_entity = GI->mp_entity;
|
||||
|
||||
flags = SV_MapIsValid( pMapName, spawn_entity, NULL );
|
||||
|
||||
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
||||
{
|
||||
@@ -187,6 +193,12 @@ static qboolean SV_ValidateMap( const char *pMapName )
|
||||
return false;
|
||||
}
|
||||
|
||||
if( check_spawn && !FBitSet( flags, MAP_HAS_SPAWNPOINT ))
|
||||
{
|
||||
Con_Printf( S_ERROR "map %s doesn't have a valid spawnpoint\n", pMapName );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -212,7 +224,7 @@ static void SV_Map_f( void )
|
||||
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
|
||||
COM_StripExtension( mapname );
|
||||
|
||||
if( !SV_ValidateMap( mapname ))
|
||||
if( !SV_ValidateMap( mapname, true ))
|
||||
return;
|
||||
|
||||
Cvar_DirectSet( &sv_hostmap, mapname );
|
||||
@@ -284,7 +296,7 @@ static void SV_MapBackground_f( void )
|
||||
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
|
||||
COM_StripExtension( mapname );
|
||||
|
||||
if( !SV_ValidateMap( mapname ))
|
||||
if( !SV_ValidateMap( mapname, false ))
|
||||
return;
|
||||
|
||||
// background map is always run as singleplayer
|
||||
@@ -334,7 +346,7 @@ static void SV_NextMap_f( void )
|
||||
Cvar_DirectSet( &sv_hostmap, nextmap );
|
||||
|
||||
// found current point, check for valid
|
||||
if( SV_ValidateMap( nextmap ))
|
||||
if( SV_ValidateMap( nextmap, true ))
|
||||
{
|
||||
// found and valid
|
||||
COM_LoadLevel( nextmap, false );
|
||||
@@ -534,7 +546,7 @@ classic change level
|
||||
*/
|
||||
static void SV_ChangeLevel_f( void )
|
||||
{
|
||||
if( Cmd_Argc() < 2 ) // allow extra arguments, for compatibility
|
||||
if( Cmd_Argc() != 2 )
|
||||
{
|
||||
Con_Printf( S_USAGE "changelevel <mapname>\n" );
|
||||
return;
|
||||
@@ -552,15 +564,13 @@ smooth change level
|
||||
*/
|
||||
static void SV_ChangeLevel2_f( void )
|
||||
{
|
||||
if( Cmd_Argc() < 2 ) // allow extra arguments, for compatibility
|
||||
if( Cmd_Argc() != 3 )
|
||||
{
|
||||
Con_Printf( S_USAGE "changelevel2 <mapname> [landmark]\n" );
|
||||
Con_Printf( S_USAGE "changelevel2 <mapname> <landmark>\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
if( Cmd_Argc() == 2 ) // with single argument, behaves like usual changelevel
|
||||
SV_QueueChangeLevel( Cmd_Argv( 1 ), NULL );
|
||||
else SV_QueueChangeLevel( Cmd_Argv( 1 ), Cmd_Argv( 2 ));
|
||||
SV_QueueChangeLevel( Cmd_Argv( 1 ), Cmd_Argv( 2 ));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -753,7 +763,7 @@ static void SV_ServerInfo_f( void )
|
||||
}
|
||||
|
||||
Info_SetValueForStarKey( svs.serverinfo, Cmd_Argv( 1 ), Cmd_Argv( 2 ), MAX_SERVERINFO_STRING );
|
||||
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", svs.serverinfo );
|
||||
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", SV_Serverinfo( ));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1007,7 +1017,6 @@ void SV_InitOperatorCommands( void )
|
||||
Cmd_AddCommand( "redirect", Rcon_Redirect_f, "force enable rcon redirection" );
|
||||
Cmd_AddCommand( "logaddress", SV_SetLogAddress_f, "sets address and port for remote logging host" );
|
||||
Cmd_AddCommand( "log", SV_ServerLog_f, "enables logging to file" );
|
||||
Cmd_AddCommand( "str64stats", SV_PrintStr64Stats_f, "print engine pool string statistics" );
|
||||
|
||||
if( host.type == HOST_NORMAL )
|
||||
{
|
||||
@@ -1046,7 +1055,6 @@ void SV_KillOperatorCommands( void )
|
||||
Cmd_RemoveCommand( "redirect" );
|
||||
Cmd_RemoveCommand( "logaddress" );
|
||||
Cmd_RemoveCommand( "log" );
|
||||
Cmd_RemoveCommand( "str64stats" );
|
||||
|
||||
if( host.type == HOST_NORMAL )
|
||||
{
|
||||
|
||||
@@ -811,17 +811,17 @@ static void SV_UpdateToReliableMessages( void )
|
||||
continue; // reliables go to all connected or spawned
|
||||
|
||||
if( MSG_GetNumBytesWritten( &sv.reliable_datagram ) < MSG_GetNumBytesLeft( &cl->netchan.message ))
|
||||
MSG_WriteBits( &cl->netchan.message, MSG_GetData( &sv.reliable_datagram ), MSG_GetNumBitsWritten( &sv.reliable_datagram ));
|
||||
MSG_WriteBits( &cl->netchan.message, MSG_GetBuf( &sv.reliable_datagram ), MSG_GetNumBitsWritten( &sv.reliable_datagram ));
|
||||
else Netchan_CreateFragments( &cl->netchan, &sv.reliable_datagram );
|
||||
|
||||
if( MSG_GetNumBytesWritten( &sv.datagram ) < MSG_GetNumBytesLeft( &cl->datagram ))
|
||||
MSG_WriteBits( &cl->datagram, MSG_GetData( &sv.datagram ), MSG_GetNumBitsWritten( &sv.datagram ));
|
||||
MSG_WriteBits( &cl->datagram, MSG_GetBuf( &sv.datagram ), MSG_GetNumBitsWritten( &sv.datagram ));
|
||||
else Con_DPrintf( S_WARN "Ignoring unreliable datagram for %s, would overflow\n", cl->name );
|
||||
|
||||
if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
|
||||
{
|
||||
if( MSG_GetNumBytesWritten( &sv.spec_datagram ) < MSG_GetNumBytesLeft( &cl->datagram ))
|
||||
MSG_WriteBits( &cl->datagram, MSG_GetData( &sv.spec_datagram ), MSG_GetNumBitsWritten( &sv.spec_datagram ));
|
||||
MSG_WriteBits( &cl->datagram, MSG_GetBuf( &sv.spec_datagram ), MSG_GetNumBitsWritten( &sv.spec_datagram ));
|
||||
else Con_DPrintf( S_WARN "Ignoring spectator datagram for %s, would overflow\n", cl->name );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,13 @@ static vec3_t viewPoint[MAX_CLIENTS];
|
||||
typedef void (__cdecl *LINK_ENTITY_FUNC)( entvars_t *pev );
|
||||
typedef void (__stdcall *GIVEFNPTRSTODLL)( enginefuncs_t* engfuncs, globalvars_t *pGlobals );
|
||||
|
||||
edict_t *SV_EdictNum( int n )
|
||||
{
|
||||
if(( n >= 0 ) && ( n < GI->max_edicts ))
|
||||
return svgame.edicts + n;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
qboolean SV_CheckEdict( const edict_t *e, const char *file, const int line )
|
||||
{
|
||||
@@ -143,6 +150,18 @@ char *SV_Serverinfo( void )
|
||||
return svs.serverinfo;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_LocalInfo
|
||||
|
||||
get local infostring
|
||||
=============
|
||||
*/
|
||||
static char *SV_Localinfo( void )
|
||||
{
|
||||
return svs.localinfo;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
SV_AngleMod
|
||||
@@ -249,6 +268,7 @@ SV_SetModel
|
||||
void GAME_EXPORT SV_SetModel( edict_t *ent, const char *modelname )
|
||||
{
|
||||
char name[MAX_QPATH];
|
||||
qboolean found = false;
|
||||
model_t *mod;
|
||||
int i = 1;
|
||||
|
||||
@@ -758,6 +778,7 @@ void SV_QueueChangeLevel( const char *level, const char *landname )
|
||||
{
|
||||
uint flags, smooth = false;
|
||||
char mapname[MAX_QPATH];
|
||||
char *spawn_entity;
|
||||
|
||||
// hold mapname to other place
|
||||
Q_strncpy( mapname, level, sizeof( mapname ));
|
||||
@@ -766,7 +787,12 @@ void SV_QueueChangeLevel( const char *level, const char *landname )
|
||||
if( COM_CheckString( landname ))
|
||||
smooth = true;
|
||||
|
||||
flags = SV_MapIsValid( mapname, landname );
|
||||
// determine spawn entity classname
|
||||
if( svs.maxclients == 1 )
|
||||
spawn_entity = GI->sp_entity;
|
||||
else spawn_entity = GI->mp_entity;
|
||||
|
||||
flags = SV_MapIsValid( mapname, spawn_entity, landname );
|
||||
|
||||
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
||||
{
|
||||
@@ -800,6 +826,15 @@ void SV_QueueChangeLevel( const char *level, const char *landname )
|
||||
return;
|
||||
}
|
||||
|
||||
if( !smooth && !FBitSet( flags, MAP_HAS_SPAWNPOINT ))
|
||||
{
|
||||
if( sv_validate_changelevel.value )
|
||||
{
|
||||
Con_Printf( S_ERROR "changelevel: %s doesn't have a valid spawnpoint. Ignored.\n", mapname );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// bad changelevel position invoke enables in one-way transition
|
||||
if( sv.framecount < 15 )
|
||||
{
|
||||
@@ -829,6 +864,7 @@ void SV_WriteEntityPatch( const char *filename )
|
||||
int lumpofs = 0, lumplen = 0;
|
||||
byte buf[MAX_TOKEN]; // 1 kb
|
||||
string bspfilename;
|
||||
dheader_t *header;
|
||||
dlump_t entities;
|
||||
file_t *f;
|
||||
|
||||
@@ -839,6 +875,7 @@ void SV_WriteEntityPatch( const char *filename )
|
||||
|
||||
memset( buf, 0, MAX_TOKEN );
|
||||
FS_Read( f, buf, MAX_TOKEN );
|
||||
header = (dheader_t *)buf;
|
||||
|
||||
// check all the lumps and some other errors
|
||||
if( !Mod_TestBmodelLumps( f, bspfilename, buf, true, &entities ))
|
||||
@@ -878,6 +915,7 @@ static char *SV_ReadEntityScript( const char *filename, int *flags )
|
||||
int lumpofs = 0, lumplen = 0;
|
||||
byte buf[MAX_TOKEN];
|
||||
char *ents = NULL;
|
||||
dheader_t *header;
|
||||
dlump_t entities;
|
||||
size_t ft1, ft2;
|
||||
file_t *f;
|
||||
@@ -892,6 +930,7 @@ static char *SV_ReadEntityScript( const char *filename, int *flags )
|
||||
SetBits( *flags, MAP_IS_EXIST );
|
||||
memset( buf, 0, MAX_TOKEN );
|
||||
FS_Read( f, buf, MAX_TOKEN );
|
||||
header = (dheader_t *)buf;
|
||||
|
||||
// check all the lumps and some other errors
|
||||
if( !Mod_TestBmodelLumps( f, bspfilename, buf, (host_developer.value) ? false : true, &entities ))
|
||||
@@ -938,7 +977,7 @@ SV_MapIsValid
|
||||
Validate map
|
||||
==============
|
||||
*/
|
||||
uint SV_MapIsValid( const char *filename, const char *landmark_name )
|
||||
uint SV_MapIsValid( const char *filename, const char *spawn_entity, const char *landmark_name )
|
||||
{
|
||||
uint flags = 0;
|
||||
char *pfile;
|
||||
@@ -954,27 +993,45 @@ uint SV_MapIsValid( const char *filename, const char *landmark_name )
|
||||
|
||||
need_landmark = COM_CheckString( landmark_name );
|
||||
|
||||
if( !need_landmark )
|
||||
// g-cont. in-dev mode we can entering on map even without "info_player_start"
|
||||
if( !need_landmark && host_developer.value )
|
||||
{
|
||||
// not transition
|
||||
Mem_Free( ents );
|
||||
|
||||
return flags;
|
||||
// skip spawnpoint checks in devmode
|
||||
return (flags|MAP_HAS_SPAWNPOINT);
|
||||
}
|
||||
|
||||
pfile = ents;
|
||||
|
||||
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
|
||||
{
|
||||
if( !Q_strcmp( token, "targetname" ))
|
||||
if( !Q_strcmp( token, "classname" ))
|
||||
{
|
||||
// check classname for spawn entity
|
||||
pfile = COM_ParseFile( pfile, check_name, sizeof( check_name ));
|
||||
if( !Q_strcmp( spawn_entity, check_name ))
|
||||
{
|
||||
SetBits( flags, MAP_HAS_SPAWNPOINT );
|
||||
|
||||
// we already find landmark, stop the parsing
|
||||
if( need_landmark && FBitSet( flags, MAP_HAS_LANDMARK ))
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( need_landmark && !Q_strcmp( token, "targetname" ))
|
||||
{
|
||||
// check targetname for landmark entity
|
||||
pfile = COM_ParseFile( pfile, check_name, sizeof( check_name ));
|
||||
|
||||
if( !Q_strcmp( landmark_name, check_name ))
|
||||
{
|
||||
// we found landmark, stop the parsing
|
||||
SetBits( flags, MAP_HAS_LANDMARK );
|
||||
break;
|
||||
|
||||
// we already find spawnpoint, stop the parsing
|
||||
if( FBitSet( flags, MAP_HAS_SPAWNPOINT ))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1117,22 +1174,15 @@ static LINK_ENTITY_FUNC SV_GetEntityClass( const char *pszClassName )
|
||||
SV_AllocPrivateData
|
||||
|
||||
allocate private data for a given edict
|
||||
|
||||
if customentity is NULL, no "custom" entity EXPORT is being done
|
||||
if customentity is not NULL, will be set to true if "custom" export
|
||||
was used to create this entity
|
||||
==============
|
||||
*/
|
||||
static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className, qboolean *customentity )
|
||||
static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className )
|
||||
{
|
||||
const char *pszClassName;
|
||||
LINK_ENTITY_FUNC SpawnEdict;
|
||||
|
||||
pszClassName = STRING( className );
|
||||
|
||||
if( customentity )
|
||||
*customentity = false;
|
||||
|
||||
if( !ent )
|
||||
{
|
||||
// allocate a new one
|
||||
@@ -1155,11 +1205,7 @@ static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className, qboolean
|
||||
if( svgame.physFuncs.SV_CreateEntity && svgame.physFuncs.SV_CreateEntity( ent, pszClassName ) != -1 )
|
||||
return ent;
|
||||
|
||||
if( customentity )
|
||||
{
|
||||
SpawnEdict = SV_GetEntityClass( "custom" );
|
||||
*customentity = SpawnEdict != NULL;
|
||||
}
|
||||
SpawnEdict = SV_GetEntityClass( "custom" );
|
||||
|
||||
if( !SpawnEdict )
|
||||
{
|
||||
@@ -1170,6 +1216,8 @@ static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className, qboolean
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SetBits( ent->v.flags, FL_CUSTOMENTITY ); // it's a custom entity but not a beam!
|
||||
}
|
||||
|
||||
SpawnEdict( &ent->v );
|
||||
@@ -1186,7 +1234,12 @@ create specified entity, alloc private data
|
||||
*/
|
||||
edict_t* SV_CreateNamedEntity( edict_t *ent, string_t className )
|
||||
{
|
||||
return SV_AllocPrivateData( ent, className, NULL );
|
||||
edict_t *ed = SV_AllocPrivateData( ent, className );
|
||||
|
||||
// for some reasons this flag should be immediately cleared
|
||||
if( ed ) ClearBits( ed->v.flags, FL_CUSTOMENTITY );
|
||||
|
||||
return ed;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2798,10 +2851,8 @@ standard path to register game variable
|
||||
static void GAME_EXPORT pfnCvar_RegisterServerVariable( cvar_t *variable )
|
||||
{
|
||||
if( variable != NULL )
|
||||
{
|
||||
SetBits( variable->flags, FCVAR_EXTDLL );
|
||||
Cvar_RegisterVariable( (convar_t *)variable );
|
||||
}
|
||||
Cvar_RegisterVariable( (convar_t *)variable );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3167,9 +3218,7 @@ string_t GAME_EXPORT SV_AllocString( const char *szValue )
|
||||
{
|
||||
char *newString = NULL;
|
||||
uint len;
|
||||
#ifdef XASH_64BIT
|
||||
int cmp;
|
||||
#endif
|
||||
|
||||
if( svgame.physFuncs.pfnAllocString != NULL )
|
||||
{
|
||||
@@ -3232,21 +3281,19 @@ string_t GAME_EXPORT SV_AllocString( const char *szValue )
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef XASH_64BIT
|
||||
void SV_PrintStr64Stats_f( void )
|
||||
{
|
||||
#ifdef XASH_64BIT
|
||||
Con_Printf( "====================\n" );
|
||||
Con_Printf( "64 bit string pool statistics\n" );
|
||||
Con_Printf( "====================\n" );
|
||||
Con_Printf( "string array size: %lu\n", str64.maxstringarray );
|
||||
Con_Printf( "total alloc %lu\n", str64.totalalloc );
|
||||
Con_Printf( "maximum array usage: %lu\n", str64.maxalloc );
|
||||
Con_Printf( "overflow counter: %lu\n", str64.numoverflows );
|
||||
Con_Printf( "dup string counter: %lu\n", str64.numdups );
|
||||
#else
|
||||
Con_Printf( "Not implemented\n" );
|
||||
#endif
|
||||
Msg( "====================\n" );
|
||||
Msg( "64 bit string pool statistics\n" );
|
||||
Msg( "====================\n" );
|
||||
Msg( "string array size: %lu\n", str64.maxstringarray );
|
||||
Msg( "total alloc %lu\n", str64.totalalloc );
|
||||
Msg( "maximum array usage: %lu\n", str64.maxalloc );
|
||||
Msg( "overflow counter: %lu\n", str64.numoverflows );
|
||||
Msg( "dup string counter: %lu\n", str64.numdups );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
=============
|
||||
@@ -3690,9 +3737,9 @@ vaild map must contain one info_player_deatchmatch
|
||||
*/
|
||||
int GAME_EXPORT pfnIsMapValid( char *filename )
|
||||
{
|
||||
uint flags = SV_MapIsValid( filename, NULL );
|
||||
uint flags = SV_MapIsValid( filename, GI->mp_entity, NULL );
|
||||
|
||||
if( FBitSet( flags, MAP_IS_EXIST ))
|
||||
if( FBitSet( flags, MAP_IS_EXIST ) && FBitSet( flags, MAP_HAS_SPAWNPOINT ))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
@@ -3826,11 +3873,11 @@ static char *GAME_EXPORT pfnGetInfoKeyBuffer( edict_t *e )
|
||||
|
||||
// NULL passes localinfo
|
||||
if( !SV_IsValidEdict( e ))
|
||||
return svs.localinfo;
|
||||
return SV_Localinfo();
|
||||
|
||||
// world passes serverinfo
|
||||
if( e == svgame.edicts )
|
||||
return svs.serverinfo;
|
||||
return SV_Serverinfo();
|
||||
|
||||
// userinfo for specified edict
|
||||
if(( cl = SV_ClientFromEdict( e, false )) != NULL )
|
||||
@@ -4773,15 +4820,6 @@ static enginefuncs_t gEngfuncs =
|
||||
pfnPEntityOfEntIndexAllEntities,
|
||||
};
|
||||
|
||||
static void SV_FreeKeyValueStrings( KeyValueData *kvd, int numpairs )
|
||||
{
|
||||
for( int i = 0; i < numpairs; i++ )
|
||||
{
|
||||
Mem_Free( kvd[i].szKeyName );
|
||||
Mem_Free( kvd[i].szValue );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
====================
|
||||
SV_ParseEdict
|
||||
@@ -4793,34 +4831,36 @@ ed should be a properly initialized empty edict.
|
||||
static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
|
||||
{
|
||||
KeyValueData pkvd[256]; // per one entity
|
||||
qboolean adjust_origin = false, customentity;
|
||||
qboolean adjust_origin = false;
|
||||
int i, numpairs = 0;
|
||||
const char *classname = NULL;
|
||||
char *classname = NULL;
|
||||
char token[2048];
|
||||
vec3_t origin;
|
||||
|
||||
// go through all the dictionary pairs
|
||||
while( 1 )
|
||||
{
|
||||
string keyname;
|
||||
char value[2048];
|
||||
int len;
|
||||
|
||||
// parse key
|
||||
if(( *pfile = COM_ParseFile( *pfile, keyname, sizeof( keyname ))) == NULL )
|
||||
if(( *pfile = COM_ParseFile( *pfile, token, sizeof( token ))) == NULL )
|
||||
Host_Error( "ED_ParseEdict: EOF without closing brace\n" );
|
||||
if( token[0] == '}' ) break; // end of desc
|
||||
|
||||
if( keyname[0] == '}' )
|
||||
break; // end of desc
|
||||
Q_strncpy( keyname, token, sizeof( keyname ));
|
||||
|
||||
// parse value
|
||||
if(( *pfile = COM_ParseFile( *pfile, value, sizeof( value ))) == NULL )
|
||||
if(( *pfile = COM_ParseFile( *pfile, token, sizeof( token ))) == NULL )
|
||||
Host_Error( "ED_ParseEdict: EOF without closing brace\n" );
|
||||
|
||||
if( value[0] == '}' )
|
||||
if( token[0] == '}' )
|
||||
Host_Error( "ED_ParseEdict: closing brace without data\n" );
|
||||
|
||||
// ignore attempts to set empty key or value
|
||||
// ignore attempts to set key ""
|
||||
if( !keyname[0] ) continue;
|
||||
|
||||
// "wad" field is already handled
|
||||
if( !keyname[0] || !value[0] || !Q_strcmp( keyname, "wad" ))
|
||||
if( !Q_strcmp( keyname, "wad" ))
|
||||
continue;
|
||||
|
||||
// keynames with a leading underscore are used for
|
||||
@@ -4828,83 +4868,57 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
|
||||
if( FBitSet( world.flags, FWORLD_SKYSPHERE ) && keyname[0] == '_' )
|
||||
continue;
|
||||
|
||||
// classname must be first
|
||||
if( !Q_strcmp( keyname, "classname" ))
|
||||
{
|
||||
KeyValueData kvd = {
|
||||
.szClassName = NULL,
|
||||
.szKeyName = keyname,
|
||||
.szValue = value,
|
||||
.fHandled = false
|
||||
};
|
||||
|
||||
// don't allow double classnames
|
||||
if( classname != NULL )
|
||||
continue;
|
||||
|
||||
svgame.dllFuncs.pfnKeyValue( ent, &kvd );
|
||||
|
||||
// ideally, all game dlls should handle classname.
|
||||
// throw an error for now, improve the logic if it causes
|
||||
// compatibility issues with Xash-based games
|
||||
if( !kvd.fHandled )
|
||||
Host_Error( "%s: game didn't handled \"%s\" classname\n", __func__, value );
|
||||
|
||||
// this lets game dll override custom entity classname
|
||||
// to something bogus that's exported in game dll
|
||||
classname = STRING( ent->v.classname );
|
||||
continue;
|
||||
}
|
||||
|
||||
// GoldSrc removes trailing spaces
|
||||
// but does this after sucking out classname
|
||||
// which doesn't have similar check
|
||||
for( len = Q_strlen( keyname ); len > 0 && keyname[len - 1] == ' '; len-- )
|
||||
keyname[len - 1] = '\0';
|
||||
// ignore attempts to set value ""
|
||||
if( !token[0] ) continue;
|
||||
|
||||
// create keyvalue strings
|
||||
pkvd[numpairs].szClassName = (char*)""; // unknown at this moment
|
||||
pkvd[numpairs].szKeyName = copystring( keyname );
|
||||
pkvd[numpairs].szValue = copystring( value );
|
||||
pkvd[numpairs].szValue = copystring( token );
|
||||
pkvd[numpairs].fHandled = false;
|
||||
numpairs++;
|
||||
|
||||
if( numpairs > ARRAYSIZE( pkvd ))
|
||||
{
|
||||
if( classname )
|
||||
Con_Printf( S_ERROR "%s: too many keyvalue pairs for %s!\n", __func__, classname );
|
||||
else Con_Printf( S_ERROR "%s: too many keyvalue pairs!\n", __func__ );
|
||||
break;
|
||||
}
|
||||
if( !Q_strcmp( keyname, "classname" ) && classname == NULL )
|
||||
classname = copystring( pkvd[numpairs].szValue );
|
||||
if( ++numpairs >= 256 ) break;
|
||||
}
|
||||
|
||||
if( classname == NULL )
|
||||
{
|
||||
// release allocated strings
|
||||
SV_FreeKeyValueStrings( pkvd, numpairs );
|
||||
for( i = 0; i < numpairs; i++ )
|
||||
{
|
||||
Mem_Free( pkvd[i].szKeyName );
|
||||
Mem_Free( pkvd[i].szValue );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ent = SV_AllocPrivateData( ent, ent->v.classname, &customentity );
|
||||
ent = SV_AllocPrivateData( ent, ALLOC_STRING( classname ));
|
||||
|
||||
if( !SV_IsValidEdict( ent ) || FBitSet( ent->v.flags, FL_KILLME ))
|
||||
{
|
||||
// release allocated strings
|
||||
SV_FreeKeyValueStrings( pkvd, numpairs );
|
||||
for( i = 0; i < numpairs; i++ )
|
||||
{
|
||||
Mem_Free( pkvd[i].szKeyName );
|
||||
Mem_Free( pkvd[i].szValue );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if( customentity )
|
||||
if( FBitSet( ent->v.flags, FL_CUSTOMENTITY ))
|
||||
{
|
||||
KeyValueData kvd = {
|
||||
.szClassName = (char *)"custom",
|
||||
.szKeyName = (char *)"customclass",
|
||||
.szValue = (char *)classname,
|
||||
.fHandled = false
|
||||
};
|
||||
if( numpairs < 256 )
|
||||
{
|
||||
pkvd[numpairs].szClassName = (char*)"custom";
|
||||
pkvd[numpairs].szKeyName = (char*)"customclass";
|
||||
pkvd[numpairs].szValue = classname;
|
||||
pkvd[numpairs].fHandled = false;
|
||||
numpairs++;
|
||||
}
|
||||
|
||||
svgame.dllFuncs.pfnKeyValue( ent, &kvd );
|
||||
// no fHandled check, GoldSrc behavior
|
||||
// clear it now - no longer used
|
||||
ClearBits( ent->v.flags, FL_CUSTOMENTITY );
|
||||
}
|
||||
|
||||
#ifdef HACKS_RELATED_HLMODS
|
||||
@@ -4918,14 +4932,6 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
|
||||
|
||||
for( i = 0; i < numpairs; i++ )
|
||||
{
|
||||
char *keyname, *value;
|
||||
char temp[MAX_VA_STRING];
|
||||
|
||||
#if 0 // this is stupid bug in GoldSrc, disable
|
||||
if( !Q_strcmp( pkvd[i].szValue, classname ))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
if( !Q_strcmp( pkvd[i].szKeyName, "angle" ))
|
||||
{
|
||||
float flYawAngle = Q_atof( pkvd[i].szValue );
|
||||
@@ -4936,6 +4942,8 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
|
||||
|
||||
if( flYawAngle >= 0.0f )
|
||||
{
|
||||
char temp[MAX_VA_STRING];
|
||||
|
||||
Q_snprintf( temp, sizeof( temp ), "%g %g %g", ent->v.angles[0], flYawAngle, ent->v.angles[2] );
|
||||
pkvd[i].szValue = copystring( temp );
|
||||
}
|
||||
@@ -4946,10 +4954,11 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
|
||||
else pkvd[i].szValue = copystring( "0 0 0" ); // technically an error
|
||||
}
|
||||
|
||||
#ifdef HACKS_RELATED_HLMODS
|
||||
if( adjust_origin && !Q_strcmp( pkvd[i].szKeyName, "origin" ))
|
||||
{
|
||||
char *pstart = pkvd[i].szValue;
|
||||
vec3_t origin;
|
||||
char temp[MAX_VA_STRING];
|
||||
char *pstart = pkvd[i].szValue;
|
||||
|
||||
COM_ParseVector( &pstart, origin, 3 );
|
||||
Mem_Free( pkvd[i].szValue ); // release old value, so we don't need these
|
||||
@@ -4957,18 +4966,24 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
|
||||
Q_snprintf( temp, sizeof( temp ), "%g %g %g", origin[0], origin[1], origin[2] - 16.0f );
|
||||
pkvd[i].szValue = copystring( temp );
|
||||
}
|
||||
#endif
|
||||
if( !pkvd[i].fHandled )
|
||||
{
|
||||
pkvd[i].szClassName = classname;
|
||||
svgame.dllFuncs.pfnKeyValue( ent, &pkvd[i] );
|
||||
}
|
||||
|
||||
// do not leak memory if game overwritten these pointers
|
||||
keyname = pkvd[i].szKeyName;
|
||||
value = pkvd[i].szValue;
|
||||
// no reason to keep this data
|
||||
if( Mem_IsAllocatedExt( host.mempool, pkvd[i].szKeyName ))
|
||||
Mem_Free( pkvd[i].szKeyName );
|
||||
|
||||
pkvd[i].szClassName = (char *)classname;
|
||||
svgame.dllFuncs.pfnKeyValue( ent, &pkvd[i] );
|
||||
|
||||
Mem_Free( keyname );
|
||||
Mem_Free( value );
|
||||
if( Mem_IsAllocatedExt( host.mempool, pkvd[i].szValue ))
|
||||
Mem_Free( pkvd[i].szValue );
|
||||
}
|
||||
|
||||
if( Mem_IsAllocatedExt( host.mempool, classname ))
|
||||
Mem_Free( classname );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5087,6 +5102,8 @@ void SV_UnloadProgs( void )
|
||||
/// SV_UnloadProgs will be disabled
|
||||
//Mod_ClearUserData ();
|
||||
|
||||
SV_FreeStringPool();
|
||||
|
||||
if( svgame.dllFuncs2.pfnGameShutdown != NULL )
|
||||
svgame.dllFuncs2.pfnGameShutdown ();
|
||||
|
||||
@@ -5107,8 +5124,6 @@ void SV_UnloadProgs( void )
|
||||
Cvar_Unlink( FCVAR_EXTDLL );
|
||||
Cmd_Unlink( CMD_SERVERDLL );
|
||||
|
||||
SV_FreeStringPool();
|
||||
|
||||
Mod_ResetStudioAPI ();
|
||||
|
||||
COM_FreeLibrary( svgame.hInstance );
|
||||
|
||||
@@ -77,7 +77,7 @@ void Log_Open( void )
|
||||
|
||||
if( fp ) svs.log.file = fp;
|
||||
Log_Printf( "Log file started (file \"%s\") (game \"%s\") (version \"%i/" XASH_VERSION "/%d\")\n",
|
||||
szTestFile, Info_ValueForKey( svs.serverinfo, "*gamedir" ), PROTOCOL_VERSION, Q_buildnum() );
|
||||
szTestFile, Info_ValueForKey( SV_Serverinfo(), "*gamedir" ), PROTOCOL_VERSION, Q_buildnum() );
|
||||
}
|
||||
|
||||
void Log_Close( void )
|
||||
|
||||
@@ -2110,7 +2110,7 @@ qboolean SV_LoadGame( const char *pPath )
|
||||
if( validload )
|
||||
{
|
||||
// now check for map problems
|
||||
flags = SV_MapIsValid( gameHeader.mapName, NULL );
|
||||
flags = SV_MapIsValid( gameHeader.mapName, GI->sp_entity, NULL );
|
||||
|
||||
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
||||
{
|
||||
@@ -2386,7 +2386,7 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment )
|
||||
uint flags;
|
||||
|
||||
// now check for map problems
|
||||
flags = SV_MapIsValid( mapName, NULL );
|
||||
flags = SV_MapIsValid( mapName, GI->sp_entity, NULL );
|
||||
|
||||
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
||||
{
|
||||
|
||||
@@ -32,6 +32,9 @@ def options(opt):
|
||||
grp.add_option('--enable-engine-fuzz', action = 'store_true', dest = 'ENGINE_FUZZ', default = False,
|
||||
help = 'add LLVM libFuzzer [default: %default]' )
|
||||
|
||||
grp.add_option('--enable-android-legacy', action = 'store_true', dest = 'ANDROID_LEGACY', default = False,
|
||||
help = 'allow build legacy android port without SDL (deprecated, need for renderers debug on ancient devices)')
|
||||
|
||||
opt.load('sdl2')
|
||||
|
||||
def configure(conf):
|
||||
@@ -75,6 +78,8 @@ def configure(conf):
|
||||
conf.define('XASH_SDL', 12)
|
||||
conf.check_cfg(package='sdl', args='--cflags --libs', uselib_store='SDL2' )
|
||||
conf.env.HAVE_SDL2 = True
|
||||
elif conf.options.ANDROID_LEGACY:
|
||||
pass #just test if it can build
|
||||
else:
|
||||
conf.load('sdl2')
|
||||
if not conf.env.HAVE_SDL2:
|
||||
|
||||
@@ -320,12 +320,6 @@ public:
|
||||
return nullptr;
|
||||
|
||||
state = new CSearchState( &searchHead, search );
|
||||
if( !state )
|
||||
{
|
||||
Mem_Free( search );
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*handle = state->handle;
|
||||
return state->search->filenames[0];
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ GNU General Public License for more details.
|
||||
|
||||
#include "port.h"
|
||||
|
||||
#if XASH_ANDROID
|
||||
#if XASH_ANDROID_ASSETS
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -276,9 +276,6 @@ searchpath_t *FS_AddAndroidAssets_Fullpath( const char *path, int flags )
|
||||
android_assets_t *assets = NULL;
|
||||
qboolean engine = true;
|
||||
|
||||
if( !jni.getPackageName || !jni.getCallingPackage || !jni.getAssetsList || !jni.getAssets )
|
||||
return NULL;
|
||||
|
||||
if( FBitSet( flags, FS_STATIC_PATH | FS_CUSTOM_PATH ))
|
||||
return NULL;
|
||||
|
||||
@@ -289,7 +286,7 @@ searchpath_t *FS_AddAndroidAssets_Fullpath( const char *path, int flags )
|
||||
|
||||
if( !assets )
|
||||
{
|
||||
Con_Reportf( S_ERROR "%s: unable to load Android assets \"%s\"\n", __func__, Android_GetPackageName( engine ));
|
||||
Con_Reportf( S_ERROR "%s: unable to load Android assets \"%s\"\n", __FUNCTION__, Android_GetPackageName( engine ));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -329,9 +326,6 @@ void FS_InitAndroid( void )
|
||||
jni.getCallingPackage = (*jni.env)->GetMethodID( jni.env, jni.activity_class, "getCallingPackage", "()Ljava/lang/String;" );
|
||||
jni.getAssetsList = (*jni.env)->GetMethodID( jni.env, jni.activity_class, "getAssetsList", "(ZLjava/lang/String;)[Ljava/lang/String;" );
|
||||
jni.getAssets = (*jni.env)->GetMethodID( jni.env, jni.activity_class, "getAssets", "(Z)Landroid/content/res/AssetManager;" );
|
||||
|
||||
if( !jni.getPackageName || !jni.getCallingPackage || !jni.getAssetsList || !jni.getAssets )
|
||||
Con_Reportf( S_WARN "%s: unable to find required JNI interface to load Android assets\n", __func__ );
|
||||
}
|
||||
|
||||
#endif // XASH_ANDROID
|
||||
#endif // XASH_ANDROID_ASSETS
|
||||
|
||||
@@ -72,7 +72,7 @@ const fs_archive_t g_archives[] =
|
||||
static const fs_archive_t g_directory_archive =
|
||||
{ NULL, SEARCHPATH_PLAIN, FS_AddDir_Fullpath, false };
|
||||
|
||||
#if XASH_ANDROID
|
||||
#if XASH_ANDROID_ASSETS
|
||||
static const fs_archive_t g_android_archive =
|
||||
{ NULL, SEARCHPATH_ANDROID_ASSETS, FS_AddAndroidAssets_Fullpath, false };
|
||||
#endif
|
||||
@@ -406,7 +406,7 @@ void FS_AddGameDirectory( const char *dir, uint flags )
|
||||
|
||||
stringlistfreecontents( &list );
|
||||
|
||||
#if XASH_ANDROID
|
||||
#if XASH_ANDROID_ASSETS
|
||||
FS_AddArchive_Fullpath( &g_android_archive, dir, flags );
|
||||
#endif
|
||||
|
||||
@@ -1461,7 +1461,7 @@ qboolean FS_InitStdio( qboolean unused_set_to_true, const char *rootdir, const c
|
||||
|
||||
FS_InitMemory();
|
||||
|
||||
#if XASH_ANDROID
|
||||
#if XASH_ANDROID_ASSETS
|
||||
FS_InitAndroid();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -358,7 +358,7 @@ searchpath_t *FS_AddPak_Fullpath( const char *pakfile, int flags )
|
||||
search->pfnFindFile = FS_FindFile_PAK;
|
||||
search->pfnSearch = FS_Search_PAK;
|
||||
|
||||
Con_Reportf( "Adding PAK: %s (%i files)\n", pakfile, pak->numfiles );
|
||||
Con_Reportf( "Adding pakfile: %s (%i files)\n", pakfile, pak->numfiles );
|
||||
|
||||
return search;
|
||||
}
|
||||
|
||||
@@ -670,6 +670,6 @@ searchpath_t *FS_AddWad_Fullpath( const char *wadfile, int flags )
|
||||
search->pfnSearch = FS_Search_WAD;
|
||||
search->pfnLoadFile = W_ReadLump;
|
||||
|
||||
Con_Reportf( "Adding WAD: %s (%i files)\n", wadfile, wad->numlumps );
|
||||
Con_Reportf( "Adding wadfile: %s (%i files)\n", wadfile, wad->numlumps );
|
||||
return search;
|
||||
}
|
||||
|
||||
@@ -701,7 +701,7 @@ searchpath_t *FS_AddZip_Fullpath( const char *zipfile, int flags )
|
||||
search->pfnSearch = FS_Search_ZIP;
|
||||
search->pfnLoadFile = FS_LoadZIPFile;
|
||||
|
||||
Con_Reportf( "Adding ZIP: %s (%i files)\n", zipfile, zip->numfiles );
|
||||
Con_Reportf( "Adding zipfile: %s (%i files)\n", zipfile, zip->numfiles );
|
||||
return search;
|
||||
}
|
||||
|
||||
|
||||
@@ -237,25 +237,19 @@ const char *Q_buildarch( void )
|
||||
=============
|
||||
Q_buildcommit
|
||||
|
||||
Returns a short hash of current commit in VCS as string
|
||||
Returns a short hash of current commit in VCS as string.
|
||||
XASH_BUILD_COMMIT must be passed in quotes
|
||||
|
||||
if XASH_BUILD_COMMIT is not defined,
|
||||
Q_buildcommit will identify this build as "notset"
|
||||
=============
|
||||
*/
|
||||
const char *Q_buildcommit( void )
|
||||
{
|
||||
#ifdef XASH_BUILD_COMMIT
|
||||
return XASH_BUILD_COMMIT;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Q_buildbranch
|
||||
|
||||
Returns current branch name in VCS as string
|
||||
XASH_BUILD_BRANCH must be passed in quotes
|
||||
=============
|
||||
*/
|
||||
const char *Q_buildbranch( void )
|
||||
{
|
||||
return XASH_BUILD_BRANCH;
|
||||
#else
|
||||
return "notset";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ const char *Q_buildos( void );
|
||||
const char *Q_ArchitectureStringByID( const int arch, const uint abi, const int endianness, const qboolean is64 );
|
||||
const char *Q_buildarch( void );
|
||||
const char *Q_buildcommit( void );
|
||||
const char *Q_buildbranch( void );
|
||||
|
||||
//
|
||||
// crtlib.c
|
||||
|
||||
207
public/utflib.c
207
public/utflib.c
@@ -1,207 +0,0 @@
|
||||
/*
|
||||
utflib.c - small unicode conversion library
|
||||
Copyright (C) 2024 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 "utflib.h"
|
||||
#include "xash3d_types.h"
|
||||
|
||||
uint32_t Q_DecodeUTF8( utfstate_t *s, uint32_t in )
|
||||
{
|
||||
// get character length
|
||||
if( s->len == 0 )
|
||||
{
|
||||
// init state
|
||||
s->uc = 0;
|
||||
|
||||
// expect ASCII symbols by default
|
||||
if( likely( in <= 0x7fu ))
|
||||
return in;
|
||||
|
||||
// invalid sequence
|
||||
if( unlikely( in >= 0xf8u ))
|
||||
return 0;
|
||||
|
||||
s->k = 0;
|
||||
|
||||
if( in >= 0xf0u )
|
||||
{
|
||||
s->uc = in & 0x07u;
|
||||
s->len = 3;
|
||||
}
|
||||
else if( in >= 0xe0u )
|
||||
{
|
||||
s->uc = in & 0x0fu;
|
||||
s->len = 2;
|
||||
}
|
||||
else if( in >= 0xc0u )
|
||||
{
|
||||
s->uc = in & 0x1fu;
|
||||
s->len = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// invalid sequence, reset
|
||||
if( unlikely( in > 0xbfu ))
|
||||
{
|
||||
s->len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s->uc <<= 6;
|
||||
s->uc += in & 0x3fu;
|
||||
s->k++;
|
||||
|
||||
// sequence complete, reset and return code point
|
||||
if( likely( s->k == s->len ))
|
||||
{
|
||||
s->len = 0;
|
||||
return s->uc;
|
||||
}
|
||||
|
||||
// feed more characters
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Q_DecodeUTF16( utfstate_t *s, uint32_t in )
|
||||
{
|
||||
// get character length
|
||||
if( s->len == 0 )
|
||||
{
|
||||
// init state
|
||||
s->uc = 0;
|
||||
|
||||
// expect simple case, after all decoding UTF-16 must be easy
|
||||
if( likely( in < 0xd800u || in > 0xdfffu ))
|
||||
return in;
|
||||
|
||||
s->uc = (( in - 0xd800u ) << 10 ) + 0x10000u;
|
||||
s->len = 1;
|
||||
s->k = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// invalid sequence, reset
|
||||
if( unlikely( in < 0xdc00u || in > 0xdfffu ))
|
||||
{
|
||||
s->len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s->uc |= in - 0xdc00u;
|
||||
s->k++;
|
||||
|
||||
// sequence complete, reset and return code point
|
||||
if( likely( s->k == s->len ))
|
||||
{
|
||||
s->len = 0;
|
||||
return s->uc;
|
||||
}
|
||||
|
||||
// feed more characters (should never happen with UTF-16)
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t Q_EncodeUTF8( char dst[4], uint32_t ch )
|
||||
{
|
||||
if( ch <= 0x7fu )
|
||||
{
|
||||
dst[0] = ch;
|
||||
return 1;
|
||||
}
|
||||
else if( ch <= 0x7ffu )
|
||||
{
|
||||
dst[0] = 0xc0u | (( ch >> 6 ) & 0x1fu );
|
||||
dst[1] = 0x80u | (( ch ) & 0x3fu );
|
||||
return 2;
|
||||
}
|
||||
else if( ch <= 0xffffu )
|
||||
{
|
||||
dst[0] = 0xe0u | (( ch >> 12 ) & 0x0fu );
|
||||
dst[1] = 0x80u | (( ch >> 6 ) & 0x3fu );
|
||||
dst[2] = 0x80u | (( ch ) & 0x3fu );
|
||||
return 3;
|
||||
}
|
||||
|
||||
dst[0] = 0xf0u | (( ch >> 18 ) & 0x07u );
|
||||
dst[1] = 0x80u | (( ch >> 12 ) & 0x3fu );
|
||||
dst[2] = 0x80u | (( ch >> 6 ) & 0x3fu );
|
||||
dst[3] = 0x80u | (( ch ) & 0x3fu );
|
||||
return 4;
|
||||
}
|
||||
|
||||
size_t Q_UTF8Length( const char *s )
|
||||
{
|
||||
size_t len = 0;
|
||||
utfstate_t state = { 0 };
|
||||
|
||||
if( !s )
|
||||
return 0;
|
||||
|
||||
for( ; *s; s++ )
|
||||
{
|
||||
uint32_t ch = Q_DecodeUTF8( &state, (uint32_t)*s );
|
||||
|
||||
if( ch == 0 )
|
||||
continue;
|
||||
|
||||
len++;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static size_t Q_CodepointLength( uint32_t ch )
|
||||
{
|
||||
if( ch <= 0x7fu )
|
||||
return 1;
|
||||
else if( ch <= 0x7ffu )
|
||||
return 2;
|
||||
else if( ch <= 0xffffu )
|
||||
return 3;
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
size_t Q_UTF16ToUTF8( char *dst, size_t dstsize, const uint16_t *src, size_t srcsize )
|
||||
{
|
||||
utfstate_t state = { 0 };
|
||||
size_t dsti = 0, srci;
|
||||
|
||||
if( !dst || !src || !dstsize || !srcsize )
|
||||
return 0;
|
||||
|
||||
for( srci = 0; srci < srcsize && src[srci]; srci++ )
|
||||
{
|
||||
uint32_t ch;
|
||||
size_t len;
|
||||
|
||||
ch = Q_DecodeUTF16( &state, src[srci] );
|
||||
|
||||
if( ch == 0 )
|
||||
continue;
|
||||
|
||||
len = Q_CodepointLength( ch );
|
||||
|
||||
if( dsti + len + 1 > dstsize )
|
||||
break;
|
||||
|
||||
dsti += Q_EncodeUTF8( &dst[dsti], ch );
|
||||
}
|
||||
|
||||
dst[dsti] = 0;
|
||||
|
||||
return dsti;
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
utflib.h - small unicode conversion library
|
||||
Copyright (C) 2024 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 UTFLIB_H
|
||||
#define UTFLIB_H
|
||||
|
||||
#include STDINT_H
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct utfstate_s
|
||||
{
|
||||
uint32_t uc;
|
||||
uint8_t len;
|
||||
uint8_t k;
|
||||
} utfstate_t;
|
||||
|
||||
// feed utf8 characters one by one
|
||||
// if it returns 0, feed more
|
||||
// utfstate_t must be zero initialized
|
||||
uint32_t Q_DecodeUTF8( utfstate_t *s, uint32_t ch );
|
||||
uint32_t Q_DecodeUTF16( utfstate_t *s, uint32_t ch );
|
||||
size_t Q_EncodeUTF8( char dst[4], uint32_t ch );
|
||||
|
||||
size_t Q_UTF8Length( const char *s );
|
||||
|
||||
// srcsize in byte pairs
|
||||
size_t Q_UTF16ToUTF8( char *dst, size_t dstsize, const uint16_t *src, size_t srcsize );
|
||||
|
||||
#endif // UTFLIB_H
|
||||
@@ -12,9 +12,7 @@ def options(opt):
|
||||
return
|
||||
|
||||
def configure(conf):
|
||||
conf.load('gitversion')
|
||||
conf.define('XASH_BUILD_COMMIT', conf.env.GIT_VERSION if conf.env.GIT_VERSION else 'unknown-commit')
|
||||
conf.define('XASH_BUILD_BRANCH', conf.env.GIT_BRANCH if conf.env.GIT_BRANCH else 'unknown-branch')
|
||||
conf.define('XASH_BUILD_COMMIT', conf.env.GIT_VERSION if conf.env.GIT_VERSION else 'notset')
|
||||
|
||||
def build(bld):
|
||||
bld(name = 'sdk_includes', export_includes = '. ../common ../pm_shared ../engine')
|
||||
|
||||
@@ -73,8 +73,7 @@ GNU General Public License for more details.
|
||||
|
||||
#define Q_min( a, b ) (((a) < (b)) ? (a) : (b))
|
||||
#define Q_max( a, b ) (((a) > (b)) ? (a) : (b))
|
||||
#define Q_equal_e( a, b, e ) (((a) > ((b) - (e))) && ((a) < ((b) + (e))))
|
||||
#define Q_equal( a, b ) Q_equal_e( a, b, EQUAL_EPSILON )
|
||||
#define Q_equal( a, b ) (((a) > ((b) - EQUAL_EPSILON)) && ((a) < ((b) + EQUAL_EPSILON)))
|
||||
#define Q_recip( a ) ((float)(1.0f / (float)(a)))
|
||||
#define Q_floor( a ) ((float)(int)(a))
|
||||
#define Q_ceil( a ) ((float)(int)((a) + 1))
|
||||
|
||||
@@ -59,7 +59,7 @@ static int g_used[8192];
|
||||
|
||||
// a pose is a single set of vertexes. a frame may be
|
||||
// an animating sequence of poses
|
||||
static int g_posenum;
|
||||
int g_posenum;
|
||||
|
||||
// the command list holds counts and s/t values that are valid for
|
||||
// every frame
|
||||
|
||||
@@ -1471,22 +1471,6 @@ static void GL_DeleteTexture( gl_texture_t *tex )
|
||||
prev = &cur->nextHash;
|
||||
}
|
||||
|
||||
// invalidate texture units state cache
|
||||
for( int i = 0; i < MAX_TEXTURE_UNITS; i++ )
|
||||
{
|
||||
if( glState.currentTextures[i] == tex->texnum )
|
||||
{
|
||||
if( glState.currentTextureTargets[i] != GL_NONE )
|
||||
{
|
||||
GL_SelectTexture( i );
|
||||
pglDisable( glState.currentTextureTargets[i] );
|
||||
}
|
||||
glState.currentTextureTargets[i] = GL_NONE;
|
||||
glState.currentTextures[i] = -1;
|
||||
glState.currentTexturesIndex[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// release source
|
||||
if( tex->original )
|
||||
gEngfuncs.FS_FreeImage( tex->original );
|
||||
|
||||
@@ -556,54 +556,70 @@ qboolean GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char
|
||||
for( func = funcs; func && func->name; func++ )
|
||||
{
|
||||
// functions are cleared before all the extensions are evaluated
|
||||
if(( *func->func = (void *)gEngfuncs.GL_GetProcAddress( func->name )) == NULL )
|
||||
{
|
||||
string name;
|
||||
char *end;
|
||||
size_t i = 0;
|
||||
string name;
|
||||
char *end;
|
||||
size_t i = 0;
|
||||
qboolean first_try = true;
|
||||
// NULL means just func->name, but empty suffix cuts ARB suffix if present
|
||||
#ifdef XASH_GLES
|
||||
const char *suffixes[] = { "", "EXT", "OES" };
|
||||
const char *suffixes[] = { "", "EXT", "OES", NULL, "ARB" };
|
||||
#else
|
||||
const char *suffixes[] = { "", "EXT" };
|
||||
const char *suffixes[] = { NULL, "", "EXT", "ARB" };
|
||||
#endif
|
||||
|
||||
// HACK: fix ARB names
|
||||
Q_strncpy( name, func->name, sizeof( name ));
|
||||
if(( end = Q_strstr( name, "ARB" )))
|
||||
{
|
||||
*end = '\0';
|
||||
}
|
||||
else // I need Q_strstrnul
|
||||
{
|
||||
end = name + Q_strlen( name );
|
||||
i++; // skip empty suffix
|
||||
}
|
||||
// Remove ARB suffix
|
||||
Q_strncpy( name, func->name, sizeof( name ));
|
||||
if(( end = Q_strstr( name, "ARB" )))
|
||||
{
|
||||
*end = '\0';
|
||||
}
|
||||
else // I need Q_strstrnul
|
||||
{
|
||||
end = name + Q_strlen( name );
|
||||
}
|
||||
|
||||
for( ; i < sizeof( suffixes ) / sizeof( suffixes[0] ); i++ )
|
||||
{
|
||||
void *f;
|
||||
for( ; i < sizeof( suffixes ) / sizeof( suffixes[0] ); i++ )
|
||||
{
|
||||
void *f;
|
||||
const char *pname = name;
|
||||
size_t name_len = end - pname;
|
||||
const char *orig_suffix = func->name + name_len;
|
||||
|
||||
if( suffixes[i] )
|
||||
{
|
||||
// if suffix is original suffix, it's handled with NULL
|
||||
if( orig_suffix[0] && !Q_strcmp( orig_suffix, suffixes[i] ))
|
||||
continue;
|
||||
Q_strncat( name, suffixes[i], sizeof( name ));
|
||||
|
||||
if(( f = gEngfuncs.GL_GetProcAddress( name )))
|
||||
{
|
||||
// GL_GetProcAddress prints errors about missing functions, so tell user that we found it with different name
|
||||
gEngfuncs.Con_Printf( S_NOTE "found %s\n", name );
|
||||
|
||||
*func->func = f;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
*end = '\0'; // cut suffix, try next
|
||||
}
|
||||
}
|
||||
|
||||
// not found...
|
||||
if( i == sizeof( suffixes ) / sizeof( suffixes[0] ))
|
||||
else
|
||||
{
|
||||
GL_SetExtension( r_ext, false );
|
||||
// if original name does not have a suffix, it will be handled with empty suffix
|
||||
if( !orig_suffix[0] )
|
||||
continue;
|
||||
pname = func->name;
|
||||
}
|
||||
|
||||
if(( f = gEngfuncs.GL_GetProcAddress( pname )))
|
||||
{
|
||||
// if we already tried this function, notify about success after previous error from GL_GetProcAddress
|
||||
if(!first_try)
|
||||
gEngfuncs.Con_Printf( S_NOTE "found %s\n", pname );
|
||||
first_try = false;
|
||||
|
||||
*func->func = f;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
*end = '\0'; // cut suffix, try next
|
||||
}
|
||||
}
|
||||
|
||||
// not found...
|
||||
if( i == sizeof( suffixes ) / sizeof( suffixes[0] ))
|
||||
{
|
||||
GL_SetExtension( r_ext, false );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -51,7 +51,6 @@ static void R_SimpleStubBool( qboolean )
|
||||
|
||||
static qboolean R_Init( void )
|
||||
{
|
||||
gEngfuncs.R_Init_Video( REF_SOFTWARE );
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -179,14 +178,7 @@ static void GL_SubdivideSurface( model_t *mod, msurface_t *fa )
|
||||
|
||||
static void R_GetSpriteParms( int *frameWidth, int *frameHeight, int *numFrames, int currentFrame, const model_t *pSprite )
|
||||
{
|
||||
if( frameWidth )
|
||||
*frameWidth = 0;
|
||||
|
||||
if( frameHeight )
|
||||
*frameHeight = 0;
|
||||
|
||||
if( numFrames )
|
||||
*numFrames = 0;
|
||||
*frameWidth = *frameHeight = *numFrames = 0;
|
||||
}
|
||||
|
||||
static int R_GetSpriteTexture( const model_t *m_pSpriteModel, int frame )
|
||||
@@ -202,7 +194,7 @@ static void Mod_LoadMapSprite( struct model_s *mod, const void *buffer, size_t s
|
||||
|
||||
static qboolean Mod_ProcessRenderData( model_t *mod, qboolean create, const byte *buffer )
|
||||
{
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Mod_StudioLoadTextures( model_t *mod, void *data )
|
||||
|
||||
@@ -44,6 +44,7 @@ class Android:
|
||||
ndk_rev = 0
|
||||
is_hardfloat = False
|
||||
clang = False
|
||||
ndk_binutils = False
|
||||
|
||||
def __init__(self, ctx, arch, toolchain, api):
|
||||
self.ctx = ctx
|
||||
@@ -214,7 +215,7 @@ class Android:
|
||||
if 'CC' in environ:
|
||||
s = environ['CC']
|
||||
|
||||
return '%s --target=%s%d' % (s, self.ndk_triplet(), self.api)
|
||||
return '%s --target=%s' % (s, self.ndk_triplet()) #%s%d' % (s, self.ndk_triplet(), self.api)
|
||||
return self.gen_toolchain_path() + ('clang' if self.is_clang() else 'gcc')
|
||||
|
||||
def cxx(self):
|
||||
@@ -225,11 +226,11 @@ class Android:
|
||||
if 'CXX' in environ:
|
||||
s = environ['CXX']
|
||||
|
||||
return '%s --target=%s%d' % (s, self.ndk_triplet(), self.api)
|
||||
return '%s --target=%s' % (s, self.ndk_triplet()) #%s%d' % (s, self.ndk_triplet(), self.api)
|
||||
return self.gen_toolchain_path() + ('clang++' if self.is_clang() else 'g++')
|
||||
|
||||
def strip(self):
|
||||
if self.is_host():
|
||||
if self.is_host() and not self.ndk_binutils:
|
||||
environ = getattr(self.ctx, 'environ', os.environ)
|
||||
|
||||
if 'STRIP' in environ:
|
||||
@@ -240,9 +241,22 @@ class Android:
|
||||
return os.path.join(self.gen_binutils_path(), 'llvm-strip')
|
||||
return os.path.join(self.gen_binutils_path(), 'strip')
|
||||
|
||||
def objcopy(self):
|
||||
if self.is_host() and not self.ndk_binutils:
|
||||
environ = getattr(self.ctx, 'environ', os.environ)
|
||||
|
||||
if 'OBJCOPY' in environ:
|
||||
return environ['OBJCOPY']
|
||||
return 'llvm-objcopy'
|
||||
|
||||
if self.ndk_rev >= 23:
|
||||
return os.path.join(self.gen_binutils_path(), 'llvm-objcopy')
|
||||
return os.path.join(self.gen_binutils_path(), 'objcopy')
|
||||
|
||||
def system_stl(self):
|
||||
# TODO: proper STL support
|
||||
return os.path.abspath(os.path.join(self.ndk_home, 'sources', 'cxx-stl', 'system', 'include'))
|
||||
#return os.path.abspath(os.path.join(self.ndk_home, 'sources', 'cxx-stl', 'system', 'include')) broken with clang-15? TODO: check different ndk versions
|
||||
return os.path.abspath(os.path.join(self.ndk_home, 'sources', 'cxx-stl', 'stlport', 'stlport'))
|
||||
|
||||
def libsysroot(self):
|
||||
arch = self.arch
|
||||
@@ -262,8 +276,15 @@ class Android:
|
||||
|
||||
def cflags(self, cxx = False):
|
||||
cflags = []
|
||||
android_from_none = False
|
||||
if self.is_host() and self.is_arm() and self.is_hardfp():
|
||||
# clang android target may change with ndk
|
||||
# override target to none while compiling and
|
||||
# add some android options manually
|
||||
android_from_none = True
|
||||
cflags += ['--target=arm-none-eabi']
|
||||
|
||||
if self.ndk_rev <= ANDROID_NDK_SYSROOT_FLAG_MAX:
|
||||
if self.ndk_rev <= ANDROID_NDK_SYSROOT_FLAG_MAX and not android_from_none:
|
||||
cflags += ['--sysroot=%s' % (self.sysroot())]
|
||||
else:
|
||||
if self.is_host():
|
||||
@@ -273,13 +294,18 @@ class Android:
|
||||
]
|
||||
|
||||
cflags += ['-I%s' % (self.system_stl())]
|
||||
if not self.is_clang():
|
||||
cflags += ['-DANDROID', '-D__ANDROID__']
|
||||
if not self.is_clang() or android_from_none:
|
||||
cflags += ['-DANDROID', '-D__ANDROID__=1']
|
||||
if android_from_none:
|
||||
cflags += [ '-D__linux__=1', '-fPIC'] # TODO: compare with linux target?
|
||||
|
||||
if cxx and not self.is_clang() and self.toolchain not in ['4.8','4.9']:
|
||||
cflags += ['-fno-sized-deallocation']
|
||||
|
||||
if self.is_clang():
|
||||
if cxx and (self.is_clang() or self.is_host()):
|
||||
cflags += [ '-Wno-dynamic-exception-spec', '-fno-rtti' ]
|
||||
|
||||
if self.is_clang() or self.is_host():
|
||||
# stpcpy() isn't available in early Android versions
|
||||
# disable it here so Clang won't use it
|
||||
if self.api < ANDROID_STPCPY_API_MIN:
|
||||
@@ -291,7 +317,7 @@ class Android:
|
||||
cflags += ['-mthumb', '-mfpu=neon', '-mcpu=cortex-a9']
|
||||
|
||||
if self.is_hardfp():
|
||||
cflags += ['-D_NDK_MATH_NO_SOFTFP=1', '-mfloat-abi=hard', '-DLOAD_HARDFP', '-DSOFTFP_LINK']
|
||||
cflags += ['-D_NDK_MATH_NO_SOFTFP=1', '-mfloat-abi=hard', '-DLOAD_HARDFP', '-DSOFTFP_LINK', '-DGLES_SOFTFLOAT']
|
||||
|
||||
if self.is_host():
|
||||
# Clang builtin redefine w/ different calling convention bug
|
||||
@@ -316,15 +342,23 @@ class Android:
|
||||
linkflags = []
|
||||
if self.is_host():
|
||||
linkflags += ['--gcc-toolchain=%s' % self.gen_gcc_toolchain_path()]
|
||||
linkflags += ['--gcc-install-dir=%s/lib/gcc/%s/4.9/' % (self.gen_gcc_toolchain_path(), self.ndk_triplet())]
|
||||
if self.ndk_binutils:
|
||||
linkflags += ['-fuse-ld=%s/bin/%s-ld.bfd' % (self.gen_gcc_toolchain_path(), self.ndk_triplet())]
|
||||
else:
|
||||
linkflags += ['-fuse-ld=lld']
|
||||
linkflags += ['--unwindlib=none']
|
||||
linkflags += ['--rtlib=libgcc']
|
||||
|
||||
if self.ndk_rev <= ANDROID_NDK_SYSROOT_FLAG_MAX:
|
||||
linkflags += ['--sysroot=%s' % (self.sysroot())]
|
||||
elif self.is_host():
|
||||
linkflags += ['--sysroot=%s/sysroot' % (self.gen_gcc_toolchain_path())]
|
||||
|
||||
if self.is_clang() or self.is_host():
|
||||
linkflags += ['-fuse-ld=lld']
|
||||
else: linkflags += ['-no-canonical-prefixes']
|
||||
#if self.is_clang() or self.is_host():
|
||||
# linkflags += ['-fuse-ld=lld']
|
||||
#else:
|
||||
linkflags += ['-no-canonical-prefixes']
|
||||
|
||||
linkflags += ['-Wl,--hash-style=sysv', '-Wl,--no-undefined']
|
||||
return linkflags
|
||||
@@ -528,6 +562,7 @@ def configure(conf):
|
||||
conf.environ['CC'] = android.cc()
|
||||
conf.environ['CXX'] = android.cxx()
|
||||
conf.environ['STRIP'] = android.strip()
|
||||
conf.environ['OBJCOPY'] = android.objcopy()
|
||||
conf.env.CFLAGS += android.cflags()
|
||||
conf.env.CXXFLAGS += android.cflags(True)
|
||||
conf.env.LINKFLAGS += android.linkflags()
|
||||
|
||||
@@ -44,16 +44,16 @@ def create_zip_archive(self):
|
||||
self.path.get_bld().mkdir()
|
||||
target = self.path.get_bld().make_node(self.name)
|
||||
|
||||
tsk = self.create_task('ziparchive', files, target)
|
||||
self.zip_task = self.create_task('ziparchive', files, target)
|
||||
|
||||
setattr(tsk, 'compresslevel', compresslevel)
|
||||
setattr(tsk, 'relative_to', relative_to)
|
||||
setattr(self.zip_task, 'compresslevel', compresslevel)
|
||||
setattr(self.zip_task, 'relative_to', relative_to)
|
||||
|
||||
try:
|
||||
inst_to = self.install_path
|
||||
self.install_task = self.add_install_files(
|
||||
install_to=inst_to, install_from=target,
|
||||
chmod=Utils.O644, task=tsk)
|
||||
chmod=Utils.O644, task=self.zip_task)
|
||||
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
@@ -601,12 +601,6 @@ void WriteQCScript( void )
|
||||
fputs( "$scale 1.0\n", fp );
|
||||
fputs( "\n", fp );
|
||||
|
||||
if( model_hdr->flags & STUDIO_HAS_BONEINFO )
|
||||
{
|
||||
if( model_hdr->flags & STUDIO_HAS_BONEWEIGHTS )
|
||||
fputs( "$boneweights\n\n", fp );
|
||||
}
|
||||
|
||||
WriteBodyGroupInfo( fp );
|
||||
|
||||
fprintf( fp, "$flags %u\n\n", model_hdr->flags &~( STUDIO_HAS_BONEINFO | STUDIO_HAS_BONEWEIGHTS ) );
|
||||
@@ -617,6 +611,10 @@ void WriteQCScript( void )
|
||||
|
||||
WriteSkinFamilyInfo( fp );
|
||||
WriteTextureRenderMode( fp );
|
||||
|
||||
if( model_hdr->flags & ( STUDIO_HAS_BONEINFO | STUDIO_HAS_BONEWEIGHTS ) )
|
||||
fputs( "$boneweights\n\n", fp );
|
||||
|
||||
WriteAttachmentInfo( fp );
|
||||
|
||||
fprintf( fp, "$bbox %f %f %f", model_hdr->min[0], model_hdr->min[1], model_hdr->min[2] );
|
||||
|
||||
50
wscript
50
wscript
@@ -2,7 +2,7 @@
|
||||
# encoding: utf-8
|
||||
# a1batross, mittorn, 2018
|
||||
|
||||
from waflib import Build, Context, Logs
|
||||
from waflib import Build, Context, Logs, Options, Configure
|
||||
from waflib.Tools import waf_unit_test
|
||||
import sys
|
||||
import os
|
||||
@@ -69,7 +69,7 @@ SUBDIRS = [
|
||||
Subproject('dllemu'),
|
||||
|
||||
# disable only by engine feature, makes no sense to even parse subprojects in dedicated mode
|
||||
Subproject('3rdparty/extras', lambda x: not x.env.DEDICATED and x.env.DEST_OS != 'android'),
|
||||
Subproject('3rdparty/extras', lambda x: not x.env.DEDICATED),
|
||||
Subproject('3rdparty/nanogl', lambda x: not x.env.DEDICATED and x.env.NANOGL),
|
||||
Subproject('3rdparty/gl-wes-v2', lambda x: not x.env.DEDICATED and x.env.GLWES),
|
||||
Subproject('3rdparty/gl4es', lambda x: not x.env.DEDICATED and x.env.GL4ES),
|
||||
@@ -104,6 +104,42 @@ REFDLLS = [
|
||||
RefDll('null', False),
|
||||
]
|
||||
|
||||
def process_extra_projects_opts(ctx):
|
||||
options, commands, envvars = ctx.parse_cmd_args(allow_unknown = True)
|
||||
projs = options.EXTRA_PROJECTS
|
||||
if not projs:
|
||||
return
|
||||
for proj in projs.split(','):
|
||||
ctx.add_subproject(proj)
|
||||
def process_extra_projects_conf(ctx):
|
||||
projs = ctx.options.EXTRA_PROJECTS
|
||||
if not projs:
|
||||
return
|
||||
ctx.env.EXTRA_PROJECTS = projs
|
||||
|
||||
for proj in projs.split(','):
|
||||
tools_orig = ctx.tools.copy()
|
||||
ctx.add_subproject(proj)
|
||||
waifulib_path = os.path.join(proj, 'scripts', 'waifulib')
|
||||
if os.path.isdir(waifulib_path):
|
||||
for tool in ctx.tools:
|
||||
if not tool in tools_orig:
|
||||
if os.path.isfile(os.path.join(waifulib_path, tool['tool'] + '.py')):
|
||||
tool['tooldir'] = [waifulib_path]
|
||||
Logs.info('External tooldir set: ' + str(tool))
|
||||
|
||||
|
||||
def process_extra_projects_bld(ctx):
|
||||
projs = ctx.env.EXTRA_PROJECTS
|
||||
if not projs:
|
||||
return
|
||||
for proj in projs.split(','):
|
||||
ctx.add_subproject(proj)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def options(opt):
|
||||
opt.load('reconfigure compiler_optimizations xshlib xcompile compiler_cxx compiler_c sdl2 clang_compilation_database strip_on_install waf_unit_test msdev msvs msvc subproject cmake')
|
||||
|
||||
@@ -154,12 +190,15 @@ def options(opt):
|
||||
|
||||
grp.add_option('--enable-fuzzer', action = 'store_true', dest = 'ENABLE_FUZZER', default = False,
|
||||
help = 'enable building libFuzzer runner [default: %default]' )
|
||||
grp.add_option('--extra-projects', action = 'store', dest = 'EXTRA_PROJECTS', default = '', type = 'string',
|
||||
help = 'add extra projects' )
|
||||
|
||||
for i in SUBDIRS:
|
||||
if not i.is_exists(opt):
|
||||
continue
|
||||
|
||||
opt.add_subproject(i.name)
|
||||
process_extra_projects_opts(opt)
|
||||
|
||||
def configure(conf):
|
||||
conf.load('fwgslib reconfigure compiler_optimizations')
|
||||
@@ -181,7 +220,7 @@ def configure(conf):
|
||||
if conf.env.COMPILER_CC == 'msvc':
|
||||
conf.load('msvc_pdb')
|
||||
|
||||
conf.load('msvs msdev subproject clang_compilation_database strip_on_install waf_unit_test enforce_pic cmake')
|
||||
conf.load('msvs msdev subproject gitversion clang_compilation_database strip_on_install waf_unit_test enforce_pic cmake')
|
||||
|
||||
# Force XP compatibility, all build targets should add subsystem=bld.env.MSVC_SUBSYSTEM
|
||||
if conf.env.MSVC_TARGETS[0] == 'x86':
|
||||
@@ -201,7 +240,8 @@ def configure(conf):
|
||||
conf.options.GL4ES = True
|
||||
conf.options.GLES3COMPAT = True
|
||||
conf.options.GL = False
|
||||
conf.define('XASH_SDLMAIN', 1)
|
||||
if conf.env.HAVE_SDL2:
|
||||
conf.define('XASH_SDLMAIN', 1)
|
||||
elif conf.env.MAGX:
|
||||
conf.options.SDL12 = True
|
||||
conf.options.NO_VGUI = True
|
||||
@@ -493,6 +533,7 @@ int main(void) { return !opus_custom_encoder_init((OpusCustomEncoder *)1, (const
|
||||
continue
|
||||
|
||||
conf.add_subproject(i.name)
|
||||
process_extra_projects_conf(conf)
|
||||
|
||||
def build(bld):
|
||||
# guard rails to not let install to root
|
||||
@@ -515,3 +556,4 @@ def build(bld):
|
||||
if bld.env.TESTS:
|
||||
bld.add_post_fun(waf_unit_test.summary)
|
||||
bld.add_post_fun(waf_unit_test.set_exit_code)
|
||||
process_extra_projects_bld(bld)
|
||||
|
||||
Reference in New Issue
Block a user