Compare commits

..

74 Commits

Author SHA1 Message Date
Alibek Omarov
5d9bc950ce wscript: do not load msvc manually, it will be loaded by compiler_{c,cxx} 2024-05-25 22:40:25 +03:00
Alibek Omarov
714da79395 mainui: update 2024-05-25 22:25:33 +03:00
Alibek Omarov
823fe9ebbd waf: upgrade to waf 2.1.1/waifu 1.3.0. Try to fix most optparse->argparse migration issues 2024-05-25 04:58:28 +03:00
Alibek Omarov
4bf72b5383 engine: forbid accessing cvars starting with con_ and scr_ through stufftext
Some stupid servers might mess up with console cvars values.
2024-05-25 02:26:42 +03:00
Alibek Omarov
51945f002b engine: server: check for invoker entity when filtering out host client during entities thinking 2024-05-23 02:06:54 +03:00
Alibek Omarov
bcca9387de engine: server: sv_pmove: always set FEV_NOTHOST for events coming from PMove (like GoldSrc) 2024-05-23 01:51:42 +03:00
Alibek Omarov
b8417fa46d ref: soft: search parent in both entity lists when drawing MOVETYPE_FOLLOW entities
Fixes the issue in Brutal Half-Life beta 2 with invisible scientist skin.

Fixes: 6862b14e59 ("ref: soft: only draw MOVETYPE_FOLLOW studio model if it's parent is visible")
2024-05-19 06:31:46 +03:00
Alibek Omarov
85b0699288 ref: gl: search parent in both entity lists when drawing MOVETYPE_FOLLOW entities
Fixes the issue in Brutal Half-Life beta 2 with invisible scientist skin.

