mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-07 04:40:43 +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:
|
task:
|
||||||
name: freebsd-13-amd64
|
name: freebsd-13-amd64
|
||||||
freebsd_instance:
|
freebsd_instance:
|
||||||
@@ -13,7 +26,7 @@ task:
|
|||||||
task:
|
task:
|
||||||
name: freebsd-14-amd64
|
name: freebsd-14-amd64
|
||||||
freebsd_instance:
|
freebsd_instance:
|
||||||
image_family: freebsd-14-0
|
image_family: freebsd-14-0-snap
|
||||||
setup_script:
|
setup_script:
|
||||||
- pkg update
|
- pkg update
|
||||||
- pkg install -y pkgconf git sdl2 python fontconfig opus
|
- 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)
|
// video backends (XASH_VIDEO)
|
||||||
#define VIDEO_NULL 0
|
#define VIDEO_NULL 0
|
||||||
#define VIDEO_SDL 1
|
#define VIDEO_SDL 1
|
||||||
|
#define VIDEO_ANDROID 2
|
||||||
#define VIDEO_FBDEV 3
|
#define VIDEO_FBDEV 3
|
||||||
#define VIDEO_DOS 4
|
#define VIDEO_DOS 4
|
||||||
|
|
||||||
// audio backends (XASH_SOUND)
|
// audio backends (XASH_SOUND)
|
||||||
#define SOUND_NULL 0
|
#define SOUND_NULL 0
|
||||||
#define SOUND_SDL 1
|
#define SOUND_SDL 1
|
||||||
|
#define SOUND_OPENSLES 2
|
||||||
#define SOUND_ALSA 3
|
#define SOUND_ALSA 3
|
||||||
|
|
||||||
// input (XASH_INPUT)
|
// input (XASH_INPUT)
|
||||||
#define INPUT_NULL 0
|
#define INPUT_NULL 0
|
||||||
#define INPUT_SDL 1
|
#define INPUT_SDL 1
|
||||||
|
#define INPUT_ANDROID 2
|
||||||
#define INPUT_EVDEV 3
|
#define INPUT_EVDEV 3
|
||||||
|
|
||||||
// timer (XASH_TIMER)
|
// timer (XASH_TIMER)
|
||||||
@@ -41,6 +44,7 @@ GNU General Public License for more details.
|
|||||||
// messageboxes (XASH_MESSAGEBOX)
|
// messageboxes (XASH_MESSAGEBOX)
|
||||||
#define MSGBOX_STDERR 0
|
#define MSGBOX_STDERR 0
|
||||||
#define MSGBOX_SDL 1
|
#define MSGBOX_SDL 1
|
||||||
|
#define MSGBOX_ANDROID 2
|
||||||
#define MSGBOX_WIN32 3
|
#define MSGBOX_WIN32 3
|
||||||
#define MSGBOX_NSWITCH 4
|
#define MSGBOX_NSWITCH 4
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,25 @@ SETUP BACKENDS DEFINITIONS
|
|||||||
#endif
|
#endif
|
||||||
#endif // XASH_MESSAGEBOX
|
#endif // XASH_MESSAGEBOX
|
||||||
#endif
|
#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
|
#elif XASH_LINUX
|
||||||
// we are building for Linux without SDL2, can draw only to framebuffer yet
|
// we are building for Linux without SDL2, can draw only to framebuffer yet
|
||||||
#ifndef XASH_VIDEO
|
#ifndef XASH_VIDEO
|
||||||
@@ -151,8 +170,6 @@ Default build-depended cvar and constant values
|
|||||||
#define DEFAULT_MODE_WIDTH 960
|
#define DEFAULT_MODE_WIDTH 960
|
||||||
#define DEFAULT_MODE_HEIGHT 544
|
#define DEFAULT_MODE_HEIGHT 544
|
||||||
#define DEFAULT_ALLOWCONSOLE 1
|
#define DEFAULT_ALLOWCONSOLE 1
|
||||||
#elif XASH_ANDROID
|
|
||||||
#define DEFAULT_TOUCH_ENABLE "1"
|
|
||||||
#elif XASH_MOBILE_PLATFORM
|
#elif XASH_MOBILE_PLATFORM
|
||||||
#define DEFAULT_TOUCH_ENABLE "1"
|
#define DEFAULT_TOUCH_ENABLE "1"
|
||||||
#define DEFAULT_M_IGNORE "1"
|
#define DEFAULT_M_IGNORE "1"
|
||||||
@@ -164,6 +181,10 @@ Default build-depended cvar and constant values
|
|||||||
#define XASH_INTERNAL_GAMELIBS
|
#define XASH_INTERNAL_GAMELIBS
|
||||||
#endif // XASH_ANDROID || XASH_IOS || XASH_EMSCRIPTEN
|
#endif // XASH_ANDROID || XASH_IOS || XASH_EMSCRIPTEN
|
||||||
|
|
||||||
|
#if XASH_ANDROID && XASH_SDL
|
||||||
|
#define XASH_ANDROID_ASSETS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
// Defaults
|
// Defaults
|
||||||
#ifndef DEFAULT_TOUCH_ENABLE
|
#ifndef DEFAULT_TOUCH_ENABLE
|
||||||
#define DEFAULT_TOUCH_ENABLE "0"
|
#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 )
|
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 );
|
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 )
|
static cvar_t *GAME_EXPORT pfnCvar_RegisterClientVariable( const char *szName, const char *szValue, int flags )
|
||||||
{
|
{
|
||||||
// a1ba: try to mitigate outdated client.dll vulnerabilities
|
// a1ba: try to mitigate outdated client.dll vulnerabilities
|
||||||
if( !Q_stricmp( szName, "motdfile" )
|
if( !Q_stricmp( szName, "motdfile" ))
|
||||||
|| !Q_stricmp( szName, "sensitivity" ))
|
|
||||||
flags |= FCVAR_PRIVILEGED;
|
flags |= FCVAR_PRIVILEGED;
|
||||||
|
|
||||||
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_CLIENTDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_CLIENTDLL ));
|
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 )
|
static void Con_ClearField( field_t *edit )
|
||||||
{
|
{
|
||||||
memset( edit->buffer, 0, sizeof( edit->buffer ));
|
memset( edit->buffer, 0, MAX_STRING );
|
||||||
edit->cursor = 0;
|
edit->cursor = 0;
|
||||||
edit->scroll = 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 )
|
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;
|
field_t *f;
|
||||||
file_t *fd;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
fd = FS_Open( "console_history.txt", "rb", true );
|
if( !aFile )
|
||||||
|
|
||||||
if( !fd )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while( !FS_Eof( fd ))
|
for( pFile = pLine = (char *)aFile; *pFile; pFile++ )
|
||||||
{
|
{
|
||||||
f = &self->lines[self->next % CON_HISTORY];
|
if( *pFile != '\n' )
|
||||||
|
|
||||||
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 )
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// skip repeating lines
|
Con_ClearField( &self->lines[self->next] );
|
||||||
if( self->next > 0 )
|
|
||||||
{
|
len = Q_min( pFile - pLine + 1, sizeof( f->buffer ));
|
||||||
field_t *prev;
|
f = &self->lines[self->next % CON_HISTORY];
|
||||||
prev = &self->lines[(self->next - 1) % CON_HISTORY];
|
f->widthInChars = con.linewidth;
|
||||||
if( !Q_stricmp( prev->buffer, f->buffer ))
|
f->cursor = len - 1;
|
||||||
continue;
|
Q_strncpy( f->buffer, pLine, len);
|
||||||
}
|
|
||||||
|
|
||||||
self->next++;
|
self->next++;
|
||||||
}
|
|
||||||
|
|
||||||
FS_Close( fd );
|
pLine = pFile + 1;
|
||||||
|
}
|
||||||
|
|
||||||
for( i = self->next; i < CON_HISTORY; i++ )
|
for( i = self->next; i < CON_HISTORY; i++ )
|
||||||
{
|
{
|
||||||
f = &self->lines[i];
|
Con_ClearField( &self->lines[i] );
|
||||||
|
self->lines[i].widthInChars = con.linewidth;
|
||||||
Con_ClearField( f );
|
|
||||||
f->widthInChars = con.linewidth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self->line = self->next;
|
self->line = self->next;
|
||||||
@@ -1504,7 +1491,7 @@ static void Con_SaveHistory( con_history_t *self )
|
|||||||
if( historyStart < 0 )
|
if( historyStart < 0 )
|
||||||
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++ )
|
for( i = historyStart; i < self->next; i++ )
|
||||||
FS_Printf( f, "%s\n", self->lines[i % CON_HISTORY].buffer );
|
FS_Printf( f, "%s\n", self->lines[i % CON_HISTORY].buffer );
|
||||||
|
|||||||
@@ -565,7 +565,7 @@ static void R_CollectRendererNames( void )
|
|||||||
"GL4ES",
|
"GL4ES",
|
||||||
#endif
|
#endif
|
||||||
#if XASH_REF_GLES3COMPAT_ENABLED
|
#if XASH_REF_GLES3COMPAT_ENABLED
|
||||||
"GLES3 (gl2_shim)",
|
"GLES3 (gl2_shim)"
|
||||||
#endif
|
#endif
|
||||||
#if XASH_REF_SOFT_ENABLED
|
#if XASH_REF_SOFT_ENABLED
|
||||||
"Software",
|
"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_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( 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( 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_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_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" );
|
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;
|
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 )
|
if( !s_listener.inmenu && soundfade.percent != 0 )
|
||||||
{
|
{
|
||||||
scale = bound( 0.0f, soundfade.percent / 100.0f, 1.0f );
|
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_lerping;
|
||||||
extern convar_t s_test; // cvar to testify new effects
|
extern convar_t s_test; // cvar to testify new effects
|
||||||
extern convar_t s_samplecount;
|
extern convar_t s_samplecount;
|
||||||
|
extern convar_t snd_mute_losefocus;
|
||||||
extern convar_t s_warn_late_precache;
|
extern convar_t s_warn_late_precache;
|
||||||
|
|
||||||
void S_InitScaletable( void );
|
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_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_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_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_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_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" );
|
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
|
Voice_InitOpusDecoder
|
||||||
@@ -67,17 +47,24 @@ Voice_InitOpusDecoder
|
|||||||
*/
|
*/
|
||||||
static qboolean Voice_InitOpusDecoder( void )
|
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] )
|
voice.decoder = opus_custom_decoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
||||||
{
|
if( !voice.decoder )
|
||||||
Con_Printf( S_ERROR "Can't create Opus decoder for %i: %s\n", i, opus_strerror( err ));
|
{
|
||||||
return false;
|
Con_Printf( S_ERROR "Can't create Opus encoder: %s\n", opus_strerror( err ));
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -91,7 +78,7 @@ Voice_InitOpusEncoder
|
|||||||
*/
|
*/
|
||||||
static qboolean Voice_InitOpusEncoder( int quality )
|
static qboolean Voice_InitOpusEncoder( int quality )
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err;
|
||||||
|
|
||||||
voice.encoder = opus_custom_encoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
voice.encoder = opus_custom_encoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
||||||
if( !voice.encoder )
|
if( !voice.encoder )
|
||||||
@@ -130,13 +117,10 @@ Voice_ShutdownOpusDecoder
|
|||||||
*/
|
*/
|
||||||
static void Voice_ShutdownOpusDecoder( void )
|
static void Voice_ShutdownOpusDecoder( void )
|
||||||
{
|
{
|
||||||
for( int i = 0; i < MAX_CLIENTS; i++ )
|
if( voice.decoder )
|
||||||
{
|
{
|
||||||
if( !voice.decoders[i] )
|
opus_custom_decoder_destroy( voice.decoder );
|
||||||
continue;
|
voice.decoder = NULL;
|
||||||
|
|
||||||
opus_custom_decoder_destroy( voice.decoders[i] );
|
|
||||||
voice.decoders[i] = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,10 +137,7 @@ static void Voice_ShutdownOpusEncoder( void )
|
|||||||
opus_custom_encoder_destroy( voice.encoder );
|
opus_custom_encoder_destroy( voice.encoder );
|
||||||
voice.encoder = NULL;
|
voice.encoder = NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void Voice_ShutdownCustomMode( void )
|
|
||||||
{
|
|
||||||
if( voice.custom_mode )
|
if( voice.custom_mode )
|
||||||
{
|
{
|
||||||
opus_custom_mode_destroy( 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 )
|
if( !voice.input_file )
|
||||||
{
|
{
|
||||||
// adjust gain before encoding, but only for input from voice
|
// 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
|
#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;
|
float gain, modifiedMax;
|
||||||
int average, blockOffset = 0;
|
int average, adjustedSample, blockOffset = 0;
|
||||||
|
|
||||||
for( ;; )
|
for( ;; )
|
||||||
{
|
{
|
||||||
@@ -279,8 +260,10 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale )
|
|||||||
localMax = absSample;
|
localMax = absSample;
|
||||||
|
|
||||||
localSum += absSample;
|
localSum += absSample;
|
||||||
|
|
||||||
gain = voice.autogain.current_gain + i * voice.autogain.gain_multiplier;
|
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 )
|
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;
|
average = localSum / blockSize;
|
||||||
modifiedMax = average + ( localMax - average ) * voice_avggain.value;
|
modifiedMax = average + ( localMax - average ) * voice_avggain.value;
|
||||||
|
|
||||||
voice.autogain.current_gain = voice.autogain.next_gain * scale;
|
voice.autogain.current_gain = voice.autogain.next_gain * voice_scale.value;
|
||||||
voice.autogain.next_gain = Q_min( (float)SHRT_MAX / modifiedMax, voice_maxgain.value ) * scale;
|
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 ) / ( blockSize - 1 );
|
voice.autogain.gain_multiplier = ( voice.autogain.next_gain - voice.autogain.current_gain ) / ( voice.autogain.block_size - 1 );
|
||||||
}
|
}
|
||||||
blockOffset += blockSize;
|
blockOffset += blockSize;
|
||||||
}
|
}
|
||||||
@@ -460,7 +443,7 @@ Feed the decoded data to engine sound subsystem
|
|||||||
static void Voice_StartChannel( uint samples, byte *data, int entnum )
|
static void Voice_StartChannel( uint samples, byte *data, int entnum )
|
||||||
{
|
{
|
||||||
SND_ForceInitMouth( 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 )
|
void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames )
|
||||||
{
|
{
|
||||||
const int playernum = ent - 1;
|
|
||||||
int samples = 0;
|
int samples = 0;
|
||||||
int ofs = 0;
|
int ofs = 0;
|
||||||
|
|
||||||
if( playernum < 0 || playernum >= cl.maxclients || !voice.decoders[playernum] )
|
if( !voice.decoder )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// decode frame by frame
|
// 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 )
|
if( ofs + compressed_size > size )
|
||||||
break;
|
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 );
|
(opus_int16*)voice.decompress_buffer + samples, voice.frame_size );
|
||||||
|
|
||||||
ofs += compressed_size;
|
ofs += compressed_size;
|
||||||
@@ -520,8 +502,8 @@ void CL_AddVoiceToDatagram( void )
|
|||||||
|
|
||||||
if( cls.state != ca_active || !Voice_IsRecording() || !voice.encoder )
|
if( cls.state != ca_active || !Voice_IsRecording() || !voice.encoder )
|
||||||
return;
|
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 )
|
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, voice_loopback.value != 0 );
|
||||||
MSG_WriteByte( &cls.datagram, frames );
|
MSG_WriteByte( &cls.datagram, frames );
|
||||||
MSG_WriteShort( &cls.datagram, size );
|
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_enable );
|
||||||
Cvar_RegisterVariable( &voice_loopback );
|
Cvar_RegisterVariable( &voice_loopback );
|
||||||
Cvar_RegisterVariable( &voice_scale );
|
Cvar_RegisterVariable( &voice_scale );
|
||||||
Cvar_RegisterVariable( &voice_transmit_scale );
|
|
||||||
Cvar_RegisterVariable( &voice_avggain );
|
Cvar_RegisterVariable( &voice_avggain );
|
||||||
Cvar_RegisterVariable( &voice_maxgain );
|
Cvar_RegisterVariable( &voice_maxgain );
|
||||||
Cvar_RegisterVariable( &voice_inputfromfile );
|
Cvar_RegisterVariable( &voice_inputfromfile );
|
||||||
@@ -563,9 +544,8 @@ static void Voice_Shutdown( void )
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
Voice_RecordStop();
|
Voice_RecordStop();
|
||||||
Voice_ShutdownOpusDecoder();
|
|
||||||
Voice_ShutdownOpusEncoder();
|
Voice_ShutdownOpusEncoder();
|
||||||
Voice_ShutdownCustomMode();
|
Voice_ShutdownOpusDecoder();
|
||||||
VoiceCapture_Shutdown();
|
VoiceCapture_Shutdown();
|
||||||
|
|
||||||
if( voice.local.talking_ack )
|
if( voice.local.talking_ack )
|
||||||
@@ -629,10 +609,11 @@ qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit )
|
|||||||
|
|
||||||
voice.autogain.block_size = 128;
|
voice.autogain.block_size = 128;
|
||||||
|
|
||||||
if( !Voice_InitCustomMode( ))
|
if( !Voice_InitOpusDecoder( ))
|
||||||
{
|
{
|
||||||
// no reason to init encoder and open audio device
|
// no reason to init encoder and open audio device
|
||||||
// if we can't hear other players
|
// if we can't hear other players
|
||||||
|
Con_Printf( S_ERROR "Voice chat disabled.\n" );
|
||||||
Voice_Shutdown();
|
Voice_Shutdown();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -652,16 +633,6 @@ qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit )
|
|||||||
|
|
||||||
if( !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();
|
voice.device_opened = VoiceCapture_Init();
|
||||||
|
|
||||||
if( !voice.device_opened )
|
if( !voice.device_opened )
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ typedef struct voice_state_s
|
|||||||
// opus stuff
|
// opus stuff
|
||||||
OpusCustomMode *custom_mode;
|
OpusCustomMode *custom_mode;
|
||||||
OpusCustomEncoder *encoder;
|
OpusCustomEncoder *encoder;
|
||||||
OpusCustomDecoder *decoders[MAX_CLIENTS];
|
OpusCustomDecoder *decoder;
|
||||||
|
|
||||||
// audio info
|
// audio info
|
||||||
uint width;
|
uint width;
|
||||||
@@ -71,7 +71,7 @@ typedef struct voice_state_s
|
|||||||
|
|
||||||
// buffers
|
// buffers
|
||||||
byte input_buffer[MAX_RAW_SAMPLES];
|
byte input_buffer[MAX_RAW_SAMPLES];
|
||||||
byte compress_buffer[MAX_RAW_SAMPLES];
|
byte output_buffer[MAX_RAW_SAMPLES];
|
||||||
byte decompress_buffer[MAX_RAW_SAMPLES];
|
byte decompress_buffer[MAX_RAW_SAMPLES];
|
||||||
fs_offset_t input_buffer_pos; // in bytes
|
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 )
|
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;
|
int i;
|
||||||
|
|
||||||
// always allow local commands
|
// 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 DEFAULT_UPDATE_PAGE "https://github.com/FWGS/xash3d-fwgs/releases/latest"
|
||||||
|
|
||||||
#define XASH_ENGINE_NAME "Xash3D FWGS"
|
#define XASH_ENGINE_NAME "Xash3D FWGS"
|
||||||
#define XASH_DEDICATED_SERVER_NAME "XashDS"
|
|
||||||
#define XASH_VERSION "0.20" // engine current version
|
#define XASH_VERSION "0.20" // engine current version
|
||||||
#define XASH_COMPAT_VERSION "0.99" // version we are based on
|
#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;
|
byte *pFinal = NULL;
|
||||||
lzss_state_t state;
|
lzss_state_t state;
|
||||||
|
|
||||||
if( !pStart )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
memset( &state, 0, sizeof( state ));
|
memset( &state, 0, sizeof( state ));
|
||||||
state.window_size = LZSS_WINDOW_SIZE;
|
state.window_size = LZSS_WINDOW_SIZE;
|
||||||
|
|
||||||
|
|||||||
@@ -866,7 +866,7 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
|||||||
return true; // exist
|
return true; // exist
|
||||||
|
|
||||||
// setup mpfilter
|
// 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 );
|
t = FS_Search( "maps/*.bsp", false, onlyingamedir );
|
||||||
|
|
||||||
if( !t )
|
if( !t )
|
||||||
@@ -900,9 +900,9 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
|||||||
|
|
||||||
if( f )
|
if( f )
|
||||||
{
|
{
|
||||||
qboolean have_spawnpoints = false;
|
int num_spawnpoints = 0;
|
||||||
dheader_t *header;
|
dheader_t *header;
|
||||||
dlump_t entities;
|
dlump_t entities;
|
||||||
|
|
||||||
memset( buf, 0, MAX_SYSPATH );
|
memset( buf, 0, MAX_SYSPATH );
|
||||||
FS_Read( f, buf, 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 )
|
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
|
||||||
{
|
{
|
||||||
if( token[0] == '}' && worldspawn )
|
if( token[0] == '}' && worldspawn )
|
||||||
{
|
|
||||||
worldspawn = false;
|
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 )
|
else if( !Q_strcmp( token, "message" ) && worldspawn )
|
||||||
{
|
{
|
||||||
// get the message contents
|
// get the message contents
|
||||||
@@ -963,23 +952,17 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
|||||||
else if( !Q_strcmp( token, "classname" ))
|
else if( !Q_strcmp( token, "classname" ))
|
||||||
{
|
{
|
||||||
pfile = COM_ParseFile( pfile, token, sizeof( token ));
|
pfile = COM_ParseFile( pfile, token, sizeof( token ));
|
||||||
|
if( !Q_strcmp( token, GI->mp_entity ) || use_filter )
|
||||||
if( !Q_strcmp( token, GI->mp_entity ))
|
num_spawnpoints++;
|
||||||
{
|
|
||||||
have_spawnpoints = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if( num_spawnpoints ) break; // valid map
|
||||||
if( have_spawnpoints )
|
|
||||||
break; // valid map
|
|
||||||
}
|
}
|
||||||
Mem_Free( ents );
|
Mem_Free( ents );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( f ) FS_Close( f );
|
if( f ) FS_Close( f );
|
||||||
|
|
||||||
if( have_spawnpoints )
|
if( num_spawnpoints )
|
||||||
{
|
{
|
||||||
// format: mapname "maptitle"\n
|
// format: mapname "maptitle"\n
|
||||||
Q_snprintf( result, sizeof( result ), "%s \"%s\"\n", mapname, message );
|
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() )
|
if ( Host_IsDedicated() )
|
||||||
{
|
{
|
||||||
// g-cont. this is a very strange behavior...
|
// g-cont. this is a very strange behavior...
|
||||||
char *info = SV_Serverinfo();
|
Info_SetValueForKey( SV_Serverinfo(), var->name, value, MAX_SERVERINFO_STRING ),
|
||||||
|
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", SV_Serverinfo( ));
|
||||||
Info_SetValueForKey( info, var->name, value, MAX_SERVERINFO_STRING ),
|
|
||||||
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", info );
|
|
||||||
}
|
}
|
||||||
#if !XASH_DEDICATED
|
#if !XASH_DEDICATED
|
||||||
else
|
else
|
||||||
@@ -955,7 +953,7 @@ static void Cvar_SetGL( const char *name, const char *value )
|
|||||||
|
|
||||||
static qboolean Cvar_ShouldSetCvar( convar_t *v, qboolean isPrivileged )
|
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;
|
int i;
|
||||||
|
|
||||||
if( isPrivileged )
|
if( isPrivileged )
|
||||||
|
|||||||
@@ -92,9 +92,8 @@ static void Sys_PrintUsage( void )
|
|||||||
O("-minidumps ", "enable writing minidumps when game is crashed")
|
O("-minidumps ", "enable writing minidumps when game is crashed")
|
||||||
#endif
|
#endif
|
||||||
O("-rodir <path> ", "set read-only base directory")
|
O("-rodir <path> ", "set read-only base directory")
|
||||||
O("-bugcomp ", "enable precise bug compatibility")
|
O("-bugcomp ", "enable precise bug compatibility. Will break games that don't require it")
|
||||||
O(" ", "will break games that don't require it")
|
O(" ", "Refer to engine documentation for more info")
|
||||||
O(" ", "refer to engine documentation for more info")
|
|
||||||
O("-disablehelp ", "disable this message")
|
O("-disablehelp ", "disable this message")
|
||||||
#if !XASH_DEDICATED
|
#if !XASH_DEDICATED
|
||||||
O("-dedicated ", "run engine in dedicated mode")
|
O("-dedicated ", "run engine in dedicated mode")
|
||||||
@@ -107,8 +106,7 @@ static void Sys_PrintUsage( void )
|
|||||||
O("-noip6 ", "disable IPv6")
|
O("-noip6 ", "disable IPv6")
|
||||||
O("-ip6 <ip> ", "set IPv6 address")
|
O("-ip6 <ip> ", "set IPv6 address")
|
||||||
O("-port6 <port> ", "set IPv6 port")
|
O("-port6 <port> ", "set IPv6 port")
|
||||||
O("-clockwindow <cw>", "adjust clockwindow used to ignore client commands")
|
O("-clockwindow <cw>", "adjust clockwindow used to ignore client commands to prevent speed hacks")
|
||||||
O(" ", "to prevent speed hacks")
|
|
||||||
|
|
||||||
"\nGame options:\n"
|
"\nGame options:\n"
|
||||||
O("-game <directory>", "set game directory to start engine with")
|
O("-game <directory>", "set game directory to start engine with")
|
||||||
@@ -941,7 +939,6 @@ static void Host_RunTests( int stage )
|
|||||||
TEST_LIST_1_CLIENT;
|
TEST_LIST_1_CLIENT;
|
||||||
#endif
|
#endif
|
||||||
Msg( "Done! %d passed, %d failed\n", tests_stats.passed, tests_stats.failed );
|
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();
|
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" );
|
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( "exec", Host_Exec_f, "execute a script file" );
|
||||||
Cmd_AddCommand( "memlist", Host_MemStats_f, "prints memory pool information" );
|
Cmd_AddCommand( "memlist", Host_MemStats_f, "prints memory pool information" );
|
||||||
Cmd_AddRestrictedCommand( "userconfigd", Host_Userconfigd_f, "execute all scripts from userconfig.d" );
|
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;
|
host.status = HOST_FRAME;
|
||||||
|
|
||||||
if( GameState->nextstate == STATE_RUNFRAME )
|
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" );
|
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
|
// execute server.cfg after commandline
|
||||||
// so we have a chance to set servercfgfile
|
// 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, '{' ))
|
if( Q_strrchr( name, '{' ))
|
||||||
{
|
{
|
||||||
// NOTE: decals with 'blue base' can be interpret as colored decals
|
// 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 );
|
SetBits( image.flags, IMAGE_ONEBIT_ALPHA );
|
||||||
rendermode = LUMP_MASKED;
|
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
|
// 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];
|
||||||
// grab the fog color
|
image.fogParams[1] = pal[3*3+1];
|
||||||
image.fogParams[0] = pal[3*3+0];
|
image.fogParams[2] = pal[3*3+2];
|
||||||
image.fogParams[1] = pal[3*3+1];
|
|
||||||
image.fogParams[2] = pal[3*3+2];
|
|
||||||
|
|
||||||
// grab the fog density
|
// grab the fog density
|
||||||
image.fogParams[3] = pal[4*3+0];
|
image.fogParams[3] = pal[4*3+0];
|
||||||
}
|
}
|
||||||
else if( hl_texture && ( rendermode == LUMP_GRADIENT ))
|
else if( hl_texture && ( rendermode == LUMP_GRADIENT ))
|
||||||
{
|
{
|
||||||
// grab the decal color
|
// grab the decal color
|
||||||
image.fogParams[0] = pal[255*3+0];
|
image.fogParams[0] = pal[255*3+0];
|
||||||
image.fogParams[1] = pal[255*3+1];
|
image.fogParams[1] = pal[255*3+1];
|
||||||
image.fogParams[2] = pal[255*3+2];
|
image.fogParams[2] = pal[255*3+2];
|
||||||
|
|
||||||
// calc the decal reflectivity
|
// calc the decal reflectivity
|
||||||
image.fogParams[3] = VectorAvg( image.fogParams );
|
image.fogParams[3] = VectorAvg( image.fogParams );
|
||||||
}
|
}
|
||||||
else
|
else if( pal != NULL )
|
||||||
|
{
|
||||||
|
// calc texture reflectivity
|
||||||
|
for( i = 0; i < 256; i++ )
|
||||||
{
|
{
|
||||||
// calc texture reflectivity
|
reflectivity[0] += pal[i*3+0];
|
||||||
for( i = 0; i < 256; i++ )
|
reflectivity[1] += pal[i*3+1];
|
||||||
{
|
reflectivity[2] += pal[i*3+2];
|
||||||
reflectivity[0] += pal[i*3+0];
|
|
||||||
reflectivity[1] += pal[i*3+1];
|
|
||||||
reflectivity[2] += pal[i*3+2];
|
|
||||||
}
|
|
||||||
|
|
||||||
VectorDivide( reflectivity, 256, image.fogParams );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VectorDivide( reflectivity, 256, image.fogParams );
|
||||||
}
|
}
|
||||||
|
|
||||||
image.type = PF_INDEXED_32; // 32-bit palete
|
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_WriteBytes( &msg, "q\xFF", 2 );
|
||||||
MSG_WriteDword( &msg, m->heartbeat_challenge );
|
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 )
|
if( sv_verbose_heartbeats.value )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -109,6 +109,85 @@ void MSG_InitMasks( void )
|
|||||||
ExtraMasks[maskBit] = (uint)BIT( maskBit ) - 1;
|
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 )
|
void MSG_WriteOneBit( sizebuf_t *sb, int nValue )
|
||||||
{
|
{
|
||||||
if( !MSG_Overflow( sb, 1 ))
|
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 );
|
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];
|
static char string[4096];
|
||||||
int l = 0, c;
|
int l = 0, c;
|
||||||
@@ -616,16 +695,6 @@ static char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
|
|||||||
return string;
|
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 )
|
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove )
|
||||||
{
|
{
|
||||||
int i, endbit = startbit + 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
|
// So PAD_NUMBER(0,4) is 0 and PAD_NUMBER(1,4) is 4
|
||||||
#define PAD_NUMBER( num, boundary ) ((( num ) + (( boundary ) - 1 )) / ( boundary )) * ( boundary )
|
#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;
|
return PAD_NUMBER( bits, 8 ) >> 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sizebuf_s
|
struct sizebuf_s
|
||||||
{
|
{
|
||||||
byte *pData;
|
qboolean bOverflow; // overflow reading or writing
|
||||||
qboolean bOverflow; // overflow reading or writing
|
const char *pDebugName; // buffer name (pointer to const name)
|
||||||
int iCurBit;
|
|
||||||
int nDataBits;
|
byte *pData;
|
||||||
const char *pDebugName; // buffer name (pointer to const name)
|
int iCurBit;
|
||||||
|
int nDataBits;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MSG_StartReading MSG_StartWriting
|
#define MSG_StartReading MSG_StartWriting
|
||||||
#define MSG_GetNumBytesRead MSG_GetNumBytesWritten
|
#define MSG_GetNumBytesRead MSG_GetNumBytesWritten
|
||||||
#define MSG_GetRealBytesRead MSG_GetRealBytesWritten
|
#define MSG_GetRealBytesRead MSG_GetRealBytesWritten
|
||||||
#define MSG_GetNumBitsRead MSG_GetNumBitsWritten
|
#define MSG_GetNumBitsRead MSG_GetNumBitsWritten
|
||||||
#define MSG_ReadBitAngles MSG_ReadBitVec3Coord
|
#define MSG_ReadBitAngles MSG_ReadBitVec3Coord
|
||||||
#define MSG_ReadAngle( sb ) (float)( MSG_ReadChar( sb ) * ( 360.0f / 256.0f ))
|
#define MSG_ReadString( sb ) MSG_ReadStringExt( sb, false )
|
||||||
#define MSG_Init( sb, name, data, bytes ) MSG_InitExt( sb, name, data, bytes, -1 )
|
#define MSG_ReadStringLine( sb ) MSG_ReadStringExt( sb, true )
|
||||||
#define MSG_CheckOverflow( sb ) MSG_Overflow( sb, 0 )
|
#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
|
// common functions
|
||||||
static inline void MSG_Clear( sizebuf_t *sb )
|
void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits );
|
||||||
{
|
void MSG_InitMasks( void ); // called once at startup engine
|
||||||
sb->bOverflow = false;
|
int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence );
|
||||||
sb->iCurBit = 0;
|
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; }
|
||||||
static inline void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nBits )
|
qboolean MSG_CheckOverflow( sizebuf_t *sb );
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if XASH_BIG_ENDIAN
|
#if XASH_BIG_ENDIAN
|
||||||
#define MSG_BigShort( x ) ( x )
|
#define MSG_BigShort( x ) ( x )
|
||||||
@@ -162,15 +73,9 @@ static inline uint16_t MSG_BigShort( const uint16_t x )
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline qboolean MSG_Overflow( sizebuf_t *sb, int nBits )
|
// init writing
|
||||||
{
|
void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits );
|
||||||
if( sb->iCurBit + nBits > sb->nDataBits )
|
void MSG_Clear( sizebuf_t *sb );
|
||||||
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 );
|
|
||||||
|
|
||||||
// Bit-write functions
|
// Bit-write functions
|
||||||
void MSG_WriteOneBit( sizebuf_t *sb, int nValue );
|
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_WriteFloat( sizebuf_t *sb, float val );
|
||||||
void MSG_WriteVec3Coord( sizebuf_t *sb, const float *fa );
|
void MSG_WriteVec3Coord( sizebuf_t *sb, const float *fa );
|
||||||
void MSG_WriteVec3Angles( 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_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_WriteStringf( sizebuf_t *sb, const char *format, ... ) _format( 2 );
|
||||||
qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes );
|
|
||||||
|
|
||||||
// helper functions
|
// 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
|
// Bit-read functions
|
||||||
int MSG_ReadOneBit( sizebuf_t *sb );
|
int MSG_ReadOneBit( sizebuf_t *sb );
|
||||||
@@ -222,8 +136,7 @@ float MSG_ReadCoord( sizebuf_t *sb );
|
|||||||
float MSG_ReadFloat( sizebuf_t *sb );
|
float MSG_ReadFloat( sizebuf_t *sb );
|
||||||
void MSG_ReadVec3Coord( sizebuf_t *sb, vec3_t fa );
|
void MSG_ReadVec3Coord( sizebuf_t *sb, vec3_t fa );
|
||||||
void MSG_ReadVec3Angles( 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 );
|
qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes );
|
||||||
|
char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine );
|
||||||
|
|
||||||
#endif//NET_BUFFER_H
|
#endif//NET_BUFFER_H
|
||||||
|
|||||||
@@ -315,43 +315,6 @@ static const delta_field_t ent_fields[] =
|
|||||||
{ NULL },
|
{ 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
|
enum
|
||||||
{
|
{
|
||||||
DT_EVENT_T = 0,
|
DT_EVENT_T = 0,
|
||||||
@@ -362,10 +325,6 @@ enum
|
|||||||
DT_ENTITY_STATE_T,
|
DT_ENTITY_STATE_T,
|
||||||
DT_ENTITY_STATE_PLAYER_T,
|
DT_ENTITY_STATE_PLAYER_T,
|
||||||
DT_CUSTOM_ENTITY_STATE_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[] =
|
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_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_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 ) },
|
[DT_CUSTOM_ENTITY_STATE_T] = { "custom_entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||||
#if XASH_ENGINE_TESTS
|
{ NULL },
|
||||||
[DT_DELTA_TEST_STRUCT_T] = { "delta_test_struct_t", test_fields, NUM_FIELDS( test_fields ) },
|
|
||||||
#endif
|
|
||||||
[DT_STRUCT_COUNT] = { NULL },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static delta_info_t *Delta_FindStruct( const char *name )
|
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;
|
dt->pFields[i].bInactive = false;
|
||||||
|
|
||||||
if( dt->userCallback )
|
if( dt->userCallback )
|
||||||
|
{
|
||||||
dt->userCallback( dt->pFields, from, to );
|
dt->userCallback( dt->pFields, from, to );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName )
|
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 );
|
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 );
|
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
||||||
toF = Delta_ClampIntegerField( pField, toF, 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 )
|
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 );
|
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 );
|
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
||||||
toF = Delta_ClampIntegerField( pField, toF, 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 )
|
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 );
|
fromF = *(uint32_t *)((int8_t *)from + pField->offset );
|
||||||
toF = *(uint32_t *)((int8_t *)to + 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 );
|
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
||||||
toF = Delta_ClampIntegerField( pField, toF, 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 ))
|
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 )
|
else if( pField->flags & DT_TIMEWINDOW_8 )
|
||||||
{
|
{
|
||||||
val_a = *(float *)((byte *)from + pField->offset );
|
val_a = Q_rint((*(float *)((byte *)from + pField->offset )) * 100.0f );
|
||||||
val_b = *(float *)((byte *)to + pField->offset );
|
val_b = Q_rint((*(float *)((byte *)to + pField->offset )) * 100.0f );
|
||||||
fromF = Q_rint(( timebase - val_a ) * 100.0 );
|
val_a -= Q_rint(timebase * 100.0);
|
||||||
toF = Q_rint(( timebase - val_b ) * 100.0 );
|
val_b -= Q_rint(timebase * 100.0);
|
||||||
|
fromF = FloatAsInt( val_a );
|
||||||
|
toF = FloatAsInt( val_b );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
||||||
{
|
{
|
||||||
val_a = *(float *)((byte *)from + pField->offset );
|
val_a = (*(float *)((byte *)from + pField->offset ));
|
||||||
val_b = *(float *)((byte *)to + 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 );
|
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 )
|
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;
|
int signbit = FBitSet( pField->flags, DT_SIGNED ) ? 1 : 0;
|
||||||
float flValue, flAngle;
|
float flValue, flAngle;
|
||||||
uint iValue;
|
uint iValue;
|
||||||
int dt;
|
|
||||||
const char *pStr;
|
const char *pStr;
|
||||||
|
|
||||||
if( Delta_CompareField( pField, from, to, timebase ))
|
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 );
|
iValue = *(int8_t *)((int8_t *)to + pField->offset );
|
||||||
else
|
else
|
||||||
iValue = *(uint8_t *)((int8_t *)to + pField->offset );
|
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 *= pField->multiplier;
|
||||||
|
|
||||||
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
|
||||||
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_SHORT )
|
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 );
|
iValue = *(int16_t *)((int8_t *)to + pField->offset );
|
||||||
else
|
else
|
||||||
iValue = *(uint16_t *)((int8_t *)to + pField->offset );
|
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 );
|
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 );
|
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_INTEGER )
|
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 );
|
iValue = *(int32_t *)((int8_t *)to + pField->offset );
|
||||||
else
|
else
|
||||||
iValue = *(uint32_t *)((int8_t *)to + pField->offset );
|
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 *= pField->multiplier;
|
||||||
|
|
||||||
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
|
||||||
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_FLOAT )
|
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 )
|
else if( pField->flags & DT_TIMEWINDOW_8 )
|
||||||
{
|
{
|
||||||
|
signbit = 1; // timewindow is always signed
|
||||||
flValue = *(float *)((byte *)to + pField->offset );
|
flValue = *(float *)((byte *)to + pField->offset );
|
||||||
dt = Q_rint(( timebase - flValue ) * 100.0 );
|
iValue = (int)Q_rint( timebase * 100.0 ) - (int)Q_rint( flValue * 100.0 );
|
||||||
dt = Delta_ClampIntegerField( pField, dt, 1, pField->bits );
|
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
||||||
MSG_WriteSBitLong( msg, dt, pField->bits );
|
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
||||||
{
|
{
|
||||||
|
signbit = 1; // timewindow is always signed
|
||||||
flValue = *(float *)((byte *)to + pField->offset );
|
flValue = *(float *)((byte *)to + pField->offset );
|
||||||
dt = Q_rint(( timebase - flValue ) * pField->multiplier );
|
iValue = (int)Q_rint( timebase * pField->multiplier ) - (int)Q_rint( flValue * pField->multiplier );
|
||||||
dt = Delta_ClampIntegerField( pField, dt, 1, pField->bits );
|
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
||||||
MSG_WriteSBitLong( msg, dt, pField->bits );
|
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_STRING )
|
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 )
|
if( pField->flags & DT_BYTE )
|
||||||
{
|
{
|
||||||
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||||
iValue /= pField->multiplier;
|
iValue /= pField->multiplier;
|
||||||
|
|
||||||
if( !Q_equal( pField->post_multiplier, 1.0 ))
|
|
||||||
iValue *= pField->post_multiplier;
|
|
||||||
|
|
||||||
if( bSigned )
|
if( bSigned )
|
||||||
*(int8_t *)((uint8_t *)to + pField->offset ) = iValue;
|
*(int8_t *)((uint8_t *)to + pField->offset ) = iValue;
|
||||||
else
|
else
|
||||||
@@ -1346,12 +1317,9 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
|||||||
else if( pField->flags & DT_SHORT )
|
else if( pField->flags & DT_SHORT )
|
||||||
{
|
{
|
||||||
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||||
iValue /= pField->multiplier;
|
iValue /= pField->multiplier;
|
||||||
|
|
||||||
if( !Q_equal( pField->post_multiplier, 1.0 ))
|
|
||||||
iValue *= pField->post_multiplier;
|
|
||||||
|
|
||||||
if( bSigned )
|
if( bSigned )
|
||||||
*(int16_t *)((uint8_t *)to + pField->offset ) = iValue;
|
*(int16_t *)((uint8_t *)to + pField->offset ) = iValue;
|
||||||
else
|
else
|
||||||
@@ -1360,12 +1328,9 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
|||||||
else if( pField->flags & DT_INTEGER )
|
else if( pField->flags & DT_INTEGER )
|
||||||
{
|
{
|
||||||
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||||
iValue /= pField->multiplier;
|
iValue /= pField->multiplier;
|
||||||
|
|
||||||
if( !Q_equal( pField->post_multiplier, 1.0 ))
|
|
||||||
iValue *= pField->post_multiplier;
|
|
||||||
|
|
||||||
if( bSigned )
|
if( bSigned )
|
||||||
*(int32_t *)((uint8_t *)to + pField->offset ) = iValue;
|
*(int32_t *)((uint8_t *)to + pField->offset ) = iValue;
|
||||||
else
|
else
|
||||||
@@ -1379,11 +1344,11 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
|||||||
else
|
else
|
||||||
flValue = iValue;
|
flValue = iValue;
|
||||||
|
|
||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||||
flValue /= pField->multiplier;
|
flValue = flValue / pField->multiplier;
|
||||||
|
|
||||||
if( !Q_equal( pField->post_multiplier, 1.0 ))
|
if( !Q_equal( pField->post_multiplier, 1.0 ) )
|
||||||
flValue *= pField->post_multiplier;
|
flValue = flValue * pField->post_multiplier;
|
||||||
|
|
||||||
*(float *)((byte *)to + pField->offset ) = flValue;
|
*(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
|
bSigned = true; // timewindow is always signed
|
||||||
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
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;
|
flTime = ( timebase * pField->multiplier - (int)iValue ) / pField->multiplier;
|
||||||
else
|
else
|
||||||
flTime = timebase - (int)iValue;
|
flTime = timebase - (int)iValue;
|
||||||
@@ -2104,103 +2069,3 @@ void GAME_EXPORT Delta_UnsetFieldByIndex( delta_t *pFields, int fieldNumber )
|
|||||||
|
|
||||||
dt->pFields[fieldNumber].bInactive = true;
|
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";
|
mode = "a";
|
||||||
else mode = "w";
|
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
|
// create log if needed
|
||||||
if( s_ld.log_active )
|
if( s_ld.log_active )
|
||||||
{
|
{
|
||||||
@@ -146,18 +142,15 @@ void Sys_InitLog( void )
|
|||||||
|
|
||||||
if ( !s_ld.logfile )
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_ld.logfileno = fileno( s_ld.logfile );
|
s_ld.logfileno = fileno( s_ld.logfile );
|
||||||
|
|
||||||
// fit to 80 columns for easier read on standard terminal
|
fprintf( s_ld.logfile, "=================================================================================\n" );
|
||||||
fputs( "================================================================================\n", s_ld.logfile );
|
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, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
fprintf( s_ld.logfile, "=================================================================================\n" );
|
||||||
fprintf( s_ld.logfile, "Game started at %s\n", Q_timestamp( TIME_FULL ));
|
|
||||||
fputs( "================================================================================\n", s_ld.logfile );
|
|
||||||
fflush( s_ld.logfile );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,11 +177,12 @@ void Sys_CloseLog( void )
|
|||||||
|
|
||||||
if( s_ld.logfile )
|
if( s_ld.logfile )
|
||||||
{
|
{
|
||||||
fputc( '\n', s_ld.logfile );
|
fprintf( s_ld.logfile, "\n");
|
||||||
fputs( "================================================================================\n", s_ld.logfile );
|
fprintf( 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());
|
if( host.change_game ) fprintf( s_ld.logfile, "\n\t%s (build %i) %s\n", s_ld.title, Q_buildnum(), event_name );
|
||||||
fprintf( s_ld.logfile, "Stopped with reason \"%s\" at %s\n", event_name, Q_timestamp( TIME_FULL ));
|
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 ));
|
||||||
fputs( "================================================================================\n", s_ld.logfile );
|
fprintf( s_ld.logfile, "=================================================================================\n");
|
||||||
|
|
||||||
fclose( s_ld.logfile );
|
fclose( s_ld.logfile );
|
||||||
s_ld.logfile = NULL;
|
s_ld.logfile = NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ GNU General Public License for more details.
|
|||||||
#include "library.h"
|
#include "library.h"
|
||||||
#include "whereami.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 );
|
Msg( "Sys_Warn: %s\n", text );
|
||||||
|
|
||||||
if( !Host_IsDedicated() ) // dedicated server should not hang on messagebox
|
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
|
// make sure that console received last message
|
||||||
if( host.change_game ) Sys_Sleep( 200 );
|
if( host.change_game ) Sys_Sleep( 200 );
|
||||||
|
|
||||||
error_on_exit = 1;
|
error_on_exit = true;
|
||||||
host.status = HOST_ERR_FATAL;
|
host.status = HOST_ERR_FATAL;
|
||||||
va_start( argptr, error );
|
va_start( argptr, error );
|
||||||
Q_vsnprintf( text, MAX_PRINT_MSG, error, argptr );
|
Q_vsnprintf( text, MAX_PRINT_MSG, error, argptr );
|
||||||
@@ -449,7 +449,7 @@ void Sys_Error( const char *error, ... )
|
|||||||
Wcon_ShowConsole( false );
|
Wcon_ShowConsole( false );
|
||||||
#endif
|
#endif
|
||||||
Sys_Print( text );
|
Sys_Print( text );
|
||||||
Platform_MessageBox( "Xash Error", text, true );
|
Platform_MessageBox( "Xash Error", text, false );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ NOTE: never change this structure because all dll descriptions in xash code
|
|||||||
writes into struct by offsets not names
|
writes into struct by offsets not names
|
||||||
========================================================================
|
========================================================================
|
||||||
*/
|
*/
|
||||||
extern int error_on_exit;
|
|
||||||
void Sys_Sleep( int msec );
|
void Sys_Sleep( int msec );
|
||||||
double Sys_DoubleTime( void );
|
double Sys_DoubleTime( void );
|
||||||
char *Sys_GetClipboardData( void );
|
char *Sys_GetClipboardData( void );
|
||||||
|
|||||||
@@ -39,15 +39,13 @@ void Test_RunCon( void );
|
|||||||
void Test_RunVOX( void );
|
void Test_RunVOX( void );
|
||||||
void Test_RunIPFilter( void );
|
void Test_RunIPFilter( void );
|
||||||
void Test_RunGamma( void );
|
void Test_RunGamma( void );
|
||||||
void Test_RunDelta( void );
|
|
||||||
|
|
||||||
#define TEST_LIST_0 \
|
#define TEST_LIST_0 \
|
||||||
Test_RunLibCommon(); \
|
Test_RunLibCommon(); \
|
||||||
Test_RunCommon(); \
|
Test_RunCommon(); \
|
||||||
Test_RunCmd(); \
|
Test_RunCmd(); \
|
||||||
Test_RunCvar(); \
|
Test_RunCvar(); \
|
||||||
Test_RunIPFilter(); \
|
Test_RunIPFilter();
|
||||||
Test_RunDelta();
|
|
||||||
|
|
||||||
#define TEST_LIST_0_CLIENT \
|
#define TEST_LIST_0_CLIENT \
|
||||||
Test_RunCon(); \
|
Test_RunCon(); \
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ GNU General Public License for more details.
|
|||||||
*/
|
*/
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
|
|
||||||
#if !defined(XASH_DEDICATED)
|
#if !defined(XASH_DEDICATED) && XASH_SDL
|
||||||
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "client.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
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
#include "build.h"
|
||||||
#if defined __ANDROID__ && !defined XASH_64BIT
|
#if !XASH_64BIT
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
#include "linker.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;
|
Elf_Sym* symtab = si->symtab;
|
||||||
const char* strtab = si->strtab;
|
const char* strtab = si->strtab;
|
||||||
|
|
||||||
if( si->nbucket == 0 )
|
if( si->nbucket == 0 )
|
||||||
return NULL;
|
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;
|
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 */
|
/* 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_GLOBAL:
|
||||||
case STB_WEAK:
|
case STB_WEAK:
|
||||||
if (s->st_shndx == SHN_UNDEF) {
|
if( s->st_shndx == SHN_UNDEF )
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,11 +62,44 @@ static Elf_Sym* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned elfhash(const char* _name) {
|
static Elf_Sym* soinfo_elf_lookup_reverse(soinfo* si, size_t addr)
|
||||||
const unsigned char* name = (const unsigned char*) _name;
|
{
|
||||||
|
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;
|
unsigned h = 0, g;
|
||||||
|
|
||||||
while(*name) {
|
while(*name)
|
||||||
|
{
|
||||||
h = (h << 4) + *name++;
|
h = (h << 4) + *name++;
|
||||||
g = h & 0xf0000000;
|
g = h & 0xf0000000;
|
||||||
h ^= g;
|
h ^= g;
|
||||||
@@ -78,21 +117,73 @@ static unsigned elfhash(const char* _name) {
|
|||||||
Binary Interface) where in Chapter 5 it discuss resolving "Shared
|
Binary Interface) where in Chapter 5 it discuss resolving "Shared
|
||||||
Object Dependencies" in breadth first search order.
|
Object Dependencies" in breadth first search order.
|
||||||
*/
|
*/
|
||||||
static Elf_Sym* dlsym_handle_lookup(soinfo* si, const char* name) {
|
static Elf_Sym* dlsym_handle_lookup( soinfo* si, const char* name )
|
||||||
return soinfo_elf_lookup(si, elfhash(name), 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;
|
soinfo* found = NULL;
|
||||||
Elf_Sym* sym = NULL;
|
Elf_Sym* sym = NULL;
|
||||||
found = reinterpret_cast<soinfo*>(handle);
|
found = reinterpret_cast<soinfo*>( handle );
|
||||||
sym = dlsym_handle_lookup(found, symbol);
|
sym = dlsym_handle_lookup( found, symbol );
|
||||||
|
|
||||||
if (sym != NULL) {
|
if ( sym != NULL ) {
|
||||||
return reinterpret_cast<void*>(sym->st_value + found->base/*load_bias*/);
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#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/lib_android.h"
|
||||||
#include "platform/android/dlsym-weak.h" // Android < 5.0
|
#include "platform/android/dlsym-weak.h" // Android < 5.0
|
||||||
|
|
||||||
|
void *ANDROID_GetServerLibrary( void )
|
||||||
|
{
|
||||||
|
return svgame.hInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void *ANDROID_LoadLibrary( const char *dllname )
|
void *ANDROID_LoadLibrary( const char *dllname )
|
||||||
{
|
{
|
||||||
char path[MAX_SYSPATH];
|
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_LoadLibrary( x ) ANDROID_LoadLibrary(( x ))
|
||||||
#define Platform_POSIX_GetProcAddress( x, y ) ANDROID_GetProcAddress(( x ), ( y ))
|
#define Platform_POSIX_GetProcAddress( x, y ) ANDROID_GetProcAddress(( x ), ( y ))
|
||||||
|
|
||||||
|
void *ANDROID_GetServerLibrary( void );
|
||||||
void *ANDROID_LoadLibrary( const char *dllname );
|
void *ANDROID_LoadLibrary( const char *dllname );
|
||||||
void *ANDROID_GetProcAddress( void *hInstance, const char *name );
|
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 void *g_hsystemd;
|
||||||
static int (*g_pfn_sd_notify)( int unset_environment, const char *state );
|
static int (*g_pfn_sd_notify)( int unset_environment, const char *state );
|
||||||
|
|
||||||
qboolean Platform_DebuggerPresent( void )
|
qboolean Sys_DebuggerPresent( void )
|
||||||
{
|
{
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
ssize_t num_read;
|
ssize_t num_read;
|
||||||
@@ -111,11 +111,6 @@ void Linux_Init( void )
|
|||||||
if( !Host_IsDedicated( ))
|
if( !Host_IsDedicated( ))
|
||||||
return;
|
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 )
|
if(( g_hsystemd = dlopen( "libsystemd.so.0", RTLD_LAZY )) == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ double Platform_DoubleTime( void );
|
|||||||
void Platform_Sleep( int msec );
|
void Platform_Sleep( int msec );
|
||||||
void Platform_ShellExecute( const char *path, const char *parms );
|
void Platform_ShellExecute( const char *path, const char *parms );
|
||||||
void Platform_MessageBox( const char *title, const char *message, qboolean parentMainWindow );
|
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 );
|
void Platform_SetStatus( const char *status );
|
||||||
qboolean Platform_DebuggerPresent( void );
|
|
||||||
|
|
||||||
// legacy iOS port functions
|
// legacy iOS port functions
|
||||||
#if TARGET_OS_IOS
|
#if TARGET_OS_IOS
|
||||||
@@ -139,15 +139,8 @@ static inline void Platform_Shutdown( void )
|
|||||||
|
|
||||||
#if XASH_SDL
|
#if XASH_SDL
|
||||||
SDLash_Shutdown( );
|
SDLash_Shutdown( );
|
||||||
#endif
|
#elif XASH_ANDROID
|
||||||
}
|
Android_Shutdown();
|
||||||
|
|
||||||
static inline qboolean Sys_DebuggerPresent( void )
|
|
||||||
{
|
|
||||||
#if XASH_LINUX || XASH_WIN32
|
|
||||||
return Platform_DebuggerPresent();
|
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -374,8 +374,14 @@ static void SDLash_ActiveEvent( int gain )
|
|||||||
{
|
{
|
||||||
host.status = HOST_FRAME;
|
host.status = HOST_FRAME;
|
||||||
if( cls.key_dest == key_game )
|
if( cls.key_dest == key_game )
|
||||||
|
{
|
||||||
IN_ActivateMouse( );
|
IN_ActivateMouse( );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( dma.initialized && snd_mute_losefocus.value )
|
||||||
|
{
|
||||||
|
SNDDMA_Activate( true );
|
||||||
|
}
|
||||||
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
|
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
|
||||||
if( vid_fullscreen.value == WINDOW_MODE_FULLSCREEN )
|
if( vid_fullscreen.value == WINDOW_MODE_FULLSCREEN )
|
||||||
VID_SetMode();
|
VID_SetMode();
|
||||||
@@ -391,8 +397,14 @@ static void SDLash_ActiveEvent( int gain )
|
|||||||
#endif
|
#endif
|
||||||
host.status = HOST_NOFOCUS;
|
host.status = HOST_NOFOCUS;
|
||||||
if( cls.key_dest == key_game )
|
if( cls.key_dest == key_game )
|
||||||
|
{
|
||||||
IN_DeactivateMouse();
|
IN_DeactivateMouse();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( dma.initialized && snd_mute_losefocus.value )
|
||||||
|
{
|
||||||
|
SNDDMA_Activate( false );
|
||||||
|
}
|
||||||
host.force_draw_version_time = host.realtime + 2.0;
|
host.force_draw_version_time = host.realtime + 2.0;
|
||||||
VID_RestoreScreenResolution();
|
VID_RestoreScreenResolution();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -504,12 +504,12 @@ void Wcon_CreateConsole( void )
|
|||||||
|
|
||||||
if( host.type == HOST_NORMAL )
|
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 ));
|
Q_strncpy( s_wcd.log_path, "engine.log", sizeof( s_wcd.log_path ));
|
||||||
}
|
}
|
||||||
else // dedicated console
|
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 ));
|
Q_strncpy( s_wcd.log_path, "dedicated.log", sizeof( s_wcd.log_path ));
|
||||||
s_wcd.log_active = true; // always make log
|
s_wcd.log_active = true; // always make log
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ void Platform_Sleep( int msec )
|
|||||||
}
|
}
|
||||||
#endif // XASH_TIMER == TIMER_WIN32
|
#endif // XASH_TIMER == TIMER_WIN32
|
||||||
|
|
||||||
qboolean Platform_DebuggerPresent( void )
|
qboolean Sys_DebuggerPresent( void )
|
||||||
{
|
{
|
||||||
return IsDebuggerPresent();
|
return IsDebuggerPresent();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,9 +43,10 @@ extern int SV_UPDATE_BACKUP;
|
|||||||
#define SVF_MERGE_VISIBILITY BIT( 1 ) // we are do portal pass
|
#define SVF_MERGE_VISIBILITY BIT( 1 ) // we are do portal pass
|
||||||
|
|
||||||
// mapvalid flags
|
// mapvalid flags
|
||||||
#define MAP_IS_EXIST BIT( 0 )
|
#define MAP_IS_EXIST BIT( 0 )
|
||||||
#define MAP_HAS_LANDMARK BIT( 2 )
|
#define MAP_HAS_SPAWNPOINT BIT( 1 )
|
||||||
#define MAP_INVALID_VERSION BIT( 3 )
|
#define MAP_HAS_LANDMARK BIT( 2 )
|
||||||
|
#define MAP_INVALID_VERSION BIT( 3 )
|
||||||
|
|
||||||
#define SV_SPAWN_TIME 0.1
|
#define SV_SPAWN_TIME 0.1
|
||||||
|
|
||||||
@@ -612,9 +613,11 @@ string_t SV_MakeString( const char *szValue );
|
|||||||
const char *SV_GetString( string_t iString );
|
const char *SV_GetString( string_t iString );
|
||||||
void SV_SetStringArrayMode( qboolean dynamic );
|
void SV_SetStringArrayMode( qboolean dynamic );
|
||||||
void SV_EmptyStringPool( void );
|
void SV_EmptyStringPool( void );
|
||||||
|
#ifdef XASH_64BIT
|
||||||
void SV_PrintStr64Stats_f( void );
|
void SV_PrintStr64Stats_f( void );
|
||||||
|
#endif
|
||||||
sv_client_t *SV_ClientFromEdict( const edict_t *pEdict, qboolean spawned_only );
|
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 );
|
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 );
|
edict_t *SV_FindGlobalEntity( string_t classname, string_t globalname );
|
||||||
qboolean SV_CreateStaticEntity( struct sizebuf_s *msg, int index );
|
qboolean SV_CreateStaticEntity( struct sizebuf_s *msg, int index );
|
||||||
@@ -625,18 +628,12 @@ void SV_RestartAmbientSounds( void );
|
|||||||
void SV_RestartDecals( void );
|
void SV_RestartDecals( void );
|
||||||
void SV_RestartStaticEnts( void );
|
void SV_RestartStaticEnts( void );
|
||||||
int pfnDropToFloor( edict_t* e );
|
int pfnDropToFloor( edict_t* e );
|
||||||
|
edict_t *SV_EdictNum( int n );
|
||||||
void SV_SetModel( edict_t *ent, const char *name );
|
void SV_SetModel( edict_t *ent, const char *name );
|
||||||
int pfnDecalIndex( const char *m );
|
int pfnDecalIndex( const char *m );
|
||||||
void SV_CreateDecal( sizebuf_t *msg, const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags, float scale );
|
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 );
|
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
|
// sv_log.c
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1690,7 +1690,7 @@ static qboolean SV_New_f( sv_client_t *cl )
|
|||||||
|
|
||||||
// server info string
|
// server info string
|
||||||
MSG_BeginServerCmd( &msg, svc_stufftext );
|
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
|
// collect the info about all the players and send to me
|
||||||
for( i = 0, cur = svs.clients; i < svs.maxclients; i++, cur++ )
|
for( i = 0, cur = svs.clients; i < svs.maxclients; i++, cur++ )
|
||||||
|
|||||||
@@ -169,11 +169,17 @@ SV_ValidateMap
|
|||||||
check map for typically errors
|
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;
|
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 ))
|
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
||||||
{
|
{
|
||||||
@@ -187,6 +193,12 @@ static qboolean SV_ValidateMap( const char *pMapName )
|
|||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +224,7 @@ static void SV_Map_f( void )
|
|||||||
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
|
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
|
||||||
COM_StripExtension( mapname );
|
COM_StripExtension( mapname );
|
||||||
|
|
||||||
if( !SV_ValidateMap( mapname ))
|
if( !SV_ValidateMap( mapname, true ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Cvar_DirectSet( &sv_hostmap, mapname );
|
Cvar_DirectSet( &sv_hostmap, mapname );
|
||||||
@@ -284,7 +296,7 @@ static void SV_MapBackground_f( void )
|
|||||||
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
|
Q_strncpy( mapname, Cmd_Argv( 1 ), sizeof( mapname ));
|
||||||
COM_StripExtension( mapname );
|
COM_StripExtension( mapname );
|
||||||
|
|
||||||
if( !SV_ValidateMap( mapname ))
|
if( !SV_ValidateMap( mapname, false ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// background map is always run as singleplayer
|
// background map is always run as singleplayer
|
||||||
@@ -334,7 +346,7 @@ static void SV_NextMap_f( void )
|
|||||||
Cvar_DirectSet( &sv_hostmap, nextmap );
|
Cvar_DirectSet( &sv_hostmap, nextmap );
|
||||||
|
|
||||||
// found current point, check for valid
|
// found current point, check for valid
|
||||||
if( SV_ValidateMap( nextmap ))
|
if( SV_ValidateMap( nextmap, true ))
|
||||||
{
|
{
|
||||||
// found and valid
|
// found and valid
|
||||||
COM_LoadLevel( nextmap, false );
|
COM_LoadLevel( nextmap, false );
|
||||||
@@ -534,7 +546,7 @@ classic change level
|
|||||||
*/
|
*/
|
||||||
static void SV_ChangeLevel_f( void )
|
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" );
|
Con_Printf( S_USAGE "changelevel <mapname>\n" );
|
||||||
return;
|
return;
|
||||||
@@ -552,15 +564,13 @@ smooth change level
|
|||||||
*/
|
*/
|
||||||
static void SV_ChangeLevel2_f( void )
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( Cmd_Argc() == 2 ) // with single argument, behaves like usual changelevel
|
SV_QueueChangeLevel( Cmd_Argv( 1 ), Cmd_Argv( 2 ));
|
||||||
SV_QueueChangeLevel( Cmd_Argv( 1 ), NULL );
|
|
||||||
else 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 );
|
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( "redirect", Rcon_Redirect_f, "force enable rcon redirection" );
|
||||||
Cmd_AddCommand( "logaddress", SV_SetLogAddress_f, "sets address and port for remote logging host" );
|
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( "log", SV_ServerLog_f, "enables logging to file" );
|
||||||
Cmd_AddCommand( "str64stats", SV_PrintStr64Stats_f, "print engine pool string statistics" );
|
|
||||||
|
|
||||||
if( host.type == HOST_NORMAL )
|
if( host.type == HOST_NORMAL )
|
||||||
{
|
{
|
||||||
@@ -1046,7 +1055,6 @@ void SV_KillOperatorCommands( void )
|
|||||||
Cmd_RemoveCommand( "redirect" );
|
Cmd_RemoveCommand( "redirect" );
|
||||||
Cmd_RemoveCommand( "logaddress" );
|
Cmd_RemoveCommand( "logaddress" );
|
||||||
Cmd_RemoveCommand( "log" );
|
Cmd_RemoveCommand( "log" );
|
||||||
Cmd_RemoveCommand( "str64stats" );
|
|
||||||
|
|
||||||
if( host.type == HOST_NORMAL )
|
if( host.type == HOST_NORMAL )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -811,17 +811,17 @@ static void SV_UpdateToReliableMessages( void )
|
|||||||
continue; // reliables go to all connected or spawned
|
continue; // reliables go to all connected or spawned
|
||||||
|
|
||||||
if( MSG_GetNumBytesWritten( &sv.reliable_datagram ) < MSG_GetNumBytesLeft( &cl->netchan.message ))
|
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 );
|
else Netchan_CreateFragments( &cl->netchan, &sv.reliable_datagram );
|
||||||
|
|
||||||
if( MSG_GetNumBytesWritten( &sv.datagram ) < MSG_GetNumBytesLeft( &cl->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 );
|
else Con_DPrintf( S_WARN "Ignoring unreliable datagram for %s, would overflow\n", cl->name );
|
||||||
|
|
||||||
if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
|
if( FBitSet( cl->flags, FCL_HLTV_PROXY ))
|
||||||
{
|
{
|
||||||
if( MSG_GetNumBytesWritten( &sv.spec_datagram ) < MSG_GetNumBytesLeft( &cl->datagram ))
|
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 );
|
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 (__cdecl *LINK_ENTITY_FUNC)( entvars_t *pev );
|
||||||
typedef void (__stdcall *GIVEFNPTRSTODLL)( enginefuncs_t* engfuncs, globalvars_t *pGlobals );
|
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
|
#ifndef NDEBUG
|
||||||
qboolean SV_CheckEdict( const edict_t *e, const char *file, const int line )
|
qboolean SV_CheckEdict( const edict_t *e, const char *file, const int line )
|
||||||
{
|
{
|
||||||
@@ -143,6 +150,18 @@ char *SV_Serverinfo( void )
|
|||||||
return svs.serverinfo;
|
return svs.serverinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
SV_LocalInfo
|
||||||
|
|
||||||
|
get local infostring
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
static char *SV_Localinfo( void )
|
||||||
|
{
|
||||||
|
return svs.localinfo;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
SV_AngleMod
|
SV_AngleMod
|
||||||
@@ -249,6 +268,7 @@ SV_SetModel
|
|||||||
void GAME_EXPORT SV_SetModel( edict_t *ent, const char *modelname )
|
void GAME_EXPORT SV_SetModel( edict_t *ent, const char *modelname )
|
||||||
{
|
{
|
||||||
char name[MAX_QPATH];
|
char name[MAX_QPATH];
|
||||||
|
qboolean found = false;
|
||||||
model_t *mod;
|
model_t *mod;
|
||||||
int i = 1;
|
int i = 1;
|
||||||
|
|
||||||
@@ -758,6 +778,7 @@ void SV_QueueChangeLevel( const char *level, const char *landname )
|
|||||||
{
|
{
|
||||||
uint flags, smooth = false;
|
uint flags, smooth = false;
|
||||||
char mapname[MAX_QPATH];
|
char mapname[MAX_QPATH];
|
||||||
|
char *spawn_entity;
|
||||||
|
|
||||||
// hold mapname to other place
|
// hold mapname to other place
|
||||||
Q_strncpy( mapname, level, sizeof( mapname ));
|
Q_strncpy( mapname, level, sizeof( mapname ));
|
||||||
@@ -766,7 +787,12 @@ void SV_QueueChangeLevel( const char *level, const char *landname )
|
|||||||
if( COM_CheckString( landname ))
|
if( COM_CheckString( landname ))
|
||||||
smooth = true;
|
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 ))
|
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
||||||
{
|
{
|
||||||
@@ -800,6 +826,15 @@ void SV_QueueChangeLevel( const char *level, const char *landname )
|
|||||||
return;
|
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
|
// bad changelevel position invoke enables in one-way transition
|
||||||
if( sv.framecount < 15 )
|
if( sv.framecount < 15 )
|
||||||
{
|
{
|
||||||
@@ -829,6 +864,7 @@ void SV_WriteEntityPatch( const char *filename )
|
|||||||
int lumpofs = 0, lumplen = 0;
|
int lumpofs = 0, lumplen = 0;
|
||||||
byte buf[MAX_TOKEN]; // 1 kb
|
byte buf[MAX_TOKEN]; // 1 kb
|
||||||
string bspfilename;
|
string bspfilename;
|
||||||
|
dheader_t *header;
|
||||||
dlump_t entities;
|
dlump_t entities;
|
||||||
file_t *f;
|
file_t *f;
|
||||||
|
|
||||||
@@ -839,6 +875,7 @@ void SV_WriteEntityPatch( const char *filename )
|
|||||||
|
|
||||||
memset( buf, 0, MAX_TOKEN );
|
memset( buf, 0, MAX_TOKEN );
|
||||||
FS_Read( f, buf, MAX_TOKEN );
|
FS_Read( f, buf, MAX_TOKEN );
|
||||||
|
header = (dheader_t *)buf;
|
||||||
|
|
||||||
// check all the lumps and some other errors
|
// check all the lumps and some other errors
|
||||||
if( !Mod_TestBmodelLumps( f, bspfilename, buf, true, &entities ))
|
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;
|
int lumpofs = 0, lumplen = 0;
|
||||||
byte buf[MAX_TOKEN];
|
byte buf[MAX_TOKEN];
|
||||||
char *ents = NULL;
|
char *ents = NULL;
|
||||||
|
dheader_t *header;
|
||||||
dlump_t entities;
|
dlump_t entities;
|
||||||
size_t ft1, ft2;
|
size_t ft1, ft2;
|
||||||
file_t *f;
|
file_t *f;
|
||||||
@@ -892,6 +930,7 @@ static char *SV_ReadEntityScript( const char *filename, int *flags )
|
|||||||
SetBits( *flags, MAP_IS_EXIST );
|
SetBits( *flags, MAP_IS_EXIST );
|
||||||
memset( buf, 0, MAX_TOKEN );
|
memset( buf, 0, MAX_TOKEN );
|
||||||
FS_Read( f, buf, MAX_TOKEN );
|
FS_Read( f, buf, MAX_TOKEN );
|
||||||
|
header = (dheader_t *)buf;
|
||||||
|
|
||||||
// check all the lumps and some other errors
|
// check all the lumps and some other errors
|
||||||
if( !Mod_TestBmodelLumps( f, bspfilename, buf, (host_developer.value) ? false : true, &entities ))
|
if( !Mod_TestBmodelLumps( f, bspfilename, buf, (host_developer.value) ? false : true, &entities ))
|
||||||
@@ -938,7 +977,7 @@ SV_MapIsValid
|
|||||||
Validate map
|
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;
|
uint flags = 0;
|
||||||
char *pfile;
|
char *pfile;
|
||||||
@@ -954,27 +993,45 @@ uint SV_MapIsValid( const char *filename, const char *landmark_name )
|
|||||||
|
|
||||||
need_landmark = COM_CheckString( 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 );
|
Mem_Free( ents );
|
||||||
|
|
||||||
return flags;
|
// skip spawnpoint checks in devmode
|
||||||
|
return (flags|MAP_HAS_SPAWNPOINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
pfile = ents;
|
pfile = ents;
|
||||||
|
|
||||||
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
|
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
|
// check targetname for landmark entity
|
||||||
pfile = COM_ParseFile( pfile, check_name, sizeof( check_name ));
|
pfile = COM_ParseFile( pfile, check_name, sizeof( check_name ));
|
||||||
|
|
||||||
if( !Q_strcmp( landmark_name, check_name ))
|
if( !Q_strcmp( landmark_name, check_name ))
|
||||||
{
|
{
|
||||||
// we found landmark, stop the parsing
|
|
||||||
SetBits( flags, MAP_HAS_LANDMARK );
|
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
|
SV_AllocPrivateData
|
||||||
|
|
||||||
allocate private data for a given edict
|
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;
|
const char *pszClassName;
|
||||||
LINK_ENTITY_FUNC SpawnEdict;
|
LINK_ENTITY_FUNC SpawnEdict;
|
||||||
|
|
||||||
pszClassName = STRING( className );
|
pszClassName = STRING( className );
|
||||||
|
|
||||||
if( customentity )
|
|
||||||
*customentity = false;
|
|
||||||
|
|
||||||
if( !ent )
|
if( !ent )
|
||||||
{
|
{
|
||||||
// allocate a new one
|
// 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 )
|
if( svgame.physFuncs.SV_CreateEntity && svgame.physFuncs.SV_CreateEntity( ent, pszClassName ) != -1 )
|
||||||
return ent;
|
return ent;
|
||||||
|
|
||||||
if( customentity )
|
SpawnEdict = SV_GetEntityClass( "custom" );
|
||||||
{
|
|
||||||
SpawnEdict = SV_GetEntityClass( "custom" );
|
|
||||||
*customentity = SpawnEdict != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !SpawnEdict )
|
if( !SpawnEdict )
|
||||||
{
|
{
|
||||||
@@ -1170,6 +1216,8 @@ static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className, qboolean
|
|||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetBits( ent->v.flags, FL_CUSTOMENTITY ); // it's a custom entity but not a beam!
|
||||||
}
|
}
|
||||||
|
|
||||||
SpawnEdict( &ent->v );
|
SpawnEdict( &ent->v );
|
||||||
@@ -1186,7 +1234,12 @@ create specified entity, alloc private data
|
|||||||
*/
|
*/
|
||||||
edict_t* SV_CreateNamedEntity( edict_t *ent, string_t className )
|
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 )
|
static void GAME_EXPORT pfnCvar_RegisterServerVariable( cvar_t *variable )
|
||||||
{
|
{
|
||||||
if( variable != NULL )
|
if( variable != NULL )
|
||||||
{
|
|
||||||
SetBits( variable->flags, FCVAR_EXTDLL );
|
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;
|
char *newString = NULL;
|
||||||
uint len;
|
uint len;
|
||||||
#ifdef XASH_64BIT
|
|
||||||
int cmp;
|
int cmp;
|
||||||
#endif
|
|
||||||
|
|
||||||
if( svgame.physFuncs.pfnAllocString != NULL )
|
if( svgame.physFuncs.pfnAllocString != NULL )
|
||||||
{
|
{
|
||||||
@@ -3232,21 +3281,19 @@ string_t GAME_EXPORT SV_AllocString( const char *szValue )
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef XASH_64BIT
|
||||||
void SV_PrintStr64Stats_f( void )
|
void SV_PrintStr64Stats_f( void )
|
||||||
{
|
{
|
||||||
#ifdef XASH_64BIT
|
Msg( "====================\n" );
|
||||||
Con_Printf( "====================\n" );
|
Msg( "64 bit string pool statistics\n" );
|
||||||
Con_Printf( "64 bit string pool statistics\n" );
|
Msg( "====================\n" );
|
||||||
Con_Printf( "====================\n" );
|
Msg( "string array size: %lu\n", str64.maxstringarray );
|
||||||
Con_Printf( "string array size: %lu\n", str64.maxstringarray );
|
Msg( "total alloc %lu\n", str64.totalalloc );
|
||||||
Con_Printf( "total alloc %lu\n", str64.totalalloc );
|
Msg( "maximum array usage: %lu\n", str64.maxalloc );
|
||||||
Con_Printf( "maximum array usage: %lu\n", str64.maxalloc );
|
Msg( "overflow counter: %lu\n", str64.numoverflows );
|
||||||
Con_Printf( "overflow counter: %lu\n", str64.numoverflows );
|
Msg( "dup string counter: %lu\n", str64.numdups );
|
||||||
Con_Printf( "dup string counter: %lu\n", str64.numdups );
|
|
||||||
#else
|
|
||||||
Con_Printf( "Not implemented\n" );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
@@ -3690,9 +3737,9 @@ vaild map must contain one info_player_deatchmatch
|
|||||||
*/
|
*/
|
||||||
int GAME_EXPORT pfnIsMapValid( char *filename )
|
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 true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -3826,11 +3873,11 @@ static char *GAME_EXPORT pfnGetInfoKeyBuffer( edict_t *e )
|
|||||||
|
|
||||||
// NULL passes localinfo
|
// NULL passes localinfo
|
||||||
if( !SV_IsValidEdict( e ))
|
if( !SV_IsValidEdict( e ))
|
||||||
return svs.localinfo;
|
return SV_Localinfo();
|
||||||
|
|
||||||
// world passes serverinfo
|
// world passes serverinfo
|
||||||
if( e == svgame.edicts )
|
if( e == svgame.edicts )
|
||||||
return svs.serverinfo;
|
return SV_Serverinfo();
|
||||||
|
|
||||||
// userinfo for specified edict
|
// userinfo for specified edict
|
||||||
if(( cl = SV_ClientFromEdict( e, false )) != NULL )
|
if(( cl = SV_ClientFromEdict( e, false )) != NULL )
|
||||||
@@ -4773,15 +4820,6 @@ static enginefuncs_t gEngfuncs =
|
|||||||
pfnPEntityOfEntIndexAllEntities,
|
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
|
SV_ParseEdict
|
||||||
@@ -4793,34 +4831,36 @@ ed should be a properly initialized empty edict.
|
|||||||
static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
|
static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
|
||||||
{
|
{
|
||||||
KeyValueData pkvd[256]; // per one entity
|
KeyValueData pkvd[256]; // per one entity
|
||||||
qboolean adjust_origin = false, customentity;
|
qboolean adjust_origin = false;
|
||||||
int i, numpairs = 0;
|
int i, numpairs = 0;
|
||||||
const char *classname = NULL;
|
char *classname = NULL;
|
||||||
|
char token[2048];
|
||||||
|
vec3_t origin;
|
||||||
|
|
||||||
// go through all the dictionary pairs
|
// go through all the dictionary pairs
|
||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
string keyname;
|
string keyname;
|
||||||
char value[2048];
|
|
||||||
int len;
|
|
||||||
|
|
||||||
// parse key
|
// 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" );
|
Host_Error( "ED_ParseEdict: EOF without closing brace\n" );
|
||||||
|
if( token[0] == '}' ) break; // end of desc
|
||||||
|
|
||||||
if( keyname[0] == '}' )
|
Q_strncpy( keyname, token, sizeof( keyname ));
|
||||||
break; // end of desc
|
|
||||||
|
|
||||||
// parse value
|
// 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" );
|
Host_Error( "ED_ParseEdict: EOF without closing brace\n" );
|
||||||
|
|
||||||
if( value[0] == '}' )
|
if( token[0] == '}' )
|
||||||
Host_Error( "ED_ParseEdict: closing brace without data\n" );
|
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
|
// "wad" field is already handled
|
||||||
if( !keyname[0] || !value[0] || !Q_strcmp( keyname, "wad" ))
|
if( !Q_strcmp( keyname, "wad" ))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// keynames with a leading underscore are used for
|
// 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] == '_' )
|
if( FBitSet( world.flags, FWORLD_SKYSPHERE ) && keyname[0] == '_' )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// classname must be first
|
// ignore attempts to set value ""
|
||||||
if( !Q_strcmp( keyname, "classname" ))
|
if( !token[0] ) continue;
|
||||||
{
|
|
||||||
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';
|
|
||||||
|
|
||||||
// create keyvalue strings
|
// create keyvalue strings
|
||||||
pkvd[numpairs].szClassName = (char*)""; // unknown at this moment
|
pkvd[numpairs].szClassName = (char*)""; // unknown at this moment
|
||||||
pkvd[numpairs].szKeyName = copystring( keyname );
|
pkvd[numpairs].szKeyName = copystring( keyname );
|
||||||
pkvd[numpairs].szValue = copystring( value );
|
pkvd[numpairs].szValue = copystring( token );
|
||||||
pkvd[numpairs].fHandled = false;
|
pkvd[numpairs].fHandled = false;
|
||||||
numpairs++;
|
|
||||||
|
|
||||||
if( numpairs > ARRAYSIZE( pkvd ))
|
if( !Q_strcmp( keyname, "classname" ) && classname == NULL )
|
||||||
{
|
classname = copystring( pkvd[numpairs].szValue );
|
||||||
if( classname )
|
if( ++numpairs >= 256 ) break;
|
||||||
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( classname == NULL )
|
if( classname == NULL )
|
||||||
{
|
{
|
||||||
// release allocated strings
|
// 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;
|
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 ))
|
if( !SV_IsValidEdict( ent ) || FBitSet( ent->v.flags, FL_KILLME ))
|
||||||
{
|
{
|
||||||
// release allocated strings
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( customentity )
|
if( FBitSet( ent->v.flags, FL_CUSTOMENTITY ))
|
||||||
{
|
{
|
||||||
KeyValueData kvd = {
|
if( numpairs < 256 )
|
||||||
.szClassName = (char *)"custom",
|
{
|
||||||
.szKeyName = (char *)"customclass",
|
pkvd[numpairs].szClassName = (char*)"custom";
|
||||||
.szValue = (char *)classname,
|
pkvd[numpairs].szKeyName = (char*)"customclass";
|
||||||
.fHandled = false
|
pkvd[numpairs].szValue = classname;
|
||||||
};
|
pkvd[numpairs].fHandled = false;
|
||||||
|
numpairs++;
|
||||||
|
}
|
||||||
|
|
||||||
svgame.dllFuncs.pfnKeyValue( ent, &kvd );
|
// clear it now - no longer used
|
||||||
// no fHandled check, GoldSrc behavior
|
ClearBits( ent->v.flags, FL_CUSTOMENTITY );
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HACKS_RELATED_HLMODS
|
#ifdef HACKS_RELATED_HLMODS
|
||||||
@@ -4918,14 +4932,6 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
|
|||||||
|
|
||||||
for( i = 0; i < numpairs; i++ )
|
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" ))
|
if( !Q_strcmp( pkvd[i].szKeyName, "angle" ))
|
||||||
{
|
{
|
||||||
float flYawAngle = Q_atof( pkvd[i].szValue );
|
float flYawAngle = Q_atof( pkvd[i].szValue );
|
||||||
@@ -4936,6 +4942,8 @@ static qboolean SV_ParseEdict( char **pfile, edict_t *ent )
|
|||||||
|
|
||||||
if( flYawAngle >= 0.0f )
|
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] );
|
Q_snprintf( temp, sizeof( temp ), "%g %g %g", ent->v.angles[0], flYawAngle, ent->v.angles[2] );
|
||||||
pkvd[i].szValue = copystring( temp );
|
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
|
else pkvd[i].szValue = copystring( "0 0 0" ); // technically an error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HACKS_RELATED_HLMODS
|
||||||
if( adjust_origin && !Q_strcmp( pkvd[i].szKeyName, "origin" ))
|
if( adjust_origin && !Q_strcmp( pkvd[i].szKeyName, "origin" ))
|
||||||
{
|
{
|
||||||
char *pstart = pkvd[i].szValue;
|
char temp[MAX_VA_STRING];
|
||||||
vec3_t origin;
|
char *pstart = pkvd[i].szValue;
|
||||||
|
|
||||||
COM_ParseVector( &pstart, origin, 3 );
|
COM_ParseVector( &pstart, origin, 3 );
|
||||||
Mem_Free( pkvd[i].szValue ); // release old value, so we don't need these
|
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 );
|
Q_snprintf( temp, sizeof( temp ), "%g %g %g", origin[0], origin[1], origin[2] - 16.0f );
|
||||||
pkvd[i].szValue = copystring( temp );
|
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
|
// no reason to keep this data
|
||||||
keyname = pkvd[i].szKeyName;
|
if( Mem_IsAllocatedExt( host.mempool, pkvd[i].szKeyName ))
|
||||||
value = pkvd[i].szValue;
|
Mem_Free( pkvd[i].szKeyName );
|
||||||
|
|
||||||
pkvd[i].szClassName = (char *)classname;
|
if( Mem_IsAllocatedExt( host.mempool, pkvd[i].szValue ))
|
||||||
svgame.dllFuncs.pfnKeyValue( ent, &pkvd[i] );
|
Mem_Free( pkvd[i].szValue );
|
||||||
|
|
||||||
Mem_Free( keyname );
|
|
||||||
Mem_Free( value );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( Mem_IsAllocatedExt( host.mempool, classname ))
|
||||||
|
Mem_Free( classname );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5087,6 +5102,8 @@ void SV_UnloadProgs( void )
|
|||||||
/// SV_UnloadProgs will be disabled
|
/// SV_UnloadProgs will be disabled
|
||||||
//Mod_ClearUserData ();
|
//Mod_ClearUserData ();
|
||||||
|
|
||||||
|
SV_FreeStringPool();
|
||||||
|
|
||||||
if( svgame.dllFuncs2.pfnGameShutdown != NULL )
|
if( svgame.dllFuncs2.pfnGameShutdown != NULL )
|
||||||
svgame.dllFuncs2.pfnGameShutdown ();
|
svgame.dllFuncs2.pfnGameShutdown ();
|
||||||
|
|
||||||
@@ -5107,8 +5124,6 @@ void SV_UnloadProgs( void )
|
|||||||
Cvar_Unlink( FCVAR_EXTDLL );
|
Cvar_Unlink( FCVAR_EXTDLL );
|
||||||
Cmd_Unlink( CMD_SERVERDLL );
|
Cmd_Unlink( CMD_SERVERDLL );
|
||||||
|
|
||||||
SV_FreeStringPool();
|
|
||||||
|
|
||||||
Mod_ResetStudioAPI ();
|
Mod_ResetStudioAPI ();
|
||||||
|
|
||||||
COM_FreeLibrary( svgame.hInstance );
|
COM_FreeLibrary( svgame.hInstance );
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ void Log_Open( void )
|
|||||||
|
|
||||||
if( fp ) svs.log.file = fp;
|
if( fp ) svs.log.file = fp;
|
||||||
Log_Printf( "Log file started (file \"%s\") (game \"%s\") (version \"%i/" XASH_VERSION "/%d\")\n",
|
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 )
|
void Log_Close( void )
|
||||||
|
|||||||
@@ -2110,7 +2110,7 @@ qboolean SV_LoadGame( const char *pPath )
|
|||||||
if( validload )
|
if( validload )
|
||||||
{
|
{
|
||||||
// now check for map problems
|
// 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 ))
|
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
||||||
{
|
{
|
||||||
@@ -2386,7 +2386,7 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment )
|
|||||||
uint flags;
|
uint flags;
|
||||||
|
|
||||||
// now check for map problems
|
// now check for map problems
|
||||||
flags = SV_MapIsValid( mapName, NULL );
|
flags = SV_MapIsValid( mapName, GI->sp_entity, NULL );
|
||||||
|
|
||||||
if( FBitSet( flags, MAP_INVALID_VERSION ))
|
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,
|
grp.add_option('--enable-engine-fuzz', action = 'store_true', dest = 'ENGINE_FUZZ', default = False,
|
||||||
help = 'add LLVM libFuzzer [default: %default]' )
|
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')
|
opt.load('sdl2')
|
||||||
|
|
||||||
def configure(conf):
|
def configure(conf):
|
||||||
@@ -75,6 +78,8 @@ def configure(conf):
|
|||||||
conf.define('XASH_SDL', 12)
|
conf.define('XASH_SDL', 12)
|
||||||
conf.check_cfg(package='sdl', args='--cflags --libs', uselib_store='SDL2' )
|
conf.check_cfg(package='sdl', args='--cflags --libs', uselib_store='SDL2' )
|
||||||
conf.env.HAVE_SDL2 = True
|
conf.env.HAVE_SDL2 = True
|
||||||
|
elif conf.options.ANDROID_LEGACY:
|
||||||
|
pass #just test if it can build
|
||||||
else:
|
else:
|
||||||
conf.load('sdl2')
|
conf.load('sdl2')
|
||||||
if not conf.env.HAVE_SDL2:
|
if not conf.env.HAVE_SDL2:
|
||||||
|
|||||||
@@ -320,12 +320,6 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
state = new CSearchState( &searchHead, search );
|
state = new CSearchState( &searchHead, search );
|
||||||
if( !state )
|
|
||||||
{
|
|
||||||
Mem_Free( search );
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
*handle = state->handle;
|
*handle = state->handle;
|
||||||
return state->search->filenames[0];
|
return state->search->filenames[0];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ GNU General Public License for more details.
|
|||||||
|
|
||||||
#include "port.h"
|
#include "port.h"
|
||||||
|
|
||||||
#if XASH_ANDROID
|
#if XASH_ANDROID_ASSETS
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
@@ -276,9 +276,6 @@ searchpath_t *FS_AddAndroidAssets_Fullpath( const char *path, int flags )
|
|||||||
android_assets_t *assets = NULL;
|
android_assets_t *assets = NULL;
|
||||||
qboolean engine = true;
|
qboolean engine = true;
|
||||||
|
|
||||||
if( !jni.getPackageName || !jni.getCallingPackage || !jni.getAssetsList || !jni.getAssets )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if( FBitSet( flags, FS_STATIC_PATH | FS_CUSTOM_PATH ))
|
if( FBitSet( flags, FS_STATIC_PATH | FS_CUSTOM_PATH ))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -289,7 +286,7 @@ searchpath_t *FS_AddAndroidAssets_Fullpath( const char *path, int flags )
|
|||||||
|
|
||||||
if( !assets )
|
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;
|
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.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.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;" );
|
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 =
|
static const fs_archive_t g_directory_archive =
|
||||||
{ NULL, SEARCHPATH_PLAIN, FS_AddDir_Fullpath, false };
|
{ NULL, SEARCHPATH_PLAIN, FS_AddDir_Fullpath, false };
|
||||||
|
|
||||||
#if XASH_ANDROID
|
#if XASH_ANDROID_ASSETS
|
||||||
static const fs_archive_t g_android_archive =
|
static const fs_archive_t g_android_archive =
|
||||||
{ NULL, SEARCHPATH_ANDROID_ASSETS, FS_AddAndroidAssets_Fullpath, false };
|
{ NULL, SEARCHPATH_ANDROID_ASSETS, FS_AddAndroidAssets_Fullpath, false };
|
||||||
#endif
|
#endif
|
||||||
@@ -406,7 +406,7 @@ void FS_AddGameDirectory( const char *dir, uint flags )
|
|||||||
|
|
||||||
stringlistfreecontents( &list );
|
stringlistfreecontents( &list );
|
||||||
|
|
||||||
#if XASH_ANDROID
|
#if XASH_ANDROID_ASSETS
|
||||||
FS_AddArchive_Fullpath( &g_android_archive, dir, flags );
|
FS_AddArchive_Fullpath( &g_android_archive, dir, flags );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1461,7 +1461,7 @@ qboolean FS_InitStdio( qboolean unused_set_to_true, const char *rootdir, const c
|
|||||||
|
|
||||||
FS_InitMemory();
|
FS_InitMemory();
|
||||||
|
|
||||||
#if XASH_ANDROID
|
#if XASH_ANDROID_ASSETS
|
||||||
FS_InitAndroid();
|
FS_InitAndroid();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -358,7 +358,7 @@ searchpath_t *FS_AddPak_Fullpath( const char *pakfile, int flags )
|
|||||||
search->pfnFindFile = FS_FindFile_PAK;
|
search->pfnFindFile = FS_FindFile_PAK;
|
||||||
search->pfnSearch = FS_Search_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;
|
return search;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -670,6 +670,6 @@ searchpath_t *FS_AddWad_Fullpath( const char *wadfile, int flags )
|
|||||||
search->pfnSearch = FS_Search_WAD;
|
search->pfnSearch = FS_Search_WAD;
|
||||||
search->pfnLoadFile = W_ReadLump;
|
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;
|
return search;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -701,7 +701,7 @@ searchpath_t *FS_AddZip_Fullpath( const char *zipfile, int flags )
|
|||||||
search->pfnSearch = FS_Search_ZIP;
|
search->pfnSearch = FS_Search_ZIP;
|
||||||
search->pfnLoadFile = FS_LoadZIPFile;
|
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;
|
return search;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -237,25 +237,19 @@ const char *Q_buildarch( void )
|
|||||||
=============
|
=============
|
||||||
Q_buildcommit
|
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
|
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 )
|
const char *Q_buildcommit( void )
|
||||||
{
|
{
|
||||||
|
#ifdef XASH_BUILD_COMMIT
|
||||||
return XASH_BUILD_COMMIT;
|
return XASH_BUILD_COMMIT;
|
||||||
}
|
#else
|
||||||
|
return "notset";
|
||||||
/*
|
#endif
|
||||||
=============
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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_ArchitectureStringByID( const int arch, const uint abi, const int endianness, const qboolean is64 );
|
||||||
const char *Q_buildarch( void );
|
const char *Q_buildarch( void );
|
||||||
const char *Q_buildcommit( void );
|
const char *Q_buildcommit( void );
|
||||||
const char *Q_buildbranch( void );
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// crtlib.c
|
// 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
|
return
|
||||||
|
|
||||||
def configure(conf):
|
def configure(conf):
|
||||||
conf.load('gitversion')
|
conf.define('XASH_BUILD_COMMIT', conf.env.GIT_VERSION if conf.env.GIT_VERSION else 'notset')
|
||||||
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')
|
|
||||||
|
|
||||||
def build(bld):
|
def build(bld):
|
||||||
bld(name = 'sdk_includes', export_includes = '. ../common ../pm_shared ../engine')
|
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_min( a, b ) (((a) < (b)) ? (a) : (b))
|
||||||
#define Q_max( 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 ) (((a) > ((b) - EQUAL_EPSILON)) && ((a) < ((b) + EQUAL_EPSILON)))
|
||||||
#define Q_equal( a, b ) Q_equal_e( a, b, EQUAL_EPSILON )
|
|
||||||
#define Q_recip( a ) ((float)(1.0f / (float)(a)))
|
#define Q_recip( a ) ((float)(1.0f / (float)(a)))
|
||||||
#define Q_floor( a ) ((float)(int)(a))
|
#define Q_floor( a ) ((float)(int)(a))
|
||||||
#define Q_ceil( a ) ((float)(int)((a) + 1))
|
#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
|
// a pose is a single set of vertexes. a frame may be
|
||||||
// an animating sequence of poses
|
// 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
|
// the command list holds counts and s/t values that are valid for
|
||||||
// every frame
|
// every frame
|
||||||
|
|||||||
@@ -1471,22 +1471,6 @@ static void GL_DeleteTexture( gl_texture_t *tex )
|
|||||||
prev = &cur->nextHash;
|
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
|
// release source
|
||||||
if( tex->original )
|
if( tex->original )
|
||||||
gEngfuncs.FS_FreeImage( 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++ )
|
for( func = funcs; func && func->name; func++ )
|
||||||
{
|
{
|
||||||
// functions are cleared before all the extensions are evaluated
|
// functions are cleared before all the extensions are evaluated
|
||||||
if(( *func->func = (void *)gEngfuncs.GL_GetProcAddress( func->name )) == NULL )
|
string name;
|
||||||
{
|
char *end;
|
||||||
string name;
|
size_t i = 0;
|
||||||
char *end;
|
qboolean first_try = true;
|
||||||
size_t i = 0;
|
// NULL means just func->name, but empty suffix cuts ARB suffix if present
|
||||||
#ifdef XASH_GLES
|
#ifdef XASH_GLES
|
||||||
const char *suffixes[] = { "", "EXT", "OES" };
|
const char *suffixes[] = { "", "EXT", "OES", NULL, "ARB" };
|
||||||
#else
|
#else
|
||||||
const char *suffixes[] = { "", "EXT" };
|
const char *suffixes[] = { NULL, "", "EXT", "ARB" };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// HACK: fix ARB names
|
// Remove ARB suffix
|
||||||
Q_strncpy( name, func->name, sizeof( name ));
|
Q_strncpy( name, func->name, sizeof( name ));
|
||||||
if(( end = Q_strstr( name, "ARB" )))
|
if(( end = Q_strstr( name, "ARB" )))
|
||||||
{
|
{
|
||||||
*end = '\0';
|
*end = '\0';
|
||||||
}
|
}
|
||||||
else // I need Q_strstrnul
|
else // I need Q_strstrnul
|
||||||
{
|
{
|
||||||
end = name + Q_strlen( name );
|
end = name + Q_strlen( name );
|
||||||
i++; // skip empty suffix
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for( ; i < sizeof( suffixes ) / sizeof( suffixes[0] ); i++ )
|
for( ; i < sizeof( suffixes ) / sizeof( suffixes[0] ); i++ )
|
||||||
{
|
{
|
||||||
void *f;
|
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 ));
|
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
// not found...
|
|
||||||
if( i == sizeof( suffixes ) / sizeof( suffixes[0] ))
|
|
||||||
{
|
{
|
||||||
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
|
#endif
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ static void R_SimpleStubBool( qboolean )
|
|||||||
|
|
||||||
static qboolean R_Init( void )
|
static qboolean R_Init( void )
|
||||||
{
|
{
|
||||||
gEngfuncs.R_Init_Video( REF_SOFTWARE );
|
|
||||||
return true;
|
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 )
|
static void R_GetSpriteParms( int *frameWidth, int *frameHeight, int *numFrames, int currentFrame, const model_t *pSprite )
|
||||||
{
|
{
|
||||||
if( frameWidth )
|
*frameWidth = *frameHeight = *numFrames = 0;
|
||||||
*frameWidth = 0;
|
|
||||||
|
|
||||||
if( frameHeight )
|
|
||||||
*frameHeight = 0;
|
|
||||||
|
|
||||||
if( numFrames )
|
|
||||||
*numFrames = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int R_GetSpriteTexture( const model_t *m_pSpriteModel, int frame )
|
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 )
|
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 )
|
static void Mod_StudioLoadTextures( model_t *mod, void *data )
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ class Android:
|
|||||||
ndk_rev = 0
|
ndk_rev = 0
|
||||||
is_hardfloat = False
|
is_hardfloat = False
|
||||||
clang = False
|
clang = False
|
||||||
|
ndk_binutils = False
|
||||||
|
|
||||||
def __init__(self, ctx, arch, toolchain, api):
|
def __init__(self, ctx, arch, toolchain, api):
|
||||||
self.ctx = ctx
|
self.ctx = ctx
|
||||||
@@ -214,7 +215,7 @@ class Android:
|
|||||||
if 'CC' in environ:
|
if 'CC' in environ:
|
||||||
s = environ['CC']
|
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')
|
return self.gen_toolchain_path() + ('clang' if self.is_clang() else 'gcc')
|
||||||
|
|
||||||
def cxx(self):
|
def cxx(self):
|
||||||
@@ -225,11 +226,11 @@ class Android:
|
|||||||
if 'CXX' in environ:
|
if 'CXX' in environ:
|
||||||
s = environ['CXX']
|
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++')
|
return self.gen_toolchain_path() + ('clang++' if self.is_clang() else 'g++')
|
||||||
|
|
||||||
def strip(self):
|
def strip(self):
|
||||||
if self.is_host():
|
if self.is_host() and not self.ndk_binutils:
|
||||||
environ = getattr(self.ctx, 'environ', os.environ)
|
environ = getattr(self.ctx, 'environ', os.environ)
|
||||||
|
|
||||||
if 'STRIP' in 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(), 'llvm-strip')
|
||||||
return os.path.join(self.gen_binutils_path(), '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):
|
def system_stl(self):
|
||||||
# TODO: proper STL support
|
# 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):
|
def libsysroot(self):
|
||||||
arch = self.arch
|
arch = self.arch
|
||||||
@@ -262,8 +276,15 @@ class Android:
|
|||||||
|
|
||||||
def cflags(self, cxx = False):
|
def cflags(self, cxx = False):
|
||||||
cflags = []
|
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())]
|
cflags += ['--sysroot=%s' % (self.sysroot())]
|
||||||
else:
|
else:
|
||||||
if self.is_host():
|
if self.is_host():
|
||||||
@@ -273,13 +294,18 @@ class Android:
|
|||||||
]
|
]
|
||||||
|
|
||||||
cflags += ['-I%s' % (self.system_stl())]
|
cflags += ['-I%s' % (self.system_stl())]
|
||||||
if not self.is_clang():
|
if not self.is_clang() or android_from_none:
|
||||||
cflags += ['-DANDROID', '-D__ANDROID__']
|
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']:
|
if cxx and not self.is_clang() and self.toolchain not in ['4.8','4.9']:
|
||||||
cflags += ['-fno-sized-deallocation']
|
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
|
# stpcpy() isn't available in early Android versions
|
||||||
# disable it here so Clang won't use it
|
# disable it here so Clang won't use it
|
||||||
if self.api < ANDROID_STPCPY_API_MIN:
|
if self.api < ANDROID_STPCPY_API_MIN:
|
||||||
@@ -291,7 +317,7 @@ class Android:
|
|||||||
cflags += ['-mthumb', '-mfpu=neon', '-mcpu=cortex-a9']
|
cflags += ['-mthumb', '-mfpu=neon', '-mcpu=cortex-a9']
|
||||||
|
|
||||||
if self.is_hardfp():
|
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():
|
if self.is_host():
|
||||||
# Clang builtin redefine w/ different calling convention bug
|
# Clang builtin redefine w/ different calling convention bug
|
||||||
@@ -316,15 +342,23 @@ class Android:
|
|||||||
linkflags = []
|
linkflags = []
|
||||||
if self.is_host():
|
if self.is_host():
|
||||||
linkflags += ['--gcc-toolchain=%s' % self.gen_gcc_toolchain_path()]
|
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:
|
if self.ndk_rev <= ANDROID_NDK_SYSROOT_FLAG_MAX:
|
||||||
linkflags += ['--sysroot=%s' % (self.sysroot())]
|
linkflags += ['--sysroot=%s' % (self.sysroot())]
|
||||||
elif self.is_host():
|
elif self.is_host():
|
||||||
linkflags += ['--sysroot=%s/sysroot' % (self.gen_gcc_toolchain_path())]
|
linkflags += ['--sysroot=%s/sysroot' % (self.gen_gcc_toolchain_path())]
|
||||||
|
|
||||||
if self.is_clang() or self.is_host():
|
#if self.is_clang() or self.is_host():
|
||||||
linkflags += ['-fuse-ld=lld']
|
# linkflags += ['-fuse-ld=lld']
|
||||||
else: linkflags += ['-no-canonical-prefixes']
|
#else:
|
||||||
|
linkflags += ['-no-canonical-prefixes']
|
||||||
|
|
||||||
linkflags += ['-Wl,--hash-style=sysv', '-Wl,--no-undefined']
|
linkflags += ['-Wl,--hash-style=sysv', '-Wl,--no-undefined']
|
||||||
return linkflags
|
return linkflags
|
||||||
@@ -528,6 +562,7 @@ def configure(conf):
|
|||||||
conf.environ['CC'] = android.cc()
|
conf.environ['CC'] = android.cc()
|
||||||
conf.environ['CXX'] = android.cxx()
|
conf.environ['CXX'] = android.cxx()
|
||||||
conf.environ['STRIP'] = android.strip()
|
conf.environ['STRIP'] = android.strip()
|
||||||
|
conf.environ['OBJCOPY'] = android.objcopy()
|
||||||
conf.env.CFLAGS += android.cflags()
|
conf.env.CFLAGS += android.cflags()
|
||||||
conf.env.CXXFLAGS += android.cflags(True)
|
conf.env.CXXFLAGS += android.cflags(True)
|
||||||
conf.env.LINKFLAGS += android.linkflags()
|
conf.env.LINKFLAGS += android.linkflags()
|
||||||
|
|||||||
@@ -44,16 +44,16 @@ def create_zip_archive(self):
|
|||||||
self.path.get_bld().mkdir()
|
self.path.get_bld().mkdir()
|
||||||
target = self.path.get_bld().make_node(self.name)
|
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(self.zip_task, 'compresslevel', compresslevel)
|
||||||
setattr(tsk, 'relative_to', relative_to)
|
setattr(self.zip_task, 'relative_to', relative_to)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
inst_to = self.install_path
|
inst_to = self.install_path
|
||||||
self.install_task = self.add_install_files(
|
self.install_task = self.add_install_files(
|
||||||
install_to=inst_to, install_from=target,
|
install_to=inst_to, install_from=target,
|
||||||
chmod=Utils.O644, task=tsk)
|
chmod=Utils.O644, task=self.zip_task)
|
||||||
|
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -601,12 +601,6 @@ void WriteQCScript( void )
|
|||||||
fputs( "$scale 1.0\n", fp );
|
fputs( "$scale 1.0\n", fp );
|
||||||
fputs( "\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 );
|
WriteBodyGroupInfo( fp );
|
||||||
|
|
||||||
fprintf( fp, "$flags %u\n\n", model_hdr->flags &~( STUDIO_HAS_BONEINFO | STUDIO_HAS_BONEWEIGHTS ) );
|
fprintf( fp, "$flags %u\n\n", model_hdr->flags &~( STUDIO_HAS_BONEINFO | STUDIO_HAS_BONEWEIGHTS ) );
|
||||||
@@ -617,6 +611,10 @@ void WriteQCScript( void )
|
|||||||
|
|
||||||
WriteSkinFamilyInfo( fp );
|
WriteSkinFamilyInfo( fp );
|
||||||
WriteTextureRenderMode( fp );
|
WriteTextureRenderMode( fp );
|
||||||
|
|
||||||
|
if( model_hdr->flags & ( STUDIO_HAS_BONEINFO | STUDIO_HAS_BONEWEIGHTS ) )
|
||||||
|
fputs( "$boneweights\n\n", fp );
|
||||||
|
|
||||||
WriteAttachmentInfo( fp );
|
WriteAttachmentInfo( fp );
|
||||||
|
|
||||||
fprintf( fp, "$bbox %f %f %f", model_hdr->min[0], model_hdr->min[1], model_hdr->min[2] );
|
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
|
# encoding: utf-8
|
||||||
# a1batross, mittorn, 2018
|
# a1batross, mittorn, 2018
|
||||||
|
|
||||||
from waflib import Build, Context, Logs
|
from waflib import Build, Context, Logs, Options, Configure
|
||||||
from waflib.Tools import waf_unit_test
|
from waflib.Tools import waf_unit_test
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
@@ -69,7 +69,7 @@ SUBDIRS = [
|
|||||||
Subproject('dllemu'),
|
Subproject('dllemu'),
|
||||||
|
|
||||||
# disable only by engine feature, makes no sense to even parse subprojects in dedicated mode
|
# 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/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/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),
|
Subproject('3rdparty/gl4es', lambda x: not x.env.DEDICATED and x.env.GL4ES),
|
||||||
@@ -104,6 +104,42 @@ REFDLLS = [
|
|||||||
RefDll('null', False),
|
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):
|
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')
|
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,
|
grp.add_option('--enable-fuzzer', action = 'store_true', dest = 'ENABLE_FUZZER', default = False,
|
||||||
help = 'enable building libFuzzer runner [default: %default]' )
|
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:
|
for i in SUBDIRS:
|
||||||
if not i.is_exists(opt):
|
if not i.is_exists(opt):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
opt.add_subproject(i.name)
|
opt.add_subproject(i.name)
|
||||||
|
process_extra_projects_opts(opt)
|
||||||
|
|
||||||
def configure(conf):
|
def configure(conf):
|
||||||
conf.load('fwgslib reconfigure compiler_optimizations')
|
conf.load('fwgslib reconfigure compiler_optimizations')
|
||||||
@@ -181,7 +220,7 @@ def configure(conf):
|
|||||||
if conf.env.COMPILER_CC == 'msvc':
|
if conf.env.COMPILER_CC == 'msvc':
|
||||||
conf.load('msvc_pdb')
|
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
|
# Force XP compatibility, all build targets should add subsystem=bld.env.MSVC_SUBSYSTEM
|
||||||
if conf.env.MSVC_TARGETS[0] == 'x86':
|
if conf.env.MSVC_TARGETS[0] == 'x86':
|
||||||
@@ -201,7 +240,8 @@ def configure(conf):
|
|||||||
conf.options.GL4ES = True
|
conf.options.GL4ES = True
|
||||||
conf.options.GLES3COMPAT = True
|
conf.options.GLES3COMPAT = True
|
||||||
conf.options.GL = False
|
conf.options.GL = False
|
||||||
conf.define('XASH_SDLMAIN', 1)
|
if conf.env.HAVE_SDL2:
|
||||||
|
conf.define('XASH_SDLMAIN', 1)
|
||||||
elif conf.env.MAGX:
|
elif conf.env.MAGX:
|
||||||
conf.options.SDL12 = True
|
conf.options.SDL12 = True
|
||||||
conf.options.NO_VGUI = True
|
conf.options.NO_VGUI = True
|
||||||
@@ -493,6 +533,7 @@ int main(void) { return !opus_custom_encoder_init((OpusCustomEncoder *)1, (const
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
conf.add_subproject(i.name)
|
conf.add_subproject(i.name)
|
||||||
|
process_extra_projects_conf(conf)
|
||||||
|
|
||||||
def build(bld):
|
def build(bld):
|
||||||
# guard rails to not let install to root
|
# guard rails to not let install to root
|
||||||
@@ -515,3 +556,4 @@ def build(bld):
|
|||||||
if bld.env.TESTS:
|
if bld.env.TESTS:
|
||||||
bld.add_post_fun(waf_unit_test.summary)
|
bld.add_post_fun(waf_unit_test.summary)
|
||||||
bld.add_post_fun(waf_unit_test.set_exit_code)
|
bld.add_post_fun(waf_unit_test.set_exit_code)
|
||||||
|
process_extra_projects_bld(bld)
|
||||||
|
|||||||
Reference in New Issue
Block a user