mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-06 04:05:11 +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,15 +1,17 @@
|
|||||||
# Bug-compatibility in Xash3D FWGS
|
# Bug-compatibility in Xash3D FWGS
|
||||||
|
|
||||||
Xash3D FWGS has special mode for games that rely on original engine bugs. In this mode, we emulate the behaviour of selected functions that may help running mods relying on engine bugs, but enabling them by default may break majority of other games.
|
Xash3D FWGS has special mode for games that rely on original engine bugs.
|
||||||
|
|
||||||
|
In this mode, we emulate the behaviour of selected functions that may help running mods relying on engine bugs, but enabling them by default may break majority of other games.
|
||||||
|
|
||||||
At this time, we only have implemented GoldSrc bug-compatibility. It can be enabled with `-bugcomp` command line switch.
|
At this time, we only have implemented GoldSrc bug-compatibility. It can be enabled with `-bugcomp` command line switch.
|
||||||
|
|
||||||
When `-bugcomp` is specified without argument, it enables everything. This behavior might be changed or removed in future versions.
|
|
||||||
|
|
||||||
When `-bugcomp` is specified with argument, it interpreted as flags separated with `+`. This way it's possible to combine multiple levels of bug-compatibility.
|
|
||||||
|
|
||||||
## GoldSrc bug-compatibility
|
## GoldSrc bug-compatibility
|
||||||
|
|
||||||
| Flag | Description | Games that require this flag |
|
### Emulated bugs
|
||||||
| ------- | ----------- | ---------------------------- |
|
|
||||||
| `peoei` | Reverts `pfnPEntityOfEntIndex` behavior to GoldSrc, where it returns NULL for last player due to incorrect player index comparison | * Counter-Strike: Condition Zero - Deleted Scenes |
|
* `pfnPEntityOfEntIndex` in GoldSrc returns NULL for last player due to incorrect player index comparison
|
||||||
|
|
||||||
|
### Games and mods that require this
|
||||||
|
|
||||||
|
* Counter-Strike: Condition Zero - Deleted Scenes
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -28,7 +28,11 @@ typedef byte rgb_t[3]; // unsigned byte colorpack
|
|||||||
typedef vec_t matrix3x4[3][4];
|
typedef vec_t matrix3x4[3][4];
|
||||||
typedef vec_t matrix4x4[4][4];
|
typedef vec_t matrix4x4[4][4];
|
||||||
|
|
||||||
|
#if XASH_64BIT
|
||||||
typedef uint32_t poolhandle_t;
|
typedef uint32_t poolhandle_t;
|
||||||
|
#else
|
||||||
|
typedef void* poolhandle_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
#undef true
|
#undef true
|
||||||
#undef false
|
#undef false
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -273,8 +273,12 @@ typedef struct
|
|||||||
|
|
||||||
typedef enum bugcomp_e
|
typedef enum bugcomp_e
|
||||||
{
|
{
|
||||||
// reverts fix for pfnPEntityOfEntIndex for bug compatibility with GoldSrc
|
// default mode, we assume that user dlls are not relying on engine bugs
|
||||||
BUGCOMP_PENTITYOFENTINDEX_FLAG = BIT( 0 ),
|
BUGCOMP_OFF,
|
||||||
|
|
||||||
|
// GoldSrc mode, user dlls are relying on GoldSrc specific bugs
|
||||||
|
// but fixing them may break regular Xash games
|
||||||
|
BUGCOMP_GOLDSRC,
|
||||||
} bugcomp_t;
|
} bugcomp_t;
|
||||||
|
|
||||||
typedef struct host_parm_s
|
typedef struct host_parm_s
|
||||||
@@ -352,7 +356,7 @@ typedef struct host_parm_s
|
|||||||
int numdecals;
|
int numdecals;
|
||||||
|
|
||||||
// bug compatibility level, for very "special" games
|
// bug compatibility level, for very "special" games
|
||||||
uint32_t bugcomp;
|
bugcomp_t bugcomp;
|
||||||
|
|
||||||
// measure time to first frame
|
// measure time to first frame
|
||||||
double starttime;
|
double starttime;
|
||||||
|
|||||||
@@ -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 )
|
||||||
|
|||||||
@@ -65,32 +65,6 @@ static CVAR_DEFINE( host_sleeptime, "sleeptime", "1", FCVAR_ARCHIVE|FCVAR_FILTER
|
|||||||
static CVAR_DEFINE_AUTO( host_sleeptime_debug, "0", 0, "print sleeps between frames" );
|
static CVAR_DEFINE_AUTO( host_sleeptime_debug, "0", 0, "print sleeps between frames" );
|
||||||
CVAR_DEFINE( con_gamemaps, "con_mapfilter", "1", FCVAR_ARCHIVE, "when true show only maps in game folder" );
|
CVAR_DEFINE( con_gamemaps, "con_mapfilter", "1", FCVAR_ARCHIVE, "when true show only maps in game folder" );
|
||||||
|
|
||||||
typedef struct feature_message_s
|
|
||||||
{
|
|
||||||
uint32_t mask;
|
|
||||||
const char *msg;
|
|
||||||
const char *arg;
|
|
||||||
} feature_message_t;
|
|
||||||
|
|
||||||
static feature_message_t bugcomp_features[] =
|
|
||||||
{
|
|
||||||
{ BUGCOMP_PENTITYOFENTINDEX_FLAG, "pfnPEntityOfEntIndex bugfix revert", "peoei" },
|
|
||||||
};
|
|
||||||
|
|
||||||
static feature_message_t engine_features[] =
|
|
||||||
{
|
|
||||||
{ ENGINE_WRITE_LARGE_COORD, "Big World Support" },
|
|
||||||
{ ENGINE_QUAKE_COMPATIBLE, "Quake Compatibility" },
|
|
||||||
{ ENGINE_LOAD_DELUXEDATA, "Deluxemap Support" },
|
|
||||||
{ ENGINE_PHYSICS_PUSHER_EXT, "Improved MOVETYPE_PUSH" },
|
|
||||||
{ ENGINE_LARGE_LIGHTMAPS, "Large Lightmaps" },
|
|
||||||
{ ENGINE_COMPENSATE_QUAKE_BUG, "Stupid Quake Bug Compensation" },
|
|
||||||
{ ENGINE_IMPROVED_LINETRACE, "Improved Trace Line" },
|
|
||||||
{ ENGINE_COMPUTE_STUDIO_LERP, "Studio MOVETYPE_STEP Lerping" },
|
|
||||||
{ ENGINE_LINEAR_GAMMA_SPACE, "Linear Gamma Space" },
|
|
||||||
{ ENGINE_STEP_POSHISTORY_LERP, "MOVETYPE_STEP Position History Based Lerping" },
|
|
||||||
};
|
|
||||||
|
|
||||||
static void Sys_PrintUsage( void )
|
static void Sys_PrintUsage( void )
|
||||||
{
|
{
|
||||||
string version_str;
|
string version_str;
|
||||||
@@ -118,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 [opts] ", "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")
|
||||||
@@ -133,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")
|
||||||
@@ -219,14 +191,31 @@ void Host_ShutdownServer( void )
|
|||||||
Host_PrintEngineFeatures
|
Host_PrintEngineFeatures
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
static void Host_PrintFeatures( uint32_t flags, const char *s, feature_message_t *features, size_t size )
|
static void Host_PrintEngineFeatures( int features )
|
||||||
{
|
{
|
||||||
size_t i;
|
struct
|
||||||
|
|
||||||
for( i = 0; i < size; i++ )
|
|
||||||
{
|
{
|
||||||
if( FBitSet( flags, features[i].mask ))
|
uint32_t mask;
|
||||||
Con_Printf( "^3%s:^7 %s is enabled\n", s, features[i].msg );
|
const char *msg;
|
||||||
|
} features_str[] =
|
||||||
|
{
|
||||||
|
{ ENGINE_WRITE_LARGE_COORD, "Big World Support" },
|
||||||
|
{ ENGINE_QUAKE_COMPATIBLE, "Quake Compatibility" },
|
||||||
|
{ ENGINE_LOAD_DELUXEDATA, "Deluxemap Support" },
|
||||||
|
{ ENGINE_PHYSICS_PUSHER_EXT, "Improved MOVETYPE_PUSH" },
|
||||||
|
{ ENGINE_LARGE_LIGHTMAPS, "Large Lightmaps" },
|
||||||
|
{ ENGINE_COMPENSATE_QUAKE_BUG, "Stupid Quake Bug Compensation" },
|
||||||
|
{ ENGINE_IMPROVED_LINETRACE, "Improved Trace Line" },
|
||||||
|
{ ENGINE_COMPUTE_STUDIO_LERP, "Studio MOVETYPE_STEP Lerping" },
|
||||||
|
{ ENGINE_LINEAR_GAMMA_SPACE, "Linear Gamma Space" },
|
||||||
|
{ ENGINE_STEP_POSHISTORY_LERP, "MOVETYPE_STEP Position History Based Lerping" },
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for( i = 0; i < ARRAYSIZE( features_str ); i++ )
|
||||||
|
{
|
||||||
|
if( FBitSet( features, features_str[i].mask ))
|
||||||
|
Con_Reportf( "^3EXT:^7 %s is enabled\n", features_str[i].msg );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +243,7 @@ void Host_ValidateEngineFeatures( uint32_t features )
|
|||||||
SetBits( features, ENGINE_STEP_POSHISTORY_LERP );
|
SetBits( features, ENGINE_STEP_POSHISTORY_LERP );
|
||||||
|
|
||||||
// print requested first
|
// print requested first
|
||||||
Host_PrintFeatures( features, "EXT", engine_features, ARRAYSIZE( engine_features ));
|
Host_PrintEngineFeatures( features );
|
||||||
|
|
||||||
// now warn about incompatible bits
|
// now warn about incompatible bits
|
||||||
if( FBitSet( features, ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ) == ( ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ))
|
if( FBitSet( features, ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ) == ( ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ))
|
||||||
@@ -950,59 +939,11 @@ 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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static uint32_t Host_CheckBugcomp( void )
|
|
||||||
{
|
|
||||||
uint32_t flags = 0;
|
|
||||||
string args, arg;
|
|
||||||
char *prev, *next;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
if( !Sys_CheckParm( "-bugcomp" ))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if( Sys_GetParmFromCmdLine( "-bugcomp", args ) && args[0] != '-' )
|
|
||||||
{
|
|
||||||
for( prev = args, next = Q_strchrnul( prev, '+' ); ; prev = next + 1, next = Q_strchrnul( prev, '+' ))
|
|
||||||
{
|
|
||||||
Q_strncpy( arg, prev, next - prev + 1 );
|
|
||||||
for( i = 0; i < ARRAYSIZE( bugcomp_features ); i++ )
|
|
||||||
{
|
|
||||||
if( !Q_stricmp( bugcomp_features[i].arg, arg ))
|
|
||||||
{
|
|
||||||
SetBits( flags, bugcomp_features[i].mask );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( i == ARRAYSIZE( bugcomp_features ))
|
|
||||||
{
|
|
||||||
Con_Printf( S_ERROR "Unknown bugcomp flag %s\n", arg );
|
|
||||||
Con_Printf( "Valid flags are:\n" );
|
|
||||||
for( i = 0; i < ARRAYSIZE( bugcomp_features ); i++ )
|
|
||||||
Con_Printf( "\t%s: %s\n", bugcomp_features[i].arg, bugcomp_features[i].msg );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !*next )
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// no argument specified -bugcomp just enables everything
|
|
||||||
flags = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Host_PrintFeatures( flags, "BUGCOMP", bugcomp_features, ARRAYSIZE( bugcomp_features ));
|
|
||||||
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
Host_InitCommon
|
Host_InitCommon
|
||||||
@@ -1107,6 +1048,13 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
|
|||||||
// member console allowing
|
// member console allowing
|
||||||
host.allow_console_init = host.allow_console;
|
host.allow_console_init = host.allow_console;
|
||||||
|
|
||||||
|
if( Sys_CheckParm( "-bugcomp" ))
|
||||||
|
{
|
||||||
|
// add argument check here when we add other levels
|
||||||
|
// of bugcompatibility
|
||||||
|
host.bugcomp = BUGCOMP_GOLDSRC;
|
||||||
|
}
|
||||||
|
|
||||||
// timeBeginPeriod( 1 ); // a1ba: Do we need this?
|
// timeBeginPeriod( 1 ); // a1ba: Do we need this?
|
||||||
|
|
||||||
// NOTE: this message couldn't be passed into game console but it doesn't matter
|
// NOTE: this message couldn't be passed into game console but it doesn't matter
|
||||||
@@ -1233,11 +1181,11 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
|
|||||||
|
|
||||||
Sys_InitLog();
|
Sys_InitLog();
|
||||||
|
|
||||||
// print current developer level to simplify processing users feedback
|
// print bugcompatibility level here, after log was initialized
|
||||||
if( developer > 0 )
|
if( host.bugcomp == BUGCOMP_GOLDSRC )
|
||||||
Con_Printf( "Developer level: ^3%i\n", developer );
|
{
|
||||||
|
Con_Printf( "^3BUGCOMP^7: GoldSrc bug-compatibility enabled\n" );
|
||||||
host.bugcomp = Host_CheckBugcomp();
|
}
|
||||||
|
|
||||||
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" );
|
||||||
@@ -1421,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
|
||||||
|
|||||||
@@ -400,8 +400,7 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet, qboolean de
|
|||||||
f = FS_Open( pakname, "rb", true );
|
f = FS_Open( pakname, "rb", true );
|
||||||
if( !f )
|
if( !f )
|
||||||
{
|
{
|
||||||
if( !quiet )
|
Con_DPrintf( S_ERROR "Couldn't find %s.\n", pakname );
|
||||||
Con_DPrintf( S_ERROR "Couldn't find %s.\n", pakname );
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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( val_a * 100.0 );
|
val_a -= Q_rint(timebase * 100.0);
|
||||||
toF = Q_rint( 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( val_a * pField->multiplier );
|
|
||||||
toF = Q_rint( 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;
|
||||||
}
|
}
|
||||||
@@ -1394,14 +1359,22 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
|||||||
}
|
}
|
||||||
else if( pField->flags & DT_TIMEWINDOW_8 )
|
else if( pField->flags & DT_TIMEWINDOW_8 )
|
||||||
{
|
{
|
||||||
iValue = MSG_ReadSBitLong( msg, pField->bits );
|
bSigned = true; // timewindow is always signed
|
||||||
flTime = ( timebase * 100.0 - (int)iValue ) / 100.0;
|
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
||||||
|
flTime = (timebase * 100.0 - (int)iValue) / 100.0;
|
||||||
|
|
||||||
*(float *)((byte *)to + pField->offset ) = flTime;
|
*(float *)((byte *)to + pField->offset ) = flTime;
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
||||||
{
|
{
|
||||||
iValue = MSG_ReadSBitLong( msg, pField->bits );
|
bSigned = true; // timewindow is always signed
|
||||||
flTime = ( timebase * pField->multiplier - (int)iValue ) / pField->multiplier;
|
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
||||||
|
|
||||||
|
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||||
|
flTime = ( timebase * pField->multiplier - (int)iValue ) / pField->multiplier;
|
||||||
|
else
|
||||||
|
flTime = timebase - (int)iValue;
|
||||||
|
|
||||||
*(float *)((byte *)to + pField->offset ) = flTime;
|
*(float *)((byte *)to + pField->offset ) = flTime;
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_STRING )
|
else if( pField->flags & DT_STRING )
|
||||||
@@ -2096,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;
|
||||||
}
|
}
|
||||||
@@ -341,18 +335,15 @@ void GAME_EXPORT Con_Printf( const char *szFmt, ... )
|
|||||||
{
|
{
|
||||||
static char buffer[MAX_PRINT_MSG];
|
static char buffer[MAX_PRINT_MSG];
|
||||||
va_list args;
|
va_list args;
|
||||||
qboolean add_newline;
|
|
||||||
|
|
||||||
if( !host.allow_console )
|
if( !host.allow_console )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
va_start( args, szFmt );
|
va_start( args, szFmt );
|
||||||
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
|
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
|
||||||
va_end( args );
|
va_end( args );
|
||||||
|
|
||||||
Sys_Print( buffer );
|
Sys_Print( buffer );
|
||||||
if( add_newline )
|
|
||||||
Sys_Print( "\n" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -365,21 +356,18 @@ void GAME_EXPORT Con_DPrintf( const char *szFmt, ... )
|
|||||||
{
|
{
|
||||||
static char buffer[MAX_PRINT_MSG];
|
static char buffer[MAX_PRINT_MSG];
|
||||||
va_list args;
|
va_list args;
|
||||||
qboolean add_newline;
|
|
||||||
|
|
||||||
if( host_developer.value < DEV_NORMAL )
|
if( host_developer.value < DEV_NORMAL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
va_start( args, szFmt );
|
va_start( args, szFmt );
|
||||||
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
|
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
|
||||||
va_end( args );
|
va_end( args );
|
||||||
|
|
||||||
if( buffer[0] == '0' && buffer[1] == '\n' && buffer[2] == '\0' )
|
if( buffer[0] == '0' && buffer[1] == '\n' && buffer[2] == '\0' )
|
||||||
return; // hlrally spam
|
return; // hlrally spam
|
||||||
|
|
||||||
Sys_Print( buffer );
|
Sys_Print( buffer );
|
||||||
if( add_newline )
|
|
||||||
Sys_Print( "\n" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -392,18 +380,15 @@ void Con_Reportf( const char *szFmt, ... )
|
|||||||
{
|
{
|
||||||
static char buffer[MAX_PRINT_MSG];
|
static char buffer[MAX_PRINT_MSG];
|
||||||
va_list args;
|
va_list args;
|
||||||
qboolean add_newline;
|
|
||||||
|
|
||||||
if( host_developer.value < DEV_EXTENDED )
|
if( host_developer.value < DEV_EXTENDED )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
va_start( args, szFmt );
|
va_start( args, szFmt );
|
||||||
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
|
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
|
||||||
va_end( args );
|
va_end( args );
|
||||||
|
|
||||||
Sys_Print( buffer );
|
Sys_Print( buffer );
|
||||||
if( add_newline )
|
|
||||||
Sys_Print( "\n" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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(); \
|
||||||
|
|||||||
@@ -25,39 +25,18 @@ GNU General Public License for more details.
|
|||||||
#include "platform/swap/swap.h"
|
#include "platform/swap/swap.h"
|
||||||
#define Q_malloc SWAP_Malloc
|
#define Q_malloc SWAP_Malloc
|
||||||
#define Q_free SWAP_Free
|
#define Q_free SWAP_Free
|
||||||
|
|
||||||
static void *Q_realloc( void *mem, size_t size )
|
|
||||||
{
|
|
||||||
void *newmem;
|
|
||||||
|
|
||||||
if( mem && size == 0 )
|
|
||||||
{
|
|
||||||
Q_free( mem );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
newmem = Q_malloc( size );
|
|
||||||
if( mem && newmem )
|
|
||||||
{
|
|
||||||
memcpy( newmem, mem, size );
|
|
||||||
Q_free( mem );
|
|
||||||
}
|
|
||||||
|
|
||||||
return newmem;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
#define Q_malloc malloc
|
#define Q_malloc malloc
|
||||||
#define Q_free free
|
#define Q_free free
|
||||||
#define Q_realloc realloc
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct memheader_s
|
typedef struct memheader_s
|
||||||
{
|
{
|
||||||
struct memheader_s *next; // next and previous memheaders in chain belonging to pool
|
struct memheader_s *next; // next and previous memheaders in chain belonging to pool
|
||||||
struct memheader_s *prev;
|
struct memheader_s *prev;
|
||||||
const char *filename; // file name and line where Mem_Alloc was called
|
struct mempool_s *pool; // pool this memheader belongs to
|
||||||
size_t size; // size of the memory after the header (excluding header and sentinel2)
|
size_t size; // size of the memory after the header (excluding header and sentinel2)
|
||||||
poolhandle_t poolptr; // pool this memheader belongs to
|
const char *filename; // file name and line where Mem_Alloc was called
|
||||||
int fileline;
|
int fileline;
|
||||||
#if !XASH_64BIT
|
#if !XASH_64BIT
|
||||||
uint32_t pad0; // doesn't have value, only to make Mem_Alloc return aligned addresses on ILP32
|
uint32_t pad0; // doesn't have value, only to make Mem_Alloc return aligned addresses on ILP32
|
||||||
@@ -69,34 +48,50 @@ typedef struct memheader_s
|
|||||||
|
|
||||||
typedef struct mempool_s
|
typedef struct mempool_s
|
||||||
{
|
{
|
||||||
|
uint32_t sentinel1; // should always be MEMHEADER_SENTINEL1
|
||||||
struct memheader_s *chain; // chain of individual memory allocations
|
struct memheader_s *chain; // chain of individual memory allocations
|
||||||
size_t totalsize; // total memory allocated in this pool (inside memheaders)
|
size_t totalsize; // total memory allocated in this pool (inside memheaders)
|
||||||
size_t realsize; // total memory allocated in this pool (actual malloc total)
|
size_t realsize; // total memory allocated in this pool (actual malloc total)
|
||||||
size_t lastchecksize; // updated each time the pool is displayed by memlist
|
size_t lastchecksize; // updated each time the pool is displayed by memlist
|
||||||
|
struct mempool_s *next; // linked into global mempool list
|
||||||
const char *filename; // file name and line where Mem_AllocPool was called
|
const char *filename; // file name and line where Mem_AllocPool was called
|
||||||
int fileline;
|
int fileline;
|
||||||
|
#if XASH_64BIT
|
||||||
|
poolhandle_t idx;
|
||||||
|
#endif
|
||||||
char name[64]; // name of the pool
|
char name[64]; // name of the pool
|
||||||
|
uint32_t sentinel2; // should always be MEMHEADER_SENTINEL1
|
||||||
} mempool_t;
|
} mempool_t;
|
||||||
|
|
||||||
static mempool_t *poolchain = NULL; // critical stuff
|
static mempool_t *poolchain = NULL; // critical stuff
|
||||||
static size_t poolcount = 0;
|
|
||||||
|
|
||||||
|
#if XASH_64BIT
|
||||||
// a1ba: due to mempool being passed with the model through reused 32-bit field
|
// a1ba: due to mempool being passed with the model through reused 32-bit field
|
||||||
// which makes engine incompatible with 64-bit pointers I changed mempool type
|
// which makes engine incompatible with 64-bit pointers I changed mempool type
|
||||||
// from pointer to 32-bit handle, thankfully mempool structure is private
|
// from pointer to 32-bit handle, thankfully mempool structure is private
|
||||||
|
// But! Mempools are handled through linked list so we can't index them safely
|
||||||
|
static poolhandle_t lastidx = 0;
|
||||||
|
|
||||||
static mempool_t *Mem_FindPool( poolhandle_t poolptr )
|
static mempool_t *Mem_FindPool( poolhandle_t poolptr )
|
||||||
{
|
{
|
||||||
if( likely( poolptr > 0 && poolptr <= poolcount ))
|
mempool_t *pool;
|
||||||
return &poolchain[poolptr - 1];
|
|
||||||
|
for( pool = poolchain; pool; pool = pool->next )
|
||||||
|
{
|
||||||
|
if( pool->idx == poolptr )
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
Sys_Error( "%s: not allocated or double freed pool %d", __FUNCTION__, poolptr );
|
Sys_Error( "%s: not allocated or double freed pool %d", __FUNCTION__, poolptr );
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
static poolhandle_t Mem_PoolIndex( mempool_t *mempool )
|
static mempool_t *Mem_FindPool( poolhandle_t poolptr )
|
||||||
{
|
{
|
||||||
return (poolhandle_t)(mempool - poolchain) + 1;
|
return (mempool_t *)poolptr;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline void Mem_PoolAdd( mempool_t *pool, size_t size )
|
static inline void Mem_PoolAdd( mempool_t *pool, size_t size )
|
||||||
{
|
{
|
||||||
@@ -116,7 +111,7 @@ static inline void Mem_PoolLinkAlloc( mempool_t *pool, memheader_t *mem )
|
|||||||
if( mem->next ) mem->next->prev = mem;
|
if( mem->next ) mem->next->prev = mem;
|
||||||
pool->chain = mem;
|
pool->chain = mem;
|
||||||
mem->prev = NULL;
|
mem->prev = NULL;
|
||||||
mem->poolptr = Mem_PoolIndex( pool );
|
mem->pool = pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
|
static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
|
||||||
@@ -124,7 +119,7 @@ static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
|
|||||||
if( mem->next ) mem->next->prev = mem->prev;
|
if( mem->next ) mem->next->prev = mem->prev;
|
||||||
if( mem->prev ) mem->prev->next = mem->next;
|
if( mem->prev ) mem->prev->next = mem->next;
|
||||||
else pool->chain = mem->next;
|
else pool->chain = mem->next;
|
||||||
mem->poolptr = 0;
|
mem->pool = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void Mem_InitAlloc( memheader_t *mem, size_t size, const char *filename, int fileline )
|
static inline void Mem_InitAlloc( memheader_t *mem, size_t size, const char *filename, int fileline )
|
||||||
@@ -170,6 +165,23 @@ static qboolean Mem_CheckAllocHeader( const char *func, const memheader_t *mem,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static qboolean Mem_CheckPool( const char *func, const mempool_t *pool, const char *filename, int fileline )
|
||||||
|
{
|
||||||
|
if( pool->sentinel1 != MEMHEADER_SENTINEL1 )
|
||||||
|
{
|
||||||
|
Sys_Error( "%s: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)\n", func, pool->filename, pool->fileline, filename, fileline );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( pool->sentinel2 != MEMHEADER_SENTINEL1 )
|
||||||
|
{
|
||||||
|
Sys_Error( "%s: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)\n", func, pool->filename, pool->fileline, filename, fileline );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
|
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
|
||||||
{
|
{
|
||||||
memheader_t *mem;
|
memheader_t *mem;
|
||||||
@@ -178,16 +190,12 @@ void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char
|
|||||||
if( size <= 0 )
|
if( size <= 0 )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if( unlikely( !poolptr ))
|
if( !poolptr )
|
||||||
{
|
{
|
||||||
Sys_Error( "%s: pool == NULL (alloc at %s:%i)\n", __func__, filename, fileline );
|
Sys_Error( "%s: pool == NULL (alloc at %s:%i)\n", __func__, filename, fileline );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pool = Mem_FindPool( poolptr );
|
|
||||||
if( !pool )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( byte ));
|
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( byte ));
|
||||||
if( mem == NULL )
|
if( mem == NULL )
|
||||||
{
|
{
|
||||||
@@ -197,6 +205,7 @@ void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char
|
|||||||
|
|
||||||
Mem_InitAlloc( mem, size, filename, fileline );
|
Mem_InitAlloc( mem, size, filename, fileline );
|
||||||
|
|
||||||
|
pool = Mem_FindPool( poolptr );
|
||||||
Mem_PoolAdd( pool, size );
|
Mem_PoolAdd( pool, size );
|
||||||
Mem_PoolLinkAlloc( pool, mem );
|
Mem_PoolLinkAlloc( pool, mem );
|
||||||
|
|
||||||
@@ -213,9 +222,7 @@ static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline
|
|||||||
if( !Mem_CheckAllocHeader( __func__, mem, filename, fileline ))
|
if( !Mem_CheckAllocHeader( __func__, mem, filename, fileline ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pool = Mem_FindPool( mem->poolptr );
|
pool = mem->pool;
|
||||||
if( !pool )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// unlink memheader from doubly linked list
|
// unlink memheader from doubly linked list
|
||||||
if(( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem ))
|
if(( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem ))
|
||||||
@@ -251,7 +258,7 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
|
|||||||
if( size <= 0 )
|
if( size <= 0 )
|
||||||
return data; // no need to reallocate
|
return data; // no need to reallocate
|
||||||
|
|
||||||
if( unlikely( !poolptr ))
|
if( !poolptr )
|
||||||
{
|
{
|
||||||
Sys_Error( "Mem_Realloc: pool == NULL (alloc at %s:%i)\n", filename, fileline );
|
Sys_Error( "Mem_Realloc: pool == NULL (alloc at %s:%i)\n", filename, fileline );
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -265,21 +272,25 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
|
|||||||
if( !Mem_CheckAllocHeader( "Mem_Realloc", mem, filename, fileline ))
|
if( !Mem_CheckAllocHeader( "Mem_Realloc", mem, filename, fileline ))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if( unlikely( mem->poolptr != poolptr ))
|
|
||||||
{
|
|
||||||
Sys_Error( "Mem_Realloc: pool migration is not allowed (alloc at %s:%i, realloc at %s:%i)\n",
|
|
||||||
Mem_CheckFilename( mem->filename ), mem->fileline, filename, fileline );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
oldsize = mem->size;
|
oldsize = mem->size;
|
||||||
if( size == oldsize )
|
if( size == oldsize )
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
|
#if XASH_CUSTOM_SWAP
|
||||||
|
{
|
||||||
|
char *nb = _Mem_Alloc( poolptr, size, clear, filename, fileline );
|
||||||
|
|
||||||
|
size_t newsize = mem->size < size ? mem->size : size; // upper data can be trucnated!
|
||||||
|
memcpy( nb, data, newsize );
|
||||||
|
_Mem_Free( data, filename, fileline ); // free unused old block
|
||||||
|
|
||||||
|
return nb;
|
||||||
|
}
|
||||||
|
#else // XASH_CUSTOM_SWAP
|
||||||
pool = Mem_FindPool( poolptr );
|
pool = Mem_FindPool( poolptr );
|
||||||
|
|
||||||
oldmem = (uintptr_t)mem;
|
oldmem = (uintptr_t)mem;
|
||||||
mem = Q_realloc( mem, sizeof( memheader_t ) + size + sizeof( byte ));
|
mem = realloc( mem, sizeof( memheader_t ) + size + sizeof( byte ));
|
||||||
|
|
||||||
if( mem == NULL )
|
if( mem == NULL )
|
||||||
{
|
{
|
||||||
@@ -301,7 +312,14 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
|
|||||||
}
|
}
|
||||||
else Mem_PoolSubtract( pool, oldsize - size );
|
else Mem_PoolSubtract( pool, oldsize - size );
|
||||||
|
|
||||||
if( oldmem != (uintptr_t)mem ) // just relink pointers
|
// if allocation was migrated from one pool to another
|
||||||
|
// (this is possible with original Mem_Realloc func)
|
||||||
|
if( unlikely( mem->pool != pool ))
|
||||||
|
{
|
||||||
|
Mem_PoolUnlinkAlloc( mem->pool, mem );
|
||||||
|
Mem_PoolLinkAlloc( pool, mem );
|
||||||
|
}
|
||||||
|
else if( oldmem != (uintptr_t)mem ) // just relink pointers
|
||||||
{
|
{
|
||||||
if( mem->next ) mem->next->prev = mem;
|
if( mem->next ) mem->next->prev = mem;
|
||||||
if( mem->prev ) mem->prev->next = mem;
|
if( mem->prev ) mem->prev->next = mem;
|
||||||
@@ -309,81 +327,69 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (void *)((byte *)mem + sizeof( memheader_t ));
|
return (void *)((byte *)mem + sizeof( memheader_t ));
|
||||||
}
|
#endif // XASH_CUSTOM_SWAP
|
||||||
|
|
||||||
static poolhandle_t Mem_InitPool( mempool_t *pool, const char *name, const char *filename, int fileline )
|
|
||||||
{
|
|
||||||
memset( pool, 0, sizeof( *pool ));
|
|
||||||
|
|
||||||
// fill header
|
|
||||||
pool->filename = filename;
|
|
||||||
pool->fileline = fileline;
|
|
||||||
pool->realsize = sizeof( mempool_t );
|
|
||||||
Q_strncpy( pool->name, name, sizeof( pool->name ));
|
|
||||||
|
|
||||||
return Mem_PoolIndex( pool );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
poolhandle_t _Mem_AllocPool( const char *name, const char *filename, int fileline )
|
poolhandle_t _Mem_AllocPool( const char *name, const char *filename, int fileline )
|
||||||
{
|
{
|
||||||
mempool_t *pool;
|
mempool_t *pool;
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
pool = (mempool_t *)Q_malloc( sizeof( mempool_t ));
|
||||||
{
|
|
||||||
if( pool->filename == NULL )
|
|
||||||
return Mem_InitPool( pool, name, filename, fileline );
|
|
||||||
}
|
|
||||||
|
|
||||||
pool = (mempool_t *)Q_realloc( poolchain, sizeof( *poolchain ) * ( poolcount + 1 ));
|
|
||||||
if( pool == NULL )
|
if( pool == NULL )
|
||||||
{
|
{
|
||||||
Sys_Error( "Mem_AllocPool: out of memory (allocpool at %s:%i)\n", filename, fileline );
|
Sys_Error( "Mem_AllocPool: out of memory (allocpool at %s:%i)\n", filename, fileline );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
memset( pool, 0, sizeof( mempool_t ));
|
||||||
|
|
||||||
|
// fill header
|
||||||
|
pool->sentinel1 = MEMHEADER_SENTINEL1;
|
||||||
|
pool->sentinel2 = MEMHEADER_SENTINEL1;
|
||||||
|
pool->filename = filename;
|
||||||
|
pool->fileline = fileline;
|
||||||
|
pool->chain = NULL;
|
||||||
|
pool->totalsize = 0;
|
||||||
|
pool->realsize = sizeof( mempool_t );
|
||||||
|
Q_strncpy( pool->name, name, sizeof( pool->name ));
|
||||||
|
pool->next = poolchain;
|
||||||
poolchain = pool;
|
poolchain = pool;
|
||||||
pool = &poolchain[poolcount++];
|
|
||||||
return Mem_InitPool( pool, name, filename, fileline );
|
#if XASH_64BIT
|
||||||
|
pool->idx = ++lastidx;
|
||||||
|
return pool->idx;
|
||||||
|
#else
|
||||||
|
return (poolhandle_t)pool;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline )
|
void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline )
|
||||||
{
|
{
|
||||||
mempool_t *pool;
|
mempool_t *pool;
|
||||||
|
mempool_t **chainaddress;
|
||||||
|
|
||||||
if( *poolptr && ( pool = Mem_FindPool( *poolptr )))
|
if( *poolptr && ( pool = Mem_FindPool( *poolptr )))
|
||||||
{
|
{
|
||||||
if( !pool->filename )
|
// unlink pool from chain
|
||||||
{
|
for( chainaddress = &poolchain; *chainaddress && *chainaddress != pool; chainaddress = &((*chainaddress)->next));
|
||||||
Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
|
if( *chainaddress != pool ) Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
|
||||||
*poolptr = 0;
|
Mem_CheckPool( "Mem_FreePool", pool, filename, fileline );
|
||||||
return;
|
*chainaddress = pool->next;
|
||||||
}
|
|
||||||
|
|
||||||
// free memory owned by the pool
|
// free memory owned by the pool
|
||||||
while( pool->chain )
|
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
|
||||||
Mem_FreeBlock( pool->chain, filename, fileline );
|
|
||||||
|
|
||||||
// free the pool itself
|
// free the pool itself
|
||||||
memset( pool, 0xBF, sizeof( mempool_t ));
|
memset( pool, 0xBF, sizeof( mempool_t ));
|
||||||
pool->chain = NULL;
|
Q_free( pool );
|
||||||
pool->filename = NULL; // mark as reusable
|
|
||||||
*poolptr = 0;
|
*poolptr = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline )
|
void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline )
|
||||||
{
|
{
|
||||||
mempool_t *pool;
|
mempool_t *pool = Mem_FindPool( poolptr );
|
||||||
if( unlikely( !poolptr ))
|
if( !poolptr ) Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
|
||||||
{
|
|
||||||
Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pool = Mem_FindPool( poolptr );
|
Mem_CheckPool( "Mem_FreePool", pool, filename, fileline );
|
||||||
if( !pool )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// free memory owned by the pool
|
// free memory owned by the pool
|
||||||
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
|
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
|
||||||
@@ -406,8 +412,7 @@ static qboolean Mem_CheckAlloc( mempool_t *pool, void *data )
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// search all pools
|
// search all pools
|
||||||
size_t i;
|
for( pool = poolchain; pool; pool = pool->next )
|
||||||
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
|
||||||
{
|
{
|
||||||
if( Mem_CheckAlloc( pool, data ))
|
if( Mem_CheckAlloc( pool, data ))
|
||||||
return true;
|
return true;
|
||||||
@@ -435,24 +440,23 @@ void _Mem_Check( const char *filename, int fileline )
|
|||||||
{
|
{
|
||||||
memheader_t *mem;
|
memheader_t *mem;
|
||||||
mempool_t *pool;
|
mempool_t *pool;
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
for( pool = poolchain; pool; pool = pool->next )
|
||||||
|
Mem_CheckPool( "Mem_CheckSentinels", pool, filename, fileline );
|
||||||
|
|
||||||
|
for( pool = poolchain; pool; pool = pool->next )
|
||||||
for( mem = pool->chain; mem; mem = mem->next )
|
for( mem = pool->chain; mem; mem = mem->next )
|
||||||
Mem_CheckAllocHeader( "Mem_CheckSentinels", mem, filename, fileline );
|
Mem_CheckAllocHeader( "Mem_CheckSentinels", mem, filename, fileline );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mem_PrintStats( void )
|
void Mem_PrintStats( void )
|
||||||
{
|
{
|
||||||
size_t count = 0, size = 0, realsize = 0, i;
|
size_t count = 0, size = 0, realsize = 0;
|
||||||
mempool_t *pool;
|
mempool_t *pool;
|
||||||
|
|
||||||
Mem_Check();
|
Mem_Check();
|
||||||
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
for( pool = poolchain; pool; pool = pool->next )
|
||||||
{
|
{
|
||||||
if( !pool->filename )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
size += pool->totalsize;
|
size += pool->totalsize;
|
||||||
realsize += pool->realsize;
|
realsize += pool->realsize;
|
||||||
@@ -466,19 +470,15 @@ void Mem_PrintList( size_t minallocationsize )
|
|||||||
{
|
{
|
||||||
mempool_t *pool;
|
mempool_t *pool;
|
||||||
memheader_t *mem;
|
memheader_t *mem;
|
||||||
size_t i;
|
|
||||||
|
|
||||||
Mem_Check();
|
Mem_Check();
|
||||||
|
|
||||||
Con_Printf( "memory pool list:\n" );
|
Con_Printf( "memory pool list:\n" );
|
||||||
Con_Printf( "\t^3size\t\t\t\tname\n");
|
Con_Printf( "\t^3size\t\t\t\tname\n");
|
||||||
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
for( pool = poolchain; pool; pool = pool->next )
|
||||||
{
|
{
|
||||||
long changed_size = (long)pool->totalsize - (long)pool->lastchecksize;
|
long changed_size = (long)pool->totalsize - (long)pool->lastchecksize;
|
||||||
|
|
||||||
if( !pool->filename )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// poolnames can contain color symbols, make sure what color is reset
|
// poolnames can contain color symbols, make sure what color is reset
|
||||||
if( pool->lastchecksize != 0 && changed_size != 0 )
|
if( pool->lastchecksize != 0 && changed_size != 0 )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============
|
=============
|
||||||
@@ -3344,10 +3391,12 @@ pfnPEntityOfEntIndex
|
|||||||
|
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
static edict_t *pfnPEntityOfEntIndexBroken( int iEntIndex )
|
static edict_t *pfnPEntityOfEntIndex( int iEntIndex )
|
||||||
{
|
{
|
||||||
// have to be bug-compatible with GoldSrc in this function
|
// have to be bug-compatible with GoldSrc in this function
|
||||||
return SV_PEntityOfEntIndex( iEntIndex, false );
|
if( host.bugcomp == BUGCOMP_GOLDSRC )
|
||||||
|
return SV_PEntityOfEntIndex( iEntIndex, false );
|
||||||
|
return SV_PEntityOfEntIndex( iEntIndex, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3688,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;
|
||||||
}
|
}
|
||||||
@@ -3824,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 )
|
||||||
@@ -4682,7 +4731,7 @@ static enginefuncs_t gEngfuncs =
|
|||||||
pfnPEntityOfEntOffset,
|
pfnPEntityOfEntOffset,
|
||||||
pfnEntOffsetOfPEntity,
|
pfnEntOffsetOfPEntity,
|
||||||
pfnIndexOfEdict,
|
pfnIndexOfEdict,
|
||||||
pfnPEntityOfEntIndexAllEntities,
|
pfnPEntityOfEntIndex,
|
||||||
pfnFindEntityByVars,
|
pfnFindEntityByVars,
|
||||||
pfnGetModelPtr,
|
pfnGetModelPtr,
|
||||||
pfnRegUserMsg,
|
pfnRegUserMsg,
|
||||||
@@ -4771,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
|
||||||
@@ -4791,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
|
||||||
@@ -4826,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
|
||||||
@@ -4916,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 );
|
||||||
@@ -4934,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 );
|
||||||
}
|
}
|
||||||
@@ -4944,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
|
||||||
@@ -4955,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5085,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 ();
|
||||||
|
|
||||||
@@ -5105,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 );
|
||||||
@@ -5153,11 +5170,6 @@ qboolean SV_LoadProgs( const char *name )
|
|||||||
// make sure what physic functions is cleared
|
// make sure what physic functions is cleared
|
||||||
memset( &svgame.physFuncs, 0, sizeof( svgame.physFuncs ));
|
memset( &svgame.physFuncs, 0, sizeof( svgame.physFuncs ));
|
||||||
|
|
||||||
// revert fix for pfnPEntityOfEntIndex to be compatible with GoldSrc
|
|
||||||
// games that rely on this bug
|
|
||||||
if( FBitSet( host.bugcomp, BUGCOMP_PENTITYOFENTINDEX_FLAG ))
|
|
||||||
gEngfuncs.pfnPEntityOfEntIndex = pfnPEntityOfEntIndexBroken;
|
|
||||||
|
|
||||||
// make local copy of engfuncs to prevent overwrite it with bots.dll
|
// make local copy of engfuncs to prevent overwrite it with bots.dll
|
||||||
memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs ));
|
memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs ));
|
||||||
|
|
||||||
@@ -5170,7 +5182,7 @@ qboolean SV_LoadProgs( const char *name )
|
|||||||
COM_FreeLibrary( svgame.hInstance );
|
COM_FreeLibrary( svgame.hInstance );
|
||||||
Con_Printf( S_ERROR "SV_LoadProgs: failed to get address of GetEntityAPI proc\n" );
|
Con_Printf( S_ERROR "SV_LoadProgs: failed to get address of GetEntityAPI proc\n" );
|
||||||
svgame.hInstance = NULL;
|
svgame.hInstance = NULL;
|
||||||
Mem_FreePool( &svgame.mempool );
|
Mem_FreePool(&svgame.mempool);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5181,7 +5193,7 @@ qboolean SV_LoadProgs( const char *name )
|
|||||||
COM_FreeLibrary( svgame.hInstance );
|
COM_FreeLibrary( svgame.hInstance );
|
||||||
Con_Printf( S_ERROR "SV_LoadProgs: failed to get address of GiveFnptrsToDll proc\n" );
|
Con_Printf( S_ERROR "SV_LoadProgs: failed to get address of GiveFnptrsToDll proc\n" );
|
||||||
svgame.hInstance = NULL;
|
svgame.hInstance = NULL;
|
||||||
Mem_FreePool( &svgame.mempool );
|
Mem_FreePool(&svgame.mempool);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5206,8 +5218,7 @@ qboolean SV_LoadProgs( const char *name )
|
|||||||
{
|
{
|
||||||
if( !GetEntityAPI2( &svgame.dllFuncs, &version ))
|
if( !GetEntityAPI2( &svgame.dllFuncs, &version ))
|
||||||
{
|
{
|
||||||
if( INTERFACE_VERSION != version )
|
Con_Printf( S_WARN "SV_LoadProgs: interface version %i should be %i\n", INTERFACE_VERSION, version );
|
||||||
Con_Printf( S_WARN "SV_LoadProgs: interface version %i should be %i\n", INTERFACE_VERSION, version );
|
|
||||||
|
|
||||||
// fallback to old API
|
// fallback to old API
|
||||||
if( !GetEntityAPI( &svgame.dllFuncs, version ))
|
if( !GetEntityAPI( &svgame.dllFuncs, version ))
|
||||||
@@ -5215,10 +5226,9 @@ qboolean SV_LoadProgs( const char *name )
|
|||||||
COM_FreeLibrary( svgame.hInstance );
|
COM_FreeLibrary( svgame.hInstance );
|
||||||
Con_Printf( S_ERROR "SV_LoadProgs: couldn't get entity API\n" );
|
Con_Printf( S_ERROR "SV_LoadProgs: couldn't get entity API\n" );
|
||||||
svgame.hInstance = NULL;
|
svgame.hInstance = NULL;
|
||||||
Mem_FreePool( &svgame.mempool );
|
Mem_FreePool(&svgame.mempool);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else Con_Reportf( "SV_LoadProgs: ^2initailized legacy EntityAPI ^7ver. %i\n", version );
|
|
||||||
}
|
}
|
||||||
else Con_Reportf( "SV_LoadProgs: ^2initailized extended EntityAPI ^7ver. %i\n", version );
|
else Con_Reportf( "SV_LoadProgs: ^2initailized extended EntityAPI ^7ver. %i\n", version );
|
||||||
}
|
}
|
||||||
@@ -5227,10 +5237,9 @@ qboolean SV_LoadProgs( const char *name )
|
|||||||
COM_FreeLibrary( svgame.hInstance );
|
COM_FreeLibrary( svgame.hInstance );
|
||||||
Con_Printf( S_ERROR "SV_LoadProgs: couldn't get entity API\n" );
|
Con_Printf( S_ERROR "SV_LoadProgs: couldn't get entity API\n" );
|
||||||
svgame.hInstance = NULL;
|
svgame.hInstance = NULL;
|
||||||
Mem_FreePool( &svgame.mempool );
|
Mem_FreePool(&svgame.mempool);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else Con_Reportf( "SV_LoadProgs: ^2initailized legacy EntityAPI ^7ver. %i\n", version );
|
|
||||||
|
|
||||||
SV_InitOperatorCommands();
|
SV_InitOperatorCommands();
|
||||||
Mod_InitStudioAPI();
|
Mod_InitStudioAPI();
|
||||||
|
|||||||
@@ -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] );
|
||||||
|
|||||||
57
wscript
57
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
|
||||||
@@ -279,7 +319,7 @@ def configure(conf):
|
|||||||
conf.env.append_unique('CXXFLAGS', cxxflags)
|
conf.env.append_unique('CXXFLAGS', cxxflags)
|
||||||
conf.env.append_unique('LINKFLAGS', linkflags)
|
conf.env.append_unique('LINKFLAGS', linkflags)
|
||||||
|
|
||||||
if conf.env.COMPILER_CC != 'msvc':
|
if conf.env.COMPILER_CC != 'msvc' and not conf.options.DISABLE_WERROR:
|
||||||
opt_flags = [
|
opt_flags = [
|
||||||
# '-Wall', '-Wextra', '-Wpedantic',
|
# '-Wall', '-Wextra', '-Wpedantic',
|
||||||
'-fdiagnostics-color=always',
|
'-fdiagnostics-color=always',
|
||||||
@@ -342,11 +382,6 @@ def configure(conf):
|
|||||||
|
|
||||||
opt_cxxflags = [] # TODO:
|
opt_cxxflags = [] # TODO:
|
||||||
|
|
||||||
if conf.options.DISABLE_WERROR:
|
|
||||||
opt_flags = []
|
|
||||||
opt_cflags = ['-Werror=implicit-function-declaration']
|
|
||||||
opt_cxxflags = []
|
|
||||||
|
|
||||||
conf.env.CFLAGS_werror = conf.filter_cflags(opt_flags + opt_cflags, cflags)
|
conf.env.CFLAGS_werror = conf.filter_cflags(opt_flags + opt_cflags, cflags)
|
||||||
conf.env.CXXFLAGS_werror = conf.filter_cxxflags(opt_flags + opt_cxxflags, cxxflags)
|
conf.env.CXXFLAGS_werror = conf.filter_cxxflags(opt_flags + opt_cxxflags, cxxflags)
|
||||||
|
|
||||||
@@ -498,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
|
||||||
@@ -520,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