Fixes: dc1d65f621 ("ref: gl: only draw MOVETYPE_FOLLOW studio model if it's parent is visible")
2024-05-19 06:29:22 +03:00
Alibek Omarov
6c03fb0226 engine: client: first attempt to use utflib to replace Con_UtfProcessCharForce calls 2024-05-15 05:25:53 +03:00
Alibek Omarov
a084dea07c public: add functions to convert from Unicode codepoints into CP1251 or CP1252 2024-05-15 05:07:18 +03:00
Alibek Omarov
2e0fc3e4c1 engine: client: do not repeatedly check cl_charset value, use generic Con_UtfProcessChar 2024-05-15 05:06:57 +03:00
Alibek Omarov
24f4d410ce filesystem: take FS_Read improvements from DarkPlaces and proper fix for buffer overflow 2024-05-15 03:43:02 +03:00
Alibek Omarov
052e0445ab engine: client: console: cleanup input buffer from line feed characters before pushing it to the console history 2024-05-15 03:08:22 +03:00
Alibek Omarov
758c908d5a public: add buffer size parameter to COM_RemoveLineFeed 2024-05-15 03:06:57 +03:00
Alibek Omarov
3917c2589d filesystem: fix buffer overflow in FS_Read when we pass single byte buffer to it with one character sitting in ungetc 2024-05-15 02:45:01 +03:00
Alibek Omarov
f4a77308ec engine: soundlib: fix possible buffer overflow in Sound_ConvertUpsample 2024-05-06 15:45:49 +03:00
Alibek Omarov
103b9724f9 scripts: waifulib: compiler_optimizations: fix linking OpenMP 2024-05-06 15:36:26 +03:00
Alibek Omarov
75a315ecf0 engine: client: add optional (compile time for now) setting to reconfigure engine to use 48kHz sounds 2024-05-06 15:10:34 +03:00
Alibek Omarov
63b3b9ef6d engine: client: fix missing upsampling for >32kHz sounds 2024-05-06 15:09:52 +03:00
Alibek Omarov
a6c2cfe89b engine: avoid constants in Q_strncpy third argument, where possible 2024-05-06 14:27:26 +03:00
Alibek Omarov
5120657386 engine: fix possible buffer overflow in S_StreamGetCurrentState 2024-05-06 06:53:22 +03:00
Alibek Omarov
e754de46d1 engine: client: fix buffer overflow in S_FindName 2024-05-06 06:42:47 +03:00
Alibek Omarov
5d718aa0d6 scripts: waifulib: compiler_optimizations: add flag for building with OpenMP (not used anywhere in the engine but let's keep it) 2024-05-06 06:42:15 +03:00
Alibek Omarov
55fcbc8880 engine: soundlib: implement linear interpolation in Sound_ResampleInternal
* split resampling into three functions
* added resampling using SDL_AudioCVT, it's slow, so isn't enabled by default
2024-05-06 06:41:23 +03:00
Alibek Omarov
e19aa001b2 engine: client: ref_common: slight refactoring, reorder ref_state_t 2024-05-06 01:59:50 +03:00
Alibek Omarov
b447ea9c18 engine: client: remove unused fields in client_static_t 2024-05-06 01:59:14 +03:00
Alibek Omarov
13274655d4 engine: client: sound: slight refactoring, removed unused s_listener.velocity 2024-05-06 01:30:06 +03:00
Alibek Omarov
3723ac60ef engine: client: s_mix: _inline -> static 2024-05-06 00:51:32 +03:00
Alibek Omarov
da578f47f1 engine: client: fix sounds being paused in menu and then blasted all at the same time in multiplayer 2024-05-06 00:41:38 +03:00
Alibek Omarov
433e7de686 engine: clean up unused soundlib flags, set SOUND_LOOPED flag on looped sounds 2024-05-05 06:16:57 +03:00
Alibek Omarov
e18e9ae2ea engine: platform: sdl: ignore keyboard events if text mode is active 2024-05-04 11:05:17 +03:00
Alibek Omarov
27d5123a61 mainui: update 2024-05-03 16:55:17 +03:00
Alibek Omarov
89b9f9ffe2 github: update SDL to 2.30.3 2024-05-03 16:04:13 +03:00
Alibek Omarov
a17b8aaa13 public: fix parameter name omitted error for older compilers 2024-05-03 16:01:24 +03:00
Alibek Omarov
e210969612 scripts: gha: build_linux: spew config.log on build failure 2024-05-03 15:57:26 +03:00
Alibek Omarov
1208356b92 ref: gl: gl2_shim: remove unused ALLOCA_H include 2024-05-03 15:53:57 +03:00
Alibek Omarov
d7cd74fe2f wscript: no need to pass PACKAGING into env 2024-05-03 15:45:20 +03:00
Alibek Omarov
31b63e9939 wscript: exclude executing large file test for PSVita 2024-05-03 15:44:35 +03:00
Alibek Omarov
b99c2c2df1 wscript: do not execute test for test for large files 2024-05-03 15:38:35 +03:00
Alibek Omarov
94d3eff9ce engine: host: fix build with Q_strchrnul returning const char * 2024-05-03 15:31:20 +03:00
Alibek Omarov
b78e9961c6 public: fix build on Windows
stristr doesn't exist actually
2024-05-03 15:30:42 +03:00
Alibek Omarov
b0704ca5d6 mainui: update 2024-05-03 06:38:21 +03:00
Alibek Omarov
31c0934108 engine: fix parsing -bugcomp flags, assume bugcomp flags only starts with alphabetic character 2024-05-03 06:28:48 +03:00
Alibek Omarov
37083c8aef ref: soft: mark sw_drawflat and sw_draworder as cheats 2024-05-01 00:52:45 +03:00
Alibek Omarov
af23b0c67b public: crtlib: refactoring with new macros, use system strlcpy/strlcat if possible 2024-04-30 02:20:14 +03:00
Alibek Omarov
a9e83fb9cf wscript: move std defining macros into libpublic's sdk_includes target, so we don't accidentally feed submodules our macros 2024-04-29 05:29:53 +03:00
Alibek Omarov
51126e1691 mainui: update 2024-04-29 05:28:41 +03:00
Alibek Omarov
dd410a2de5 engine: implement small Message Rewrite Facitility that allows to run mods that directly write internal GoldSrc messages 2024-04-28 06:59:18 +03:00
Alibek Omarov
7ccb0b5c02 public: make simple ctype functions inlined 2024-04-28 06:59:18 +03:00
Alibek Omarov
7f3e62e456 public: remove unneeded copy in Q_atov 2024-04-28 06:59:18 +03:00
Alibek Omarov
fcfc29d7ea public: fix variables types in COM_HashKey, they are all supposed to be unsigned integers 2024-04-28 06:59:18 +03:00
Alibek Omarov
2f3429a144 engine: common: base_cmd: use flexible array to store basecmd name 2024-04-28 06:59:18 +03:00
Alibek Omarov
20782693f4 engine: server: rename symbols for svs, sv and SV_DropClient to avoid AMXModX trying to acquire their pointers 2024-04-28 06:59:18 +03:00
Alibek Omarov
0cfb354374 common: add RENAME_SYMBOL macro that renames symbol for compatibility with nasty mods (also reformat this portion, while we're at it) 2024-04-28 06:59:18 +03:00
Alibek Omarov
9be5b7c6c9 engine: physint: empty-define ALLOC_CHECK if not defined by SDK, so this header can be freely moved to another SDK 2024-04-28 06:59:18 +03:00
Alibek Omarov
e7653d2ea6 engine: soundlib: fix searching for a RIFF/WAVE chunks in streams 2024-04-27 10:51:56 +03:00
Alibek Omarov
1494887e29 engine: soundlib: snd_wav: replace strncmp by IsFourCC helper function 2024-04-26 06:29:38 +03:00
Alibek Omarov
42dab2b1a5 engine: soundlib: snd_wav: attempt to fix misleading warning about truncated file 2024-04-26 06:25:18 +03:00
Alibek Omarov
36a0c1fb17 ref: if the entity is opaque, check the renderfx too, it might become translucent 2024-04-26 04:15:21 +03:00
Alibek Omarov
60c6767337 filesystem: copy absolute path to library in FS_FindLibrary for compatibility
Extend fullPath for longer absolute paths.
2024-04-22 04:02:46 +03:00
Alibek Omarov
75451cc7fa engine: client: print correct message names in legacymode 2024-04-22 04:02:46 +03:00
Alibek Omarov
db10035d9d engine: add GoldSrc protocol definitions 2024-04-22 04:02:46 +03:00
Alibek Omarov
de21d845ec engine: don't forget to put newline at the end of overflowed console message 2024-04-21 20:21:17 +03:00
Alibek Omarov
320f8466e6 engine: hpak: don't print error about missing custom.hpak in quiet mode 2024-04-21 20:05:37 +03:00
Alibek Omarov
f3208e95b2 engine: server: remove misleading message about interface version in case when GetEntityAPI2 has failed
Add message when GetEntityAPI was used instead
2024-04-21 20:05:34 +03:00
Alibek Omarov
ea34bc8652 engine: turn bugcomp into flags that can be enabled/disabled separately 2024-04-21 16:52:15 +03:00
Alibek Omarov
3daf014af8 wscript: always enable -Werror=implicit-function-declaration 2024-04-20 20:48:01 +03:00
Alibek Omarov
ca9d3d262a engine: common: net_encode: directly call MSG_ReadSBitLong for DT_TIMEWINDOW_*, don't do the multiplier check for DT_TIMEWINDOW_BIG 2024-04-20 20:48:01 +03:00
Alibek Omarov
a08f5e439d engine: common: net_encode: fix comparing DT_TIMEWINDOW_* fields
Fixes: 35783bcec2 ("engine: common: net_encode: fix inaccuracy in DT_TIMEWINDOW_* encoding")
2024-04-19 01:51:25 +03:00
Alibek Omarov
8f6771dff4 engine: common: zone: check that Mem_FindPool might return NULL (it can if Sys_Error was called inside of a Sys_Error) 2024-04-19 00:14:26 +03:00
Alibek Omarov
cd47c6b5b3 engine: common: zone: disallow migrating allocations from one pool to another, as this isn't practically used anywhere 2024-04-19 00:14:26 +03:00
Alibek Omarov
1f4f3d7fda engine: common: zone: remove mempool sentinels as pools aren't subject to buffer overflow or double free anymore 2024-04-19 00:14:26 +03:00
Alibek Omarov
e81b5144b3 engine: common: zone: use realloc for managing mem pools
rearrange data in memheader_s to avoid unnecessary paddings
2024-04-19 00:14:26 +03:00
Alibek Omarov
9ec1caed53 engine: common: zone: implement dummy Q_realloc for XASH_CUSTOM_SWAP 2024-04-19 00:14:26 +03:00
78 changed files with 1655 additions and 1059 deletions

View File

@@ -44,7 +44,7 @@ jobs:
targetos: win32
targetarch: i386
env:
SDL_VERSION: 2.28.5
SDL_VERSION: 2.30.3
GH_CPU_ARCH: ${{ matrix.targetarch }}
steps:
- name: Checkout

View File

@@ -1,17 +1,16 @@
# 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.
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
### Emulated bugs
* `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
| Flag | Description | Games that require this flag |
| ------- | ----------- | ---------------------------- |
| `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 |
| `gsmrf` | Rewrites message at the moment when Game DLL attempts to write an internal engine message, usually specific to GoldSrc protocol. Right now only supports `svc_spawnstaticsound`, more messages added by request. | * MetaMod/AMXModX based mods |

View File

@@ -28,11 +28,7 @@ typedef byte rgb_t[3]; // unsigned byte colorpack
typedef vec_t matrix3x4[3][4];
typedef vec_t matrix4x4[4][4];
#if XASH_64BIT
typedef uint32_t poolhandle_t;
#else
typedef void* poolhandle_t;
#endif
#undef true
#undef false
@@ -74,48 +70,48 @@ typedef uint64_t longtime_t;
#define IsColorString( p ) ( p && *( p ) == '^' && *(( p ) + 1) && *(( p ) + 1) >= '0' && *(( p ) + 1 ) <= '9' )
#define ColorIndex( c ) ((( c ) - '0' ) & 7 )
#if defined(__GNUC__)
#ifdef __i386__
#define EXPORT __attribute__ ((visibility ("default"),force_align_arg_pointer))
#define GAME_EXPORT __attribute((force_align_arg_pointer))
#if defined( __GNUC__ )
#if defined( __i386__ )
#define EXPORT __attribute__(( visibility( "default" ), force_align_arg_pointer ))
#define GAME_EXPORT __attribute(( force_align_arg_pointer ))
#else
#define EXPORT __attribute__ ((visibility ("default")))
#define EXPORT __attribute__(( visibility ( "default" )))
#define GAME_EXPORT
#endif
#define _format(x) __attribute__((format(printf, x, x+1)))
#define NORETURN __attribute__((noreturn))
#define NONNULL __attribute__((nonnull))
#define ALLOC_CHECK(x) __attribute__((alloc_size(x)))
#elif defined(_MSC_VER)
#define EXPORT __declspec( dllexport )
#define GAME_EXPORT
#define _format(x)
#define NORETURN
#define NONNULL
#define ALLOC_CHECK(x)
#define NORETURN __attribute__(( noreturn ))
#define NONNULL __attribute__(( nonnull ))
#define _format( x ) __attribute__(( format( printf, x, x + 1 )))
#define ALLOC_CHECK( x ) __attribute__(( alloc_size( x )))
#define RENAME_SYMBOL( x ) asm( x )
#else
#define EXPORT
#if defined( _MSC_VER )
#define EXPORT __declspec( dllexport )
#else
#define EXPORT
#endif
#define GAME_EXPORT
#define _format(x)
#define NORETURN
#define NONNULL
#define ALLOC_CHECK(x)
#define _format( x )
#define ALLOC_CHECK( x )
#define RENAME_SYMBOL( x )
#endif
#if ( __GNUC__ >= 3 )
#define unlikely(x) __builtin_expect(x, 0)
#define likely(x) __builtin_expect(x, 1)
#define unlikely( x ) __builtin_expect( x, 0 )
#define likely( x ) __builtin_expect( x, 1 )
#elif defined( __has_builtin )
#if __has_builtin( __builtin_expect )
#define unlikely(x) __builtin_expect(x, 0)
#define likely(x) __builtin_expect(x, 1)
#define unlikely( x ) __builtin_expect( x, 0 )
#define likely( x ) __builtin_expect( x, 1 )
#else
#define unlikely(x) (x)
#define likely(x) (x)
#define unlikely( x ) ( x )
#define likely( x ) ( x )
#endif
#else
#define unlikely(x) (x)
#define likely(x) (x)
#define unlikely( x ) ( x )
#define likely( x ) ( x )
#endif
#if __STDC_VERSION__ >= 202311L || __cplusplus >= 201103L // C23 or C++ static_assert is a keyword

View File

@@ -50,7 +50,15 @@ const char *CL_MsgInfo( int cmd )
if( cmd >= 0 && cmd <= svc_lastmsg )
{
// get engine message name
Q_strncpy( sz, svc_strings[cmd], sizeof( sz ));
const char *svc_string = NULL;
if( cls.legacymode )
svc_string = svc_legacy_strings[cmd];
if( !svc_string )
svc_string = svc_strings[cmd];
Q_strncpy( sz, svc_string, sizeof( sz ));
}
else if( cmd > svc_lastmsg && cmd <= ( svc_lastmsg + MAX_USER_MESSAGES ))
{

View File

@@ -192,7 +192,7 @@ void CL_RegisterEvent( int lastnum, const char *szEvName, pfnEventHook func )
ev = clgame.events[lastnum];
// NOTE: ev->index will be set later
Q_strncpy( ev->name, szEvName, MAX_QPATH );
Q_strncpy( ev->name, szEvName, sizeof( ev->name ));
ev->func = func;
}

View File

@@ -1877,8 +1877,12 @@ void CL_ParseHLTV( sizebuf_t *msg )
break;
case HLTV_LISTEN:
cls.signon = SIGNONS;
#if 1
MSG_ReadString( msg );
#else
NET_StringToAdr( MSG_ReadString( msg ), &cls.hltv_listen_address );
// NET_JoinGroup( cls.netchan.sock, cls.hltv_listen_address );
NET_JoinGroup( cls.netchan.sock, cls.hltv_listen_address );
#endif
SCR_EndLoadingPlaque();
break;
default:

View File

@@ -194,7 +194,7 @@ static void CL_LegacyPrecacheModel( sizebuf_t *msg )
if( modelIndex < 0 || modelIndex >= MAX_MODELS )
Host_Error( "CL_PrecacheModel: bad modelindex %i\n", modelIndex );
Q_strncpy( model, MSG_ReadString( msg ), MAX_STRING );
Q_strncpy( model, MSG_ReadString( msg ), sizeof( model ));
//Q_strncpy( cl.model_precache[modelIndex], BF_ReadString( msg ), sizeof( cl.model_precache[0] ));
// when we loading map all resources is precached sequentially
@@ -261,7 +261,7 @@ static void CL_LegacyParseResourceList( sizebuf_t *msg )
for( i = 0; i < reslist.rescount; i++ )
{
reslist.restype[i] = MSG_ReadWord( msg );
Q_strncpy( reslist.resnames[i], MSG_ReadString( msg ), MAX_QPATH );
Q_strncpy( reslist.resnames[i], MSG_ReadString( msg ), sizeof( reslist.resnames[i] ));
}
if( CL_IsPlaybackDemo() )

View File

@@ -853,7 +853,7 @@ static void CL_SetupPMove( playermove_t *pmove, const local_state_t *from, const
VectorCopy( cd->vuser4, pmove->vuser4 );
pmove->cmd = *ucmd; // copy current cmds
Q_strncpy( pmove->physinfo, cls.physinfo, MAX_INFO_STRING );
Q_strncpy( pmove->physinfo, cls.physinfo, sizeof( pmove->physinfo ));
}
static const void CL_FinishPMove( const playermove_t *pmove, local_state_t *to )

View File

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

View File

@@ -539,12 +539,8 @@ typedef struct
poolhandle_t mempool; // client premamnent pool: edicts etc
netadr_t hltv_listen_address;
int signon; // 0 to SIGNONS, for the signon sequence.
int quakePort; // a 16 bit value that allows quake servers
// to work around address translating routers
// g-cont. this port allow many copies of engine in multiplayer game
// connection information
char servername[MAX_QPATH]; // name of server from original connect
double connect_time; // for connection retransmits

View File

@@ -21,6 +21,7 @@ GNU General Public License for more details.
#include "qfont.h"
#include "wadfile.h"
#include "input.h"
#include "utflib.h"
static CVAR_DEFINE_AUTO( scr_conspeed, "600", FCVAR_ARCHIVE, "console moving speed" );
static CVAR_DEFINE_AUTO( con_notifytime, "3", FCVAR_ARCHIVE, "notify time to live" );
@@ -610,19 +611,6 @@ static void Con_LoadConchars( void )
con.curFont = &con.chars[fontSize];
}
// CP1251 table
int table_cp1251[64] = {
0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
0x007F, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457
};
/*
============================
Con_UtfProcessChar
@@ -632,83 +620,24 @@ Convert utf char to current font's single-byte encoding
*/
int Con_UtfProcessCharForce( int in )
{
static int m = -1, k = 0; //multibyte state
static int uc = 0; //unicode char
// TODO: get rid of global state where possible
static utfstate_t state = { 0 };
if( !in )
{
m = -1;
k = 0;
uc = 0;
return 0;
}
int ch = Q_DecodeUTF8( &state, in );
// Get character length
if(m == -1)
{
uc = 0;
if( in >= 0xF8 )
return 0;
else if( in >= 0xF0 )
uc = in & 0x07, m = 3;
else if( in >= 0xE0 )
uc = in & 0x0F, m = 2;
else if( in >= 0xC0 )
uc = in & 0x1F, m = 1;
else if( in <= 0x7F)
return in; //ascii
// return 0 if we need more chars to decode one
k=0;
return 0;
}
// get more chars
else if( k <= m )
{
uc <<= 6;
uc += in & 0x3F;
k++;
}
if( in > 0xBF || m < 0 )
{
m = -1;
return 0;
}
if( k == m )
{
k = m = -1;
if( g_codepage == 1251 )
{
// cp1251 now
if( uc >= 0x0410 && uc <= 0x042F )
return uc - 0x410 + 0xC0;
if( uc >= 0x0430 && uc <= 0x044F )
return uc - 0x430 + 0xE0;
else
{
int i;
for( i = 0; i < 64; i++ )
if( table_cp1251[i] == uc )
return i + 0x80;
}
}
else if( g_codepage == 1252 )
{
if( uc < 255 )
return uc;
}
if( g_codepage == 1251 )
return Q_UnicodeToCP1251( ch );
if( g_codepage == 1252 )
return Q_UnicodeToCP1252( ch );
// not implemented yet
return '?';
}
return 0;
return '?'; // not implemented yet
}
int GAME_EXPORT Con_UtfProcessChar( int in )
{
if( !g_utf8 )
return in;
else
return Con_UtfProcessCharForce( in );
return Con_UtfProcessCharForce( in );
}
/*
=================
@@ -719,16 +648,22 @@ get position of previous printful char
*/
int Con_UtfMoveLeft( char *str, int pos )
{
int i, k = 0;
// int j;
utfstate_t state = { 0 };
int k = 0;
int i;
if( !g_utf8 )
return pos - 1;
Con_UtfProcessChar( 0 );
if(pos == 1) return 0;
for( i = 0; i < pos-1; i++ )
if( Con_UtfProcessChar( (unsigned char)str[i] ) )
k = i+1;
Con_UtfProcessChar( 0 );
if( pos == 1 )
return 0;
for( i = 0; i < pos - 1; i++ )
{
if( Q_DecodeUTF8( &state, (byte)str[i] ))
k = i + 1;
}
return k;
}
@@ -741,17 +676,19 @@ get next of previous printful char
*/
int Con_UtfMoveRight( char *str, int pos, int length )
{
utfstate_t state = { 0 };
int i;
if( !g_utf8 )
return pos + 1;
Con_UtfProcessChar( 0 );
for( i = pos; i <= length; i++ )
{
if( Con_UtfProcessChar( (unsigned char)str[i] ) )
return i+1;
if( Q_DecodeUTF8( &state, (byte)str[i] ))
return i + 1;
}
Con_UtfProcessChar( 0 );
return pos+1;
return pos + 1;
}
static void Con_DrawCharToConback( int num, const byte *conchars, byte *dest )
@@ -1138,7 +1075,7 @@ Field_Set
static void Field_Set( field_t *f, const char *string )
{
f->scroll = 0;
f->cursor = Q_strncpy( f->buffer, string, MAX_STRING );
f->cursor = Q_strncpy( f->buffer, string, sizeof( f->buffer ));
}
/*
@@ -1549,6 +1486,9 @@ void Key_Console( int key )
Con_Printf( ">%s\n", con.input.buffer );
// copy line to history buffer
// just in case, remove all CR and LF characters pushing it to the history
// not sure how they get even added in the first place
COM_RemoveLineFeed( con.input.buffer, sizeof( con.input.buffer ));
Con_HistoryAppend( &con.history, &con.input );
Con_ClearField( &con.input );

View File

@@ -1055,10 +1055,7 @@ static qboolean OSK_KeyEvent( int key, int down )
break;
}
if( !Q_stricmp( cl_charset.string, "utf-8" ) )
ch = (unsigned char)osk.curbutton.val;
else
ch = Con_UtfProcessCharForce( (unsigned char)osk.curbutton.val );
ch = Con_UtfProcessChar((byte)osk.curbutton.val );
if( !ch )
break;

View File

@@ -18,19 +18,18 @@ GNU General Public License for more details.
#include "ref_api.h"
#define RP_LOCALCLIENT( e ) ((e) != NULL && (e)->index == ( cl.playernum + 1 ) && e->player )
#define RP_LOCALCLIENT( e ) ((e) != NULL && (e)->index == ( cl.playernum + 1 ) && e->player )
struct ref_state_s
{
qboolean initialized;
HINSTANCE hInstance;
HINSTANCE hInstance;
qboolean initialized;
int numRenderers;
ref_interface_t dllFuncs;
// depends on build configuration
int numRenderers;
const char **shortNames;
const char **readableNames;
const char **shortNames;
const char **readableNames;
};
extern struct ref_state_s ref;
@@ -46,8 +45,8 @@ void R_GetTextureParms( int *w, int *h, int texnum );
void GL_RenderFrame( const struct ref_viewpass_s *rvp );
// common engine and renderer cvars
extern convar_t r_decals;
extern convar_t r_adjust_fov;
extern convar_t r_decals;
extern convar_t r_adjust_fov;
extern convar_t gl_clear;
qboolean R_Init( void );

View File

@@ -52,8 +52,11 @@ void S_SoundList_f( void )
{
totalSize += sc->size;
if( sc->loopStart >= 0 ) Con_Printf( "L" );
else Con_Printf( " " );
if( FBitSet( sc->flags, SOUND_LOOPED ))
Con_Printf( "L" );
else
Con_Printf( " " );
if( sfx->name[0] == '*' || !Q_strncmp( sfx->name, DEFAULT_SOUNDPATH, sizeof( DEFAULT_SOUNDPATH ) - 1 ))
Con_Printf( " (%2db) %s : %s\n", sc->width * 8, Q_memprint( sc->size ), sfx->name );
else Con_Printf( " (%2db) %s : " DEFAULT_SOUNDPATH "%s\n", sc->width * 8, Q_memprint( sc->size ), sfx->name );
@@ -110,7 +113,7 @@ static wavdata_t *S_CreateDefaultSound( void )
sc->width = 2;
sc->channels = 1;
sc->loopStart = -1;
sc->loopStart = 0;
sc->rate = SOUND_DMA_SPEED;
sc->samples = SOUND_DMA_SPEED;
sc->size = sc->samples * sc->width * sc->channels;
@@ -155,7 +158,7 @@ wavdata_t *S_LoadSound( sfx_t *sfx )
Sound_Process( &sc, SOUND_11k, sc->width, SOUND_RESAMPLE );
else if( sc->rate > SOUND_11k && sc->rate < SOUND_22k ) // some bad sounds
Sound_Process( &sc, SOUND_22k, sc->width, SOUND_RESAMPLE );
else if( sc->rate > SOUND_22k && sc->rate <= SOUND_32k ) // some bad sounds
else if( sc->rate > SOUND_22k && sc->rate < SOUND_44k ) // some bad sounds
Sound_Process( &sc, SOUND_44k, sc->width, SOUND_RESAMPLE );
sfx->cache = sc;
@@ -218,7 +221,7 @@ sfx_t *S_FindName( const char *pname, int *pfInCache )
sfx = &s_knownSfx[i];
memset( sfx, 0, sizeof( *sfx ));
if( pfInCache ) *pfInCache = false;
Q_strncpy( sfx->name, name, MAX_STRING );
Q_strncpy( sfx->name, name, sizeof( sfx->name ));
sfx->servercount = cl.servercount;
sfx->hashValue = COM_HashKey( sfx->name, MAX_SFX_HASH );
@@ -377,7 +380,7 @@ S_InitSounds
void S_InitSounds( void )
{
// create unused 0-entry
Q_strncpy( s_knownSfx->name, "*default", MAX_QPATH );
Q_strncpy( s_knownSfx->name, "*default", sizeof( s_knownSfx->name ));
s_knownSfx->hashValue = COM_HashKey( s_knownSfx->name, MAX_SFX_HASH );
s_knownSfx->hashNext = s_sfxHashList[s_knownSfx->hashValue];
s_sfxHashList[s_knownSfx->hashValue] = s_knownSfx;

View File

@@ -70,6 +70,12 @@ float S_GetMasterVolume( void )
return 0.0f;
}
if( s_listener.inmenu && !ui_renderworld.value && !Host_IsLocalGame( ))
{
// mute sounds in menu when it's not transparent and we're in multiplayer
return 0.0f;
}
if( !s_listener.inmenu && soundfade.percent != 0 )
{
scale = bound( 0.0f, soundfade.percent / 100.0f, 1.0f );
@@ -328,7 +334,7 @@ channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx, qboolean
// don't restart looping sounds for the same entity
wavdata_t *sc = channels[first_to_die].sfx->cache;
if( sc && sc->loopStart != -1 )
if( sc && FBitSet( sc->flags, SOUND_LOOPED ))
{
channel_t *ch = &channels[first_to_die];
@@ -503,7 +509,7 @@ static void SND_Spatialize( channel_t *ch )
pSource = ch->sfx->cache;
if( ch->use_loop && pSource && pSource->loopStart != -1 )
if( ch->use_loop && pSource && FBitSet( pSource->flags, SOUND_LOOPED ))
looping = true;
if( !ch->staticsound )
@@ -641,7 +647,7 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv
if( !target_chan->leftvol && !target_chan->rightvol )
{
// looping sounds don't use this optimization because they should stick around until they're killed.
if( !sfx->cache || sfx->cache->loopStart == -1 )
if( !sfx->cache || !FBitSet( sfx->cache->flags, SOUND_LOOPED ))
{
// if this is a streaming sound, play the whole thing.
if( chan != CHAN_STREAM )
@@ -893,7 +899,7 @@ int S_GetCurrentStaticSounds( soundlist_t *pout, int size )
VectorCopy( channels[i].origin, pout->origin );
pout->volume = (float)channels[i].master_vol / 255.0f;
pout->attenuation = channels[i].dist_mult * SND_CLIP_DISTANCE;
pout->looping = ( channels[i].use_loop && channels[i].sfx->cache->loopStart != -1 );
pout->looping = ( channels[i].use_loop && FBitSet( channels[i].sfx->cache->flags, SOUND_LOOPED ));
pout->pitch = channels[i].basePitch;
pout->channel = channels[i].entchannel;
pout->wordIndex = channels[i].wordIndex;
@@ -928,7 +934,7 @@ int S_GetCurrentDynamicSounds( soundlist_t *pout, int size )
if( !channels[i].sfx || !channels[i].sfx->name[0] || !Q_stricmp( channels[i].sfx->name, "*default" ))
continue; // don't serialize default sounds
looped = ( channels[i].use_loop && channels[i].sfx->cache->loopStart != -1 );
looped = ( channels[i].use_loop && FBitSet( channels[i].sfx->cache->flags, SOUND_LOOPED ));
if( channels[i].entchannel == CHAN_STATIC && looped && !Host_IsQuakeCompatible())
continue; // never serialize static looped sounds. It will be restoring in game code
@@ -1599,7 +1605,6 @@ void SND_UpdateSound( void )
// release raw-channels that no longer used more than 10 secs
S_FreeIdleRawChannels();
VectorCopy( cl.simvel, s_listener.velocity );
s_listener.frametime = (cl.time - cl.oldtime);
s_listener.waterlevel = cl.local.waterlevel;
s_listener.active = CL_IsInGame();

View File

@@ -17,30 +17,56 @@ GNU General Public License for more details.
#include "sound.h"
#include "client.h"
#define IPAINTBUFFER 0
#define IROOMBUFFER 1
#define ISTREAMBUFFER 2
enum
{
IPAINTBUFFER = 0,
IROOMBUFFER,
ISTREAMBUFFER,
CPAINTBUFFERS,
};
#define FILTERTYPE_NONE 0
#define FILTERTYPE_LINEAR 1
#define FILTERTYPE_CUBIC 2
enum
{
FILTERTYPE_NONE = 0,
FILTERTYPE_LINEAR,
FILTERTYPE_CUBIC,
};
#define CCHANVOLUMES 2
#define SND_SCALE_BITS 7
#define SND_SCALE_SHIFT (8 - SND_SCALE_BITS)
#define SND_SCALE_LEVELS (1 << SND_SCALE_BITS)
#define SND_SCALE_BITS 7
#define SND_SCALE_SHIFT ( 8 - SND_SCALE_BITS )
#define SND_SCALE_LEVELS ( 1 << SND_SCALE_BITS )
portable_samplepair_t *g_curpaintbuffer;
portable_samplepair_t streambuffer[(PAINTBUFFER_SIZE+1)];
portable_samplepair_t paintbuffer[(PAINTBUFFER_SIZE+1)];
portable_samplepair_t roombuffer[(PAINTBUFFER_SIZE+1)];
portable_samplepair_t facingbuffer[(PAINTBUFFER_SIZE+1)];
portable_samplepair_t temppaintbuffer[(PAINTBUFFER_SIZE+1)];
paintbuffer_t paintbuffers[CPAINTBUFFERS];
// sound mixing buffer
#define CPAINTFILTERMEM 3
#define CPAINTFILTERS 4 // maximum number of consecutive upsample passes per paintbuffer
int snd_scaletable[SND_SCALE_LEVELS][256];
// fixed point stuff for real-time resampling
#define FIX_BITS 28
#define FIX_SCALE ( 1 << FIX_BITS )
#define FIX_MASK (( 1 << FIX_BITS ) - 1 )
#define FIX_FLOAT( a ) ((int)(( a ) * FIX_SCALE ))
#define FIX( a ) (((int)( a )) << FIX_BITS )
#define FIX_INTPART( a ) (((int)( a )) >> FIX_BITS )
#define FIX_FRACPART( a ) (( a ) & FIX_MASK )
typedef struct
{
qboolean factive; // if true, mix to this paintbuffer using flags
portable_samplepair_t *pbuf; // front stereo mix buffer, for 2 or 4 channel mixing
int ifilter; // current filter memory buffer to use for upsampling pass
portable_samplepair_t fltmem[CPAINTFILTERS][CPAINTFILTERMEM];
} paintbuffer_t;
static portable_samplepair_t *g_curpaintbuffer;
static portable_samplepair_t streambuffer[(PAINTBUFFER_SIZE+1)];
static portable_samplepair_t paintbuffer[(PAINTBUFFER_SIZE+1)];
static portable_samplepair_t roombuffer[(PAINTBUFFER_SIZE+1)];
static portable_samplepair_t temppaintbuffer[(PAINTBUFFER_SIZE+1)];
static paintbuffer_t paintbuffers[CPAINTBUFFERS];
static int snd_scaletable[SND_SCALE_LEVELS][256];
void S_InitScaletable( void )
{
int i, j;
@@ -67,7 +93,7 @@ static void S_TransferPaintBuffer( int endtime )
dword *pbuf;
pbuf = (dword *)dma.buffer;
snd_p = (int *)PAINTBUFFER;
snd_p = (int *)g_curpaintbuffer;
lpaintedtime = paintedtime;
sampleMask = ((dma.samples >> 1) - 1);
@@ -111,20 +137,20 @@ static void S_TransferPaintBuffer( int endtime )
//===============================================================================
// Activate a paintbuffer. All active paintbuffers are mixed in parallel within
// MIX_MixChannelsToPaintbuffer, according to flags
_inline void MIX_ActivatePaintbuffer( int ipaintbuffer )
static void MIX_ActivatePaintbuffer( int ipaintbuffer )
{
Assert( ipaintbuffer < CPAINTBUFFERS );
paintbuffers[ipaintbuffer].factive = true;
}
_inline void MIX_SetCurrentPaintbuffer( int ipaintbuffer )
static void MIX_SetCurrentPaintbuffer( int ipaintbuffer )
{
Assert( ipaintbuffer < CPAINTBUFFERS );
g_curpaintbuffer = paintbuffers[ipaintbuffer].pbuf;
Assert( g_curpaintbuffer != NULL );
}
_inline int MIX_GetCurrentPaintbufferIndex( void )
static int MIX_GetCurrentPaintbufferIndex( void )
{
int i;
@@ -136,7 +162,7 @@ _inline int MIX_GetCurrentPaintbufferIndex( void )
return 0;
}
_inline paintbuffer_t *MIX_GetCurrentPaintbufferPtr( void )
static paintbuffer_t *MIX_GetCurrentPaintbufferPtr( void )
{
int ipaint = MIX_GetCurrentPaintbufferIndex();
@@ -145,7 +171,7 @@ _inline paintbuffer_t *MIX_GetCurrentPaintbufferPtr( void )
}
// Don't mix into any paintbuffers
_inline void MIX_DeactivateAllPaintbuffers( void )
static void MIX_DeactivateAllPaintbuffers( void )
{
int i;
@@ -154,7 +180,7 @@ _inline void MIX_DeactivateAllPaintbuffers( void )
}
// set upsampling filter indexes back to 0
_inline void MIX_ResetPaintbufferFilterCounters( void )
static void MIX_ResetPaintbufferFilterCounters( void )
{
int i;
@@ -163,13 +189,13 @@ _inline void MIX_ResetPaintbufferFilterCounters( void )
}
// return pointer to front paintbuffer pbuf, given index
_inline portable_samplepair_t *MIX_GetPFrontFromIPaint( int ipaintbuffer )
static portable_samplepair_t *MIX_GetPFrontFromIPaint( int ipaintbuffer )
{
Assert( ipaintbuffer < CPAINTBUFFERS );
return paintbuffers[ipaintbuffer].pbuf;
}
_inline paintbuffer_t *MIX_GetPPaintFromIPaint( int ipaint )
static paintbuffer_t *MIX_GetPPaintFromIPaint( int ipaint )
{
Assert( ipaint < CPAINTBUFFERS );
return &paintbuffers[ipaint];
@@ -523,6 +549,7 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
wavdata_t *pSource;
int i, sampleCount;
qboolean bZeroVolume;
qboolean local = Host_IsLocalGame();
// mix each channel into paintbuffer
ch = channels;
@@ -549,7 +576,7 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
{
// play, playvol
}
else if(( s_listener.inmenu || s_listener.paused ) && !ch->localsound )
else if(( s_listener.inmenu || s_listener.paused ) && !ch->localsound && local )
{
// play only local sounds, keep pause for other
continue;
@@ -567,6 +594,7 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
// Don't mix sound data for sounds with zero volume. If it's a non-looping sound,
// just remove the sound when its volume goes to zero.
bZeroVolume = !ch->leftvol && !ch->rightvol;
if( !bZeroVolume )
@@ -576,7 +604,7 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
bZeroVolume = true;
}
if( !pSource || ( bZeroVolume && pSource->loopStart == -1 ))
if( !pSource || ( bZeroVolume && !FBitSet( pSource->flags, SOUND_LOOPED )))
{
if( !pSource )
{
@@ -629,7 +657,7 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
}
// pass in index -1...count+2, return pointer to source sample in either paintbuffer or delay buffer
_inline portable_samplepair_t *S_GetNextpFilter( int i, portable_samplepair_t *pbuffer, portable_samplepair_t *pfiltermem )
static portable_samplepair_t *S_GetNextpFilter( int i, portable_samplepair_t *pbuffer, portable_samplepair_t *pfiltermem )
{
// The delay buffer is assumed to precede the paintbuffer by 6 duplicated samples
if( i == -1 ) return (&(pfiltermem[0]));
@@ -838,6 +866,14 @@ static void MIX_MixPaintbuffers( int ibuf1, int ibuf2, int ibuf3, int count, flo
pbuf2 = paintbuffers[ibuf2].pbuf;
pbuf3 = paintbuffers[ibuf3].pbuf;
if( !gain )
{
// do not mix buf2 into buf3, just copy
if( pbuf1 != pbuf3 )
memcpy( pbuf3, pbuf1, sizeof( *pbuf1 ) * count );
return;
}
// destination buffer stereo - average n chans down to stereo
// destination 2ch:

View File

@@ -142,7 +142,7 @@ S_StreamGetCurrentState
save\restore code
=================
*/
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position )
qboolean S_StreamGetCurrentState( char *currentTrack, size_t currentTrackSize, char *loopTrack, size_t loopTrackSize, int *position )
{
if( !s_bgTrack.stream )
return false; // not active
@@ -150,15 +150,15 @@ qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *posi
if( currentTrack )
{
if( s_bgTrack.current[0] )
Q_strncpy( currentTrack, s_bgTrack.current, MAX_STRING );
else Q_strncpy( currentTrack, "*", MAX_STRING ); // no track
Q_strncpy( currentTrack, s_bgTrack.current, currentTrackSize );
else Q_strncpy( currentTrack, "*", currentTrackSize ); // no track
}
if( loopTrack )
{
if( s_bgTrack.loopName[0] )
Q_strncpy( loopTrack, s_bgTrack.loopName, MAX_STRING );
else Q_strncpy( loopTrack, "*", MAX_STRING ); // no track
Q_strncpy( loopTrack, s_bgTrack.loopName, loopTrackSize );
else Q_strncpy( loopTrack, "*", loopTrackSize ); // no track
}
if( position )

View File

@@ -27,7 +27,7 @@ int S_ConvertLoopedPosition( wavdata_t *pSource, int samplePosition, qboolean us
// convert to a position within the loop
// At the end of the loop, we return a short buffer, and subsequent call
// will loop back and get the rest of the buffer
if( pSource->loopStart >= 0 && samplePosition >= pSource->samples && use_loop )
if( FBitSet( pSource->flags, SOUND_LOOPED ) && samplePosition >= pSource->samples && use_loop )
{
// size of loop
int loopSize = pSource->samples - pSource->loopStart;

View File

@@ -20,206 +20,178 @@ extern poolhandle_t sndpool;
#include "xash3d_mathlib.h"
// sound engine rate defines
#define SOUND_DMA_SPEED 44100 // hardware playback rate
#define SOUND_11k 11025 // 11khz sample rate
#define SOUND_16k 16000 // 16khz sample rate
#define SOUND_22k 22050 // 22khz sample rate
#define SOUND_32k 32000 // 32khz sample rate
#define SOUND_44k 44100 // 44khz sample rate
#define DMA_MSEC_PER_SAMPLE ((float)(1000.0 / SOUND_DMA_SPEED))
#define XASH_AUDIO_CD_QUALITY 1 // some platforms might need this
// fixed point stuff for real-time resampling
#define FIX_BITS 28
#define FIX_SCALE (1 << FIX_BITS)
#define FIX_MASK ((1 << FIX_BITS)-1)
#define FIX_FLOAT(a) ((int)((a) * FIX_SCALE))
#define FIX(a) (((int)(a)) << FIX_BITS)
#define FIX_INTPART(a) (((int)(a)) >> FIX_BITS)
#define FIX_FRACTION(a,b) (FIX(a)/(b))
#define FIX_FRACPART(a) ((a) & FIX_MASK)
// sound engine rate defines
#if XASH_AUDIO_CD_QUALITY
#define SOUND_11k 11025 // 11khz sample rate
#define SOUND_22k 22050 // 22khz sample rate
#define SOUND_44k 44100 // 44khz sample rate
#else // XASH_AUDIO_CD_QUALITY
#define SOUND_11k 12000 // 11khz sample rate
#define SOUND_22k 24000 // 22khz sample rate
#define SOUND_44k 48000 // 44khz sample rate
#endif // XASH_AUDIO_CD_QUALITY
#define SOUND_DMA_SPEED SOUND_44k // hardware playback rate
// NOTE: clipped sound at 32760 to avoid overload
#define CLIP( x ) (( x ) > 32760 ? 32760 : (( x ) < -32760 ? -32760 : ( x )))
#define CLIP( x ) (( x ) > 32760 ? 32760 : (( x ) < -32760 ? -32760 : ( x )))
#define PAINTBUFFER_SIZE 1024 // 44k: was 512
#define PAINTBUFFER (g_curpaintbuffer)
#define CPAINTBUFFERS 3
#define PAINTBUFFER_SIZE 1024 // 44k: was 512
// sound mixing buffer
#define CPAINTFILTERMEM 3
#define CPAINTFILTERS 4 // maximum number of consecutive upsample passes per paintbuffer
#define S_RAW_SOUND_IDLE_SEC 10 // time interval for idling raw sound before it's freed
#define S_RAW_SOUND_BACKGROUNDTRACK -2
#define S_RAW_SOUND_SOUNDTRACK -1
#define S_RAW_SAMPLES_PRECISION_BITS 14
#define CIN_FRAMETIME (1.0f / 30.0f)
#define S_RAW_SOUND_IDLE_SEC 10 // time interval for idling raw sound before it's freed
#define S_RAW_SOUND_BACKGROUNDTRACK -2
#define S_RAW_SOUND_SOUNDTRACK -1
#define S_RAW_SAMPLES_PRECISION_BITS 14
typedef struct
{
int left;
int right;
int left;
int right;
} portable_samplepair_t;
typedef struct
{
qboolean factive; // if true, mix to this paintbuffer using flags
portable_samplepair_t *pbuf; // front stereo mix buffer, for 2 or 4 channel mixing
int ifilter; // current filter memory buffer to use for upsampling pass
portable_samplepair_t fltmem[CPAINTFILTERS][CPAINTFILTERMEM];
} paintbuffer_t;
typedef struct sfx_s
{
char name[MAX_QPATH];
wavdata_t *cache;
char name[MAX_QPATH];
wavdata_t *cache;
int servercount;
uint hashValue;
struct sfx_s *hashNext;
int servercount;
uint hashValue;
struct sfx_s *hashNext;
} sfx_t;
extern portable_samplepair_t paintbuffer[];
extern portable_samplepair_t roombuffer[];
extern portable_samplepair_t temppaintbuffer[];
extern portable_samplepair_t *g_curpaintbuffer;
extern paintbuffer_t paintbuffers[];
// structure used for fading in and out client sound volume.
typedef struct
{
float initial_percent;
float percent; // how far to adjust client's volume down by.
float starttime; // GetHostTime() when we started adjusting volume
float fadeouttime; // # of seconds to get to faded out state
float holdtime; // # of seconds to hold
float fadeintime; // # of seconds to restore
float initial_percent;
float percent; // how far to adjust client's volume down by.
float starttime; // GetHostTime() when we started adjusting volume
float fadeouttime; // # of seconds to get to faded out state
float holdtime; // # of seconds to hold
float fadeintime; // # of seconds to restore
} soundfade_t;
typedef struct
{
float percent;
float percent;
} musicfade_t;
typedef struct snd_format_s
{
unsigned int speed;
unsigned int width;
unsigned int channels;
uint speed;
byte width;
byte channels;
} snd_format_t;
typedef struct
{
snd_format_t format;
int samples; // mono samples in buffer
int samplepos; // in mono samples
byte *buffer;
qboolean initialized; // sound engine is active
const char *backendName;
snd_format_t format;
int samples; // mono samples in buffer
int samplepos; // in mono samples
qboolean initialized; // sound engine is active
byte *buffer;
const char *backendName;
} dma_t;
#include "vox.h"
typedef struct
{
double sample;
wavdata_t *pData;
double forcedEndSample;
qboolean finished;
double sample;
wavdata_t *pData;
double forcedEndSample;
qboolean finished;
} mixer_t;
typedef struct rawchan_s
{
int entnum;
int master_vol;
int leftvol; // 0-255 left volume
int rightvol; // 0-255 right volume
float dist_mult; // distance multiplier (attenuation/clipK)
vec3_t origin; // only use if fixed_origin is set
volatile uint s_rawend;
wavdata_t sound_info; // advance play position
float oldtime; // catch time jumps
size_t max_samples; // buffer length
portable_samplepair_t rawsamples[1]; // variable sized
int entnum;
int master_vol;
int leftvol; // 0-255 left volume
int rightvol; // 0-255 right volume
float dist_mult; // distance multiplier (attenuation/clipK)
vec3_t origin; // only use if fixed_origin is set
volatile uint s_rawend;
float oldtime; // catch time jumps
wavdata_t sound_info; // advance play position
size_t max_samples; // buffer length
portable_samplepair_t rawsamples[1]; // variable sized
} rawchan_t;
typedef struct channel_s
{
char name[16]; // keept sentence name
sfx_t *sfx; // sfx number
char name[16]; // keep sentence name
sfx_t *sfx; // sfx number
int leftvol; // 0-255 left volume
int rightvol; // 0-255 right volume
int leftvol; // 0-255 left volume
int rightvol; // 0-255 right volume
int entnum; // entity soundsource
int entchannel; // sound channel (CHAN_STREAM, CHAN_VOICE, etc.)
vec3_t origin; // only use if fixed_origin is set
float dist_mult; // distance multiplier (attenuation/clipK)
int master_vol; // 0-255 master volume
qboolean isSentence; // bit who indicated sentence
int basePitch; // base pitch percent (100% is normal pitch playback)
float pitch; // real-time pitch after any modulation or shift by dynamic data
qboolean use_loop; // don't loop default and local sounds
qboolean staticsound; // use origin instead of fetching entnum's origin
qboolean localsound; // it's a local menu sound (not looped, not paused)
mixer_t pMixer;
int entnum; // entity soundsource
int entchannel; // sound channel (CHAN_STREAM, CHAN_VOICE, etc.)
vec3_t origin; // only use if fixed_origin is set
float dist_mult; // distance multiplier (attenuation/clipK)
int master_vol; // 0-255 master volume
int basePitch; // base pitch percent (100% is normal pitch playback)
float pitch; // real-time pitch after any modulation or shift by dynamic data
qboolean use_loop; // don't loop default and local sounds
qboolean staticsound; // use origin instead of fetching entnum's origin
qboolean localsound; // it's a local menu sound (not looped, not paused)
mixer_t pMixer;
// sentence mixer
int wordIndex;
mixer_t *currentWord; // NULL if sentence is finished
voxword_t words[CVOXWORDMAX];
qboolean isSentence; // bit indicating sentence
int wordIndex;
mixer_t *currentWord; // NULL if sentence is finished
voxword_t words[CVOXWORDMAX];
} channel_t;
typedef struct
{
vec3_t origin; // simorg + view_ofs
vec3_t velocity;
vec3_t forward;
vec3_t right;
vec3_t up;
vec3_t origin; // simorg + view_ofs
vec3_t forward;
vec3_t right;
vec3_t up;
int entnum;
int waterlevel;
float frametime; // used for sound fade
qboolean active;
qboolean inmenu; // listener in-menu ?
qboolean paused;
qboolean streaming; // playing AVI-file
qboolean stream_paused; // pause only background track
int entnum;
int waterlevel;
float frametime; // used for sound fade
qboolean active;
qboolean inmenu; // listener in-menu ?
qboolean paused;
qboolean streaming; // playing AVI-file
qboolean stream_paused; // pause only background track
} listener_t;
typedef struct
{
string current; // a currently playing track
string loopName; // may be empty
stream_t *stream;
int source; // may be game, menu, etc
string current; // a currently playing track
string loopName; // may be empty
stream_t *stream;
int source; // may be game, menu, etc
} bg_track_t;
//====================================================================
#define MAX_DYNAMIC_CHANNELS (60 + NUM_AMBIENTS)
#define MAX_CHANNELS (256 + MAX_DYNAMIC_CHANNELS) // Scourge Of Armagon has too many static sounds on hip2m4.bsp
#define MAX_RAW_CHANNELS 48
#define MAX_RAW_SAMPLES 8192
#define MAX_DYNAMIC_CHANNELS (60 + NUM_AMBIENTS)
#define MAX_CHANNELS (256 + MAX_DYNAMIC_CHANNELS) // Scourge Of Armagon has too many static sounds on hip2m4.bsp
#define MAX_RAW_CHANNELS 48
#define MAX_RAW_SAMPLES 8192
extern sound_t ambient_sfx[NUM_AMBIENTS];
extern qboolean snd_ambient;
extern channel_t channels[MAX_CHANNELS];
extern rawchan_t *raw_channels[MAX_RAW_CHANNELS];
extern int total_channels;
extern int paintedtime;
extern int soundtime;
extern listener_t s_listener;
extern int idsp_room;
extern dma_t dma;
extern sound_t ambient_sfx[NUM_AMBIENTS];
extern qboolean snd_ambient;
extern channel_t channels[MAX_CHANNELS];
extern rawchan_t *raw_channels[MAX_RAW_CHANNELS];
extern int total_channels;
extern int paintedtime;
extern int soundtime;
extern listener_t s_listener;
extern int idsp_room;
extern dma_t dma;
extern convar_t s_musicvolume;
extern convar_t s_lerping;
extern convar_t s_test; // cvar to testify new effects
extern convar_t s_musicvolume;
extern convar_t s_lerping;
extern convar_t s_test; // cvar to test new effects
extern convar_t s_samplecount;
extern convar_t s_warn_late_precache;
@@ -292,7 +264,6 @@ void SND_ForceCloseMouth( int entnum );
//
void S_StreamSoundTrack( void );
void S_StreamBackgroundTrack( void );
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position );
void S_PrintBackgroundTrackState( void );
void S_FadeMusicVolume( float fadePercent );

View File

@@ -31,7 +31,7 @@ typedef struct OpusCustomMode OpusCustomMode;
#define VOICE_PCM_CHANNELS 1 // always mono
// never change these parameters when using opuscustom
#define VOICE_OPUS_CUSTOM_SAMPLERATE SOUND_44k
#define VOICE_OPUS_CUSTOM_SAMPLERATE 44100
// must follow opus custom requirements
// also be divisible with MAX_RAW_SAMPLES
#define VOICE_OPUS_CUSTOM_FRAME_SIZE 1024

View File

@@ -16,21 +16,20 @@ GNU General Public License for more details.
#ifndef VOX_H
#define VOX_H
#define CVOXWORDMAX 64
#define SENTENCE_INDEX -99999 // unique sentence index
#define CVOXWORDMAX 64
#define SENTENCE_INDEX -99999 // unique sentence index
typedef struct voxword_s
{
int volume; // increase percent, ie: 125 = 125% increase
int pitch; // pitch shift up percent
int start; // offset start of wave percent
int end; // offset end of wave percent
int cbtrim; // end of wave after being trimmed to 'end'
int fKeepCached; // 1 if this word was already in cache before sentence referenced it
int samplefrac; // if pitch shifting, this is position into wav * 256
int timecompress; // % of wave to skip during playback (causes no pitch shift)
sfx_t *sfx; // name and cache pointer
int volume; // increase percent, ie: 125 = 125% increase
int pitch; // pitch shift up percent
int start; // offset start of wave percent
int end; // offset end of wave percent
int cbtrim; // end of wave after being trimmed to 'end'
int fKeepCached; // 1 if this word was already in cache before sentence referenced it
int samplefrac; // if pitch shifting, this is position into wav * 256
int timecompress; // % of wave to skip during playback (causes no pitch shift)
sfx_t *sfx; // name and cache pointer
} voxword_t;
struct channel_s;

View File

@@ -19,13 +19,15 @@ GNU General Public License for more details.
#define HASH_SIZE 128 // 128 * 4 * 4 == 2048 bytes
typedef struct base_command_hashmap_s
typedef struct base_command_hashmap_s base_command_hashmap_t;
struct base_command_hashmap_s
{
base_command_t *basecmd; // base command: cvar, alias or command
const char *name; // key for searching
base_command_type_e type; // type for faster searching
struct base_command_hashmap_s *next;
} base_command_hashmap_t;
base_command_t *basecmd; // base command: cvar, alias or command
base_command_hashmap_t *next;
base_command_type_e type; // type for faster searching
char name[1]; // key for searching
};
static base_command_hashmap_t *hashed_cmds[HASH_SIZE];
@@ -124,11 +126,12 @@ void BaseCmd_Insert( base_command_type_e type, base_command_t *basecmd, const ch
{
base_command_hashmap_t *elem, *cur, *find;
uint hash = BaseCmd_HashKey( name );
size_t len = Q_strlen( name );
elem = Z_Malloc( sizeof( base_command_hashmap_t ) );
elem = Z_Malloc( sizeof( base_command_hashmap_t ) + len );
elem->basecmd = basecmd;
elem->type = type;
elem->name = name;
Q_strncpy( elem->name, name, len + 1 );
// link the variable in alphanumerical order
for( cur = NULL, find = hashed_cmds[hash];

View File

@@ -31,8 +31,6 @@ typedef enum base_command_type
typedef void base_command_t;
void BaseCmd_Init( void );
base_command_t *BaseCmd_Find( base_command_type_e type, const char *name );
void BaseCmd_FindAll( const char *name,

View File

@@ -949,7 +949,7 @@ static void Cmd_Else_f( void )
static qboolean Cmd_ShouldAllowCommand( cmd_t *cmd, qboolean isPrivileged )
{
const char *prefixes[] = { "cl_", "gl_", "r_", "m_", "hud_", "joy_" };
const char *prefixes[] = { "cl_", "gl_", "r_", "m_", "hud_", "joy_", "con_", "scr_" };
int i;
// always allow local commands
@@ -1015,7 +1015,7 @@ static void Cmd_ExecuteStringWithPrivilegeCheck( const char *text, qboolean isPr
*ptoken++ = *text++;
*ptoken = 0;
len += Q_strncpy( pcmd, Cvar_VariableString( token ), MAX_CMD_LINE - len );
len += Q_strncpy( pcmd, Cvar_VariableString( token ), sizeof( token ) - len );
pcmd = command + len;
if( !*text ) break;

View File

@@ -273,12 +273,12 @@ typedef struct
typedef enum bugcomp_e
{
// default mode, we assume that user dlls are not relying on engine bugs
BUGCOMP_OFF,
// reverts fix for pfnPEntityOfEntIndex for bug compatibility with GoldSrc
BUGCOMP_PENTITYOFENTINDEX_FLAG = BIT( 0 ),
// GoldSrc mode, user dlls are relying on GoldSrc specific bugs
// but fixing them may break regular Xash games
BUGCOMP_GOLDSRC,
// rewrites mod's attempts to write GoldSrc-specific messages into Xash protocol
// (new wrappers are added by request)
BUGCOMP_MESSAGE_REWRITE_FACILITY_FLAG = BIT( 1 ),
} bugcomp_t;
typedef struct host_parm_s
@@ -356,7 +356,7 @@ typedef struct host_parm_s
int numdecals;
// bug compatibility level, for very "special" games
bugcomp_t bugcomp;
uint32_t bugcomp;
// measure time to first frame
double starttime;
@@ -479,14 +479,6 @@ typedef enum
WF_TOTALCOUNT, // must be last
} sndformat_t;
// soundlib global settings
typedef enum
{
SL_USE_LERPING = BIT(0), // lerping sounds during resample
SL_KEEP_8BIT = BIT(1), // don't expand 8bit sounds automatically up to 16 bit
SL_ALLOW_OVERWRITE = BIT(2), // allow to overwrite stored sounds
} slFlags_t;
// wavdata output flags
typedef enum
{
@@ -495,21 +487,20 @@ typedef enum
SOUND_STREAM = BIT( 1 ), // this is a streaminfo, not a real sound
// Sound_Process manipulation flags
SOUND_RESAMPLE = BIT(12), // resample sound to specified rate
SOUND_CONVERT16BIT = BIT(13), // change sound resolution from 8 bit to 16
SOUND_RESAMPLE = BIT( 12 ), // resample sound to specified rate
} sndFlags_t;
typedef struct
{
word rate; // num samples per second (e.g. 11025 - 11 khz)
byte width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2)
byte channels; // num channels (1 - mono, 2 - stereo)
int loopStart; // offset at this point sound will be looping while playing more than only once
int samples; // total samplecount in wav
uint type; // compression type
uint flags; // misc sound flags
byte *buffer; // sound buffer
size_t size; // for bounds checking
word rate; // num samples per second (e.g. 11025 - 11 khz)
byte width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2)
byte channels; // num channels (1 - mono, 2 - stereo)
uint loopStart; // offset at this point sound will be looping while playing more than only once
uint samples; // total samplecount in wav
uint type; // compression type
uint flags; // misc sound flags
byte *buffer; // sound buffer
size_t size; // for bounds checking
} wavdata_t;
//
@@ -704,7 +695,7 @@ void Log_Printf( const char *fmt, ... ) _format( 1 );
void SV_BroadcastCommand( const char *fmt, ... ) _format( 1 );
void SV_BroadcastPrintf( struct sv_client_s *ignore, const char *fmt, ... ) _format( 2 );
void CL_ClearStaticEntities( void );
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position );
qboolean S_StreamGetCurrentState( char *currentTrack, size_t currentTrackSize, char *loopTrack, size_t loopTrackSize, int *position );
void CL_ServerCommand( qboolean reliable, const char *fmt, ... ) _format( 2 );
void CL_HudMessage( const char *pMessage );
const char *CL_MsgInfo( int cmd );

View File

@@ -465,7 +465,7 @@ static qboolean Cmd_GetSoundList( const char *s, char *completedname, int length
t = FS_Search( va( "%s%s*.*", DEFAULT_SOUNDPATH, s ), true, false );
if( !t ) return false;
Q_strncpy( matchbuf, t->filenames[0] + sizeof( DEFAULT_SOUNDPATH ) - 1, MAX_STRING );
Q_strncpy( matchbuf, t->filenames[0] + sizeof( DEFAULT_SOUNDPATH ) - 1, sizeof( matchbuf ));
COM_StripExtension( matchbuf );
if( completedname && length )
Q_strncpy( completedname, matchbuf, length );
@@ -478,7 +478,7 @@ static qboolean Cmd_GetSoundList( const char *s, char *completedname, int length
if( Q_stricmp( ext, "wav" ) && Q_stricmp( ext, "mp3" ))
continue;
Q_strncpy( matchbuf, t->filenames[i] + sizeof( DEFAULT_SOUNDPATH ) - 1, MAX_STRING );
Q_strncpy( matchbuf, t->filenames[i] + sizeof( DEFAULT_SOUNDPATH ) - 1, sizeof( matchbuf ));
COM_StripExtension( matchbuf );
Con_Printf( "%16s\n", matchbuf );
numsounds++;
@@ -764,14 +764,14 @@ static qboolean Cmd_GetGamesList( const char *s, char *completedname, int length
}
if( !numgamedirs ) return false;
Q_strncpy( matchbuf, gamedirs[0], MAX_STRING );
Q_strncpy( matchbuf, gamedirs[0], sizeof( matchbuf ));
if( completedname && length )
Q_strncpy( completedname, matchbuf, length );
if( numgamedirs == 1 ) return true;
for( i = 0; i < numgamedirs; i++ )
{
Q_strncpy( matchbuf, gamedirs[i], MAX_STRING );
Q_strncpy( matchbuf, gamedirs[i], sizeof( matchbuf ));
Con_Printf( "%16s\n", matchbuf );
}
@@ -825,14 +825,14 @@ static qboolean Cmd_GetCDList( const char *s, char *completedname, int length )
}
if( !numcdcommands ) return false;
Q_strncpy( matchbuf, cdcommands[0], MAX_STRING );
Q_strncpy( matchbuf, cdcommands[0], sizeof( matchbuf ));
if( completedname && length )
Q_strncpy( completedname, matchbuf, length );
if( numcdcommands == 1 ) return true;
for( i = 0; i < numcdcommands; i++ )
{
Q_strncpy( matchbuf, cdcommands[i], MAX_STRING );
Q_strncpy( matchbuf, cdcommands[i], sizeof( matchbuf ));
Con_Printf( "%16s\n", matchbuf );
}
@@ -901,12 +901,10 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
if( f )
{
qboolean have_spawnpoints = false;
dheader_t *header;
dlump_t entities;
memset( buf, 0, MAX_SYSPATH );
FS_Read( f, buf, MAX_SYSPATH );
header = (dheader_t *)buf;
// check all the lumps and some other errors
if( !Mod_TestBmodelLumps( f, t->filenames[i], buf, true, &entities ))
@@ -937,7 +935,7 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
char token[MAX_TOKEN];
qboolean worldspawn = true;
Q_strncpy( message, "No Title", MAX_STRING );
Q_strncpy( message, "No Title", sizeof( message ));
pfile = ents;
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )

View File

@@ -955,7 +955,7 @@ static void Cvar_SetGL( const char *name, const char *value )
static qboolean Cvar_ShouldSetCvar( convar_t *v, qboolean isPrivileged )
{
const char *prefixes[] = { "cl_", "gl_", "m_", "r_", "hud_", "joy_" };
const char *prefixes[] = { "cl_", "gl_", "m_", "r_", "hud_", "joy_", "con_", "scr_" };
int i;
if( isPrivileged )

View File

@@ -89,32 +89,32 @@ qboolean FS_LoadProgs( void )
if( !fs_hInstance )
{
Host_Error( "FS_LoadProgs: can't load filesystem library %s: %s\n", name, COM_GetLibraryError() );
Host_Error( "%s: can't load filesystem library %s: %s\n", __func__, name, COM_GetLibraryError() );
return false;
}
if( !( GetFSAPI = (FSAPI)COM_GetProcAddress( fs_hInstance, GET_FS_API )))
{
FS_UnloadProgs();
Host_Error( "FS_LoadProgs: can't find GetFSAPI entry point in %s\n", name );
Host_Error( "%s: can't find GetFSAPI entry point in %s\n", __func__, name );
return false;
}
if( !GetFSAPI( FS_API_VERSION, &g_fsapi, &FI, &fs_memfuncs ))
if( GetFSAPI( FS_API_VERSION, &g_fsapi, &FI, &fs_memfuncs ) != FS_API_VERSION )
{
FS_UnloadProgs();
Host_Error( "FS_LoadProgs: can't initialize filesystem API: wrong version\n" );
Host_Error( "%s: can't initialize filesystem API: wrong version\n", __func__ );
return false;
}
if( !( fs_pfnCreateInterface = (pfnCreateInterface_t)COM_GetProcAddress( fs_hInstance, "CreateInterface" )))
{
FS_UnloadProgs();
Host_Error( "FS_LoadProgs: can't find CreateInterface entry point in %s\n", name );
Host_Error( "%s: can't find CreateInterface entry point in %s\n", __func__, name );
return false;
}
Con_DPrintf( "FS_LoadProgs: filesystem_stdio successfully loaded\n" );
Con_DPrintf( "%s: filesystem_stdio successfully loaded\n", __func__ );
return true;
}

View File

@@ -65,6 +65,33 @@ static CVAR_DEFINE( host_sleeptime, "sleeptime", "1", FCVAR_ARCHIVE|FCVAR_FILTER
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" );
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" },
{ BUGCOMP_MESSAGE_REWRITE_FACILITY_FLAG, "GoldSrc Message Rewrite Facility", "gsmrf" },
};
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 )
{
string version_str;
@@ -92,7 +119,7 @@ static void Sys_PrintUsage( void )
O("-minidumps ", "enable writing minidumps when game is crashed")
#endif
O("-rodir <path> ", "set read-only base directory")
O("-bugcomp ", "enable precise bug compatibility")
O("-bugcomp [opts] ", "enable precise bug compatibility")
O(" ", "will break games that don't require it")
O(" ", "refer to engine documentation for more info")
O("-disablehelp ", "disable this message")
@@ -193,31 +220,14 @@ void Host_ShutdownServer( void )
Host_PrintEngineFeatures
================
*/
static void Host_PrintEngineFeatures( int features )
static void Host_PrintFeatures( uint32_t flags, const char *s, feature_message_t *features, size_t size )
{
struct
{
uint32_t mask;
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;
size_t i;
for( i = 0; i < ARRAYSIZE( features_str ); i++ )
for( i = 0; i < size; i++ )
{
if( FBitSet( features, features_str[i].mask ))
Con_Reportf( "^3EXT:^7 %s is enabled\n", features_str[i].msg );
if( FBitSet( flags, features[i].mask ))
Con_Printf( "^3%s:^7 %s is enabled\n", s, features[i].msg );
}
}
@@ -245,7 +255,7 @@ void Host_ValidateEngineFeatures( uint32_t features )
SetBits( features, ENGINE_STEP_POSHISTORY_LERP );
// print requested first
Host_PrintEngineFeatures( features );
Host_PrintFeatures( features, "EXT", engine_features, ARRAYSIZE( engine_features ));
// now warn about incompatible bits
if( FBitSet( features, ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ) == ( ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ))
@@ -855,7 +865,7 @@ void GAME_EXPORT Host_Error( const char *error, ... )
}
recursive = true;
Q_strncpy( hosterror2, hosterror1, MAX_SYSPATH );
Q_strncpy( hosterror2, hosterror1, sizeof( hosterror2 ));
host.errorframe = host.framecount; // to avoid multply calls per frame
Q_snprintf( host.finalmsg, sizeof( host.finalmsg ), "Server crashed: %s", hosterror1 );
@@ -947,6 +957,53 @@ static void Host_RunTests( int stage )
}
#endif
static uint32_t Host_CheckBugcomp( void )
{
const char *prev, *next;
uint32_t flags = 0;
string args, arg;
size_t i;
if( !Sys_CheckParm( "-bugcomp" ))
return 0;
if( Sys_GetParmFromCmdLine( "-bugcomp", args ) && isalpha( 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
@@ -1051,13 +1108,6 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
// member console allowing
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?
// NOTE: this message couldn't be passed into game console but it doesn't matter
@@ -1184,16 +1234,11 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
Sys_InitLog();
// print bugcompatibility level here, after log was initialized
if( host.bugcomp == BUGCOMP_GOLDSRC )
{
Con_Printf( "^3BUGCOMP^7: GoldSrc bug-compatibility enabled\n" );
}
// print current developer level to simplify processing users feedback
if( developer > 0 ) {
if( developer > 0 )
Con_Printf( "Developer level: ^3%i\n", developer );
}
host.bugcomp = Host_CheckBugcomp();
Cmd_AddCommand( "exec", Host_Exec_f, "execute a script file" );
Cmd_AddCommand( "memlist", Host_MemStats_f, "prints memory pool information" );

View File

@@ -400,7 +400,8 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet, qboolean de
f = FS_Open( pakname, "rb", true );
if( !f )
{
Con_DPrintf( S_ERROR "Couldn't find %s.\n", pakname );
if( !quiet )
Con_DPrintf( S_ERROR "Couldn't find %s.\n", pakname );
return true;
}

View File

@@ -24,7 +24,8 @@ typedef struct dll_user_s
qboolean custom_loader; // a bit who indicated loader type
qboolean encrypted; // dll is crypted (some client.dll in HL, CS etc)
char dllName[32]; // for debug messages
string fullPath, shortPath; // actual dll paths
char fullPath[2048];
string shortPath; // actual dll paths
// ordinals stuff, valid only on Win32
word *ordinals;

View File

@@ -262,7 +262,7 @@ static void NET_AddMaster( const char *addr, qboolean save )
}
master = Mem_Malloc( host.mempool, sizeof( master_t ) );
Q_strncpy( master->address, addr, MAX_STRING );
Q_strncpy( master->address, addr, sizeof( master->address ));
master->sent = false;
master->save = save;
master->next = NULL;

View File

@@ -1823,8 +1823,8 @@ static void Mod_LoadEntities( model_t *mod, dbspmodel_t *bmod )
{
char *pszWadFile;
Q_strncpy( wadstring, token, MAX_TOKEN - 2 );
wadstring[MAX_TOKEN - 2] = 0;
Q_strncpy( wadstring, token, sizeof( wadstring ) - 2 );
wadstring[sizeof( wadstring ) - 2] = 0;
if( !Q_strchr( wadstring, ';' ))
Q_strncat( wadstring, ";", sizeof( wadstring ));

View File

@@ -89,6 +89,36 @@ const char *svc_strings[svc_lastmsg+1] =
"svc_exec",
};
const char *svc_legacy_strings[svc_lastmsg+1] =
{
[svc_legacy_changing] = "svc_legacy_changing",
[svc_legacy_ambientsound] = "svc_legacy_ambientsound",
[svc_legacy_soundindex] = "svc_legacy_soundindex",
[svc_legacy_ambientsound] = "svc_legacy_ambientsound",
[svc_legacy_modelindex] = "svc_legacy_modelindex",
[svc_legacy_eventindex] = "svc_legacy_eventindex",
[svc_legacy_chokecount] = "svc_legacy_chokecount",
};
const char *svc_goldsrc_strings[svc_lastmsg+1] =
{
[svc_goldsrc_version] = "svc_goldsrc_version",
[svc_goldsrc_serverinfo] = "svc_goldsrc_serverinfo",
[svc_goldsrc_deltadescription] = "svc_goldsrc_deltadescription",
[svc_goldsrc_stopsound] = "svc_goldsrc_stopsound",
[svc_goldsrc_damage] = "svc_goldsrc_damage",
[svc_goldsrc_killedmonster] = "svc_goldsrc_killedmonster",
[svc_goldsrc_foundsecret] = "svc_goldsrc_foundsecret",
[svc_goldsrc_spawnstaticsound] = "svc_goldsrc_spawnstaticsound",
[svc_goldsrc_decalname] = "svc_goldsrc_decalname",
[svc_goldsrc_newusermsg] = "svc_goldsrc_newusermsg",
[svc_goldsrc_newmovevars] = "svc_goldsrc_newmovevars",
[svc_goldsrc_sendextrainfo] = "svc_goldsrc_sendextrainfo",
[svc_goldsrc_timescale] = "svc_goldsrc_timescale",
[svc_goldsrc_sendcvarvalue] = "svc_goldsrc_sendcvarvalue",
[svc_goldsrc_sendcvarvalue2] = "svc_goldsrc_sendcvarvalue2",
};
void MSG_InitMasks( void )
{
uint startbit, endbit;

View File

@@ -1079,15 +1079,15 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
{
val_a = *(float *)((byte *)from + pField->offset );
val_b = *(float *)((byte *)to + pField->offset );
fromF = Q_rint(( timebase - val_a ) * 100.0 );
toF = Q_rint(( timebase - val_b ) * 100.0 );
fromF = Q_rint( val_a * 100.0 );
toF = Q_rint( val_b * 100.0 );
}
else if( pField->flags & DT_TIMEWINDOW_BIG )
{
val_a = *(float *)((byte *)from + pField->offset );
val_b = *(float *)((byte *)to + pField->offset );
fromF = Q_rint(( timebase - val_a ) * pField->multiplier );
toF = Q_rint(( timebase - val_b ) * pField->multiplier );
fromF = Q_rint( val_a * pField->multiplier );
toF = Q_rint( val_b * pField->multiplier );
}
else if( pField->flags & DT_STRING )
{
@@ -1394,22 +1394,14 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
}
else if( pField->flags & DT_TIMEWINDOW_8 )
{
bSigned = true; // timewindow is always signed
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
flTime = (timebase * 100.0 - (int)iValue) / 100.0;
iValue = MSG_ReadSBitLong( msg, pField->bits );
flTime = ( timebase * 100.0 - (int)iValue ) / 100.0;
*(float *)((byte *)to + pField->offset ) = flTime;
}
else if( pField->flags & DT_TIMEWINDOW_BIG )
{
bSigned = true; // timewindow is always signed
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;
iValue = MSG_ReadSBitLong( msg, pField->bits );
flTime = ( timebase * pField->multiplier - (int)iValue ) / pField->multiplier;
*(float *)((byte *)to + pField->offset ) = flTime;
}
else if( pField->flags & DT_STRING )

View File

@@ -278,6 +278,8 @@ GNU General Public License for more details.
#define SU_WEAPON (1<<14)
extern const char *svc_strings[svc_lastmsg+1];
extern const char *svc_legacy_strings[svc_lastmsg+1];
extern const char *svc_goldsrc_strings[svc_lastmsg+1];
extern const char *clc_strings[clc_lastmsg+1];
// FWGS extensions
@@ -316,4 +318,40 @@ extern const char *clc_strings[clc_lastmsg+1];
// Master Server protocol
#define MS_SCAN_REQUEST "1\xFF" "0.0.0.0:0\0" // TODO: implement IP filter
// GoldSrc protocol definitions
#define PROTOCOL_GOLDSRC_VERSION_REAL 48
#define PROTOCOL_GOLDSRC_VERSION (PROTOCOL_GOLDSRC_VERSION_REAL | (BIT( 7 ))) // should be 48, only to differentiate it from PROTOCOL_LEGACY_VERSION
#define svc_goldsrc_version svc_changing
#define svc_goldsrc_serverinfo svc_serverdata
#define svc_goldsrc_deltadescription svc_deltatable
#define svc_goldsrc_stopsound svc_resource
#define svc_goldsrc_damage svc_restoresound
#define svc_goldsrc_killedmonster 27
#define svc_goldsrc_foundsecret 28
#define svc_goldsrc_spawnstaticsound 29
#define svc_goldsrc_decalname svc_bspdecal
#define svc_goldsrc_newusermsg svc_usermessage
#define svc_goldsrc_newmovevars svc_deltamovevars
#define svc_goldsrc_sendextrainfo 54
#define svc_goldsrc_timescale 55
#define svc_goldsrc_sendcvarvalue svc_querycvarvalue
#define svc_goldsrc_sendcvarvalue2 svc_querycvarvalue2
#define clc_goldsrc_hltv clc_requestcvarvalue // 9
#define clc_goldsrc_requestcvarvalue clc_requestcvarvalue2 // 10
#define clc_goldsrc_requestcvarvalue2 11
#define clc_goldsrc_lastmsg 12
#define S2C_REJECT_BADPASSWORD '8'
#define S2C_REJECT '9'
#define S2C_CHALLENGE "A00000000"
#define S2C_CONNECTION "B"
#define MAX_GOLDSRC_RESOURCE_BITS 12
#define MAX_GOLDSRC_ENTITY_BITS 11
// #define MAX_GOLDSRC_EDICTS BIT( MAX_ENTITY_BITS )
#define MAX_GOLDSRC_EDICTS ( BIT( MAX_ENTITY_BITS ) + ( MAX_CLIENTS * 15 ))
#define LAST_GOLDSRC_EDICT ( BIT( MAX_ENTITY_BITS ) - 1 )
#endif//NET_PROTOCOL_H

View File

@@ -216,7 +216,7 @@ wavdata_t *FS_StreamInfo( stream_t *stream )
if( !stream ) return NULL;
// fill structure
info.loopStart = -1;
info.loopStart = 0;
info.rate = stream->rate;
info.width = stream->width;
info.channels = stream->channels;

View File

@@ -74,7 +74,10 @@ static uint32_t Sound_ParseSynchInteger( uint32_t v )
static void Sound_HandleCustomID3Comment( const char *key, const char *value )
{
if( !Q_strcmp( key, "LOOP_START" ) || !Q_strcmp( key, "LOOPSTART" ))
{
sound.loopstart = Q_atoi( value );
SetBits( sound.flags, SOUND_LOOPED );
}
// unknown comment is not an error
}
@@ -233,7 +236,6 @@ qboolean Sound_LoadMPG( const char *name, const byte *buffer, fs_offset_t filesi
sound.channels = sc.channels;
sound.rate = sc.rate;
sound.width = 2; // always 16-bit PCM
sound.loopstart = -1;
sound.size = ( sound.channels * sound.rate * sound.width ) * ( sc.playtime / 1000 ); // in bytes
padsize = sound.size % FRAME_SIZE;
pos += FRAME_SIZE; // evaluate pos
@@ -241,7 +243,6 @@ qboolean Sound_LoadMPG( const char *name, const byte *buffer, fs_offset_t filesi
if( !Sound_ParseID3Tag( buffer, filesize ))
{
Con_DPrintf( S_WARN "Sound_LoadMPG: (%s) failed to extract LOOP_START tag\n", name );
sound.loopstart = -1;
}
if( !sound.size )

View File

@@ -14,6 +14,9 @@ GNU General Public License for more details.
*/
#include "soundlib.h"
#if XASH_SDL
#include <SDL_audio.h>
#endif // XASH_SDL
/*
=============================================================================
@@ -130,7 +133,309 @@ uint GAME_EXPORT Sound_GetApproxWavePlayLen( const char *filepath )
return msecs;
}
#define drint( v ) (int)( v + 0.5 )
static qboolean Sound_ConvertNoResample( wavdata_t *sc, int inwidth, int outwidth, int outcount )
{
size_t i;
if( inwidth == 1 && outwidth == 2 ) // S8 to S16
{
for( i = 0; i < outcount * sc->channels; i++ )
((int16_t*)sound.tempbuffer)[i] = ((int8_t *)sc->buffer)[i] * 256;
return true;
}
if( inwidth == 2 && outwidth == 1 ) // S16 to S8
{
for( i = 0; i < outcount * sc->channels; i++ )
((int8_t*)sound.tempbuffer)[i] = ((int16_t *)sc->buffer)[i] / 256;
return true;
}
return false;
}
static qboolean Sound_ConvertDownsample( wavdata_t *sc, int inwidth, int outwidth, int outcount, double stepscale )
{
size_t i;
double j;
if( inwidth == 1 && outwidth == 1 )
{
int8_t *data = (int8_t *)sc->buffer;
if( outwidth == 1 )
{
int8_t *outdata = (int8_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0];
outdata[i*2+1] = data[((int)j)*2+1];
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j];
}
}
return true;
}
if( outwidth == 2 )
{
int16_t *outdata = (int16_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0] * 256;
outdata[i*2+1] = data[((int)j)*2+1] * 256;
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j] * 256;
}
}
return true;
}
}
if( inwidth == 2 )
{
int16_t *data = (int16_t *)sc->buffer;
if( outwidth == 1 )
{
int8_t *outdata = (int8_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0] / 256;
outdata[i*2+1] = data[((int)j)*2+1] / 256;
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j] / 256;
}
}
return true;
}
if( outwidth == 2 )
{
int16_t *outdata = (int16_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0];
outdata[i*2+1] = data[((int)j)*2+1];
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j];
}
}
return true;
}
}
return false;
}
static qboolean Sound_ConvertUpsample( wavdata_t *sc, int inwidth, int outwidth, int outcount, int incount, double stepscale )
{
size_t i;
double j;
double frac;
incount--; // to not go past last sample while interpolating
if( inwidth == 1 )
{
int8_t *data = (int8_t *)sc->buffer;
if( outwidth == 1 )
{
int8_t *outdata = (int8_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0];
outdata[i*2+1] = data[((int)j)*2+1];
if( j != (int)j && j < incount )
{
frac = j - (int)j;
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
}
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j];
if( j != (int)j && j < incount )
{
frac = j - (int)j;
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
}
}
}
return true;
}
if( outwidth == 2 )
{
int16_t *outdata = (int16_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0] * 256;
outdata[i*2+1] = data[((int)j)*2+1] * 256;
if( j != (int)j && j < incount )
{
frac = ( j - (int)j ) * 256;
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
}
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j] * 256;
if( j != (int)j && j < incount )
{
frac = ( j - (int)j ) * 256;
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
}
}
}
return true;
}
}
if( inwidth == 2 )
{
int16_t *data = (int16_t *)sc->buffer;
if( outwidth == 1 )
{
int8_t *outdata = (int8_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0] / 256;
outdata[i*2+1] = data[((int)j)*2+1] / 256;
if( j != (int)j && j < incount )
{
frac = ( j - (int)j ) / 256;
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
}
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j] / 256;
if( j != (int)j && j < incount )
{
frac = ( j - (int)j ) / 256;
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
}
}
}
return true;
}
if( outwidth == 2 )
{
int16_t *outdata = (int16_t *)sound.tempbuffer;
if( sc->channels == 2 )
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i*2+0] = data[((int)j)*2+0];
outdata[i*2+1] = data[((int)j)*2+1];
if( j != (int)j && j < incount )
{
frac = j - (int)j;
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
}
}
}
else
{
for( i = 0; i < outcount; i++ )
{
j = stepscale * i;
outdata[i] = data[(int)j];
if( j != (int)j && j < incount )
{
frac = j - (int)j;
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
}
}
}
return true;
}
}
return false;
}
/*
================
@@ -141,125 +446,70 @@ We need convert sound to signed even if nothing to resample
*/
static qboolean Sound_ResampleInternal( wavdata_t *sc, int inrate, int inwidth, int outrate, int outwidth )
{
double stepscale, j;
int outcount;
int i;
const size_t oldsize = sc->size;
qboolean handled = false;
double stepscale;
double t1, t2;
int outcount, incount = sc->samples;
if( inrate == outrate && inwidth == outwidth )
return false;
t1 = Sys_DoubleTime();
stepscale = (double)inrate / outrate; // this is usually 0.5, 1, or 2
outcount = sc->samples / stepscale;
sc->size = outcount * outwidth * sc->channels;
sound.tempbuffer = (byte *)Mem_Realloc( host.soundpool, sound.tempbuffer, sc->size );
sc->samples = outcount;
if( sc->loopStart != -1 )
if( FBitSet( sc->flags, SOUND_LOOPED ))
sc->loopStart = sc->loopStart / stepscale;
if( inrate == outrate )
#if 0 && XASH_SDL // slow but somewhat accurate
{
if( inwidth == 1 && outwidth == 2 ) // S8 to S16
{
for( i = 0; i < outcount * sc->channels; i++ )
((int16_t*)sound.tempbuffer)[i] = ((int8_t *)sc->buffer)[i] * 256;
handled = true;
}
else if( inwidth == 2 && outwidth == 1 ) // S16 to S8
{
for( i = 0; i < outcount * sc->channels; i++ )
((int8_t*)sound.tempbuffer)[i] = ((int16_t *)sc->buffer)[i] / 256;
handled = true;
}
}
else // resample case
{
if( inwidth == 1 )
{
int8_t *data = (int8_t *)sc->buffer;
const SDL_AudioFormat infmt = inwidth == 1 ? AUDIO_S8 : AUDIO_S16;
const SDL_AudioFormat outfmt = outwidth == 1 ? AUDIO_S8 : AUDIO_S16;
SDL_AudioCVT cvt;
if( outwidth == 1 )
{
if( sc->channels == 2 )
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
{
((int8_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0];
((int8_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1];
}
}
else
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
((int8_t*)sound.tempbuffer)[i] = data[(int)j];
}
handled = true;
}
else if( outwidth == 2 )
{
if( sc->channels == 2 )
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
{
((int16_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0] * 256;
((int16_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1] * 256;
}
}
else
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
((int16_t*)sound.tempbuffer)[i] = data[(int)j] * 256;
}
handled = true;
}
}
else if( inwidth == 2 )
// SDL_AudioCVT does conversion in place, original buffer is used for it
if( SDL_BuildAudioCVT( &cvt, infmt, sc->channels, inrate, outfmt, sc->channels, outrate ) > 0 && cvt.needed )
{
int16_t *data = (int16_t *)sc->buffer;
sc->buffer = (byte *)Mem_Realloc( host.soundpool, sc->buffer, oldsize * cvt.len_mult );
cvt.len = oldsize;
cvt.buf = sc->buffer;
if( outwidth == 1 )
if( !SDL_ConvertAudio( &cvt ))
{
if( sc->channels == 2 )
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
{
((int8_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0] / 256;
((int8_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1] / 256;
}
}
else
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
((int8_t*)sound.tempbuffer)[i] = data[(int)j] / 256;
}
handled = true;
}
else if( outwidth == 2 )
{
if( sc->channels == 2 )
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
{
((int16_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0];
((int16_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1];
}
}
else
{
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
((int16_t*)sound.tempbuffer)[i] = data[(int)j];
}
handled = true;
t2 = Sys_DoubleTime();
Con_Reportf( "Sound_Resample: from [%d bit %d Hz] to [%d bit %d Hz] (took %.3fs through SDL)\n", inwidth * 8, inrate, outwidth * 8, outrate, t2 - t1 );
sc->rate = outrate;
sc->width = outwidth;
return false; // HACKHACK: return false so Sound_Process won't reallocate buffer
}
}
}
#endif
sound.tempbuffer = (byte *)Mem_Realloc( host.soundpool, sound.tempbuffer, sc->size );
if( inrate == outrate ) // no resampling, just copy data
handled = Sound_ConvertNoResample( sc, inwidth, outwidth, outcount );
else if( inrate > outrate ) // fast case, usually downsample but is also ok for upsampling
handled = Sound_ConvertDownsample( sc, inwidth, outwidth, outcount, stepscale );
else // upsample case, w/ interpolation
handled = Sound_ConvertUpsample( sc, inwidth, outwidth, outcount, incount, stepscale );
t2 = Sys_DoubleTime();
if( handled )
Con_Reportf( "Sound_Resample: from [%d bit %d Hz] to [%d bit %d Hz]\n", inwidth * 8, inrate, outwidth * 8, outrate );
{
if( t2 - t1 > 0.01f ) // critical, report to mod developer
Con_Printf( S_WARN "Sound_Resample: from [%d bit %d Hz] to [%d bit %d Hz] (took %.3fs)\n", inwidth * 8, inrate, outwidth * 8, outrate, t2 - t1 );
else
Con_Reportf( "Sound_Resample: from [%d bit %d Hz] to [%d bit %d Hz] (took %.3fs)\n", inwidth * 8, inrate, outwidth * 8, outrate, t2 - t1 );
}
else
Con_Reportf( S_ERROR "Sound_Resample: unsupported from [%d bit %d Hz] to [%d bit %d Hz]\n", inwidth * 8, inrate, outwidth * 8, outrate );
Con_Printf( S_ERROR "Sound_Resample: unsupported from [%d bit %d Hz] to [%d bit %d Hz]\n", inwidth * 8, inrate, outwidth * 8, outrate );
sc->rate = outrate;
sc->width = outwidth;
@@ -276,23 +526,20 @@ qboolean Sound_Process( wavdata_t **wav, int rate, int width, uint flags )
if( !snd || !snd->buffer )
return false;
if(( flags & SOUND_RESAMPLE ) && ( width > 0 || rate > 0 ))
if( FBitSet( flags, SOUND_RESAMPLE ) && ( width > 0 || rate > 0 ))
{
if( Sound_ResampleInternal( snd, snd->rate, snd->width, rate, width ))
result = Sound_ResampleInternal( snd, snd->rate, snd->width, rate, width );
if( result )
{
Mem_Free( snd->buffer ); // free original image buffer
snd->buffer = Sound_Copy( snd->size ); // unzone buffer (don't touch image.tempbuffer)
}
else
{
// not resampled
result = false;
snd->buffer = Sound_Copy( snd->size ); // unzone buffer (don't touch sound.tempbuffer)
}
}
*wav = snd;
return false;
return result;
}
qboolean Sound_SupportedFileFormat( const char *fileext )

View File

@@ -23,6 +23,11 @@ static const byte *iff_end;
static const byte *iff_lastChunk;
static int iff_chunkLen;
static int IsFourCC( const byte *ptr, const byte *fourcc )
{
return 0 == memcmp( ptr, fourcc, 4 );
}
/*
=================
GetLittleShort
@@ -86,7 +91,21 @@ static void FindNextChunk( const char *filename, const char *name )
if( iff_chunkLen > remaining )
{
Con_DPrintf( "%s: '%s' truncated by %i bytes\n", __func__, filename, iff_chunkLen - remaining );
// only print this warning if selected chunk is truncated
//
// otherwise this warning becomes misleading because some
// idiot programs like CoolEdit (i.e. Adobe Audition) don't always
// respect pad byte. The file isn't actually truncated, it just
// can't be reliably parsed as a whole
if( IsFourCC( iff_lastChunk, "RIFF" )
|| IsFourCC( iff_lastChunk, "fmt " )
|| IsFourCC( iff_lastChunk, "cue " )
|| IsFourCC( iff_lastChunk, "LIST" )
|| IsFourCC( iff_lastChunk, "data" ))
{
Con_DPrintf( "%s: '%s' truncated by %i bytes\n", __func__, filename, iff_chunkLen - remaining );
}
iff_chunkLen = remaining;
}
@@ -94,9 +113,9 @@ static void FindNextChunk( const char *filename, const char *name )
iff_dataPtr -= 8;
iff_lastChunk = iff_dataPtr + 8 + iff_chunkLen;
if ((iff_chunkLen&1) && remaining)
if(( iff_chunkLen & 1 ) && remaining )
iff_lastChunk++;
if (!Q_strncmp(iff_dataPtr, name, 4))
if( IsFourCC( iff_dataPtr, name ))
return;
}
}
@@ -130,15 +149,18 @@ static qboolean StreamFindNextChunk( file_t *file, const char *name, int *last_c
return false; // didn't find the chunk
FS_Seek( file, 4, SEEK_CUR );
FS_Read( file, &iff_chunk_len, sizeof( iff_chunk_len ));
if( FS_Read( file, &iff_chunk_len, sizeof( iff_chunk_len )) != sizeof( iff_chunk_len ))
return false;
if( iff_chunk_len < 0 )
return false; // didn't find the chunk
FS_Seek( file, -8, SEEK_CUR );
*last_chunk = FS_Tell( file ) + 8 + (( iff_chunk_len + 1 ) & ~1 );
FS_Read( file, chunkName, 4 );
if( FS_Read( file, chunkName, sizeof( chunkName )) != sizeof( chunkName ))
return false;
if( !Q_strncmp( chunkName, name, 4 ))
if( IsFourCC( chunkName, name ))
return true;
}
@@ -164,7 +186,7 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
// find "RIFF" chunk
FindChunk( name, "RIFF" );
if( !( iff_dataPtr && !Q_strncmp( (const char *)iff_dataPtr + 8, "WAVE", 4 )))
if( !iff_dataPtr || !IsFourCC( iff_dataPtr + 8, "WAVE" ))
{
Con_DPrintf( S_ERROR "Sound_LoadWAV: %s missing 'RIFF/WAVE' chunks\n", name );
return false;
@@ -223,11 +245,12 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
{
iff_dataPtr += 32;
sound.loopstart = GetLittleLong();
SetBits( sound.flags, SOUND_LOOPED );
FindNextChunk( name, "LIST" ); // if the next chunk is a LIST chunk, look for a cue length marker
if( iff_dataPtr )
{
if( !Q_strncmp( (const char *)iff_dataPtr + 28, "mark", 4 ))
if( IsFourCC( iff_dataPtr + 28, "mark" ))
{
// this is not a proper parse, but it works with CoolEdit...
iff_dataPtr += 24;
@@ -237,7 +260,7 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
}
else
{
sound.loopstart = -1;
sound.loopstart = 0;
sound.samples = 0;
}
@@ -342,8 +365,16 @@ stream_t *Stream_OpenWAV( const char *filename )
return NULL;
}
FS_Read( file, chunkName, 4 );
if( !Q_strncmp( chunkName, "WAVE", 4 ))
FS_Seek( file, 4, SEEK_CUR );
if( FS_Read( file, chunkName, 4 ) != 4 )
{
Con_DPrintf( S_ERROR "%s: %s missing WAVE chunk, truncated\n", filename );
FS_Close( file );
return false;
}
if( !IsFourCC( chunkName, "WAVE" ))
{
Con_DPrintf( S_ERROR "Stream_OpenWAV: %s missing WAVE chunk\n", filename );
FS_Close( file );
@@ -351,7 +382,7 @@ stream_t *Stream_OpenWAV( const char *filename )
}
// get "fmt " chunk
iff_data = FS_Tell( file ) + 4;
iff_data = FS_Tell( file );
last_chunk = iff_data;
if( !StreamFindNextChunk( file, "fmt ", &last_chunk ))
{

View File

@@ -50,7 +50,7 @@ typedef struct sndlib_s
int rate; // num samples per second (e.g. 11025 - 11 khz)
int width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2)
int channels; // num channels (1 - mono, 2 - stereo)
int loopstart; // start looping from
uint loopstart; // start looping from
uint samples; // total samplecount in sound
uint flags; // additional sound flags
size_t size; // sound unpacked size (for bounds checking)

View File

@@ -341,15 +341,18 @@ void GAME_EXPORT Con_Printf( const char *szFmt, ... )
{
static char buffer[MAX_PRINT_MSG];
va_list args;
qboolean add_newline;
if( !host.allow_console )
return;
va_start( args, szFmt );
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
va_end( args );
Sys_Print( buffer );
if( add_newline )
Sys_Print( "\n" );
}
/*
@@ -362,18 +365,21 @@ void GAME_EXPORT Con_DPrintf( const char *szFmt, ... )
{
static char buffer[MAX_PRINT_MSG];
va_list args;
qboolean add_newline;
if( host_developer.value < DEV_NORMAL )
return;
va_start( args, szFmt );
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
va_end( args );
if( buffer[0] == '0' && buffer[1] == '\n' && buffer[2] == '\0' )
return; // hlrally spam
Sys_Print( buffer );
if( add_newline )
Sys_Print( "\n" );
}
/*
@@ -386,15 +392,18 @@ void Con_Reportf( const char *szFmt, ... )
{
static char buffer[MAX_PRINT_MSG];
va_list args;
qboolean add_newline;
if( host_developer.value < DEV_EXTENDED )
return;
va_start( args, szFmt );
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
va_end( args );
Sys_Print( buffer );
if( add_newline )
Sys_Print( "\n" );
}

View File

@@ -25,18 +25,39 @@ GNU General Public License for more details.
#include "platform/swap/swap.h"
#define Q_malloc SWAP_Malloc
#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
#define Q_malloc malloc
#define Q_free free
#define Q_realloc realloc
#endif
typedef struct memheader_s
{
struct memheader_s *next; // next and previous memheaders in chain belonging to pool
struct memheader_s *prev;
struct mempool_s *pool; // pool this memheader belongs to
size_t size; // size of the memory after the header (excluding header and sentinel2)
const char *filename; // file name and line where Mem_Alloc was called
size_t size; // size of the memory after the header (excluding header and sentinel2)
poolhandle_t poolptr; // pool this memheader belongs to
int fileline;
#if !XASH_64BIT
uint32_t pad0; // doesn't have value, only to make Mem_Alloc return aligned addresses on ILP32
@@ -48,50 +69,34 @@ typedef struct memheader_s
typedef struct mempool_s
{
uint32_t sentinel1; // should always be MEMHEADER_SENTINEL1
struct memheader_s *chain; // chain of individual memory allocations
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 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
int fileline;
#if XASH_64BIT
poolhandle_t idx;
#endif
char name[64]; // name of the pool
uint32_t sentinel2; // should always be MEMHEADER_SENTINEL1
} mempool_t;
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
// which makes engine incompatible with 64-bit pointers I changed mempool type
// 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 )
{
mempool_t *pool;
for( pool = poolchain; pool; pool = pool->next )
{
if( pool->idx == poolptr )
return pool;
}
if( likely( poolptr > 0 && poolptr <= poolcount ))
return &poolchain[poolptr - 1];
Sys_Error( "%s: not allocated or double freed pool %d", __FUNCTION__, poolptr );
return NULL;
}
#else
static mempool_t *Mem_FindPool( poolhandle_t poolptr )
static poolhandle_t Mem_PoolIndex( mempool_t *mempool )
{
return (mempool_t *)poolptr;
return (poolhandle_t)(mempool - poolchain) + 1;
}
#endif
static inline void Mem_PoolAdd( mempool_t *pool, size_t size )
{
@@ -111,7 +116,7 @@ static inline void Mem_PoolLinkAlloc( mempool_t *pool, memheader_t *mem )
if( mem->next ) mem->next->prev = mem;
pool->chain = mem;
mem->prev = NULL;
mem->pool = pool;
mem->poolptr = Mem_PoolIndex( pool );
}
static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
@@ -119,7 +124,7 @@ static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
if( mem->next ) mem->next->prev = mem->prev;
if( mem->prev ) mem->prev->next = mem->next;
else pool->chain = mem->next;
mem->pool = NULL;
mem->poolptr = 0;
}
static inline void Mem_InitAlloc( memheader_t *mem, size_t size, const char *filename, int fileline )
@@ -165,23 +170,6 @@ static qboolean Mem_CheckAllocHeader( const char *func, const memheader_t *mem,
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 )
{
memheader_t *mem;
@@ -190,12 +178,16 @@ void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char
if( size <= 0 )
return NULL;
if( !poolptr )
if( unlikely( !poolptr ))
{
Sys_Error( "%s: pool == NULL (alloc at %s:%i)\n", __func__, filename, fileline );
return NULL;
}
pool = Mem_FindPool( poolptr );
if( !pool )
return NULL;
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( byte ));
if( mem == NULL )
{
@@ -205,7 +197,6 @@ void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char
Mem_InitAlloc( mem, size, filename, fileline );
pool = Mem_FindPool( poolptr );
Mem_PoolAdd( pool, size );
Mem_PoolLinkAlloc( pool, mem );
@@ -222,7 +213,9 @@ static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline
if( !Mem_CheckAllocHeader( __func__, mem, filename, fileline ))
return;
pool = mem->pool;
pool = Mem_FindPool( mem->poolptr );
if( !pool )
return;
// unlink memheader from doubly linked list
if(( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem ))
@@ -258,7 +251,7 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
if( size <= 0 )
return data; // no need to reallocate
if( !poolptr )
if( unlikely( !poolptr ))
{
Sys_Error( "Mem_Realloc: pool == NULL (alloc at %s:%i)\n", filename, fileline );
return NULL;
@@ -272,25 +265,21 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
if( !Mem_CheckAllocHeader( "Mem_Realloc", mem, filename, fileline ))
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;
if( size == oldsize )
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 );
oldmem = (uintptr_t)mem;
mem = realloc( mem, sizeof( memheader_t ) + size + sizeof( byte ));
mem = Q_realloc( mem, sizeof( memheader_t ) + size + sizeof( byte ));
if( mem == NULL )
{
@@ -312,14 +301,7 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
}
else Mem_PoolSubtract( pool, oldsize - size );
// 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( oldmem != (uintptr_t)mem ) // just relink pointers
{
if( mem->next ) mem->next->prev = mem;
if( mem->prev ) mem->prev->next = mem;
@@ -327,69 +309,81 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
}
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 )
{
mempool_t *pool;
size_t i;
pool = (mempool_t *)Q_malloc( sizeof( mempool_t ));
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
{
if( pool->filename == NULL )
return Mem_InitPool( pool, name, filename, fileline );
}
pool = (mempool_t *)Q_realloc( poolchain, sizeof( *poolchain ) * ( poolcount + 1 ));
if( pool == NULL )
{
Sys_Error( "Mem_AllocPool: out of memory (allocpool at %s:%i)\n", filename, fileline );
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;
#if XASH_64BIT
pool->idx = ++lastidx;
return pool->idx;
#else
return (poolhandle_t)pool;
#endif
pool = &poolchain[poolcount++];
return Mem_InitPool( pool, name, filename, fileline );
}
void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline )
{
mempool_t *pool;
mempool_t **chainaddress;
if( *poolptr && ( pool = Mem_FindPool( *poolptr )))
{
// unlink pool from chain
for( chainaddress = &poolchain; *chainaddress && *chainaddress != pool; chainaddress = &((*chainaddress)->next));
if( *chainaddress != pool ) Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
Mem_CheckPool( "Mem_FreePool", pool, filename, fileline );
*chainaddress = pool->next;
if( !pool->filename )
{
Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
*poolptr = 0;
return;
}
// free memory owned by the pool
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
while( pool->chain )
Mem_FreeBlock( pool->chain, filename, fileline );
// free the pool itself
memset( pool, 0xBF, sizeof( mempool_t ));
Q_free( pool );
pool->chain = NULL;
pool->filename = NULL; // mark as reusable
*poolptr = 0;
}
}
void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline )
{
mempool_t *pool = Mem_FindPool( poolptr );
if( !poolptr ) Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
mempool_t *pool;
if( unlikely( !poolptr ))
{
Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
return;
}
Mem_CheckPool( "Mem_FreePool", pool, filename, fileline );
pool = Mem_FindPool( poolptr );
if( !pool )
return;
// free memory owned by the pool
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
@@ -412,7 +406,8 @@ static qboolean Mem_CheckAlloc( mempool_t *pool, void *data )
else
{
// search all pools
for( pool = poolchain; pool; pool = pool->next )
size_t i;
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
{
if( Mem_CheckAlloc( pool, data ))
return true;
@@ -440,23 +435,24 @@ void _Mem_Check( const char *filename, int fileline )
{
memheader_t *mem;
mempool_t *pool;
size_t i;
for( pool = poolchain; pool; pool = pool->next )
Mem_CheckPool( "Mem_CheckSentinels", pool, filename, fileline );
for( pool = poolchain; pool; pool = pool->next )
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
for( mem = pool->chain; mem; mem = mem->next )
Mem_CheckAllocHeader( "Mem_CheckSentinels", mem, filename, fileline );
}
void Mem_PrintStats( void )
{
size_t count = 0, size = 0, realsize = 0;
size_t count = 0, size = 0, realsize = 0, i;
mempool_t *pool;
Mem_Check();
for( pool = poolchain; pool; pool = pool->next )
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
{
if( !pool->filename )
continue;
count++;
size += pool->totalsize;
realsize += pool->realsize;
@@ -470,15 +466,19 @@ void Mem_PrintList( size_t minallocationsize )
{
mempool_t *pool;
memheader_t *mem;
size_t i;
Mem_Check();
Con_Printf( "memory pool list:\n" );
Con_Printf( "\t^3size\t\t\t\tname\n");
for( pool = poolchain; pool; pool = pool->next )
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
{
long changed_size = (long)pool->totalsize - (long)pool->lastchecksize;
if( !pool->filename )
continue;
// poolnames can contain color symbols, make sure what color is reset
if( pool->lastchecksize != 0 && changed_size != 0 )
{

View File

@@ -50,6 +50,10 @@ GNU General Public License for more details.
#define LUMP_SAVE_NO_DATA 7
#define LUMP_SAVE_CORRUPTED 8
#ifndef ALLOC_CHECK
#define ALLOC_CHECK( x )
#endif
typedef struct areanode_s
{
int axis; // -1 = leaf node

View File

@@ -175,11 +175,13 @@ void Evdev_Autodetect_f( void )
if( evdev.devices >= MAX_EVDEV_DEVICES )
continue;
Q_snprintf( path, MAX_STRING, "/dev/input/%s", entry->d_name );
Q_snprintf( path, sizeof( path ), "/dev/input/%s", entry->d_name );
for( i = 0; i < evdev.devices; i++ )
if( !Q_strncmp( evdev.paths[i], path, MAX_STRING ) )
{
if( !Q_strncmp( evdev.paths[i], path, sizeof( evdev.paths[i] ))
goto next;
}
if( Q_strncmp( entry->d_name, "event", 5 ) )
continue;
@@ -220,7 +222,7 @@ void Evdev_Autodetect_f( void )
}
goto close;
open:
Q_strncpy( evdev.paths[evdev.devices], path, MAX_STRING );
Q_strncpy( evdev.paths[evdev.devices], path, sizeof( evdev.paths[0] ));
evdev.fds[evdev.devices++] = fd;
Con_Printf( "Opened device %s\n", path );
#if XASH_INPUT == INPUT_EVDEV
@@ -260,7 +262,7 @@ void Evdev_OpenDevice ( const char *path )
for( i = 0; i < evdev.devices; i++ )
{
if( !Q_strncmp( evdev.paths[i], path, MAX_STRING ) )
if( !Q_strncmp( evdev.paths[i], path, sizeof( evdev.paths[i] )))
{
Con_Printf( "device %s already open!\n", path );
return;
@@ -275,7 +277,7 @@ void Evdev_OpenDevice ( const char *path )
}
Con_Printf( "Input device #%d: %s opened sucessfully\n", evdev.devices, path );
evdev.fds[evdev.devices] = ret;
Q_strncpy( evdev.paths[evdev.devices++], path, MAX_STRING );
Q_strncpy( evdev.paths[evdev.devices++], path, sizeof( evdev.paths[0] ));
#if XASH_INPUT == INPUT_EVDEV
if( Sys_CheckParm( "-grab" ) )
@@ -309,7 +311,7 @@ void Evdev_CloseDevice_f ( void )
if( Q_isdigit( arg ) )
i = Q_atoi( arg );
else for( i = 0; i < evdev.devices; i++ )
if( !Q_strncmp( evdev.paths[i], arg, MAX_STRING ) )
if( !Q_strncmp( evdev.paths[i], arg, sizeof( evdev.paths[i] )))
break;
if( i >= evdev.devices )
@@ -324,7 +326,7 @@ void Evdev_CloseDevice_f ( void )
for( ; i < evdev.devices; i++ )
{
Q_strncpy( evdev.paths[i], evdev.paths[i+1], MAX_STRING );
Q_strncpy( evdev.paths[i], evdev.paths[i+1], sizeof( evdev.paths[i] ));
evdev.fds[i] = evdev.fds[i+1];
}
}

View File

@@ -148,7 +148,6 @@ static void SDLash_KeyEvent( SDL_KeyboardEvent key )
#else
int keynum = key.keysym.sym;
#endif
qboolean numLock = FBitSet( SDL_GetModState(), KMOD_NUM );
#if XASH_ANDROID
if( keynum == SDL_SCANCODE_VOLUMEUP || keynum == SDL_SCANCODE_VOLUMEDOWN )
@@ -157,32 +156,39 @@ static void SDLash_KeyEvent( SDL_KeyboardEvent key )
}
#endif
if( SDL_IsTextInputActive() && down && cls.key_dest != key_game )
if( SDL_IsTextInputActive( ))
{
if( FBitSet( SDL_GetModState(), KMOD_CTRL ))
// this is how engine understands ctrl+c, ctrl+v and other hotkeys
if( down && cls.key_dest != key_game )
{
if( keynum >= SDL_SCANCODE_A && keynum <= SDL_SCANCODE_Z )
if( FBitSet( SDL_GetModState(), KMOD_CTRL ))
{
keynum = keynum - SDL_SCANCODE_A + 1;
CL_CharEvent( keynum );
}
if( keynum >= SDL_SCANCODE_A && keynum <= SDL_SCANCODE_Z )
{
keynum = keynum - SDL_SCANCODE_A + 1;
CL_CharEvent( keynum );
}
return;
return;
}
}
#if !SDL_VERSION_ATLEAST( 2, 0, 0 )
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
// ignore printable keys, they are coming through SDL_TEXTINPUT
if(( keynum >= SDL_SCANCODE_A && keynum <= SDL_SCANCODE_Z )
|| ( keynum >= SDL_SCANCODE_1 && keynum <= SDL_SCANCODE_0 )
|| ( keynum >= SDL_SCANCODE_KP_1 && keynum <= SDL_SCANCODE_KP_0 ))
return;
#else
if( keynum >= SDLK_KP0 && keynum <= SDLK_KP9 )
keynum -= SDLK_KP0 + '0';
if( isprint( keynum ) )
if( isprint( keynum ))
{
if( FBitSet( SDL_GetModState(), KMOD_SHIFT ))
{
keynum = Key_ToUpper( keynum );
}
CL_CharEvent( keynum );
return;
}
#endif
}
@@ -198,6 +204,8 @@ static void SDLash_KeyEvent( SDL_KeyboardEvent key )
else DECLARE_KEY_RANGE( SDL_SCANCODE_F1, SDL_SCANCODE_F12, K_F1 )
else
{
qboolean numLock = FBitSet( SDL_GetModState(), KMOD_NUM );
switch( keynum )
{
case SDL_SCANCODE_GRAVE: keynum = '`'; break;
@@ -355,10 +363,7 @@ static void SDLash_InputEvent( SDL_TextInputEvent input )
{
int ch;
if( !Q_stricmp( cl_charset.string, "utf-8" ) )
ch = (unsigned char)*text;
else
ch = Con_UtfProcessCharForce( (unsigned char)*text );
ch = Con_UtfProcessChar((byte)*text );
if( !ch )
continue;

View File

@@ -329,6 +329,8 @@ typedef struct
int msg_realsize; // left in bytes
int msg_index; // for debug messages
int msg_dest; // msg destination ( MSG_ONE, MSG_ALL etc )
int msg_rewrite_index;
int msg_rewrite_pos;
qboolean msg_started; // to avoid recursive included messages
edict_t *msg_ent; // user message member entity
vec3_t msg_org; // user message member origin
@@ -392,10 +394,10 @@ typedef struct
//=============================================================================
extern server_static_t svs; // persistant server info
extern server_t sv; // local server
extern svgame_static_t svgame; // persistant game info
extern areanode_t sv_areanodes[]; // AABB dynamic tree
extern server_static_t svs RENAME_SYMBOL( "svs_" ); // persistant server info
extern server_t sv RENAME_SYMBOL( "sv_" ); // local server
extern svgame_static_t svgame; // persistant game info
extern areanode_t sv_areanodes[]; // AABB dynamic tree
extern convar_t mp_logecho;
extern convar_t mp_logfile;
@@ -480,7 +482,7 @@ extern convar_t sv_aim;
//
void SV_FinalMessage( const char *message, qboolean reconnect );
void SV_KickPlayer( sv_client_t *cl, const char *fmt, ... ) _format( 2 );
void SV_DropClient( sv_client_t *cl, qboolean crash );
void SV_DropClient( sv_client_t *cl, qboolean crash ) RENAME_SYMBOL( "SV_DropClient_" );
void SV_UpdateMovevars( qboolean initialize );
int SV_ModelIndex( const char *name );
int SV_SoundIndex( const char *name );

View File

@@ -417,7 +417,7 @@ static void SV_ConnectClient( netadr_t from )
newcl->userid = g_userid++; // create unique userid
newcl->state = cs_connected;
newcl->extensions = extensions & (NET_EXT_SPLITSIZE);
Q_strncpy( newcl->useragent, protinfo, MAX_INFO_STRING );
Q_strncpy( newcl->useragent, protinfo, sizeof( newcl->useragent ));
// reset viewentities (from previous level)
memset( newcl->viewentity, 0, sizeof( newcl->viewentity ));

View File

@@ -690,7 +690,7 @@ static void SV_ConSay_f( void )
}
p = Cmd_Args();
Q_strncpy( text, *p == '"' ? p + 1 : p, MAX_SYSPATH );
Q_strncpy( text, *p == '"' ? p + 1 : p, sizeof( text ));
if( *p == '"' )
{

View File

@@ -666,7 +666,7 @@ void SV_RestartAmbientSounds( void )
#if !XASH_DEDICATED // TODO: ???
// restart soundtrack
if( S_StreamGetCurrentState( curtrack, looptrack, &position ))
if( S_StreamGetCurrentState( curtrack, sizeof( curtrack ), looptrack, sizeof( looptrack ), &position ))
{
SV_StartMusic( curtrack, looptrack, position );
}
@@ -2501,6 +2501,62 @@ int GAME_EXPORT pfnDecalIndex( const char *m )
return -1;
}
static int SV_CanRewriteMessage( int msg_num )
{
// feature is disabled
if( !FBitSet( host.bugcomp, BUGCOMP_MESSAGE_REWRITE_FACILITY_FLAG ))
return 0;
switch( msg_num )
{
case svc_goldsrc_spawnstaticsound:
return svc_sound;
}
return 0;
}
static qboolean SV_RewriteMessage( void )
{
vec3_t origin;
const char *sample = NULL;
float vol, attn;
int ent, pitch, flags, idx;
int cmd;
MSG_SeekToBit( &sv.multicast, svgame.msg_rewrite_pos, SEEK_SET );
cmd = MSG_ReadCmd( &sv.multicast, NS_SERVER );
switch( cmd )
{
case svc_goldsrc_spawnstaticsound:
MSG_ReadVec3Coord( &sv.multicast, origin );
idx = MSG_ReadShort( &sv.multicast );
vol = MSG_ReadByte( &sv.multicast );
attn = MSG_ReadByte( &sv.multicast ) / 64.0f;
ent = MSG_ReadShort( &sv.multicast );
pitch = MSG_ReadByte( &sv.multicast );
flags = MSG_ReadByte( &sv.multicast );
if( FBitSet( flags, SND_SENTENCE ))
sample = va( "!%i", idx );
else if( idx >= 0 && idx < MAX_SOUNDS )
sample = sv.sound_precache[idx];
if( !COM_CheckString( sample ))
{
Con_Printf( S_ERROR "%s: unrecognized sample in svc_spawnstaticsound, index %d, flags 0x%x\n", __func__, idx, flags );
return false;
}
MSG_SeekToBit( &sv.multicast, svgame.msg_rewrite_pos, SEEK_SET );
return SV_BuildSoundMsg( &sv.multicast, EDICT_NUM( ent ), CHAN_STATIC, sample, vol, attn, flags, pitch, origin );
}
return false;
}
/*
=============
pfnMessageBegin
@@ -2518,10 +2574,24 @@ static void GAME_EXPORT pfnMessageBegin( int msg_dest, int msg_num, const float
// check range
msg_num = bound( svc_bad, msg_num, 255 );
svgame.msg_rewrite_index = 0;
svgame.msg_rewrite_pos = 0;
if( msg_num <= svc_lastmsg )
{
svgame.msg_index = -msg_num; // this is a system message
svgame.msg_name = svc_strings[msg_num];
// check if we should rewrite this message into something else...
if( SV_CanRewriteMessage( msg_num ))
{
svgame.msg_index = -SV_CanRewriteMessage( msg_num );
svgame.msg_name = svc_goldsrc_strings[msg_num] ? svc_goldsrc_strings[msg_num] : svc_strings[msg_num];
svgame.msg_rewrite_index = msg_num;
svgame.msg_rewrite_pos = MSG_TellBit( &sv.multicast );
}
else
{
svgame.msg_index = -msg_num; // this is a system message
svgame.msg_name = svc_strings[msg_num];
}
if( msg_num == svc_temp_entity )
iSize = -1; // temp entity have variable size
@@ -2596,6 +2666,25 @@ static void GAME_EXPORT pfnMessageEnd( void )
return;
}
if( svgame.msg_rewrite_index != 0 )
{
if( SV_RewriteMessage( ))
{
if( MSG_CheckOverflow( &sv.multicast ))
{
Con_Printf( S_ERROR "MessageEnd: %s has overflow multicast buffer (post-rewrite)\n", name );
MSG_Clear( &sv.multicast );
return;
}
}
else
{
Con_Printf( S_ERROR "MessageEnd: failed to rewrite message %s\n", name );
MSG_Clear( &sv.multicast );
return;
}
}
// check for system message
if( svgame.msg_index < 0 )
{
@@ -2662,9 +2751,7 @@ static void GAME_EXPORT pfnMessageEnd( void )
// update some messages in case their was format was changed and we want to keep backward compatibility
if( svgame.msg_index < 0 )
{
int svc_msg = abs( svgame.msg_index );
if(( svc_msg == svc_finale || svc_msg == svc_cutscene ) && svgame.msg_realsize == 0 )
if(( svgame.msg_index == -svc_finale || svgame.msg_index == -svc_cutscene ) && svgame.msg_realsize == 0 )
MSG_WriteChar( &sv.multicast, 0 ); // write null string
}
@@ -3344,12 +3431,10 @@ pfnPEntityOfEntIndex
=============
*/
static edict_t *pfnPEntityOfEntIndex( int iEntIndex )
static edict_t *pfnPEntityOfEntIndexBroken( int iEntIndex )
{
// have to be bug-compatible with GoldSrc in this function
if( host.bugcomp == BUGCOMP_GOLDSRC )
return SV_PEntityOfEntIndex( iEntIndex, false );
return SV_PEntityOfEntIndex( iEntIndex, true );
return SV_PEntityOfEntIndex( iEntIndex, false );
}
/*
@@ -4097,7 +4182,16 @@ void GAME_EXPORT SV_PlaybackEventFull( int flags, const edict_t *pInvoker, word
continue;
}
if( FBitSet( flags, FEV_NOTHOST ) && cl == sv.current_client && FBitSet( cl->flags, FCL_LOCAL_WEAPONS ))
// a1ba: GoldSrc never cleans up host_client pointer (similar to sv.current_client)
// so it's always points at some client and in singleplayer this check always succeedes
// in Xash, however, sv.current_client might be reset and set to NULL
// this is especially dangerous when weapons play events in Think functions
//
// IMHO, it doesn't make sense to me to compare it against current client when we have
// invoker edict pointer but to preserve behaviour check for them both
//
// if it breaks some mods, probably sv.current_client semantics must be reworked to match GoldSrc
if( FBitSet( flags, FEV_NOTHOST ) && ( cl == sv.current_client || cl->edict == pInvoker ) && FBitSet( cl->flags, FCL_LOCAL_WEAPONS ))
continue; // will be played on client side
if( FBitSet( flags, FEV_HOSTONLY ) && cl->edict != pInvoker )
@@ -4684,7 +4778,7 @@ static enginefuncs_t gEngfuncs =
pfnPEntityOfEntOffset,
pfnEntOffsetOfPEntity,
pfnIndexOfEdict,
pfnPEntityOfEntIndex,
pfnPEntityOfEntIndexAllEntities,
pfnFindEntityByVars,
pfnGetModelPtr,
pfnRegUserMsg,
@@ -5155,6 +5249,11 @@ qboolean SV_LoadProgs( const char *name )
// make sure what physic functions is cleared
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
memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs ));
@@ -5167,7 +5266,7 @@ qboolean SV_LoadProgs( const char *name )
COM_FreeLibrary( svgame.hInstance );
Con_Printf( S_ERROR "SV_LoadProgs: failed to get address of GetEntityAPI proc\n" );
svgame.hInstance = NULL;
Mem_FreePool(&svgame.mempool);
Mem_FreePool( &svgame.mempool );
return false;
}
@@ -5178,7 +5277,7 @@ qboolean SV_LoadProgs( const char *name )
COM_FreeLibrary( svgame.hInstance );
Con_Printf( S_ERROR "SV_LoadProgs: failed to get address of GiveFnptrsToDll proc\n" );
svgame.hInstance = NULL;
Mem_FreePool(&svgame.mempool);
Mem_FreePool( &svgame.mempool );
return false;
}
@@ -5203,7 +5302,8 @@ qboolean SV_LoadProgs( const char *name )
{
if( !GetEntityAPI2( &svgame.dllFuncs, &version ))
{
Con_Printf( S_WARN "SV_LoadProgs: interface version %i should be %i\n", INTERFACE_VERSION, version );
if( INTERFACE_VERSION != version )
Con_Printf( S_WARN "SV_LoadProgs: interface version %i should be %i\n", INTERFACE_VERSION, version );
// fallback to old API
if( !GetEntityAPI( &svgame.dllFuncs, version ))
@@ -5211,9 +5311,10 @@ qboolean SV_LoadProgs( const char *name )
COM_FreeLibrary( svgame.hInstance );
Con_Printf( S_ERROR "SV_LoadProgs: couldn't get entity API\n" );
svgame.hInstance = NULL;
Mem_FreePool(&svgame.mempool);
Mem_FreePool( &svgame.mempool );
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 );
}
@@ -5222,9 +5323,10 @@ qboolean SV_LoadProgs( const char *name )
COM_FreeLibrary( svgame.hInstance );
Con_Printf( S_ERROR "SV_LoadProgs: couldn't get entity API\n" );
svgame.hInstance = NULL;
Mem_FreePool(&svgame.mempool);
Mem_FreePool( &svgame.mempool );
return false;
}
else Con_Reportf( "SV_LoadProgs: ^2initailized legacy EntityAPI ^7ver. %i\n", version );
SV_InitOperatorCommands();
Mod_InitStudioAPI();

View File

@@ -418,10 +418,8 @@ static void GAME_EXPORT pfnPlaybackEventFull( int flags, int clientindex, word e
ent = EDICT_NUM( clientindex + 1 );
if( !SV_IsValidEdict( ent )) return;
if( Host_IsDedicated() )
flags |= FEV_NOTHOST; // no local clients for dedicated server
SV_PlaybackEventFull( flags, ent, eventindex,
// GoldSrc always sets FEV_NOTHOST in PMove version of this function
SV_PlaybackEventFull( flags | FEV_NOTHOST, ent, eventindex,
delay, origin, angles,
fparam1, fparam2,
iparam1, iparam2,
@@ -590,7 +588,7 @@ static void SV_SetupPMove( playermove_t *pmove, sv_client_t *cl, usercmd_t *ucmd
pmove->cmd = *ucmd; // setup current cmds
pmove->runfuncs = true;
Q_strncpy( pmove->physinfo, physinfo, MAX_INFO_STRING );
Q_strncpy( pmove->physinfo, physinfo, sizeof( pmove->physinfo ));
// setup physents
pmove->numvisent = 0;

View File

@@ -652,7 +652,7 @@ static void DirectoryCopy( const char *pPath, file_t *pFile )
fileSize = FS_FileLength( pCopy );
memset( szName, 0, sizeof( szName )); // clearing the string to prevent garbage in output file
Q_strncpy( szName, COM_FileWithoutPath( t->filenames[i] ), MAX_OSPATH );
Q_strncpy( szName, COM_FileWithoutPath( t->filenames[i] ), sizeof( szName ));
FS_Write( pFile, szName, MAX_OSPATH );
FS_Write( pFile, &fileSize, sizeof( int ));
FS_FileCopy( pFile, pCopy, fileSize );
@@ -1202,7 +1202,7 @@ static void SaveClientState( SAVERESTOREDATA *pSaveData, const char *level, int
header.soundCount = S_GetCurrentDynamicSounds( soundInfo, MAX_CHANNELS );
#if !XASH_DEDICATED
// music not reqiured to save position: it's just continue playing on a next level
S_StreamGetCurrentState( header.introTrack, header.mainTrack, &header.trackPosition );
S_StreamGetCurrentState( header.introTrack, sizeof( header.introTrack ), header.mainTrack, sizeof( header.mainTrack ), &header.trackPosition );
#endif
}

View File

@@ -21,16 +21,16 @@ def options(opt):
help = 'enable custom swap allocator. For devices with no swap support')
grp.add_option('--enable-legacy-sdl', action = 'store_true', dest = 'SDL12', default = False,
help = 'enable using SDL1.2 instead of SDL2(not recommended) [default: %default]')
help = 'enable using SDL1.2 instead of SDL2(not recommended) [default: %(default)s]')
grp.add_option('--enable-static-binary', action = 'store_true', dest = 'STATIC', default = False,
help = 'build static binary(not recommended, --single-binary required) [default: %default]')
help = 'build static binary(not recommended, --single-binary required) [default: %(default)s]')
grp.add_option('--enable-engine-tests', action = 'store_true', dest = 'ENGINE_TESTS', default = False,
help = 'embed tests into the engine, jump into them by -runtests command line switch [default: %default]')
help = 'embed tests into the engine, jump into them by -runtests command line switch [default: %(default)s]')
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)s]' )
opt.load('sdl2')

View File

@@ -1363,8 +1363,13 @@ static qboolean FS_FindLibrary( const char *dllname, qboolean directpath, fs_dll
if( index >= 0 && !dllInfo->encrypted && search )
{
Q_snprintf( dllInfo->fullPath, sizeof( dllInfo->fullPath ),
"%s%s", search->filename, dllInfo->shortPath );
// gamedll might resolve it's own path using dladdr()
// combine it with engine returned path to gamedir
// it might lead to double gamedir like this
// - valve/valve/dlls/hl.so
// instead of expected
// - valve/dlls/hl.so
Q_snprintf( dllInfo->fullPath, sizeof( dllInfo->fullPath ), "%s/%s%s", fs_rootdir, search->filename, dllInfo->shortPath );
dllInfo->custom_loader = false; // we can loading from disk and use normal debugging
}
else
@@ -2120,7 +2125,7 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
{
fs_offset_t done;
fs_offset_t nb;
size_t count;
fs_offset_t count;
// nothing to copy
if( buffersize == 0 ) return 1;
@@ -2139,12 +2144,13 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
if( file->buff_ind < file->buff_len )
{
count = file->buff_len - file->buff_ind;
count = ( buffersize > count ) ? count : (fs_offset_t)buffersize;
done += ( buffersize > count ) ? (fs_offset_t)count : (fs_offset_t)buffersize;
memcpy( buffer, &file->buff[file->buff_ind], done );
file->buff_ind += done;
done += count;
memcpy( buffer, &file->buff[file->buff_ind], count );
file->buff_ind += count;
buffersize -= done;
buffersize -= count;
if( buffersize == 0 )
return done;
}
@@ -2158,10 +2164,10 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
// if we have a lot of data to get, put them directly into "buffer"
if( buffersize > sizeof( file->buff ) / 2 )
{
if( count > buffersize )
count = buffersize;
if( count > (fs_offset_t)buffersize )
count = (fs_offset_t)buffersize;
lseek( file->handle, file->offset + file->position, SEEK_SET );
nb = read( file->handle, (byte *)buffer + done, count );
nb = read( file->handle, &((byte *)buffer)[done], count );
if( nb > 0 )
{
@@ -2173,8 +2179,8 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
}
else
{
if( count > sizeof( file->buff ))
count = sizeof( file->buff );
if( count > (fs_offset_t)sizeof( file->buff ))
count = (fs_offset_t)sizeof( file->buff );
lseek( file->handle, file->offset + file->position, SEEK_SET );
nb = read( file->handle, file->buff, count );

View File

@@ -31,7 +31,7 @@ extern "C"
{
#endif // __cplusplus
#define FS_API_VERSION 2 // not stable yet!
#define FS_API_VERSION 3 // not stable yet!
#define FS_API_CREATEINTERFACE_TAG "XashFileSystem002" // follow FS_API_VERSION!!!
#define FILESYSTEM_INTERFACE_VERSION "VFileSystem009" // never change this!
@@ -121,8 +121,8 @@ typedef enum
typedef struct fs_dllinfo_t
{
string fullPath;
string shortPath;
char fullPath[2048]; // absolute disk path
string shortPath; // vfs path
qboolean encrypted;
qboolean custom_loader;
} fs_dllinfo_t;

View File

@@ -12,7 +12,7 @@ def options(opt):
grp = opt.add_option_group('Game launcher options')
grp.add_option('--disable-menu-changegame', action = 'store_true', dest = 'DISABLE_MENU_CHANGEGAME', default = False,
help = 'disable changing the game from the menu [default: %default]')
help = 'disable changing the game from the menu [default: %(default)s]')
def configure(conf):
if conf.env.DEST_OS == 'win32':

View File

@@ -434,7 +434,7 @@ returns hash key for string
*/
uint COM_HashKey( const char *string, uint hashSize )
{
int hashKey = 5381;
uint hashKey = 5381;
unsigned char i;
while(( i = *string++ ))

View File

@@ -18,7 +18,6 @@ GNU General Public License for more details.
#include "const.h"
#include <math.h>
#include <stdarg.h>
#include <ctype.h>
#include <time.h>
#include "stdio.h"
#include "crtlib.h"
@@ -38,26 +37,6 @@ void Q_strnlwr( const char *in, char *out, size_t size_out )
*out = '\0';
}
qboolean Q_isdigit( const char *str )
{
if( str && *str )
{
while( isdigit( *str )) str++;
if( !*str ) return true;
}
return false;
}
qboolean Q_isspace( const char *str )
{
if( str && *str )
{
while( isspace( *str ) ) str++;
if( !*str ) return true;
}
return false;
}
size_t Q_colorstr( const char *string )
{
size_t len;
@@ -81,59 +60,6 @@ size_t Q_colorstr( const char *string )
return len;
}
char Q_toupper( const char in )
{
char out;
if( in >= 'a' && in <= 'z' )
out = in + 'A' - 'a';
else out = in;
return out;
}
char Q_tolower( const char in )
{
char out;
if( in >= 'A' && in <= 'Z' )
out = in + 'a' - 'A';
else out = in;
return out;
}
size_t Q_strncat( char *dst, const char *src, size_t size )
{
register char *d = dst;
register const char *s = src;
register size_t n = size;
size_t dlen;
if( !dst || !src || !size )
return 0;
// find the end of dst and adjust bytes left but don't go past end
while( n-- != 0 && *d != '\0' ) d++;
dlen = d - dst;
n = size - dlen;
if( n == 0 ) return( dlen + Q_strlen( s ));
while( *s != '\0' )
{
if( n != 1 )
{
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return( dlen + ( s - src )); // count does not include NULL
}
int Q_atoi( const char *str )
{
int val = 0;
@@ -253,13 +179,11 @@ float Q_atof( const char *str )
void Q_atov( float *vec, const char *str, size_t siz )
{
string buffer;
char *pstr, *pfront;
const char *pstr, *pfront;
int j;
Q_strncpy( buffer, str, sizeof( buffer ));
memset( vec, 0, sizeof( vec_t ) * siz );
pstr = pfront = buffer;
pstr = pfront = str;
for( j = 0; j < siz; j++ )
{
@@ -394,7 +318,7 @@ const char* Q_timestamp( int format )
return timestamp;
}
#if !defined( HAVE_STRCASESTR )
#if !HAVE_STRCASESTR
char *Q_stristr( const char *string, const char *string2 )
{
int c;
@@ -721,14 +645,14 @@ void COM_ReplaceExtension( char *path, const char *extension, size_t size )
COM_RemoveLineFeed
============
*/
void COM_RemoveLineFeed( char *str )
void COM_RemoveLineFeed( char *str, size_t bufsize )
{
while( *str != '\0' )
size_t i;
for( i = 0; i < bufsize && *str != '\0'; i++, str++ )
{
if( *str == '\r' || *str == '\n' )
*str = '\0';
++str;
}
}

View File

@@ -18,6 +18,7 @@ GNU General Public License for more details.
#include <string.h>
#include <stdarg.h>
#include <ctype.h>
#include "build.h"
#include "xash3d_types.h"
@@ -63,11 +64,6 @@ const char *Q_buildbranch( void );
void Q_strnlwr( const char *in, char *out, size_t size_out );
#define Q_strlen( str ) (( str ) ? strlen(( str )) : 0 )
size_t Q_colorstr( const char *string );
char Q_toupper( const char in );
char Q_tolower( const char in );
size_t Q_strncat( char *dst, const char *src, size_t siz );
qboolean Q_isdigit( const char *str );
qboolean Q_isspace( const char *str );
int Q_atoi( const char *str );
float Q_atof( const char *str );
void Q_atov( float *vec, const char *str, size_t siz );
@@ -90,7 +86,7 @@ void COM_ReplaceExtension( char *path, const char *extension, size_t size );
void COM_ExtractFilePath( const char *path, char *dest );
const char *COM_FileWithoutPath( const char *in );
void COM_StripExtension( char *path );
void COM_RemoveLineFeed( char *str );
void COM_RemoveLineFeed( char *str, size_t bufsize );
void COM_FixSlashes( char *pname );
void COM_PathSlashFix( char *path );
char COM_Hex2Char( uint8_t hex );
@@ -103,91 +99,186 @@ char *COM_ParseFileSafe( char *data, char *token, const int size, unsigned int f
int matchpattern( const char *in, const char *pattern, qboolean caseinsensitive );
int matchpattern_with_separator( const char *in, const char *pattern, qboolean caseinsensitive, const char *separators, qboolean wildcard_least_one );
// libc implementations
static inline char Q_toupper( const char in )
{
char out;
if( in >= 'a' && in <= 'z' )
out = in + 'A' - 'a';
else out = in;
return out;
}
static inline char Q_tolower( const char in )
{
char out;
if( in >= 'A' && in <= 'Z' )
out = in + 'a' - 'A';
else out = in;
return out;
}
static inline qboolean Q_isdigit( const char *str )
{
if( likely( str && *str ))
{
while( isdigit( *str )) str++;
if( !*str ) return true;
}
return false;
}
static inline qboolean Q_isspace( const char *str )
{
if( likely( str && *str ))
{
while( isspace( *str ) ) str++;
if( !*str ) return true;
}
return false;
}
static inline int Q_strcmp( const char *s1, const char *s2 )
{
return unlikely(!s1) ?
( !s2 ? 0 : -1 ) :
( unlikely(!s2) ? 1 : strcmp( s1, s2 ));
if( likely( s1 && s2 ))
return strcmp( s1, s2 );
return ( s1 ? 1 : 0 ) - ( s2 ? 1 : 0 );
}
static inline int Q_strncmp( const char *s1, const char *s2, size_t n )
{
return unlikely(!s1) ?
( !s2 ? 0 : -1 ) :
( unlikely(!s2) ? 1 : strncmp( s1, s2, n ));
if( likely( s1 && s2 ))
return strncmp( s1, s2, n );
return ( s1 ? 1 : 0 ) - ( s2 ? 1 : 0 );
}
static inline char *Q_strstr( const char *s1, const char *s2 )
{
return unlikely( !s1 || !s2 ) ? NULL : (char*)strstr( s1, s2 );
if( likely( s1 && s2 ))
return (char *)strstr( s1, s2 );
return NULL;
}
// Q_strncpy is the same as strlcpy
static inline size_t Q_strncpy( char *dst, const char *src, size_t siz )
// libc extensions, be careful what to enable or what not
static inline size_t Q_strncpy( char *dst, const char *src, size_t size )
{
#if HAVE_STRLCPY
if( unlikely( !dst || !src || !size ))
return 0;
return strlcpy( dst, src, size );
#else
size_t len;
if( unlikely( !dst || !src || !siz ))
if( unlikely( !dst || !src || !size ))
return 0;
len = strlen( src );
if( len + 1 > siz ) // check if truncate
if( len + 1 > size ) // check if truncate
{
memcpy( dst, src, siz - 1 );
dst[siz - 1] = 0;
memcpy( dst, src, size - 1 );
dst[size - 1] = 0;
}
else memcpy( dst, src, len + 1 );
return len; // count does not include NULL
#endif
}
// libc extensions, be careful
static inline size_t Q_strncat( char *dst, const char *src, size_t size )
{
#if HAVE_STRLCAT
if( unlikely( !dst || !src || !size ))
return 0;
return strlcat( dst, src, size );
#else
char *d = dst;
const char *s = src;
size_t n = size;
size_t dlen;
#if XASH_WIN32
#define strcasecmp stricmp
#define strncasecmp strnicmp
#endif // XASH_WIN32
if( unlikely( !dst || !src || !size ))
return 0;
// find the end of dst and adjust bytes left but don't go past end
while( n-- != 0 && *d != '\0' ) d++;
dlen = d - dst;
n = size - dlen;
if( n == 0 ) return( dlen + Q_strlen( s ));
while( *s != '\0' )
{
if( n != 1 )
{
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return( dlen + ( s - src )); // count does not include NULL
#endif
}
#if HAVE_STRICMP || HAVE_STRCASECMP
static inline int Q_stricmp( const char *s1, const char *s2 )
{
return unlikely(!s1) ?
( !s2 ? 0 : -1 ) :
( unlikely(!s2) ? 1 : strcasecmp( s1, s2 ));
if( likely( s1 && s2 ))
{
#if HAVE_STRICMP
return stricmp( s1, s2 );
#elif HAVE_STRCASECMP
return strcasecmp( s1, s2 );
#endif
}
return ( s1 ? 1 : 0 ) - ( s2 ? 1 : 0 );
}
#else
int Q_stricmp( const char *s1, const char *s2 );
#endif
#if HAVE_STRICMP || HAVE_STRCASECMP
static inline int Q_strnicmp( const char *s1, const char *s2, size_t n )
{
return unlikely(!s1) ?
( !s2 ? 0 : -1 ) :
( unlikely(!s2) ? 1 : strncasecmp( s1, s2, n ));
}
#if defined( HAVE_STRCASESTR )
#if XASH_WIN32
#define strcasestr stristr
if( likely( s1 && s2 ))
{
#if HAVE_STRICMP
return strnicmp( s1, s2, n );
#elif HAVE_STRCASECMP
return strncasecmp( s1, s2, n );
#endif
}
return ( s1 ? 1 : 0 ) - ( s2 ? 1 : 0 );
}
#else
int Q_strnicmp( const char *s1, const char *s2, size_t n );
#endif
#if HAVE_STRCASESTR
static inline char *Q_stristr( const char *s1, const char *s2 )
{
return unlikely( !s1 || !s2 ) ? NULL : (char *)strcasestr( s1, s2 );
if( likely( s1 && s2 ))
return (char *)strcasestr( s1, s2 );
return NULL;
}
#else // defined( HAVE_STRCASESTR )
#else // !HAVE_STRCASESTR
char *Q_stristr( const char *s1, const char *s2 );
#endif // defined( HAVE_STRCASESTR )
#endif // !HAVE_STRCASESTR
#if defined( HAVE_STRCHRNUL )
#if HAVE_STRCHRNUL
#define Q_strchrnul strchrnul
#else
#else // !HAVE_STRCHRNUL
static inline const char *Q_strchrnul( const char *s, int c )
{
const char *p = Q_strchr( s, c );
if( p )
return p;
if( p ) return p;
return s + Q_strlen( s );
}
#endif
#endif // !HAVE_STRCHRNUL
#ifdef __cplusplus
}

View File

@@ -205,3 +205,42 @@ size_t Q_UTF16ToUTF8( char *dst, size_t dstsize, const uint16_t *src, size_t src
return dsti;
}
static uint16_t table_cp1251[64] = {
0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
0x007F, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457
};
uint32_t Q_UnicodeToCP1251( uint32_t uc )
{
size_t i;
if( uc < 0x80 )
return uc;
if( uc >= 0x0410 && uc <= 0x042F )
return uc - 0x410 + 0xC0;
if( uc >= 0x0430 && uc <= 0x044F )
return uc - 0x430 + 0xE0;
for( i = 0; i < sizeof( table_cp1251 ) / sizeof( table_cp1251[0] ); i++ )
{
if( uc == (uint32_t)table_cp1251[i] )
return i + 0x80;
}
return '?';
}
uint32_t Q_UnicodeToCP1252( uint32_t uc )
{
// this is NOT valid way to convert Unicode codepoint back to CP1252!!!
return uc < 0xFF ? uc : '?';
}

View File

@@ -37,4 +37,8 @@ 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 );
// function to convert Unicode codepoints into CP1251 or CP1252
uint32_t Q_UnicodeToCP1251( uint32_t uc );
uint32_t Q_UnicodeToCP1252( uint32_t uc );
#endif // UTFLIB_H

View File

@@ -2,22 +2,110 @@
# encoding: utf-8
# mittorn, 2018
from waflib import Logs
from waflib import Logs, Configure
import os
top = '.'
TGMATH_H_TEST = '''#include <tgmath.h>
const float val = 2, val2 = 3;
int main(void){ return (int)(-asin(val) + cos(val2)); }'''
STRNCASECMP_TEST = '''#include <string.h>
int main(int argc, char **argv) { return strncasecmp(argv[1], argv[2], 10); }'''
STRCASECMP_TEST = '''#include <string.h>
int main(int argc, char **argv) { return strcasecmp(argv[1], argv[2]); }'''
STRCASESTR_TEST = '''#include <string.h>
int main(int argc, char **argv) { argv[0] = strcasestr(argv[1], argv[2]); return 0; }'''
STRCHRNUL_TEST = '''#include <string.h>
int main(int argc, char **argv) { argv[2] = strchrnul(argv[1], 'x'); return 0; }'''
STRLCPY_TEST = '''#include <string.h>
int main(int argc, char **argv) { return strlcpy(argv[1], argv[2], 10); }'''
STRLCAT_TEST = '''#include <string.h>
int main(int argc, char **argv) { return strlcat(argv[1], argv[2], 10); }'''
ALLOCA_TEST = '''#include <%s>
int main(void) { alloca(1); return 0; }'''
HEADER_TEST = '''#include <%s>
int main(void) { return 0; }
'''
def options(opt):
# stub
return
def header_frag(header_name):
return '#include <%s>' % header_name + EMPTY_PROGRAM
@Configure.conf
def export_define(conf, define, value=1):
if not value:
return
if value is True:
value = 1 # so python won't define it as string True
conf.env.EXPORT_DEFINES_LIST += ['%s=%s' % (define, value)]
@Configure.conf
def simple_check(conf, fragment, msg, mandatory=False, **kw):
return conf.check_cc(fragment=fragment, msg='Checking for %s' % msg, mandatory=mandatory, **kw)
def configure(conf):
# private to libpublic
conf.load('gitversion')
conf.define('XASH_BUILD_COMMIT', conf.env.GIT_VERSION if conf.env.GIT_VERSION else 'unknown-commit')
conf.define('XASH_BUILD_BRANCH', conf.env.GIT_BRANCH if conf.env.GIT_BRANCH else 'unknown-branch')
# need to expose it for everyone using libpublic headers
conf.env.EXPORT_DEFINES_LIST = []
conf.export_define('_CRT_SILENCE_NONCONFORMING_TGMATH_H', conf.env.COMPILER_CC == 'msvc')
conf.export_define('_GNU_SOURCE', conf.env.DEST_OS != 'win32')
# create temporary uselib that just enables extensions
conf.env.DEFINES_export = list(conf.env.EXPORT_DEFINES_LIST)
# check platform-specific header name for alloca(3)
if conf.simple_check(ALLOCA_TEST % 'alloca.h', msg='alloca in alloca.h'):
conf.export_define('ALLOCA_H', '<alloca.h>')
elif conf.simple_check(ALLOCA_TEST % 'malloc.h', msg='alloca in malloc.h'):
conf.export_define('ALLOCA_H', '<malloc.h>')
elif conf.simple_check(ALLOCA_TEST % 'stdlib.h', msg='alloca in stdlib.h'):
conf.export_define('ALLOCA_H', '<stdlib.h>')
conf.export_define('STDINT_H', '<stdint.h>' if conf.simple_check(HEADER_TEST % 'stdint.h', 'stdint.h') else '<pstdint.h>')
conf.export_define('HAVE_TGMATH_H', conf.simple_check(TGMATH_H_TEST, 'tgmath.h', use='M werror export'))
# save some time on Windows, msvc is too slow
# these calls must be available with both msvc and mingw
if conf.env.DEST_OS == 'win32':
conf.export_define('HAVE_STRNICMP')
conf.export_define('HAVE_STRICMP')
else:
# TODO: multicheck for speed
def check_libc_extension(frag, msg, define):
conf.export_define(define, conf.simple_check(frag, msg, use='werror export'))
check_libc_extension(STRNCASECMP_TEST, 'strncasecmp', 'HAVE_STRNCASECMP')
check_libc_extension(STRCASECMP_TEST, 'strcasecmp', 'HAVE_STRCASECMP')
check_libc_extension(STRCASESTR_TEST, 'strcasestr', 'HAVE_STRCASESTR')
check_libc_extension(STRCHRNUL_TEST, 'strchrnul', 'HAVE_STRCHRNUL')
check_libc_extension(STRLCPY_TEST, 'strlcpy', 'HAVE_STRLCPY')
check_libc_extension(STRLCAT_TEST, 'strlcat', 'HAVE_STRLCAT')
# kill temporary uselib
del conf.env.DEFINES_export
def build(bld):
bld(name = 'sdk_includes', export_includes = '. ../common ../pm_shared ../engine')
bld(name = 'sdk_includes',
export_includes = '. ../common ../pm_shared ../engine',
export_defines = bld.env.EXPORT_DEFINES_LIST)
bld.stlib(source = bld.path.ant_glob('*.c'),
target = 'public',
features = 'c',

View File

@@ -34,7 +34,6 @@ Limitations:
#include "gl_local.h"
#ifndef XASH_GL_STATIC
#include "gl2_shim.h"
#include ALLOCA_H
#define MAX_SHADERLEN 4096
// increase this when adding more attributes

View File

@@ -64,7 +64,16 @@ Opaque entity can be brush or studio model but sprite
qboolean R_OpaqueEntity( cl_entity_t *ent )
{
if( R_GetEntityRenderMode( ent ) == kRenderNormal )
return true;
{
switch( ent->curstate.renderfx )
{
case kRenderFxNone:
case kRenderFxDeadPlayer:
case kRenderFxLightMultiplier:
case kRenderFxExplode:
return true;
}
}
return false;
}

View File

@@ -3560,6 +3560,19 @@ static void R_StudioDrawModelInternal( cl_entity_t *e, int flags )
}
}
static cl_entity_t *R_FindParentEntity( cl_entity_t *e, cl_entity_t **entities, uint num_entities )
{
uint i;
for( i = 0; i < num_entities; i++ )
{
if( entities[i]->index == e->curstate.aiment )
return entities[i];
}
return NULL;
}
/*
=================
R_DrawStudioModel
@@ -3576,38 +3589,27 @@ void R_DrawStudioModel( cl_entity_t *e )
{
R_StudioDrawModelInternal( e, STUDIO_RENDER|STUDIO_EVENTS );
}
else if( e->curstate.movetype == MOVETYPE_FOLLOW && e->curstate.aiment > 0 )
else if( e->curstate.movetype == MOVETYPE_FOLLOW )
{
cl_entity_t *parent = CL_GetEntityByIndex( e->curstate.aiment ), **entities;
uint i, num_entities;
cl_entity_t *parent = CL_GetEntityByIndex( e->curstate.aiment );
if( !parent || !parent->model || parent->model->type != mod_studio )
return;
if( R_OpaqueEntity( parent ))
{
entities = tr.draw_list->solid_entities;
num_entities = tr.draw_list->num_solid_entities;
}
else
{
entities = tr.draw_list->trans_entities;
num_entities = tr.draw_list->num_solid_entities;
}
parent = R_FindParentEntity( e, tr.draw_list->solid_entities, tr.draw_list->num_solid_entities );
for( i = 0; i < num_entities; i++ )
{
if( (*entities)[i].index != e->curstate.aiment )
continue;
if( !parent )
parent = R_FindParentEntity( e, tr.draw_list->trans_entities, tr.draw_list->num_trans_entities );
RI.currententity = &(*entities)[i];
if( parent )
{
RI.currententity = parent;
R_StudioDrawModelInternal( RI.currententity, 0 );
VectorCopy( RI.currententity->curstate.origin, e->curstate.origin );
VectorCopy( RI.currententity->origin, e->origin );
RI.currententity = e;
R_StudioDrawModelInternal( e, STUDIO_RENDER|STUDIO_EVENTS );
break;
}
}
else

View File

@@ -11,7 +11,7 @@ def options(opt):
grp = opt.add_option_group('ref_gl options')
grp.add_option('--enable-static-gl', action='store_true', dest='GL_STATIC', default=False,
help = 'enable direct linking to opengl [default: %default]')
help = 'enable direct linking to opengl [default: %(default)s]')
# stub
return

View File

@@ -57,8 +57,8 @@ int r_screenwidth;
int r_viewcluster, r_oldviewcluster;
CVAR_DEFINE_AUTO( sw_clearcolor, "48999", 0, "screen clear color");
CVAR_DEFINE_AUTO( sw_drawflat, "0", 0, "");
CVAR_DEFINE_AUTO( sw_draworder, "0", 0, "");
CVAR_DEFINE_AUTO( sw_drawflat, "0", FCVAR_CHEAT, "");
CVAR_DEFINE_AUTO( sw_draworder, "0", FCVAR_CHEAT, "");
CVAR_DEFINE_AUTO( sw_maxedges, "32", 0, "");
static CVAR_DEFINE_AUTO( sw_maxsurfs, "0", 0, "");
CVAR_DEFINE_AUTO( sw_mipscale, "1", FCVAR_GLCONFIG, "nothing");
@@ -150,7 +150,16 @@ qboolean R_OpaqueEntity( cl_entity_t *ent )
int rendermode = R_GetEntityRenderMode( ent );
if( rendermode == kRenderNormal )
return true;
{
switch( ent->curstate.renderfx )
{
case kRenderFxNone:
case kRenderFxDeadPlayer:
case kRenderFxLightMultiplier:
case kRenderFxExplode:
return true;
}
}
if( sw_notransbrushes.value && ent->model && ent->model->type == mod_brush && rendermode == kRenderTransTexture )
return true;

View File

@@ -3326,6 +3326,19 @@ static void R_StudioDrawModelInternal( cl_entity_t *e, int flags )
}
}
static cl_entity_t *R_FindParentEntity( cl_entity_t *e, cl_entity_t **entities, uint num_entities )
{
uint i;
for( i = 0; i < num_entities; i++ )
{
if( entities[i]->index == e->curstate.aiment )
return entities[i];
}
return NULL;
}
/*
=================
R_DrawStudioModel
@@ -3342,38 +3355,27 @@ void R_DrawStudioModel( cl_entity_t *e )
{
R_StudioDrawModelInternal( e, STUDIO_RENDER|STUDIO_EVENTS );
}
else if( e->curstate.movetype == MOVETYPE_FOLLOW && e->curstate.aiment > 0 )
else if( e->curstate.movetype == MOVETYPE_FOLLOW )
{
cl_entity_t *parent = CL_GetEntityByIndex( e->curstate.aiment ), **entities;
uint i, num_entities;
cl_entity_t *parent = CL_GetEntityByIndex( e->curstate.aiment );
if( !parent || !parent->model || parent->model->type != mod_studio )
return;
if( R_OpaqueEntity( parent ))
{
entities = tr.draw_list->solid_entities;
num_entities = tr.draw_list->num_solid_entities;
}
else
{
entities = tr.draw_list->trans_entities;
num_entities = tr.draw_list->num_solid_entities;
}
parent = R_FindParentEntity( e, tr.draw_list->solid_entities, tr.draw_list->num_solid_entities );
for( i = 0; i < num_entities; i++ )
{
if( (*entities)[i].index != e->curstate.aiment )
continue;
if( !parent )
parent = R_FindParentEntity( e, tr.draw_list->trans_entities, tr.draw_list->num_trans_entities );
RI.currententity = &(*entities)[i];
if( parent )
{
RI.currententity = parent;
R_StudioDrawModelInternal( RI.currententity, 0 );
VectorCopy( RI.currententity->curstate.origin, e->curstate.origin );
VectorCopy( RI.currententity->origin, e->origin );
RI.currententity = e;
R_StudioDrawModelInternal( e, STUDIO_RENDER|STUDIO_EVENTS );
break;
}
}
else

View File

@@ -52,12 +52,12 @@ build_engine()
if [ "$1" = "dedicated" ]; then
./waf configure -T release -d $AMD64 --enable-tests --enable-lto || die_configure
elif [ "$1" = "full" ]; then
./waf configure --sdl2=SDL2_linux -T release --enable-stb $AMD64 --enable-utils --enable-tests --enable-lto || die_confgure
./waf configure --sdl2=SDL2_linux -T release --enable-stb $AMD64 --enable-utils --enable-tests --enable-lto || die_configure
else
die
fi
./waf build || die
./waf build || die_configure
}
build_appimage()

View File

@@ -137,10 +137,8 @@ def options(opt):
:param opt: Options context from the *waf* build environment.
:type opt: waflib.Options.OptionsContext
'''
opt.add_option('--cmake', dest='cmake', default=False,
action='store_true', help='select cmake for export/import actions')
opt.add_option('--clean', dest='clean', default=False,
action='store_true', help='delete exported files')
opt.add_option('--cmake', dest='cmake', default=False, action='store_true', help='select cmake for export/import actions')
opt.add_option('--cmake-clean', dest='cmake_clean', default=False, action='store_true', help='delete exported cmake files')
def configure(conf):
@@ -179,7 +177,7 @@ class CMakeContext(BuildContext):
pass
self.cmake = True
if self.options.clean:
if self.options.cmake_clean:
cleanup(self)
else:
export(self)
@@ -224,7 +222,7 @@ def cleanup(bld):
:param bld: a *waf* build instance from the top level *wscript*.
:type bld: waflib.Build.BuildContext
'''
if not bld.options.clean:
if not bld.options.cmake_clean:
return
loc = bld.path.relpath().replace('\\', '/')

View File

@@ -121,6 +121,17 @@ POLLY_CFLAGS = {
# msvc sosat :(
}
OPENMP_CFLAGS = {
'gcc': ['-fopenmp'],
'clang': ['-fopenmp'],
'msvc': ['/openmp']
}
OPENMP_LINKFLAGS = {
'gcc': ['-fopenmp'],
'clang': ['-fopenmp'],
}
PROFILE_GENERATE_CFLAGS = {
'gcc': ['-fprofile-generate=xash3d-prof'],
}
@@ -144,16 +155,19 @@ def options(opt):
help = 'build type: debug, release or none(custom flags)')
grp.add_option('--enable-lto', action = 'store_true', dest = 'LTO', default = False,
help = 'enable Link Time Optimization if possible [default: %default]')
help = 'enable Link Time Optimization if possible [default: %(default)s]')
grp.add_option('--enable-poly-opt', action = 'store_true', dest = 'POLLY', default = False,
help = 'enable polyhedral optimization if possible [default: %default]')
help = 'enable polyhedral optimization if possible [default: %(default)s]')
grp.add_option('--enable-openmp', action = 'store_true', dest = 'OPENMP', default = False,
help = 'enable OpenMP extensions [default: %(default)s]')
grp.add_option('--enable-profile', action = 'store_true', dest = 'PROFILE_GENERATE', default = False,
help = 'enable profile generating build (stored in xash3d-prof directory) [default: %default]')
help = 'enable profile generating build (stored in xash3d-prof directory) [default: %(default)s]')
grp.add_option('--use-profile', action = 'store', dest = 'PROFILE_USE', default = None,
help = 'use profile during build [default: %default]')
help = 'use profile during build [default: %(default)s]')
def configure(conf):
conf.start_msg('Build type')
@@ -171,6 +185,7 @@ def configure(conf):
conf.msg('LTO build', 'yes' if conf.options.LTO else 'no')
conf.msg('PolyOpt build', 'yes' if conf.options.POLLY else 'no')
conf.msg('OpenMP build', 'yes' if conf.options.OPENMP else 'no')
conf.msg('Generate profile', 'yes' if conf.options.PROFILE_GENERATE else 'no')
conf.msg('Use profile', conf.options.PROFILE_USE if not conf.options.PROFILE_GENERATE else 'no')
@@ -203,6 +218,10 @@ def get_optimization_flags(conf):
if conf.options.POLLY:
cflags += conf.get_flags_by_compiler(POLLY_CFLAGS, conf.env.COMPILER_CC)
if conf.options.OPENMP:
linkflags+= conf.get_flags_by_compiler(OPENMP_LINKFLAGS, conf.env.COMPILER_CC)
cflags += conf.get_flags_by_compiler(OPENMP_CFLAGS, conf.env.COMPILER_CC)
if conf.options.PROFILE_GENERATE:
linkflags+= conf.get_flags_by_compiler(PROFILE_GENERATE_LINKFLAGS, conf.env.COMPILER_CC)
cflags += conf.get_flags_by_compiler(PROFILE_GENERATE_CFLAGS, conf.env.COMPILER_CC)

View File

@@ -17,10 +17,10 @@ def options(opt):
vgui_dev_path = os.path.join(opt.path.path_from(opt.root), 'vgui-dev')
grp.add_option('--vgui', action = 'store', dest = 'VGUI_DEV', default=vgui_dev_path,
help = 'path to vgui-dev repo [default: %default]')
help = 'path to vgui-dev repo [default: %(default)s]')
grp.add_option('--skip-vgui-sanity-check', action = 'store_false', dest = 'VGUI_SANITY_CHECK', default=True,
help = 'skip checking VGUI sanity [default: %default]' )
help = 'skip checking VGUI sanity [default: %(default)s]' )
return
@conf

View File

@@ -503,13 +503,13 @@ def options(opt):
xc.add_option('--android', action='store', dest='ANDROID_OPTS', default=None,
help='enable building for android, format: --android=<arch>,<toolchain>,<api>, example: --android=armeabi-v7a-hard,4.9,9')
xc.add_option('--enable-magx', action='store_true', dest='MAGX', default=False,
help='enable building for Motorola MAGX [default: %default]')
help='enable building for Motorola MAGX [default: %(default)s]')
xc.add_option('--enable-msvc-wine', action='store_true', dest='MSVC_WINE', default=False,
help='enable building with MSVC using Wine [default: %default]')
help='enable building with MSVC using Wine [default: %(default)s]')
xc.add_option('--nswitch', action='store_true', dest='NSWITCH', default = False,
help='enable building for Nintendo Switch [default: %default]')
help='enable building for Nintendo Switch [default: %(default)s]')
xc.add_option('--psvita', action='store_true', dest='PSVITA', default = False,
help='enable building for PlayStation Vita [default: %default]')
help='enable building for PlayStation Vita [default: %(default)s]')
xc.add_option('--sailfish', action='store', dest='SAILFISH', default = None,
help='enable building for Sailfish/Aurora')

View File

@@ -79,7 +79,7 @@ qboolean LoadActivityList( const char *appname )
return false;
}
COM_RemoveLineFeed( buf );
COM_RemoveLineFeed( buf, sizeof( buf ));
activity_names[activity_count - 1] = strdup( buf );

View File

@@ -7,7 +7,7 @@ def options(opt):
grp = opt.get_option_group('Utilities options')
grp.add_option('--disable-utils-mdldec', action = 'store_true', dest = 'DISABLE_UTILS_MDLDEC', default = False,
help = 'disable studio model decompiler utility [default: %default]')
help = 'disable studio model decompiler utility [default: %(default)s]')
def configure(conf):
conf.env.DISABLE_UTILS_MDLDEC = conf.options.DISABLE_UTILS_MDLDEC

20
waf vendored

File diff suppressed because one or more lines are too long

95
wscript
View File

@@ -3,7 +3,7 @@
# a1batross, mittorn, 2018
from waflib import Build, Context, Logs
from waflib.Tools import waf_unit_test
from waflib.Tools import waf_unit_test, c_tests
import sys
import os
@@ -14,6 +14,9 @@ default_prefix = '/' # Waf uses it to set default prefix
Context.Context.line_just = 55 # should fit for everything on 80x26
c_tests.LARGE_FRAGMENT='''#include <unistd.h>
int check[sizeof(off_t) >= 8 ? 1 : -1]; int main(void) { return 0; }'''
class Subproject:
def __init__(self, name, fnFilter = None):
self.name = name
@@ -50,7 +53,7 @@ class RefDll:
kw['dest'] = self.dest
kw['default'] = self.default
kw['help'] = '%s %s renderer [default: %%default]' % (act, self.name)
kw['help'] = '%s %s renderer [default: %%(default)s]' % (act, self.name)
opt.add_option(key, **kw)
@@ -105,36 +108,36 @@ REFDLLS = [
]
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 subproject cmake')
grp = opt.add_option_group('Common options')
grp.add_option('-d', '--dedicated', action = 'store_true', dest = 'DEDICATED', default = False,
help = 'build Xash Dedicated Server [default: %default]')
help = 'build Xash Dedicated Server [default: %(default)s]')
grp.add_option('--gamedir', action = 'store', dest = 'GAMEDIR', default = 'valve',
help = 'engine default game directory [default: %default]')
help = 'engine default game directory [default: %(default)s]')
grp.add_option('-8', '--64bits', action = 'store_true', dest = 'ALLOW64', default = False,
help = 'allow targetting 64-bit engine(Linux/Windows/OSX x86 only) [default: %default]')
help = 'allow targetting 64-bit engine(Linux/Windows/OSX x86 only) [default: %(default)s]')
grp.add_option('-P', '--enable-packaging', action = 'store_true', dest = 'PACKAGING', default = False,
help = 'respect prefix option, useful for packaging for various operating systems [default: %default]')
help = 'respect prefix option, useful for packaging for various operating systems [default: %(default)s]')
grp.add_option('--enable-bundled-deps', action = 'store_true', dest = 'BUILD_BUNDLED_DEPS', default = False,
help = 'prefer to build bundled dependencies (like opus) instead of relying on system provided')
grp.add_option('--enable-bsp2', action = 'store_true', dest = 'SUPPORT_BSP2_FORMAT', default = False,
help = 'build engine and renderers with BSP2 map support(recommended for Quake, breaks compatibility!) [default: %default]')
help = 'build engine and renderers with BSP2 map support(recommended for Quake, breaks compatibility!) [default: %(default)s]')
grp.add_option('--low-memory-mode', action = 'store', dest = 'LOW_MEMORY', default = 0, type = 'int',
grp.add_option('--low-memory-mode', action = 'store', dest = 'LOW_MEMORY', default = 0, type = int,
help = 'enable low memory mode (only for devices have <128 ram)')
grp.add_option('--disable-werror', action = 'store_true', dest = 'DISABLE_WERROR', default = False,
help = 'disable compilation abort on warning')
grp.add_option('--enable-tests', action = 'store_true', dest = 'TESTS', default = False,
help = 'enable building standalone tests (does not enable engine tests!) [default: %default]')
help = 'enable building standalone tests (does not enable engine tests!) [default: %(default)s]')
# a1ba: special option for me
grp.add_option('--debug-all-servers', action='store_true', dest='ALL_SERVERS', default=False, help='')
@@ -142,7 +145,7 @@ def options(opt):
grp = opt.add_option_group('Renderers options')
grp.add_option('--enable-all-renderers', action='store_true', dest='ALL_RENDERERS', default=False,
help = 'enable all renderers supported by Xash3D FWGS [default: %default]')
help = 'enable all renderers supported by Xash3D FWGS [default: %(default)s]')
for dll in REFDLLS:
dll.register_option(grp)
@@ -150,10 +153,10 @@ def options(opt):
grp = opt.add_option_group('Utilities options')
grp.add_option('--enable-utils', action = 'store_true', dest = 'ENABLE_UTILS', default = False,
help = 'enable building various development utilities [default: %default]')
help = 'enable building various development utilities [default: %(default)s]')
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)s]' )
for i in SUBDIRS:
if not i.is_exists(opt):
@@ -279,7 +282,7 @@ def configure(conf):
conf.env.append_unique('CXXFLAGS', cxxflags)
conf.env.append_unique('LINKFLAGS', linkflags)
if conf.env.COMPILER_CC != 'msvc' and not conf.options.DISABLE_WERROR:
if conf.env.COMPILER_CC != 'msvc':
opt_flags = [
# '-Wall', '-Wextra', '-Wpedantic',
'-fdiagnostics-color=always',
@@ -342,6 +345,11 @@ def configure(conf):
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.CXXFLAGS_werror = conf.filter_cxxflags(opt_flags + opt_cxxflags, cxxflags)
@@ -374,18 +382,6 @@ def configure(conf):
conf.define('XASH_GAMEDIR', conf.options.GAMEDIR)
conf.define_cond('XASH_ALL_SERVERS', conf.options.ALL_SERVERS)
# check if we can use C99 stdint
conf.define('STDINT_H', 'stdint.h' if conf.check_cc(header_name='stdint.h', mandatory=False) else 'pstdint.h')
# check if we can use alloca.h or malloc.h
if conf.check_cc(header_name='alloca.h', mandatory=False):
conf.define('ALLOCA_H', 'alloca.h')
elif conf.check_cc(header_name='malloc.h', mandatory=False):
conf.define('ALLOCA_H', 'malloc.h')
elif conf.check_cc(fragment = '''#include <stdlib.h>
int main(void) { alloca(1); }''', msg = 'Checking for alloca in stdlib.h'):
conf.define('ALLOCA_H', 'stdlib.h')
if conf.env.DEST_OS == 'nswitch':
conf.check_cfg(package='solder', args='--cflags --libs', uselib_store='SOLDER')
if conf.env.HAVE_SOLDER and conf.env.LIB_SOLDER and conf.options.BUILD_TYPE == 'debug':
@@ -417,53 +413,12 @@ def configure(conf):
conf.check_cc(lib='m')
# check if we can use C99 tgmath
if conf.check_cc(header_name='tgmath.h', mandatory=False):
if conf.env.COMPILER_CC == 'msvc':
conf.define('_CRT_SILENCE_NONCONFORMING_TGMATH_H', 1)
tgmath_usable = conf.check_cc(fragment='''#include<tgmath.h>
const float val = 2, val2 = 3;
int main(void){ return (int)(-asin(val) + cos(val2)); }''',
msg='Checking if tgmath.h is usable', mandatory=False, use='M werror')
conf.define_cond('HAVE_TGMATH_H', tgmath_usable)
else:
conf.undefine('HAVE_TGMATH_H')
# set _FILE_OFFSET_BITS=64 for filesystems with 64-bit inodes
if conf.env.DEST_OS != 'win32' and conf.env.DEST_SIZEOF_VOID_P == 4:
# check was borrowed from libarchive source code
file_offset_bits_usable = conf.check_cc(fragment='''
#define _FILE_OFFSET_BITS 64
#include <sys/types.h>
#define KB ((off_t)1024)
#define MB ((off_t)1024 * KB)
#define GB ((off_t)1024 * MB)
#define TB ((off_t)1024 * GB)
int t2[(((64 * GB -1) % 671088649) == 268434537)
&& (((TB - (64 * GB -1) + 255) % 1792151290) == 305159546)? 1: -1];
int main(void) { return 0; }''',
msg='Checking if _FILE_OFFSET_BITS can be defined to 64', mandatory=False, use='werror')
if file_offset_bits_usable:
conf.define('_FILE_OFFSET_BITS', 64)
else: conf.undefine('_FILE_OFFSET_BITS')
if conf.env.DEST_OS != 'win32':
strcasestr_frag = '''#include <string.h>
int main(int argc, char **argv) { strcasestr(argv[1], argv[2]); return 0; }'''
strchrnul_frag = '''#include <string.h>
int main(int argc, char **argv) { strchrnul(argv[1], 'x'); return 0; }'''
def check_gnu_function(frag, msg, define):
if conf.check_cc(msg=msg, mandatory=False, fragment=frag, use='werror'):
conf.define(define, 1)
elif conf.check_cc(msg='... with _GNU_SOURCE?', mandatory=False, fragment=frag, defines='_GNU_SOURCE=1', use='werror'):
conf.define(define, 1)
conf.define('_GNU_SOURCE', 1)
check_gnu_function(strcasestr_frag, 'Checking for strcasestr', 'HAVE_STRCASESTR')
check_gnu_function(strchrnul_frag, 'Checking for strchrnul', 'HAVE_STRCHRNUL')
# must be set globally as it changes ABI
if conf.env.DEST_OS not in ['psvita']:
conf.check_large_file(compiler = 'c', execute = False)
# indicate if we are packaging for Linux/BSD
conf.env.PACKAGING = conf.options.PACKAGING
if conf.options.PACKAGING:
conf.env.PREFIX = conf.options.prefix
if conf.env.SAILFISH == "aurora":