mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-05 03:24:56 +08:00
Compare commits
186 Commits
continuous
...
continuous
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
004af02e99 | ||
|
|
8ad56eb085 | ||
|
|
578a77518f | ||
|
|
2457ecf226 | ||
|
|
8cd99885f1 | ||
|
|
684e229ac8 | ||
|
|
c0f1d8c647 | ||
|
|
c3b8696957 | ||
|
|
3ca413dbab | ||
|
|
92dc04ff3c | ||
|
|
ad6db91285 | ||
|
|
90a0f74087 | ||
|
|
4f7f5288a1 | ||
|
|
c23b4bfe61 | ||
|
|
4780f70ea2 | ||
|
|
98a04c7764 | ||
|
|
7da9772143 | ||
|
|
32def35408 | ||
|
|
952ccb1247 | ||
|
|
6f0fb594e7 | ||
|
|
f0b29bac1b | ||
|
|
7b5ff606bd | ||
|
|
3e22ee64ae | ||
|
|
c86c45503f | ||
|
|
ef75a4c28d | ||
|
|
bccd3f2271 | ||
|
|
7bbc3e8238 | ||
|
|
c34e0c66d9 | ||
|
|
e5d80878b8 | ||
|
|
1e075d25b7 | ||
|
|
d29e53481d | ||
|
|
d23a2fd2df | ||
|
|
f6f15cc204 | ||
|
|
4f2249ed8e | ||
|
|
9f322df498 | ||
|
|
b554d7e215 | ||
|
|
719093c10b | ||
|
|
c2da140ccc | ||
|
|
375998dffb | ||
|
|
787444f63d | ||
|
|
0c50076ff0 | ||
|
|
8ce01c38c7 | ||
|
|
cac6206984 | ||
|
|
a5c88bdda9 | ||
|
|
fc017286a6 | ||
|
|
20d4e3e719 | ||
|
|
4eaa32fc10 | ||
|
|
b7c025b167 | ||
|
|
f29c588e0f | ||
|
|
2065ef143a | ||
|
|
a5c02c85f0 | ||
|
|
9a8761f1d8 | ||
|
|
273990d292 | ||
|
|
0e27d8717c | ||
|
|
8a9b209db0 | ||
|
|
232d1f8583 | ||
|
|
6cfa5877a4 | ||
|
|
154df00f94 | ||
|
|
c5649c94d5 | ||
|
|
a1da10fe38 | ||
|
|
17a71ffc96 | ||
|
|
4609fbc0c5 | ||
|
|
d278d3bdd7 | ||
|
|
7811b60292 | ||
|
|
870fad5606 | ||
|
|
3e93aa459d | ||
|
|
626c5e44f6 | ||
|
|
c906aa0106 | ||
|
|
0a41b70e44 | ||
|
|
ea338adc46 | ||
|
|
5fa777578b | ||
|
|
5b9db5940b | ||
|
|
4b1b3aa13c | ||
|
|
2d51d23d89 | ||
|
|
b5b6dad39c | ||
|
|
a5619e9960 | ||
|
|
a75666a3cd | ||
|
|
49426721d8 | ||
|
|
04125284a3 | ||
|
|
1d4f7b2f94 | ||
|
|
38c82a3f76 | ||
|
|
785632a437 | ||
|
|
4be75af214 | ||
|
|
dcdca01e86 | ||
|
|
201d9c8f80 | ||
|
|
69341e36a3 | ||
|
|
3532a77643 | ||
|
|
35dc072b26 | ||
|
|
f92a3695b3 | ||
|
|
a7b776f3b9 | ||
|
|
f2fb668c9e | ||
|
|
90e493fa3a | ||
|
|
692bcc4073 | ||
|
|
823642b10d | ||
|
|
07189ca2f5 | ||
|
|
0d55441830 | ||
|
|
98ff33d9e2 | ||
|
|
baa8fbaaec | ||
|
|
a0b46da04b | ||
|
|
e70ba7ad64 | ||
|
|
8a41be9d47 | ||
|
|
47aff9e30b | ||
|
|
ced8744ac9 | ||
|
|
734c07ddab | ||
|
|
ceb603488a | ||
|
|
80bac157eb | ||
|
|
b45581c630 | ||
|
|
d4fe3d6f8a | ||
|
|
1907485895 | ||
|
|
cfebb3e1d6 | ||
|
|
f9a0057c28 | ||
|
|
ceb2b0c5e4 | ||
|
|
83b5edea88 | ||
|
|
9d2a85f11f | ||
|
|
93d3df81ee | ||
|
|
2a7f13151a | ||
|
|
0c4f6ae61d | ||
|
|
b7150c3208 | ||
|
|
d6ebff81e2 | ||
|
|
ce4148f351 | ||
|
|
08c2632c14 | ||
|
|
03eac904c1 | ||
|
|
62f3354f4e | ||
|
|
d5b6eff0c0 | ||
|
|
c9ee844a24 | ||
|
|
687c9b004f | ||
|
|
14e79f04ac | ||
|
|
5d6cf48687 | ||
|
|
88949a9ee6 | ||
|
|
2d1e76199b | ||
|
|
a5d78ecfd7 | ||
|
|
3576e474e6 | ||
|
|
d50927f21f | ||
|
|
c6e3146290 | ||
|
|
9811988cce | ||
|
|
48bdd4238e | ||
|
|
fd2b7e9197 | ||
|
|
0e42e5b9e3 | ||
|
|
65750f0cf3 | ||
|
|
6469b0a5f5 | ||
|
|
4f98187e9a | ||
|
|
74c19a1557 | ||
|
|
cfebee6ea8 | ||
|
|
bd0d6644e0 | ||
|
|
f41450127a | ||
|
|
70897af362 | ||
|
|
f1d7101ad8 | ||
|
|
ac9d960eef | ||
|
|
0c471aecb1 | ||
|
|
72d0d70587 | ||
|
|
bec526a77e | ||
|
|
4d1119391a | ||
|
|
1dd622fcbb | ||
|
|
af4b64983a | ||
|
|
e751092555 | ||
|
|
ce06b1d3d7 | ||
|
|
a834f4996f | ||
|
|
fdcf267fe3 | ||
|
|
7f2ebd1b5e | ||
|
|
68b2d9f269 | ||
|
|
3f1eed9f59 | ||
|
|
0637dbaab1 | ||
|
|
85388e97c1 | ||
|
|
de961eb45e | ||
|
|
3d60770b84 | ||
|
|
93c5853356 | ||
|
|
98e587285b | ||
|
|
2aa13c8347 | ||
|
|
53344771fd | ||
|
|
2373743920 | ||
|
|
90a3497afe | ||
|
|
339aebb08c | ||
|
|
b4afe390d6 | ||
|
|
ca0c5f929a | ||
|
|
48cc526c7e | ||
|
|
8b4b0479c8 | ||
|
|
c8bf7e5630 | ||
|
|
4987080e1e | ||
|
|
1d78e400ff | ||
|
|
2d1a885954 | ||
|
|
43ba2e747b | ||
|
|
eefb823ee2 | ||
|
|
a3c33e0fa9 | ||
|
|
16fe6b1b1a | ||
|
|
4275829bd5 | ||
|
|
1884f0a3ce |
@@ -1,10 +1,10 @@
|
||||
task:
|
||||
name: freebsd-14-amd64
|
||||
freebsd_instance:
|
||||
image_family: freebsd-14-0
|
||||
image_family: freebsd-14-2
|
||||
setup_script:
|
||||
- pkg update
|
||||
- pkg install -y pkgconf git sdl2 python fontconfig opus
|
||||
- pkg install -y pkgconf git sdl2 python fontconfig libvorbis opusfile bzip2
|
||||
- git submodule update --init --recursive
|
||||
test_script:
|
||||
- ./scripts/cirrus/build_freebsd.sh dedicated
|
||||
@@ -16,7 +16,7 @@ task:
|
||||
image_family: freebsd-15-0-snap
|
||||
setup_script:
|
||||
- pkg update
|
||||
- pkg install -y pkgconf git sdl2 python fontconfig opus
|
||||
- pkg install -y pkgconf git sdl2 python fontconfig libvorbis opusfile bzip2
|
||||
- git submodule update --init --recursive
|
||||
test_script:
|
||||
- ./scripts/cirrus/build_freebsd.sh dedicated
|
||||
|
||||
4
.github/workflows/c-cpp.yml
vendored
4
.github/workflows/c-cpp.yml
vendored
@@ -66,8 +66,10 @@ jobs:
|
||||
targetos: apple
|
||||
targetarch: amd64
|
||||
env:
|
||||
SDL_VERSION: 2.30.9
|
||||
SDL_VERSION: 2.30.11
|
||||
FFMPEG_VERSION: 7.1
|
||||
GH_CPU_ARCH: ${{ matrix.targetarch }}
|
||||
GH_CPU_OS: ${{ matrix.targetos }}
|
||||
GH_CROSSCOMPILING: ${{ matrix.cross }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
||||
1
3rdparty/extras/wscript
vendored
1
3rdparty/extras/wscript
vendored
@@ -25,5 +25,4 @@ def build(bld):
|
||||
name = 'extras.pk3',
|
||||
files = srcdir.ant_glob('**/*'),
|
||||
relative_to = srcdir,
|
||||
compresslevel = 0,
|
||||
install_path = install_path)
|
||||
|
||||
2
3rdparty/mainui
vendored
2
3rdparty/mainui
vendored
Submodule 3rdparty/mainui updated: c92a06e979...695ea1be2e
@@ -5,5 +5,10 @@ This can be useful to test engine in Wine without using virtual machines or dual
|
||||
0. Clone and install https://github.com/mstorsjo/msvc-wine (you can skip CMake part)
|
||||
1. Set environment variable MSVC_WINE_PATH to the path to installed MSVC toolchain
|
||||
2. Pre-load wine: `wineserver -k; wineserver -p; wine64 wineboot`
|
||||
3. Run `./waf configure -T <build-type> --enable-wine-msvc --sdl2=../SDL2_VC`. Configuration step will take more time than usual.
|
||||
3. Run `PKGCONFIG=/bin/false ./waf configure -T <build-type> --enable-wine-msvc --sdl2=../SDL2_VC`. Configuration step will take more time than usual.
|
||||
4. .. other typical steps to build from console ...
|
||||
|
||||
> [!NOTE]
|
||||
> Notice the usage of PKGCONFIG=/bin/false here. We're disabling pkg-config so we don't accidentally pull
|
||||
> system-wide dependencies and force building them from source. In future builds we might set custom
|
||||
> directory to pull dependencies from, like ffmpeg...
|
||||
|
||||
@@ -85,6 +85,9 @@ These strings are specific to Xash3D FWGS.
|
||||
As Xash3D accidentally supports GoldSrc games, it also supports parsing liblist.gam.\
|
||||
Xash3D will use this file if gameinfo.txt is absent, or if its modification timestamp is older than liblist.gam.
|
||||
|
||||
> [!NOTE]
|
||||
> Starting from January 2025, Xash3D FWGS doesn't automatically generate gameinfo.txt from liblist.gam. The key conversion table still remains but if you wish to use gameinfo.txt instead of liblist.gam, you can execute `fs_make_gameinfo` in console.
|
||||
|
||||
For game creators who plan supporting only Xash3D, using this file is not recommended.
|
||||
|
||||
The table below defines conversion rules from liblist.gam to gameinfo.txt. Some keys' interpretation does differ from `gameinfo.txt`, in this case a note will be left. If `liblist.gam` key isn't present in this table, it's ignored.
|
||||
|
||||
@@ -38,6 +38,9 @@ Uploaded to github by Oleg Cherkasky - https://github.com/gunrunners-paradise/Ct
|
||||
## Deathmatch Classic
|
||||
Available in Valve's Half-Life repository - https://github.com/ValveSoftware/halflife/tree/master/dmc
|
||||
|
||||
## Earth Special Forces
|
||||
Alpha 2.0 - https://www.gamers-desire.de/details/2830
|
||||
|
||||
## ESHQ
|
||||
Official github repository - https://github.com/adslbarxatov/xash3d-for-ESHQ
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
||||
[](https://builds.sr.ht/~a1batross/xash3d-fwgs?) [](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml) [](https://cirrus-ci.com/github/FWGS/xash3d-fwgs) [](http://fwgsdiscord.mentality.rip/) \
|
||||
[](https://github.com/FWGS/xash3d-fwgs/releases/latest) [](https://github.com/FWGS/xash3d-fwgs/releases/tag/continuous)
|
||||
|
||||
Xash3D (pronounced `[ksɑʂ]`) FWGS is a game engine, aimed to provide compatibility with Half-Life Engine and extend it, as well as to give game developers well known workflow.
|
||||
Xash3D ([pronounced](https://ipa-reader.com/?text=ks%C9%91%CA%82) `[ksɑʂ]`) FWGS is a game engine, aimed to provide compatibility with Half-Life Engine and extend it, as well as to give game developers well known workflow.
|
||||
|
||||
Xash3D FWGS is a heavily modified fork of an original [Xash3D Engine](https://www.moddb.com/engines/xash3d-engine) by Unkle Mike.
|
||||
|
||||
|
||||
@@ -30,6 +30,18 @@ public class XashActivity extends SDLActivity {
|
||||
AndroidBug5497Workaround.assistActivity(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy()
|
||||
{
|
||||
super.onDestroy();
|
||||
|
||||
// Now that we don't exit from native code, we need to exit here, resetting
|
||||
// application state (actually global variables that we don't cleanup on exit)
|
||||
//
|
||||
// When the issue with global variables will be resolved, remove that exit() call
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getLibraries() {
|
||||
return new String[]{"SDL2", "xash"};
|
||||
|
||||
@@ -50,4 +50,8 @@ GNU General Public License for more details.
|
||||
#define LIB_WIN32 2
|
||||
#define LIB_STATIC 3
|
||||
|
||||
// movies (XASH_AVI)
|
||||
#define AVI_NULL 0
|
||||
#define AVI_FFMPEG 1
|
||||
|
||||
#endif /* BACKENDS_H */
|
||||
|
||||
@@ -16,8 +16,6 @@ GNU General Public License for more details.
|
||||
#ifndef BSPFILE_H
|
||||
#define BSPFILE_H
|
||||
|
||||
//#define SUPPORT_BSP2_FORMAT // allow to loading Darkplaces BSP2 maps (with broke binary compatibility)
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
@@ -65,7 +63,6 @@ BRUSH MODELS
|
||||
#define MAX_MAP_CLIPNODES_BSP2 524288
|
||||
|
||||
// these limis not using by modelloader but only for displaying 'mapstats' correctly
|
||||
#ifdef SUPPORT_BSP2_FORMAT
|
||||
#define MAX_MAP_MODELS 2048 // embedded models
|
||||
#define MAX_MAP_ENTSTRING 0x200000 // 2 Mb should be enough
|
||||
#define MAX_MAP_PLANES 131072 // can be increased without problems
|
||||
@@ -75,18 +72,6 @@ BRUSH MODELS
|
||||
#define MAX_MAP_VERTS 524288 // can be increased without problems
|
||||
#define MAX_MAP_FACES 262144 // can be increased without problems
|
||||
#define MAX_MAP_MARKSURFACES 524288 // can be increased without problems
|
||||
#else
|
||||
// increased to match PrimeXT compilers
|
||||
#define MAX_MAP_MODELS 1024 // embedded models
|
||||
#define MAX_MAP_ENTSTRING 0x100000 // 1 Mb should be enough
|
||||
#define MAX_MAP_PLANES 65536 // can be increased without problems
|
||||
#define MAX_MAP_NODES 32767 // because negative shorts are leafs
|
||||
#define MAX_MAP_CLIPNODES MAX_MAP_CLIPNODES_HLBSP // because negative shorts are contents
|
||||
#define MAX_MAP_LEAFS 32767 // signed short limit
|
||||
#define MAX_MAP_VERTS 65535 // unsigned short limit
|
||||
#define MAX_MAP_FACES 65535 // unsigned short limit
|
||||
#define MAX_MAP_MARKSURFACES 65535 // unsigned short limit
|
||||
#endif
|
||||
|
||||
#define MAX_MAP_ENTITIES 8192 // network limit
|
||||
#define MAX_MAP_TEXINFO MAX_MAP_FACES // in theory each face may have personal texinfo
|
||||
|
||||
@@ -60,26 +60,29 @@ typedef struct
|
||||
vec3_t position;
|
||||
} mvertex_t;
|
||||
|
||||
typedef struct
|
||||
typedef struct mclipnode32_s
|
||||
{
|
||||
int planenum;
|
||||
#ifdef SUPPORT_BSP2_FORMAT
|
||||
int children[2]; // negative numbers are contents
|
||||
#else
|
||||
short children[2]; // negative numbers are contents
|
||||
#endif
|
||||
} mclipnode_t;
|
||||
int planenum;
|
||||
int children[2]; // negative numbers are contents
|
||||
} mclipnode32_t;
|
||||
|
||||
typedef struct mclipnode16_s
|
||||
{
|
||||
int planenum;
|
||||
short children[2]; // negative numbers are contents
|
||||
} mclipnode16_t;
|
||||
|
||||
// size is matched but representation is not
|
||||
typedef struct
|
||||
typedef struct medge32_s
|
||||
{
|
||||
#ifdef SUPPORT_BSP2_FORMAT
|
||||
unsigned int v[2];
|
||||
#else
|
||||
} medge32_t;
|
||||
|
||||
typedef struct medge16_s
|
||||
{
|
||||
unsigned short v[2];
|
||||
unsigned int cachededgeoffset;
|
||||
#endif
|
||||
} medge_t;
|
||||
} medge16_t;
|
||||
|
||||
typedef struct texture_s
|
||||
{
|
||||
@@ -156,13 +159,31 @@ typedef struct mnode_s
|
||||
|
||||
// node specific
|
||||
mplane_t *plane;
|
||||
struct mnode_s *children[2];
|
||||
#ifdef SUPPORT_BSP2_FORMAT
|
||||
int firstsurface;
|
||||
int numsurfaces;
|
||||
|
||||
#if !XASH_64BIT
|
||||
union
|
||||
{
|
||||
struct mnode_s *children_[2];
|
||||
struct
|
||||
{
|
||||
// the ordering is important
|
||||
int child_0_leaf : 1;
|
||||
int child_0_off : 23;
|
||||
int firstsurface_1 : 8;
|
||||
int child_1_leaf : 1;
|
||||
int child_1_off : 23;
|
||||
int numsurfaces_1 : 8;
|
||||
};
|
||||
};
|
||||
unsigned short firstsurface_0;
|
||||
unsigned short numsurfaces_0;
|
||||
#else
|
||||
unsigned short firstsurface;
|
||||
unsigned short numsurfaces;
|
||||
// in 64-bit ABI this struct has 4 more bytes of padding, let's use it!
|
||||
struct mnode_s *children_[2];
|
||||
unsigned short firstsurface_0;
|
||||
unsigned short numsurfaces_0;
|
||||
unsigned short firstsurface_1;
|
||||
unsigned short numsurfaces_1;
|
||||
#endif
|
||||
} mnode_t;
|
||||
|
||||
@@ -203,7 +224,6 @@ typedef struct mleaf_s
|
||||
int nummarksurfaces;
|
||||
int cluster; // helper to acess to uncompressed visdata
|
||||
byte ambient_sound_level[NUM_AMBIENTS];
|
||||
|
||||
} mleaf_t;
|
||||
|
||||
// surface extradata
|
||||
@@ -291,7 +311,11 @@ struct msurface_s
|
||||
|
||||
typedef struct hull_s
|
||||
{
|
||||
mclipnode_t *clipnodes;
|
||||
union
|
||||
{
|
||||
mclipnode16_t *clipnodes16;
|
||||
mclipnode32_t *clipnodes32;
|
||||
};
|
||||
mplane_t *planes;
|
||||
int firstclipnode;
|
||||
int lastclipnode;
|
||||
@@ -341,7 +365,12 @@ typedef struct model_s
|
||||
mvertex_t *vertexes;
|
||||
|
||||
int numedges;
|
||||
medge_t *edges;
|
||||
union
|
||||
{
|
||||
medge16_t *edges16;
|
||||
medge32_t *edges32;
|
||||
};
|
||||
|
||||
|
||||
int numnodes;
|
||||
mnode_t *nodes;
|
||||
@@ -356,7 +385,11 @@ typedef struct model_s
|
||||
int *surfedges;
|
||||
|
||||
int numclipnodes;
|
||||
mclipnode_t *clipnodes;
|
||||
union
|
||||
{
|
||||
mclipnode16_t *clipnodes16;
|
||||
mclipnode32_t *clipnodes32;
|
||||
};
|
||||
|
||||
int nummarksurfaces;
|
||||
msurface_t **marksurfaces;
|
||||
@@ -550,16 +583,68 @@ typedef struct
|
||||
#define ANIM_CYCLE 2
|
||||
#define MOD_FRAMES 20
|
||||
|
||||
|
||||
|
||||
#define MAX_DEMOS 32
|
||||
#define MAX_MOVIES 8
|
||||
#define MAX_CDTRACKS 32
|
||||
#define MAX_CLIENT_SPRITES 512 // SpriteTextures (0-256 hud, 256-512 client)
|
||||
#define MAX_REQUESTS 64
|
||||
|
||||
STATIC_CHECK_SIZEOF( mnode_t, 52, 72 );
|
||||
STATIC_CHECK_SIZEOF( mextrasurf_t, 324, 496 );
|
||||
STATIC_CHECK_SIZEOF( decal_t, 60, 88 );
|
||||
STATIC_CHECK_SIZEOF( mfaceinfo_t, 176, 304 );
|
||||
|
||||
// model flags (stored in model_t->flags)
|
||||
#define MODEL_QBSP2 BIT( 28 ) // uses 32-bit types
|
||||
|
||||
// access functions
|
||||
static inline mnode_t *node_child( const mnode_t *n, int side, const model_t *mod )
|
||||
{
|
||||
#if !XASH_64BIT
|
||||
if( unlikely( mod->flags & MODEL_QBSP2 )) // MODEL_QBSP2
|
||||
{
|
||||
if( side == 0 )
|
||||
{
|
||||
if( n->child_0_leaf )
|
||||
return (mnode_t *)(mod->leafs + n->child_0_off);
|
||||
else
|
||||
return (mnode_t *)(mod->nodes + n->child_0_off);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( n->child_1_leaf )
|
||||
return (mnode_t *)(mod->leafs + n->child_1_off);
|
||||
else
|
||||
return (mnode_t *)(mod->nodes + n->child_1_off);
|
||||
}
|
||||
}
|
||||
|
||||
return n->children_[side];
|
||||
#else
|
||||
return n->children_[side];
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void node_children( mnode_t *children[2], const mnode_t *n, const model_t *mod )
|
||||
{
|
||||
children[0] = node_child( n, 0, mod );
|
||||
children[1] = node_child( n, 1, mod );
|
||||
}
|
||||
|
||||
static inline int node_firstsurface( const mnode_t *n, const model_t *mod )
|
||||
{
|
||||
if( mod->flags & MODEL_QBSP2 )
|
||||
return n->firstsurface_0 + ( n->firstsurface_1 << 16 );
|
||||
else
|
||||
return n->firstsurface_0;
|
||||
}
|
||||
|
||||
static inline int node_numsurfaces( const mnode_t *n, const model_t *mod )
|
||||
{
|
||||
if( mod->flags & MODEL_QBSP2 )
|
||||
return n->numsurfaces_0 + ( n->numsurfaces_1 << 16 );
|
||||
else
|
||||
return n->numsurfaces_0;
|
||||
}
|
||||
|
||||
#endif//COM_MODEL_H
|
||||
|
||||
@@ -78,7 +78,6 @@ SETUP BACKENDS DEFINITIONS
|
||||
// usually only 10-20 fds availiable
|
||||
#define XASH_REDUCE_FD
|
||||
#endif
|
||||
|
||||
#endif // XASH_DEDICATED
|
||||
|
||||
//
|
||||
@@ -105,6 +104,17 @@ SETUP BACKENDS DEFINITIONS
|
||||
#endif // !XASH_WIN32
|
||||
#endif
|
||||
|
||||
//
|
||||
// determine movie playback backend
|
||||
//
|
||||
#ifndef XASH_AVI
|
||||
#if HAVE_FFMPEG
|
||||
#define XASH_AVI AVI_FFMPEG
|
||||
#else
|
||||
#define XASH_AVI AVI_NULL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef XASH_STATIC_LIBS
|
||||
#define XASH_LIB LIB_STATIC
|
||||
#define XASH_INTERNAL_GAMELIBS
|
||||
|
||||
@@ -157,6 +157,23 @@ typedef struct decallist_s
|
||||
modelstate_t studio_state; // studio decals only
|
||||
} decallist_t;
|
||||
|
||||
enum movie_parms_e
|
||||
{
|
||||
AVI_PARM_LAST = 0, // marker for SetParm to end parse parsing arguments
|
||||
AVI_RENDER_TEXNUM, // (int) sets texture to draw into, if 0 will draw to screen
|
||||
AVI_RENDER_X, // (int) when set to screen, sets position where to draw
|
||||
AVI_RENDER_Y,
|
||||
AVI_RENDER_W, // (int) sets texture or screen width
|
||||
AVI_RENDER_H, // set to -1 to draw full screen
|
||||
AVI_REWIND, // no argument, rewind playback to the beginning
|
||||
AVI_ENTNUM, // (int) entity number, -1 for no spatialization
|
||||
AVI_VOLUME, // (int) volume from 0 to 255
|
||||
AVI_ATTN, // (float) attenuation value
|
||||
AVI_PAUSE, // no argument, pauses playback
|
||||
AVI_RESUME, // no argument, resumes playback
|
||||
};
|
||||
|
||||
struct movie_state_s;
|
||||
struct ref_viewpass_s;
|
||||
|
||||
typedef struct render_api_s
|
||||
@@ -193,16 +210,16 @@ typedef struct render_api_s
|
||||
void (*R_EntityRemoveDecals)( struct model_s *mod ); // remove all the decals from specified entity (BSP only)
|
||||
|
||||
// AVIkit support
|
||||
void *(*AVI_LoadVideo)( const char *filename, qboolean load_audio );
|
||||
int (*AVI_GetVideoInfo)( void *Avi, int *xres, int *yres, float *duration ); // a1ba: changed longs to int
|
||||
int (*AVI_GetVideoFrameNumber)( void *Avi, float time );
|
||||
byte *(*AVI_GetVideoFrame)( void *Avi, int frame );
|
||||
struct movie_state_s *(*AVI_LoadVideo)( const char *filename, qboolean load_audio );
|
||||
qboolean (*AVI_GetVideoInfo)( struct movie_state_s *Avi, int *xres, int *yres, float *duration ); // a1ba: changed longs to int
|
||||
int (*AVI_GetVideoFrameNumber)( struct movie_state_s *Avi, float time );
|
||||
byte *(*AVI_GetVideoFrame)( struct movie_state_s *Avi, int frame );
|
||||
void (*AVI_UploadRawFrame)( int texture, int cols, int rows, int width, int height, const byte *data );
|
||||
void (*AVI_FreeVideo)( void *Avi );
|
||||
int (*AVI_IsActive)( void *Avi );
|
||||
void (*AVI_StreamSound)( void *Avi, int entnum, float fvol, float attn, float synctime );
|
||||
void (*AVI_Reserved0)( void ); // for potential interface expansion without broken compatibility
|
||||
void (*AVI_Reserved1)( void );
|
||||
void (*AVI_FreeVideo)( struct movie_state_s *Avi );
|
||||
qboolean (*AVI_IsActive)( struct movie_state_s *Avi );
|
||||
void (*AVI_StreamSound)( struct movie_state_s *Avi, int entnum, float fvol, float attn, float synctime );
|
||||
qboolean (*AVI_Think)( struct movie_state_s *Avi );
|
||||
qboolean (*AVI_SetParm)( struct movie_state_s *Avi, enum movie_parms_e parm, ... );
|
||||
|
||||
// glState related calls (must use this instead of normal gl-calls to prevent de-synchornize local states between engine and the client)
|
||||
void (*GL_Bind)( int tmu, unsigned int texnum );
|
||||
|
||||
@@ -16,19 +16,17 @@
|
||||
#include STDINT_H
|
||||
#include <assert.h>
|
||||
|
||||
typedef unsigned char byte;
|
||||
typedef int sound_t;
|
||||
typedef float vec_t;
|
||||
typedef vec_t vec2_t[2];
|
||||
typedef vec_t vec3_t[3];
|
||||
typedef vec_t vec4_t[4];
|
||||
typedef vec_t quat_t[4];
|
||||
typedef byte rgba_t[4]; // unsigned byte colorpack
|
||||
typedef byte rgb_t[3]; // unsigned byte colorpack
|
||||
typedef vec_t matrix3x4[3][4];
|
||||
typedef vec_t matrix4x4[4][4];
|
||||
|
||||
typedef uint32_t poolhandle_t;
|
||||
typedef uint8_t byte;
|
||||
typedef float vec_t;
|
||||
typedef vec_t vec2_t[2];
|
||||
typedef vec_t vec3_t[3];
|
||||
typedef vec_t vec4_t[4];
|
||||
typedef vec_t quat_t[4];
|
||||
typedef byte rgba_t[4]; // unsigned byte colorpack
|
||||
typedef byte rgb_t[3]; // unsigned byte colorpack
|
||||
typedef vec_t matrix3x4[3][4];
|
||||
typedef vec_t matrix4x4[4][4];
|
||||
typedef uint32_t poolhandle_t;
|
||||
|
||||
#undef true
|
||||
#undef false
|
||||
@@ -39,18 +37,10 @@ typedef enum { false, true } qboolean;
|
||||
typedef int qboolean;
|
||||
#endif
|
||||
|
||||
typedef uint64_t longtime_t;
|
||||
|
||||
#define MAX_STRING 256 // generic string
|
||||
#define MAX_INFO_STRING 256 // infostrings are transmitted across network
|
||||
#define MAX_SERVERINFO_STRING 512 // server handles too many settings. expand to 1024?
|
||||
#define MAX_LOCALINFO_STRING 32768 // localinfo used on server and not sended to the clients
|
||||
#define MAX_SYSPATH 1024 // system filepath
|
||||
#define MAX_VA_STRING 1024 // string length returned by va()
|
||||
#define MAX_PRINT_MSG 8192 // how many symbols can handle single call of Con_Printf or Con_DPrintf
|
||||
#define MAX_TOKEN 2048 // parse token length
|
||||
#define MAX_MODS 512 // environment games that engine can keep visible
|
||||
#define MAX_USERMSG_LENGTH 2048 // don't modify it's relies on a client-side definitions
|
||||
#define MAX_STRING 256 // generic string
|
||||
#define MAX_VA_STRING 1024 // compatibility macro
|
||||
#define MAX_SYSPATH 1024 // system filepath
|
||||
#define MAX_MODS 512 // environment games that engine can keep visible
|
||||
|
||||
#define BIT( n ) ( 1U << ( n ))
|
||||
#define BIT64( n ) ( 1ULL << ( n ))
|
||||
@@ -209,34 +199,16 @@ _inline float LittleFloat( float f )
|
||||
#endif
|
||||
|
||||
|
||||
typedef unsigned int dword;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
typedef char string[MAX_STRING];
|
||||
typedef struct file_s file_t; // normal file
|
||||
typedef struct stream_s stream_t; // sound stream for background music playing
|
||||
typedef off_t fs_offset_t;
|
||||
typedef unsigned int dword;
|
||||
typedef unsigned int uint;
|
||||
typedef char string[MAX_STRING];
|
||||
typedef off_t fs_offset_t;
|
||||
#if XASH_WIN32
|
||||
typedef int fs_size_t; // return type of _read, _write funcs
|
||||
typedef int fs_size_t; // return type of _read, _write funcs
|
||||
#else /* !XASH_WIN32 */
|
||||
typedef ssize_t fs_size_t;
|
||||
typedef ssize_t fs_size_t;
|
||||
#endif /* !XASH_WIN32 */
|
||||
|
||||
typedef struct dllfunc_s
|
||||
{
|
||||
const char *name;
|
||||
void **func;
|
||||
} dllfunc_t;
|
||||
|
||||
typedef struct dll_info_s
|
||||
{
|
||||
const char *name; // name of library
|
||||
const dllfunc_t *fcts; // list of dll exports
|
||||
qboolean crash; // crash if dll not found
|
||||
void *link; // hinstance of loading library
|
||||
} dll_info_t;
|
||||
|
||||
typedef void (*setpair_t)( const char *key, const void *value, const void *buffer, void *numpairs );
|
||||
typedef void *(*pfnCreateInterface_t)( const char *, int * );
|
||||
|
||||
// config strings are a general means of communication from
|
||||
|
||||
@@ -18,12 +18,11 @@ GNU General Public License for more details.
|
||||
//
|
||||
// avikit.c
|
||||
//
|
||||
typedef struct movie_state_s movie_state_t;
|
||||
typedef struct movie_state_s movie_state_t;
|
||||
int AVI_GetVideoFrameNumber( movie_state_t *Avi, float time );
|
||||
byte *AVI_GetVideoFrame( movie_state_t *Avi, int frame );
|
||||
qboolean AVI_GetVideoInfo( movie_state_t *Avi, int *xres, int *yres, float *duration );
|
||||
qboolean AVI_GetAudioInfo( movie_state_t *Avi, wavdata_t *snd_info );
|
||||
int AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, int offset, int length );
|
||||
qboolean AVI_HaveAudioTrack( const movie_state_t *Avi );
|
||||
void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, int quiet );
|
||||
movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio );
|
||||
int AVI_TimeToSoundPosition( movie_state_t *Avi, int time );
|
||||
@@ -34,4 +33,7 @@ movie_state_t *AVI_GetState( int num );
|
||||
qboolean AVI_Initailize( void );
|
||||
void AVI_Shutdown( void );
|
||||
|
||||
qboolean AVI_SetParm( movie_state_t *Avi, enum movie_parms_e parm, ... );
|
||||
qboolean AVI_Think( movie_state_t *Avi );
|
||||
|
||||
#endif // AVI_H
|
||||
|
||||
761
engine/client/avi/avi_ffmpeg.c
Normal file
761
engine/client/avi/avi_ffmpeg.c
Normal file
@@ -0,0 +1,761 @@
|
||||
/*
|
||||
avi_ffmpreg.c - playing AVI files (ffmpeg backend)
|
||||
Copyright (C) FTEQW developers (for plugins/avplug/avdecode.c)
|
||||
Copyright (C) Sam Lantinga (for tests/testffmpeg.c)
|
||||
Copyright (C) 2023-2024 Alibek Omarov
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "defaults.h"
|
||||
#include "common.h"
|
||||
#include "client.h"
|
||||
|
||||
static qboolean avi_initialized;
|
||||
static poolhandle_t avi_mempool;
|
||||
|
||||
#if XASH_AVI == AVI_FFMPEG
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavutil/imgutils.h>
|
||||
#include <libswscale/swscale.h>
|
||||
#include <libswresample/swresample.h>
|
||||
|
||||
struct movie_state_s
|
||||
{
|
||||
// ffmpeg contexts
|
||||
AVFormatContext *fmt_ctx;
|
||||
AVCodecContext *video_ctx;
|
||||
AVCodecContext *audio_ctx;
|
||||
struct SwsContext *sws_ctx;
|
||||
struct SwrContext *swr_ctx;
|
||||
|
||||
AVPacket *pkt;
|
||||
AVFrame *aframe;
|
||||
AVFrame *vframe;
|
||||
AVFrame *vframe_copy;
|
||||
|
||||
int64_t first_time;
|
||||
int64_t last_time;
|
||||
|
||||
// video stream
|
||||
byte *dst;
|
||||
double duration;
|
||||
int video_stream;
|
||||
int xres;
|
||||
int yres;
|
||||
int dst_linesize;
|
||||
enum AVPixelFormat pix_fmt;
|
||||
|
||||
// rendering video parameters
|
||||
int x, y, w, h; // passed to R_DrawStretchRaw
|
||||
int texture; // passed to R_UploadStretchRaw
|
||||
|
||||
// audio stream
|
||||
int audio_stream;
|
||||
int channels;
|
||||
int rate;
|
||||
enum AVSampleFormat s_fmt;
|
||||
|
||||
byte *cached_audio;
|
||||
size_t cached_audio_buf_len; // absolute size of cached_audio array
|
||||
size_t cached_audio_len; // how many data in bytes we have in cached_audio array
|
||||
size_t cached_audio_pos; // how far we've read into cached_audio array
|
||||
|
||||
// rendering audio parameters
|
||||
float attn;
|
||||
int16_t entnum; // MAX_ENTITY_BITS is 13
|
||||
byte volume;
|
||||
byte active : 1;
|
||||
byte quiet : 1;
|
||||
byte paused : 1;
|
||||
};
|
||||
|
||||
qboolean AVI_SetParm( movie_state_t *Avi, enum movie_parms_e parm, ... )
|
||||
{
|
||||
qboolean ret = true;
|
||||
va_list va;
|
||||
va_start( va, parm );
|
||||
|
||||
while( parm != AVI_PARM_LAST )
|
||||
{
|
||||
float fval;
|
||||
int val;
|
||||
|
||||
switch( parm )
|
||||
{
|
||||
case AVI_RENDER_TEXNUM:
|
||||
Avi->texture = va_arg( va, int );
|
||||
break;
|
||||
case AVI_RENDER_X:
|
||||
Avi->x = va_arg( va, int );
|
||||
break;
|
||||
case AVI_RENDER_Y:
|
||||
Avi->y = va_arg( va, int );
|
||||
break;
|
||||
case AVI_RENDER_W:
|
||||
Avi->w = va_arg( va, int );
|
||||
break;
|
||||
case AVI_RENDER_H:
|
||||
Avi->h = va_arg( va, int );
|
||||
break;
|
||||
case AVI_REWIND:
|
||||
if( Avi->audio_ctx )
|
||||
avcodec_flush_buffers( Avi->audio_ctx );
|
||||
avcodec_flush_buffers( Avi->video_ctx );
|
||||
Avi->cached_audio_len = Avi->cached_audio_pos = 0;
|
||||
Avi->last_time = -1;
|
||||
Avi->first_time = 0;
|
||||
av_seek_frame( Avi->fmt_ctx, -1, 0, AVSEEK_FLAG_FRAME | AVSEEK_FLAG_BACKWARD );
|
||||
break;
|
||||
case AVI_ENTNUM:
|
||||
val = va_arg( va, int );
|
||||
Avi->entnum = bound( 0, val, MAX_EDICTS );
|
||||
break;
|
||||
case AVI_VOLUME:
|
||||
val = va_arg( va, int );
|
||||
Avi->volume = bound( 0, val, 255 );
|
||||
break;
|
||||
case AVI_ATTN:
|
||||
fval = va_arg( va, double );
|
||||
Avi->attn = Q_max( 0.0f, fval );
|
||||
break;
|
||||
case AVI_PAUSE:
|
||||
Avi->paused = true;
|
||||
break;
|
||||
case AVI_RESUME:
|
||||
Avi->paused = false;
|
||||
break;
|
||||
default:
|
||||
ret = false;
|
||||
}
|
||||
|
||||
parm = va_arg( va, enum movie_parms_e );
|
||||
}
|
||||
|
||||
va_end( va );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void AVI_SpewError( qboolean quiet, const char *fmt, ... ) FORMAT_CHECK( 2 );
|
||||
static void AVI_SpewError( qboolean quiet, const char *fmt, ... )
|
||||
{
|
||||
char buf[MAX_VA_STRING];
|
||||
va_list va;
|
||||
|
||||
if( quiet )
|
||||
return;
|
||||
|
||||
va_start( va, fmt );
|
||||
Q_vsnprintf( buf, sizeof( buf ), fmt, va );
|
||||
va_end( va );
|
||||
|
||||
Con_Printf( S_ERROR "%s", buf );
|
||||
}
|
||||
|
||||
static void AVI_SpewAvError( qboolean quiet, const char *func, int numerr )
|
||||
{
|
||||
if( !quiet )
|
||||
Con_Printf( S_ERROR "%s: %s (%d)\n", func, av_err2str( numerr ), numerr );
|
||||
}
|
||||
|
||||
static int AVI_OpenCodecContext( AVCodecContext **dst_dec_ctx, AVFormatContext *fmt_ctx, enum AVMediaType type, qboolean quiet )
|
||||
{
|
||||
const AVCodec *dec;
|
||||
AVCodecContext *dec_ctx;
|
||||
AVStream *st;
|
||||
int idx, ret;
|
||||
|
||||
if(( ret = av_find_best_stream( fmt_ctx, type, -1, -1, NULL, 0 )) < 0 )
|
||||
{
|
||||
AVI_SpewAvError( quiet, "av_find_best_stream", ret );
|
||||
return ret;
|
||||
}
|
||||
|
||||
idx = ret;
|
||||
st = fmt_ctx->streams[idx];
|
||||
|
||||
if( !( dec = avcodec_find_decoder( st->codecpar->codec_id )))
|
||||
{
|
||||
AVI_SpewError( quiet, S_ERROR "Failed to find %s codec\n", av_get_media_type_string( type ));
|
||||
return AVERROR( EINVAL );
|
||||
}
|
||||
|
||||
if( !( dec_ctx = avcodec_alloc_context3( dec )))
|
||||
{
|
||||
AVI_SpewError( quiet, S_ERROR "Failed to allocate %s codec context", dec->name );
|
||||
return AVERROR( ENOMEM );
|
||||
}
|
||||
|
||||
if(( ret = avcodec_parameters_to_context( dec_ctx, st->codecpar )) < 0 )
|
||||
{
|
||||
AVI_SpewAvError( quiet, "avcodec_parameters_to_context", ret );
|
||||
avcodec_free_context( &dec_ctx );
|
||||
return ret;
|
||||
}
|
||||
|
||||
dec_ctx->pkt_timebase = st->time_base;
|
||||
|
||||
if(( ret = avcodec_open2( dec_ctx, dec, NULL )) < 0 )
|
||||
{
|
||||
AVI_SpewAvError( quiet, "avcodec_open2", ret );
|
||||
|
||||
avcodec_free_context( &dec_ctx );
|
||||
return ret;
|
||||
}
|
||||
|
||||
*dst_dec_ctx = dec_ctx;
|
||||
return idx; // always positive
|
||||
}
|
||||
|
||||
int AVI_GetVideoFrameNumber( movie_state_t *Avi, float time )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AVI_TimeToSoundPosition( movie_state_t *Avi, int time )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
qboolean AVI_GetVideoInfo( movie_state_t *Avi, int *xres, int *yres, float *duration )
|
||||
{
|
||||
if( !Avi->active )
|
||||
return false;
|
||||
|
||||
if( xres )
|
||||
*xres = Avi->xres;
|
||||
|
||||
if( yres )
|
||||
*yres = Avi->yres;
|
||||
|
||||
if( duration )
|
||||
*duration = Avi->duration;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
qboolean AVI_HaveAudioTrack( const movie_state_t *Avi )
|
||||
{
|
||||
return Avi ? Avi->active && Avi->audio_ctx : false;
|
||||
}
|
||||
|
||||
// just let it compile, bruh!
|
||||
byte *AVI_GetVideoFrame( movie_state_t *Avi, int target )
|
||||
{
|
||||
return Avi->dst;
|
||||
}
|
||||
|
||||
static void AVI_StreamAudio( movie_state_t *Avi )
|
||||
{
|
||||
int buffer_samples, file_samples, file_bytes;
|
||||
rawchan_t *ch = NULL;
|
||||
|
||||
// keep the same semantics, when S_RAW_SOUND_SOUNDTRACK doesn't play if S_StartStreaming wasn't enabled
|
||||
qboolean disable_stream = Avi->entnum == S_RAW_SOUND_SOUNDTRACK ? !s_listener.streaming : false;
|
||||
|
||||
if( !dma.initialized || disable_stream || s_listener.paused || !Avi->cached_audio )
|
||||
return;
|
||||
|
||||
ch = S_FindRawChannel( Avi->entnum, true );
|
||||
|
||||
if( !ch )
|
||||
return;
|
||||
|
||||
ch->master_vol = Avi->volume;
|
||||
ch->dist_mult = (Avi->attn / SND_CLIP_DISTANCE);
|
||||
|
||||
if( ch->s_rawend < soundtime )
|
||||
ch->s_rawend = soundtime;
|
||||
|
||||
while( ch->s_rawend < soundtime + ch->max_samples )
|
||||
{
|
||||
size_t copy;
|
||||
|
||||
buffer_samples = ch->max_samples - (ch->s_rawend - soundtime);
|
||||
|
||||
file_samples = buffer_samples * ((float)Avi->rate / SOUND_DMA_SPEED);
|
||||
if( file_samples <= 1 ) return; // no more samples need
|
||||
|
||||
file_bytes = file_samples * av_get_bytes_per_sample( Avi->s_fmt ) * Avi->channels;
|
||||
|
||||
if( file_bytes > ch->max_samples )
|
||||
{
|
||||
file_bytes = ch->max_samples;
|
||||
file_samples = file_bytes / ( av_get_bytes_per_sample( Avi->s_fmt ) * Avi->channels );
|
||||
}
|
||||
|
||||
copy = Q_min( file_bytes, Q_max( Avi->cached_audio_len - Avi->cached_audio_pos, 0 ));
|
||||
|
||||
if( !copy )
|
||||
break;
|
||||
|
||||
if( file_bytes > copy )
|
||||
{
|
||||
file_bytes = copy;
|
||||
file_samples = file_bytes / ( av_get_bytes_per_sample( Avi->s_fmt ) * Avi->channels );
|
||||
}
|
||||
|
||||
ch->s_rawend = S_RawSamplesStereo( ch->rawsamples, ch->s_rawend, ch->max_samples, file_samples, Avi->rate, av_get_bytes_per_sample( Avi->s_fmt ), Avi->channels, Avi->cached_audio + Avi->cached_audio_pos );
|
||||
Avi->cached_audio_pos += copy;
|
||||
}
|
||||
}
|
||||
|
||||
static void AVI_HandleAudio( movie_state_t *Avi, const AVFrame *frame )
|
||||
{
|
||||
int samples = frame->nb_samples;
|
||||
size_t len = samples * av_get_bytes_per_sample( Avi->s_fmt ) * Avi->channels;
|
||||
int outsamples;
|
||||
uint8_t *ptr;
|
||||
|
||||
// allocate data
|
||||
if( !Avi->cached_audio )
|
||||
{
|
||||
Avi->cached_audio_buf_len = len;
|
||||
Avi->cached_audio_pos = 0;
|
||||
Avi->cached_audio_len = 0;
|
||||
Avi->cached_audio = Mem_Malloc( avi_mempool, len );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( Avi->cached_audio_pos )
|
||||
{
|
||||
// Con_Printf( "%s: erasing old data of size %d\n", __func__, Avi->cached_audio_pos );
|
||||
Avi->cached_audio_len -= Avi->cached_audio_pos;
|
||||
memmove( Avi->cached_audio, Avi->cached_audio + Avi->cached_audio_pos, Avi->cached_audio_len );
|
||||
Avi->cached_audio_pos = 0;
|
||||
}
|
||||
|
||||
if( len + Avi->cached_audio_len > Avi->cached_audio_buf_len )
|
||||
{
|
||||
// Con_Printf( "%s: resizing old buffer of size %d to size %d\n", __func__, Avi->cached_audio_buf_len, len + Avi->cached_audio_buf_len );
|
||||
Avi->cached_audio_buf_len = len + Avi->cached_audio_len;
|
||||
Avi->cached_audio = Mem_Realloc( avi_mempool, Avi->cached_audio, Avi->cached_audio_buf_len );
|
||||
}
|
||||
}
|
||||
|
||||
ptr = Avi->cached_audio + Avi->cached_audio_len;
|
||||
outsamples = swr_convert( Avi->swr_ctx, &ptr, samples, (void *)frame->data, samples );
|
||||
Avi->cached_audio_len += outsamples * av_get_bytes_per_sample( Avi->s_fmt ) * Avi->channels;
|
||||
|
||||
// Con_Printf( "%s: got audio chunk of size %d samples\n", __func__, outsamples );
|
||||
}
|
||||
|
||||
qboolean AVI_Think( movie_state_t *Avi )
|
||||
{
|
||||
qboolean decoded = false;
|
||||
qboolean flushing = false;
|
||||
qboolean redraw = false;
|
||||
const double timebase = (double)Avi->video_ctx->pkt_timebase.den / Avi->video_ctx->pkt_timebase.num;
|
||||
int64_t curtime = round( Platform_DoubleTime() * timebase );
|
||||
|
||||
if( !Avi->first_time ) // always remember at which timestamp we started playing
|
||||
Avi->first_time = curtime;
|
||||
|
||||
if( Avi->paused )
|
||||
{
|
||||
// FIXME: there might be a better way to do this
|
||||
Avi->last_time = curtime;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Con_NPrintf( 1, "cached_audio_buf_len = %zu", Avi->cached_audio_buf_len );
|
||||
|
||||
while( 1 ) // try to get multiple decoded frames to keep up when we're running at low fps
|
||||
{
|
||||
int res;
|
||||
|
||||
AVI_StreamAudio( Avi ); // always flush audio buffers
|
||||
|
||||
// recalc time so we always play last possible frame
|
||||
curtime = round( Platform_DoubleTime() * timebase );
|
||||
|
||||
if( Avi->last_time > curtime )
|
||||
break;
|
||||
|
||||
if(( res = av_read_frame( Avi->fmt_ctx, Avi->pkt )) >= 0 )
|
||||
{
|
||||
if( Avi->pkt->stream_index == Avi->audio_stream )
|
||||
{
|
||||
res = avcodec_send_packet( Avi->audio_ctx, Avi->pkt );
|
||||
if( res < 0 )
|
||||
AVI_SpewAvError( Avi->quiet, "avcodec_send_packet (audio)", res );
|
||||
}
|
||||
else if( Avi->pkt->stream_index == Avi->video_stream )
|
||||
{
|
||||
res = avcodec_send_packet( Avi->video_ctx, Avi->pkt );
|
||||
if( res < 0 )
|
||||
AVI_SpewAvError( Avi->quiet, "avcodec_send_packet (video)", res );
|
||||
}
|
||||
av_packet_unref( Avi->pkt );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( res != AVERROR_EOF )
|
||||
AVI_SpewAvError( Avi->quiet, "av_read_frame", res );
|
||||
|
||||
if( Avi->audio_ctx )
|
||||
avcodec_flush_buffers( Avi->audio_ctx );
|
||||
|
||||
avcodec_flush_buffers( Avi->video_ctx );
|
||||
flushing = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if( Avi->audio_ctx )
|
||||
{
|
||||
while( avcodec_receive_frame( Avi->audio_ctx, Avi->aframe ) == 0 )
|
||||
{
|
||||
AVI_HandleAudio( Avi, Avi->aframe );
|
||||
decoded = true;
|
||||
}
|
||||
}
|
||||
|
||||
while( avcodec_receive_frame( Avi->video_ctx, Avi->vframe ) == 0 )
|
||||
{
|
||||
Avi->last_time = Avi->first_time + Avi->vframe->best_effort_timestamp;
|
||||
decoded = true;
|
||||
|
||||
if( FBitSet( Avi->vframe->flags, AV_FRAME_FLAG_CORRUPT|AV_FRAME_FLAG_DISCARD ))
|
||||
continue;
|
||||
|
||||
if( Avi->vframe->decode_error_flags != 0 )
|
||||
continue;
|
||||
|
||||
av_frame_unref( Avi->vframe_copy );
|
||||
if( av_frame_ref( Avi->vframe_copy, Avi->vframe ) == 0 )
|
||||
redraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( redraw )
|
||||
{
|
||||
sws_scale( Avi->sws_ctx, (void*)Avi->vframe_copy->data, Avi->vframe_copy->linesize, 0, Avi->video_ctx->height,
|
||||
&Avi->dst, &Avi->dst_linesize );
|
||||
av_frame_unref( Avi->vframe_copy );
|
||||
}
|
||||
|
||||
if( Avi->texture == 0 )
|
||||
{
|
||||
int w = Avi->w >= 0 ? Avi->w : refState.width;
|
||||
int h = Avi->h >= 0 ? Avi->h : refState.height;
|
||||
|
||||
ref.dllFuncs.R_DrawStretchRaw( Avi->x, Avi->y, w, h, Avi->xres, Avi->yres, Avi->dst, redraw );
|
||||
}
|
||||
else if( redraw && Avi->texture > 0 )
|
||||
ref.dllFuncs.AVI_UploadRawFrame( Avi->texture, Avi->xres, Avi->yres, Avi->w, Avi->h, Avi->dst );
|
||||
|
||||
if( flushing && !decoded )
|
||||
return false; // probably hit an EOF
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, int quiet )
|
||||
{
|
||||
byte *dst[4];
|
||||
int dst_linesize[4];
|
||||
int ret;
|
||||
|
||||
if( Avi->active )
|
||||
AVI_CloseVideo( Avi );
|
||||
|
||||
if( !filename || !avi_initialized )
|
||||
return;
|
||||
|
||||
Avi->active = false;
|
||||
Avi->quiet = quiet;
|
||||
Avi->video_ctx = Avi->audio_ctx = NULL;
|
||||
Avi->fmt_ctx = NULL;
|
||||
|
||||
if(( ret = avformat_open_input( &Avi->fmt_ctx, filename, NULL, NULL )) < 0 )
|
||||
{
|
||||
AVI_SpewAvError( quiet, "avformat_open_input", ret );
|
||||
return;
|
||||
}
|
||||
|
||||
if(( ret = avformat_find_stream_info( Avi->fmt_ctx, NULL )) < 0 )
|
||||
{
|
||||
AVI_SpewAvError( quiet, "avformat_find_stream_info", ret );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !( Avi->pkt = av_packet_alloc( )))
|
||||
{
|
||||
AVI_SpewAvError( quiet, "av_packet_alloc", 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !( Avi->vframe = av_frame_alloc( )))
|
||||
{
|
||||
AVI_SpewAvError( quiet, "av_frame_alloc (video)", 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !( Avi->vframe_copy = av_frame_alloc( )))
|
||||
{
|
||||
AVI_SpewAvError( quiet, "av_frame_alloc (video)", 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Avi->video_stream = AVI_OpenCodecContext( &Avi->video_ctx, Avi->fmt_ctx, AVMEDIA_TYPE_VIDEO, quiet );
|
||||
|
||||
if( Avi->video_stream < 0 )
|
||||
return;
|
||||
|
||||
Avi->xres = Avi->video_ctx->width;
|
||||
Avi->yres = Avi->video_ctx->height;
|
||||
Avi->pix_fmt = Avi->video_ctx->pix_fmt;
|
||||
Avi->duration = Avi->fmt_ctx->duration / (double)AV_TIME_BASE;
|
||||
Avi->entnum = S_RAW_SOUND_SOUNDTRACK;
|
||||
Avi->attn = ATTN_NONE;
|
||||
Avi->volume = 255;
|
||||
|
||||
if( !( Avi->sws_ctx = sws_getContext( Avi->xres, Avi->yres, Avi->pix_fmt,
|
||||
Avi->xres, Avi->yres, AV_PIX_FMT_BGR0, SWS_POINT, NULL, NULL, NULL )))
|
||||
{
|
||||
AVI_SpewAvError( quiet, "sws_getContext", 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
if(( ret = av_image_alloc( dst, dst_linesize, Avi->xres, Avi->yres, AV_PIX_FMT_BGR0, 1 )) < 0 )
|
||||
{
|
||||
AVI_SpewAvError( quiet, "av_image_alloc", ret );
|
||||
return;
|
||||
}
|
||||
|
||||
Avi->dst = dst[0];
|
||||
Avi->dst_linesize = dst_linesize[0];
|
||||
|
||||
if( load_audio )
|
||||
{
|
||||
if( !( Avi->aframe = av_frame_alloc( )))
|
||||
{
|
||||
AVI_SpewAvError( quiet, "av_frame_alloc (audio)", 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
Avi->audio_stream = AVI_OpenCodecContext( &Avi->audio_ctx, Avi->fmt_ctx, AVMEDIA_TYPE_AUDIO, quiet );
|
||||
|
||||
// audio stream was requested but it wasn't found
|
||||
if( Avi->audio_stream < 0 )
|
||||
return;
|
||||
|
||||
Avi->channels = Q_min( Avi->audio_ctx->ch_layout.nb_channels, 2 );
|
||||
if( Avi->audio_ctx->sample_fmt == AV_SAMPLE_FMT_U8 || Avi->audio_ctx->sample_fmt == AV_SAMPLE_FMT_U8P )
|
||||
Avi->s_fmt = AV_SAMPLE_FMT_U8;
|
||||
else Avi->s_fmt = AV_SAMPLE_FMT_S16;
|
||||
Avi->rate = Avi->audio_ctx->sample_rate;
|
||||
|
||||
if(( ret = swr_alloc_set_opts2( &Avi->swr_ctx, &Avi->audio_ctx->ch_layout, Avi->s_fmt, Avi->rate,
|
||||
&Avi->audio_ctx->ch_layout, Avi->audio_ctx->sample_fmt, Avi->audio_ctx->sample_rate, 0, 0 )) < 0 )
|
||||
{
|
||||
AVI_SpewAvError( quiet, "swr_alloc_set_opts2", ret );
|
||||
return;
|
||||
}
|
||||
|
||||
if(( ret = swr_init( Avi->swr_ctx )) < 0 )
|
||||
{
|
||||
AVI_SpewAvError( quiet, "swr_init", ret );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Avi->active = true;
|
||||
}
|
||||
|
||||
void AVI_CloseVideo( movie_state_t *Avi )
|
||||
{
|
||||
if( Avi->active )
|
||||
{
|
||||
if( Avi->cached_audio )
|
||||
Mem_Free( Avi->cached_audio );
|
||||
|
||||
swr_free( &Avi->swr_ctx );
|
||||
avcodec_free_context( &Avi->audio_ctx );
|
||||
av_frame_free( &Avi->aframe );
|
||||
|
||||
av_free( Avi->dst );
|
||||
sws_freeContext( Avi->sws_ctx );
|
||||
avcodec_free_context( &Avi->video_ctx );
|
||||
av_frame_free( &Avi->vframe );
|
||||
av_frame_free( &Avi->vframe_copy );
|
||||
|
||||
av_packet_free( &Avi->pkt );
|
||||
|
||||
avformat_close_input( &Avi->fmt_ctx );
|
||||
}
|
||||
|
||||
memset( Avi, 0, sizeof( *Avi ));
|
||||
}
|
||||
|
||||
static void AVI_PrintFFmpegVersion( void )
|
||||
{
|
||||
uint ver;
|
||||
|
||||
// print version we're compiled with and which version we're running with
|
||||
ver = avutil_version();
|
||||
Con_Reportf( "AVI: %s (runtime %d.%d.%d)\n", LIBAVUTIL_IDENT, AV_VERSION_MAJOR( ver ), AV_VERSION_MINOR( ver ), AV_VERSION_MICRO( ver ));
|
||||
|
||||
ver = avformat_version();
|
||||
Con_Reportf( "AVI: %s (runtime %d.%d.%d)\n", LIBAVFORMAT_IDENT, AV_VERSION_MAJOR( ver ), AV_VERSION_MINOR( ver ), AV_VERSION_MICRO( ver ));
|
||||
|
||||
ver = avformat_version();
|
||||
Con_Reportf( "AVI: %s (runtime %d.%d.%d)\n", LIBAVCODEC_IDENT, AV_VERSION_MAJOR( ver ), AV_VERSION_MINOR( ver ), AV_VERSION_MICRO( ver ));
|
||||
|
||||
ver = swscale_version();
|
||||
Con_Reportf( "AVI: %s (runtime %d.%d.%d)\n", LIBSWSCALE_IDENT, AV_VERSION_MAJOR( ver ), AV_VERSION_MINOR( ver ), AV_VERSION_MICRO( ver ));
|
||||
|
||||
ver = swresample_version();
|
||||
Con_Reportf( "AVI: %s (runtime %d.%d.%d)\n", LIBSWRESAMPLE_IDENT, AV_VERSION_MAJOR( ver ), AV_VERSION_MINOR( ver ), AV_VERSION_MICRO( ver ));
|
||||
}
|
||||
#else
|
||||
struct movie_state_s
|
||||
{
|
||||
qboolean active;
|
||||
};
|
||||
|
||||
int AVI_GetVideoFrameNumber( movie_state_t *Avi, float time )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
byte *AVI_GetVideoFrame( movie_state_t *Avi, int frame )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qboolean AVI_GetVideoInfo( movie_state_t *Avi, int *xres, int *yres, float *duration )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean AVI_HaveAudioTrack( const movie_state_t *Avi )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, int quiet )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
int AVI_TimeToSoundPosition( movie_state_t *Avi, int time )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AVI_CloseVideo( movie_state_t *Avi )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
qboolean AVI_Think( movie_state_t *Avi )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean AVI_SetParm( movie_state_t *Avi, enum movie_parms_e parm, ... )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static void AVI_PrintFFmpegVersion( void )
|
||||
{
|
||||
|
||||
}
|
||||
#endif // XASH_AVI == AVI_NULL
|
||||
|
||||
static movie_state_t avi[2];
|
||||
movie_state_t *AVI_GetState( int num )
|
||||
{
|
||||
return &avi[num];
|
||||
}
|
||||
|
||||
qboolean AVI_IsActive( movie_state_t *Avi )
|
||||
{
|
||||
return Avi ? Avi->active : false;
|
||||
}
|
||||
|
||||
qboolean AVI_Initailize( void )
|
||||
{
|
||||
if( XASH_AVI == AVI_NULL )
|
||||
{
|
||||
Con_Printf( "AVI: Not supported\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( Sys_CheckParm( "-noavi" ))
|
||||
{
|
||||
Con_Printf( "AVI: Disabled\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
AVI_PrintFFmpegVersion();
|
||||
|
||||
avi_initialized = true;
|
||||
avi_mempool = Mem_AllocPool( "AVI Zone" );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AVI_Shutdown( void )
|
||||
{
|
||||
Mem_FreePool( &avi_mempool );
|
||||
avi_initialized = XASH_AVI != AVI_NULL;
|
||||
}
|
||||
|
||||
movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio )
|
||||
{
|
||||
movie_state_t *Avi;
|
||||
string path;
|
||||
const char *fullpath;
|
||||
|
||||
// fast reject
|
||||
if( !avi_initialized )
|
||||
return NULL;
|
||||
|
||||
// open cinematic
|
||||
Q_snprintf( path, sizeof( path ), "media/%s", filename );
|
||||
COM_DefaultExtension( path, ".avi", sizeof( path ));
|
||||
fullpath = FS_GetDiskPath( path, false );
|
||||
|
||||
if( FS_FileExists( path, false ) && !fullpath )
|
||||
{
|
||||
Con_Printf( "Couldn't load %s from packfile. Please extract it\n", path );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Avi = Mem_Calloc( avi_mempool, sizeof( movie_state_t ));
|
||||
AVI_OpenVideo( Avi, fullpath, load_audio, false );
|
||||
|
||||
if( !AVI_IsActive( Avi ))
|
||||
{
|
||||
AVI_FreeVideo( Avi ); // something bad happens
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// all done
|
||||
return Avi;
|
||||
}
|
||||
|
||||
void AVI_FreeVideo( movie_state_t *Avi )
|
||||
{
|
||||
if( !Avi )
|
||||
return;
|
||||
|
||||
AVI_CloseVideo( Avi );
|
||||
|
||||
if( Mem_IsAllocatedExt( avi_mempool, Avi ))
|
||||
Mem_Free( Avi );
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
avi_stub.c - playing AVI files (stub)
|
||||
Copyright (C) 2018 a1batross
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "build.h"
|
||||
#if !XASH_WIN32
|
||||
#include "common.h"
|
||||
|
||||
int AVI_GetVideoFrameNumber( movie_state_t *Avi, float time )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
byte *AVI_GetVideoFrame( movie_state_t *Avi, int frame )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qboolean AVI_GetVideoInfo( movie_state_t *Avi, int *xres, int *yres, float *duration )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean AVI_GetAudioInfo( movie_state_t *Avi, wavdata_t *snd_info )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, int offset, int length )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, int quiet )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int AVI_TimeToSoundPosition( movie_state_t *Avi, int time )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void AVI_CloseVideo( movie_state_t *Avi )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
qboolean AVI_IsActive( movie_state_t *Avi )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void AVI_FreeVideo( movie_state_t *Avi )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
movie_state_t *AVI_GetState( int num )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qboolean AVI_Initailize( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void AVI_Shutdown( void )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
#endif // WIN32
|
||||
@@ -1,735 +0,0 @@
|
||||
/*
|
||||
avi_win.c - playing AVI files (based on original AVIKit code, Win32 version)
|
||||
Copyright (c) 2003-2004, Ruari O'Sullivan
|
||||
Copyright (C) 2010 Uncle Mike
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "build.h"
|
||||
#if XASH_WIN32
|
||||
#include "common.h"
|
||||
#include "client.h"
|
||||
#include <vfw.h> // video for windows
|
||||
|
||||
// msvfw32.dll exports
|
||||
static HDRAWDIB (_stdcall *pDrawDibOpen)( void );
|
||||
static BOOL (_stdcall *pDrawDibClose)( HDRAWDIB hdd );
|
||||
static BOOL (_stdcall *pDrawDibDraw)( HDRAWDIB, HDC, int, int, int, int, LPBITMAPINFOHEADER, void*, int, int, int, int, uint );
|
||||
|
||||
static dllfunc_t msvfw_funcs[] =
|
||||
{
|
||||
{ "DrawDibOpen", (void **) &pDrawDibOpen },
|
||||
{ "DrawDibDraw", (void **) &pDrawDibDraw },
|
||||
{ "DrawDibClose", (void **) &pDrawDibClose },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
dll_info_t msvfw_dll = { "msvfw32.dll", msvfw_funcs, false };
|
||||
|
||||
// msacm32.dll exports
|
||||
static MMRESULT (_stdcall *pacmStreamOpen)( LPHACMSTREAM, HACMDRIVER, LPWAVEFORMATEX, LPWAVEFORMATEX, LPWAVEFILTER, DWORD, DWORD, DWORD );
|
||||
static MMRESULT (_stdcall *pacmStreamPrepareHeader)( HACMSTREAM, LPACMSTREAMHEADER, DWORD );
|
||||
static MMRESULT (_stdcall *pacmStreamUnprepareHeader)( HACMSTREAM, LPACMSTREAMHEADER, DWORD );
|
||||
static MMRESULT (_stdcall *pacmStreamConvert)( HACMSTREAM, LPACMSTREAMHEADER, DWORD );
|
||||
static MMRESULT (_stdcall *pacmStreamSize)( HACMSTREAM, DWORD, LPDWORD, DWORD );
|
||||
static MMRESULT (_stdcall *pacmStreamClose)( HACMSTREAM, DWORD );
|
||||
|
||||
static dllfunc_t msacm_funcs[] =
|
||||
{
|
||||
{ "acmStreamOpen", (void **) &pacmStreamOpen },
|
||||
{ "acmStreamPrepareHeader", (void **) &pacmStreamPrepareHeader },
|
||||
{ "acmStreamUnprepareHeader", (void **) &pacmStreamUnprepareHeader },
|
||||
{ "acmStreamConvert", (void **) &pacmStreamConvert },
|
||||
{ "acmStreamSize", (void **) &pacmStreamSize },
|
||||
{ "acmStreamClose", (void **) &pacmStreamClose },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
dll_info_t msacm_dll = { "msacm32.dll", msacm_funcs, false };
|
||||
|
||||
// avifil32.dll exports
|
||||
static int (_stdcall *pAVIStreamInfo)( PAVISTREAM pavi, AVISTREAMINFO *psi, LONG lSize );
|
||||
static int (_stdcall *pAVIStreamRead)( PAVISTREAM pavi, LONG lStart, LONG lSamples, void *lpBuffer, LONG cbBuffer, LONG *plBytes, LONG *plSamples );
|
||||
static PGETFRAME (_stdcall *pAVIStreamGetFrameOpen)( PAVISTREAM pavi, LPBITMAPINFOHEADER lpbiWanted );
|
||||
static int (_stdcall *pAVIStreamTimeToSample)( PAVISTREAM pavi, LONG lTime );
|
||||
static void* (_stdcall *pAVIStreamGetFrame)( PGETFRAME pg, LONG lPos );
|
||||
static int (_stdcall *pAVIStreamGetFrameClose)( PGETFRAME pg );
|
||||
static dword (_stdcall *pAVIStreamRelease)( PAVISTREAM pavi );
|
||||
static int (_stdcall *pAVIFileOpenW)( PAVIFILE *ppfile, LPCWSTR szFile, UINT uMode, LPCLSID lpHandler );
|
||||
static int (_stdcall *pAVIFileGetStream)( PAVIFILE pfile, PAVISTREAM *ppavi, DWORD fccType, LONG lParam );
|
||||
static int (_stdcall *pAVIStreamReadFormat)( PAVISTREAM pavi, LONG lPos,LPVOID lpFormat, LONG *lpcbFormat );
|
||||
static int (_stdcall *pAVIStreamStart)( PAVISTREAM pavi );
|
||||
static dword (_stdcall *pAVIFileRelease)( PAVIFILE pfile );
|
||||
static void (_stdcall *pAVIFileInit)( void );
|
||||
static void (_stdcall *pAVIFileExit)( void );
|
||||
|
||||
static dllfunc_t avifile_funcs[] =
|
||||
{
|
||||
{ "AVIFileExit", (void **) &pAVIFileExit },
|
||||
{ "AVIFileGetStream", (void **) &pAVIFileGetStream },
|
||||
{ "AVIFileInit", (void **) &pAVIFileInit },
|
||||
{ "AVIFileOpenW", (void **) &pAVIFileOpenW },
|
||||
{ "AVIFileRelease", (void **) &pAVIFileRelease },
|
||||
{ "AVIStreamGetFrame", (void **) &pAVIStreamGetFrame },
|
||||
{ "AVIStreamGetFrameClose", (void **) &pAVIStreamGetFrameClose },
|
||||
{ "AVIStreamGetFrameOpen", (void **) &pAVIStreamGetFrameOpen },
|
||||
{ "AVIStreamInfoA", (void **) &pAVIStreamInfo },
|
||||
{ "AVIStreamRead", (void **) &pAVIStreamRead },
|
||||
{ "AVIStreamReadFormat", (void **) &pAVIStreamReadFormat },
|
||||
{ "AVIStreamRelease", (void **) &pAVIStreamRelease },
|
||||
{ "AVIStreamStart", (void **) &pAVIStreamStart },
|
||||
{ "AVIStreamTimeToSample", (void **) &pAVIStreamTimeToSample },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
dll_info_t avifile_dll = { "avifil32.dll", avifile_funcs, false };
|
||||
|
||||
typedef struct movie_state_s
|
||||
{
|
||||
qboolean active;
|
||||
qboolean quiet; // ignore error messages
|
||||
|
||||
PAVIFILE pfile; // avi file pointer
|
||||
PAVISTREAM video_stream; // video stream pointer
|
||||
PGETFRAME video_getframe; // pointer to getframe object for video stream
|
||||
int video_frames; // total frames
|
||||
int video_xres; // video stream resolution
|
||||
int video_yres;
|
||||
float video_fps; // video stream fps
|
||||
|
||||
PAVISTREAM audio_stream; // audio stream pointer
|
||||
WAVEFORMAT *audio_header; // audio stream header
|
||||
int audio_header_size; // WAVEFORMAT is returned for PCM data; WAVEFORMATEX for others
|
||||
int audio_codec; // WAVE_FORMAT_PCM is oldstyle: anything else needs conversion
|
||||
int audio_length; // in converted samples
|
||||
int audio_bytes_per_sample; // guess.
|
||||
|
||||
// compressed audio specific data
|
||||
dword cpa_blockalign; // block size to read
|
||||
HACMSTREAM cpa_conversion_stream;
|
||||
ACMSTREAMHEADER cpa_conversion_header;
|
||||
byte *cpa_srcbuffer; // maintained buffer for raw data
|
||||
byte *cpa_dstbuffer;
|
||||
|
||||
dword cpa_blocknum; // current block
|
||||
dword cpa_blockpos; // read position in current block
|
||||
dword cpa_blockoffset; // corresponding offset in bytes in the output stream
|
||||
|
||||
// for additional unpack Ms-RLE codecs etc
|
||||
HDC hDC; // compatible DC
|
||||
HDRAWDIB hDD; // DrawDib handler
|
||||
HBITMAP hBitmap; // for DIB conversions
|
||||
byte *pframe_data; // converted framedata
|
||||
} movie_state_t;
|
||||
|
||||
static qboolean avi_initialized = false;
|
||||
static movie_state_t avi[2];
|
||||
|
||||
// Converts a compressed audio stream into uncompressed PCM.
|
||||
qboolean AVI_ACMConvertAudio( movie_state_t *Avi )
|
||||
{
|
||||
WAVEFORMATEX dest_header, *sh, *dh;
|
||||
AVISTREAMINFO stream_info;
|
||||
dword dest_length;
|
||||
short bits;
|
||||
|
||||
// WMA codecs, both versions - they simply don't work.
|
||||
if( Avi->audio_header->wFormatTag == 0x160 || Avi->audio_header->wFormatTag == 0x161 )
|
||||
{
|
||||
if( !Avi->quiet )
|
||||
Con_Reportf( S_ERROR "ACM does not support this audio codec.\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// get audio stream info to work with
|
||||
pAVIStreamInfo( Avi->audio_stream, &stream_info, sizeof( stream_info ));
|
||||
|
||||
if( Avi->audio_header_size < sizeof( WAVEFORMATEX ))
|
||||
{
|
||||
if( !Avi->quiet )
|
||||
Con_Reportf( S_ERROR "ACM failed to open conversion stream.\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
sh = (WAVEFORMATEX *)Avi->audio_header;
|
||||
bits = 16; // predict state
|
||||
|
||||
// how much of this is actually required?
|
||||
dest_header.wFormatTag = WAVE_FORMAT_PCM; // yay
|
||||
dest_header.wBitsPerSample = bits; // 16bit
|
||||
dest_header.nChannels = sh->nChannels;
|
||||
dest_header.nSamplesPerSec = sh->nSamplesPerSec; // take straight from the source stream
|
||||
dest_header.nAvgBytesPerSec = (bits >> 3) * sh->nChannels * sh->nSamplesPerSec;
|
||||
dest_header.nBlockAlign = (bits >> 3) * sh->nChannels;
|
||||
dest_header.cbSize = 0; // no more data.
|
||||
|
||||
dh = &dest_header;
|
||||
|
||||
// open the stream
|
||||
if( pacmStreamOpen( &Avi->cpa_conversion_stream, NULL, sh, dh, NULL, 0, 0, 0 ) != MMSYSERR_NOERROR )
|
||||
{
|
||||
// try with 8 bit destination instead
|
||||
bits = 8;
|
||||
|
||||
dest_header.wBitsPerSample = bits; // 8bit
|
||||
dest_header.nAvgBytesPerSec = ( bits >> 3 ) * sh->nChannels * sh->nSamplesPerSec;
|
||||
dest_header.nBlockAlign = ( bits >> 3 ) * sh->nChannels; // 1 sample at a time
|
||||
|
||||
if( pacmStreamOpen( &Avi->cpa_conversion_stream, NULL, sh, dh, NULL, 0, 0, 0 ) != MMSYSERR_NOERROR )
|
||||
{
|
||||
if( !Avi->quiet )
|
||||
Con_Reportf( S_ERROR "ACM failed to open conversion stream.\n" );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Avi->cpa_blockalign = sh->nBlockAlign;
|
||||
dest_length = 0;
|
||||
|
||||
// mp3 specific fix
|
||||
if( sh->wFormatTag == 0x55 )
|
||||
{
|
||||
LPMPEGLAYER3WAVEFORMAT k;
|
||||
|
||||
k = (LPMPEGLAYER3WAVEFORMAT)sh;
|
||||
Avi->cpa_blockalign = k->nBlockSize;
|
||||
}
|
||||
|
||||
// get the size of the output buffer for streaming the compressed audio
|
||||
if( pacmStreamSize( Avi->cpa_conversion_stream, Avi->cpa_blockalign, &dest_length, ACM_STREAMSIZEF_SOURCE ) != MMSYSERR_NOERROR )
|
||||
{
|
||||
if( !Avi->quiet )
|
||||
Con_Reportf( S_ERROR "Couldn't get ACM conversion stream size.\n" );
|
||||
pacmStreamClose( Avi->cpa_conversion_stream, 0 );
|
||||
return false;
|
||||
}
|
||||
|
||||
Avi->cpa_srcbuffer = (byte *)Mem_Malloc( cls.mempool, Avi->cpa_blockalign );
|
||||
Avi->cpa_dstbuffer = (byte *)Mem_Malloc( cls.mempool, dest_length ); // maintained buffer for raw data
|
||||
|
||||
// prep the headers!
|
||||
Avi->cpa_conversion_header.cbStruct = sizeof( ACMSTREAMHEADER );
|
||||
Avi->cpa_conversion_header.fdwStatus = 0;
|
||||
Avi->cpa_conversion_header.dwUser = 0; // no user data
|
||||
Avi->cpa_conversion_header.pbSrc = Avi->cpa_srcbuffer; // source buffer
|
||||
Avi->cpa_conversion_header.cbSrcLength = Avi->cpa_blockalign; // source buffer size
|
||||
Avi->cpa_conversion_header.cbSrcLengthUsed = 0;
|
||||
Avi->cpa_conversion_header.dwSrcUser = 0; // no user data
|
||||
Avi->cpa_conversion_header.pbDst = Avi->cpa_dstbuffer; // dest buffer
|
||||
Avi->cpa_conversion_header.cbDstLength = dest_length; // dest buffer size
|
||||
Avi->cpa_conversion_header.cbDstLengthUsed = 0;
|
||||
Avi->cpa_conversion_header.dwDstUser = 0; // no user data
|
||||
|
||||
if( pacmStreamPrepareHeader( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, 0 ) != MMSYSERR_NOERROR )
|
||||
{
|
||||
if( !Avi->quiet )
|
||||
Con_Reportf( S_ERROR "couldn't prepare stream headers.\n" );
|
||||
pacmStreamClose( Avi->cpa_conversion_stream, 0 );
|
||||
return false;
|
||||
}
|
||||
|
||||
Avi->cpa_blocknum = 0; // start at 0.
|
||||
Avi->cpa_blockpos = 0;
|
||||
Avi->cpa_blockoffset = 0;
|
||||
|
||||
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
|
||||
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN|ACM_STREAMCONVERTF_START );
|
||||
|
||||
// convert first chunk twice. it often fails the first time. BLACK MAGIC.
|
||||
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
|
||||
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN );
|
||||
|
||||
Avi->audio_bytes_per_sample = (bits >> 3 ) * Avi->audio_header->nChannels;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
qboolean AVI_GetVideoInfo( movie_state_t *Avi, int *xres, int *yres, float *duration )
|
||||
{
|
||||
if( !Avi->active )
|
||||
return false;
|
||||
|
||||
if( xres != NULL )
|
||||
*xres = Avi->video_xres;
|
||||
|
||||
if( yres != NULL )
|
||||
*yres = Avi->video_yres;
|
||||
|
||||
if( duration != NULL )
|
||||
*duration = (float)Avi->video_frames / Avi->video_fps;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// returns a unique frame identifier
|
||||
int AVI_GetVideoFrameNumber( movie_state_t *Avi, float time )
|
||||
{
|
||||
if( !Avi->active )
|
||||
return 0;
|
||||
|
||||
return (time * Avi->video_fps);
|
||||
}
|
||||
|
||||
int AVI_TimeToSoundPosition( movie_state_t *Avi, int time )
|
||||
{
|
||||
if( !Avi->active || !Avi->audio_stream )
|
||||
return 0;
|
||||
|
||||
// UNDONE: what about compressed audio?
|
||||
return pAVIStreamTimeToSample( Avi->audio_stream, time ) * Avi->audio_bytes_per_sample;
|
||||
}
|
||||
|
||||
// gets the raw frame data
|
||||
byte *AVI_GetVideoFrame( movie_state_t *Avi, int frame )
|
||||
{
|
||||
LPBITMAPINFOHEADER frame_info;
|
||||
byte *frame_raw;
|
||||
|
||||
if( !Avi->active ) return NULL;
|
||||
|
||||
if( frame >= Avi->video_frames )
|
||||
frame = Avi->video_frames - 1;
|
||||
|
||||
frame_info = (LPBITMAPINFOHEADER)pAVIStreamGetFrame( Avi->video_getframe, frame );
|
||||
frame_raw = (byte *)frame_info + frame_info->biSize + frame_info->biClrUsed * sizeof( RGBQUAD );
|
||||
pDrawDibDraw( Avi->hDD, Avi->hDC, 0, 0, Avi->video_xres, Avi->video_yres, frame_info, frame_raw, 0, 0, Avi->video_xres, Avi->video_yres, 0 );
|
||||
|
||||
return Avi->pframe_data;
|
||||
}
|
||||
|
||||
qboolean AVI_GetAudioInfo( movie_state_t *Avi, wavdata_t *snd_info )
|
||||
{
|
||||
if( !Avi->active || Avi->audio_stream == NULL || snd_info == NULL )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
snd_info->rate = Avi->audio_header->nSamplesPerSec;
|
||||
snd_info->channels = Avi->audio_header->nChannels;
|
||||
|
||||
if( Avi->audio_codec == WAVE_FORMAT_PCM ) // uncompressed audio!
|
||||
snd_info->width = ( Avi->audio_bytes_per_sample > Avi->audio_header->nChannels ) ? 2 : 1;
|
||||
else snd_info->width = 2; // assume compressed audio is always 16 bit
|
||||
|
||||
snd_info->size = snd_info->rate * snd_info->width * snd_info->channels;
|
||||
snd_info->loopStart = 0; // using loopStart as streampos
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// sync the current audio read to a specific offset
|
||||
qboolean AVI_SeekPosition( movie_state_t *Avi, dword offset )
|
||||
{
|
||||
int breaker;
|
||||
|
||||
if( offset < Avi->cpa_blockoffset ) // well, shit. we can't seek backwards... restart
|
||||
{
|
||||
if( Avi->cpa_blockoffset - offset < 500000 )
|
||||
return false; // don't bother if it's gonna catch up soon
|
||||
|
||||
Avi->cpa_blocknum = 0; // start at 0, eh.
|
||||
Avi->cpa_blockpos = 0;
|
||||
Avi->cpa_blockoffset = 0;
|
||||
|
||||
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
|
||||
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN|ACM_STREAMCONVERTF_START );
|
||||
|
||||
// convert first chunk twice. it often fails the first time. BLACK MAGIC.
|
||||
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
|
||||
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN );
|
||||
}
|
||||
|
||||
// now then: seek forwards to the required block
|
||||
breaker = 30; // maximum zero blocks: anti-freeze protection
|
||||
|
||||
while( Avi->cpa_blockoffset + Avi->cpa_conversion_header.cbDstLengthUsed < offset )
|
||||
{
|
||||
Avi->cpa_blocknum++;
|
||||
Avi->cpa_blockoffset += Avi->cpa_conversion_header.cbDstLengthUsed;
|
||||
|
||||
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
|
||||
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN );
|
||||
|
||||
if( Avi->cpa_conversion_header.cbDstLengthUsed == 0 )
|
||||
breaker--;
|
||||
else breaker = 30;
|
||||
|
||||
if( breaker <= 0 )
|
||||
return false;
|
||||
|
||||
Avi->cpa_blockpos = 0;
|
||||
}
|
||||
|
||||
// seek to the right position inside the block
|
||||
Avi->cpa_blockpos = offset - Avi->cpa_blockoffset;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// get a chunk of audio from the stream (in bytes)
|
||||
int AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, int offset, int length )
|
||||
{
|
||||
int result = 0;
|
||||
int i;
|
||||
|
||||
// zero data past the end of the file
|
||||
if( offset + length > Avi->audio_length )
|
||||
{
|
||||
if( offset <= Avi->audio_length )
|
||||
{
|
||||
int remaining_length = Avi->audio_length - offset;
|
||||
|
||||
AVI_GetAudioChunk( Avi, audiodata, offset, remaining_length );
|
||||
|
||||
for( i = remaining_length; i < length; i++ )
|
||||
audiodata[i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we out of soundtrack, just zeroing buffer
|
||||
for( i = 0; i < length; i++ )
|
||||
audiodata[i] = 0;
|
||||
|
||||
// return length;
|
||||
}
|
||||
}
|
||||
|
||||
// uncompressed audio!
|
||||
if( Avi->audio_codec == WAVE_FORMAT_PCM )
|
||||
{
|
||||
// very simple - read straight out
|
||||
pAVIStreamRead( Avi->audio_stream, offset / Avi->audio_bytes_per_sample, length / Avi->audio_bytes_per_sample, audiodata, length, &result, NULL );
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
// compressed audio!
|
||||
result = 0;
|
||||
|
||||
// seek to correct chunk and all that stuff
|
||||
if( !AVI_SeekPosition( Avi, offset ))
|
||||
return 0; // don't continue if we're waiting for the play pointer to catch up
|
||||
|
||||
while( length > 0 )
|
||||
{
|
||||
int blockread = Avi->cpa_conversion_header.cbDstLengthUsed - Avi->cpa_blockpos;
|
||||
|
||||
if( blockread <= 0 ) // read next
|
||||
{
|
||||
Avi->cpa_blocknum++;
|
||||
Avi->cpa_blockoffset += Avi->cpa_conversion_header.cbDstLengthUsed;
|
||||
|
||||
pAVIStreamRead( Avi->audio_stream, Avi->cpa_blocknum * Avi->cpa_blockalign, Avi->cpa_blockalign, Avi->cpa_srcbuffer, Avi->cpa_blockalign, NULL, NULL );
|
||||
pacmStreamConvert( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, ACM_STREAMCONVERTF_BLOCKALIGN );
|
||||
|
||||
Avi->cpa_blockpos = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( blockread > length )
|
||||
blockread = length;
|
||||
|
||||
// copy the data
|
||||
memcpy( audiodata + result, (void *)( Avi->cpa_dstbuffer + Avi->cpa_blockpos ), blockread );
|
||||
|
||||
Avi->cpa_blockpos += blockread;
|
||||
result += blockread;
|
||||
length -= blockread;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void AVI_CloseVideo( movie_state_t *Avi )
|
||||
{
|
||||
if( Avi->active )
|
||||
{
|
||||
pAVIStreamGetFrameClose( Avi->video_getframe );
|
||||
|
||||
if( Avi->audio_stream != NULL )
|
||||
{
|
||||
pAVIStreamRelease( Avi->audio_stream );
|
||||
Mem_Free( Avi->audio_header );
|
||||
|
||||
if( Avi->audio_codec != WAVE_FORMAT_PCM )
|
||||
{
|
||||
pacmStreamUnprepareHeader( Avi->cpa_conversion_stream, &Avi->cpa_conversion_header, 0 );
|
||||
pacmStreamClose( Avi->cpa_conversion_stream, 0 );
|
||||
Mem_Free( Avi->cpa_srcbuffer );
|
||||
Mem_Free( Avi->cpa_dstbuffer );
|
||||
}
|
||||
}
|
||||
|
||||
pAVIStreamRelease( Avi->video_stream );
|
||||
|
||||
DeleteObject( Avi->hBitmap );
|
||||
pDrawDibClose( Avi->hDD );
|
||||
DeleteDC( Avi->hDC );
|
||||
}
|
||||
|
||||
memset( Avi, 0, sizeof( movie_state_t ));
|
||||
}
|
||||
|
||||
void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, int quiet )
|
||||
{
|
||||
BITMAPINFOHEADER bmih;
|
||||
AVISTREAMINFO stream_info;
|
||||
int opened_streams = 0;
|
||||
LONG hr;
|
||||
wchar_t pathBuffer[MAX_PATH];
|
||||
|
||||
// default state: non-working.
|
||||
Avi->active = false;
|
||||
Avi->quiet = quiet;
|
||||
|
||||
// can't load Video For Windows :-(
|
||||
if( !avi_initialized ) return;
|
||||
|
||||
// convert to wide char
|
||||
if( MultiByteToWideChar( CP_UTF8, 0, filename, -1, pathBuffer, ARRAYSIZE( pathBuffer )) <= 0 )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "filename buffer limit exceeded\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// load the AVI
|
||||
hr = pAVIFileOpenW( &Avi->pfile, pathBuffer, OF_SHARE_DENY_WRITE, 0L );
|
||||
|
||||
if( hr != 0 ) // error opening AVI:
|
||||
{
|
||||
switch( hr )
|
||||
{
|
||||
case AVIERR_BADFORMAT:
|
||||
if( !Avi->quiet )
|
||||
Con_DPrintf( S_ERROR "corrupt file or unknown format.\n" );
|
||||
break;
|
||||
case AVIERR_MEMORY:
|
||||
if( !Avi->quiet )
|
||||
Con_DPrintf( S_ERROR "insufficient memory to open file.\n" );
|
||||
break;
|
||||
case AVIERR_FILEREAD:
|
||||
if( !Avi->quiet )
|
||||
Con_DPrintf( S_ERROR "disk error reading file.\n" );
|
||||
break;
|
||||
case AVIERR_FILEOPEN:
|
||||
if( !Avi->quiet )
|
||||
Con_DPrintf( S_ERROR "disk error opening file.\n" );
|
||||
break;
|
||||
case REGDB_E_CLASSNOTREG:
|
||||
default:
|
||||
if( !Avi->quiet )
|
||||
Con_DPrintf( S_ERROR "no handler found (or file not found).\n" );
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Avi->video_stream = Avi->audio_stream = NULL;
|
||||
|
||||
// open the streams until a stream is not available.
|
||||
while( 1 )
|
||||
{
|
||||
PAVISTREAM stream = NULL;
|
||||
|
||||
if( pAVIFileGetStream( Avi->pfile, &stream, 0L, opened_streams++ ) != AVIERR_OK )
|
||||
break;
|
||||
|
||||
if( stream == NULL )
|
||||
break;
|
||||
|
||||
pAVIStreamInfo( stream, &stream_info, sizeof( stream_info ));
|
||||
|
||||
if( stream_info.fccType == streamtypeVIDEO && Avi->video_stream == NULL )
|
||||
{
|
||||
Avi->video_stream = stream;
|
||||
Avi->video_frames = stream_info.dwLength;
|
||||
Avi->video_xres = stream_info.rcFrame.right - stream_info.rcFrame.left;
|
||||
Avi->video_yres = stream_info.rcFrame.bottom - stream_info.rcFrame.top;
|
||||
Avi->video_fps = (float)stream_info.dwRate / (float)stream_info.dwScale;
|
||||
}
|
||||
else if( stream_info.fccType == streamtypeAUDIO && Avi->audio_stream == NULL && load_audio )
|
||||
{
|
||||
int size;
|
||||
|
||||
Avi->audio_stream = stream;
|
||||
|
||||
// read the audio header
|
||||
pAVIStreamReadFormat( Avi->audio_stream, pAVIStreamStart( Avi->audio_stream ), 0, &size );
|
||||
|
||||
Avi->audio_header = (WAVEFORMAT *)Mem_Malloc( cls.mempool, size );
|
||||
pAVIStreamReadFormat( Avi->audio_stream, pAVIStreamStart( Avi->audio_stream ), Avi->audio_header, &size );
|
||||
Avi->audio_header_size = size;
|
||||
Avi->audio_codec = Avi->audio_header->wFormatTag;
|
||||
|
||||
// length of converted audio in samples
|
||||
Avi->audio_length = (int)((float)stream_info.dwLength / Avi->audio_header->nAvgBytesPerSec );
|
||||
Avi->audio_length *= Avi->audio_header->nSamplesPerSec;
|
||||
|
||||
if( Avi->audio_codec != WAVE_FORMAT_PCM )
|
||||
{
|
||||
if( !AVI_ACMConvertAudio( Avi ))
|
||||
{
|
||||
Mem_Free( Avi->audio_header );
|
||||
Avi->audio_stream = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else Avi->audio_bytes_per_sample = Avi->audio_header->nBlockAlign;
|
||||
Avi->audio_length *= Avi->audio_bytes_per_sample;
|
||||
}
|
||||
else
|
||||
{
|
||||
pAVIStreamRelease( stream );
|
||||
}
|
||||
}
|
||||
|
||||
// display error message-stream not found.
|
||||
if( Avi->video_stream == NULL )
|
||||
{
|
||||
if( Avi->pfile ) // if file is open, close it
|
||||
pAVIFileRelease( Avi->pfile );
|
||||
if( !Avi->quiet )
|
||||
Con_DPrintf( S_ERROR "couldn't find a valid video stream.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
pAVIFileRelease( Avi->pfile ); // release the file
|
||||
Avi->video_getframe = pAVIStreamGetFrameOpen( Avi->video_stream, NULL ); // open the frame getter
|
||||
|
||||
if( Avi->video_getframe == NULL )
|
||||
{
|
||||
if( !Avi->quiet )
|
||||
Con_DPrintf( S_ERROR "error attempting to read video frames.\n" );
|
||||
return; // couldn't open frame getter.
|
||||
}
|
||||
|
||||
bmih.biSize = sizeof( BITMAPINFOHEADER );
|
||||
bmih.biPlanes = 1;
|
||||
bmih.biBitCount = 32;
|
||||
bmih.biCompression = BI_RGB;
|
||||
bmih.biWidth = Avi->video_xres;
|
||||
bmih.biHeight = -Avi->video_yres; // invert height to flip image upside down
|
||||
|
||||
Avi->hDC = CreateCompatibleDC( 0 );
|
||||
Avi->hDD = pDrawDibOpen();
|
||||
Avi->hBitmap = CreateDIBSection( Avi->hDC, (BITMAPINFO*)(&bmih), DIB_RGB_COLORS, (void**)(&Avi->pframe_data), NULL, 0 );
|
||||
SelectObject( Avi->hDC, Avi->hBitmap );
|
||||
|
||||
Avi->active = true; // done
|
||||
}
|
||||
|
||||
qboolean AVI_IsActive( movie_state_t *Avi )
|
||||
{
|
||||
if( Avi != NULL )
|
||||
return Avi->active;
|
||||
return false;
|
||||
}
|
||||
|
||||
movie_state_t *AVI_GetState( int num )
|
||||
{
|
||||
return &avi[num];
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
AVIKit user interface
|
||||
|
||||
=============
|
||||
*/
|
||||
movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio )
|
||||
{
|
||||
movie_state_t *Avi;
|
||||
string path;
|
||||
const char *fullpath;
|
||||
|
||||
// fast reject
|
||||
if( !avi_initialized )
|
||||
return NULL;
|
||||
|
||||
// open cinematic
|
||||
Q_snprintf( path, sizeof( path ), "media/%s", filename );
|
||||
COM_DefaultExtension( path, ".avi", sizeof( path ));
|
||||
fullpath = FS_GetDiskPath( path, false );
|
||||
|
||||
if( FS_FileExists( path, false ) && !fullpath )
|
||||
{
|
||||
Con_Printf( "Couldn't load %s from packfile. Please extract it\n", path );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Avi = Mem_Malloc( cls.mempool, sizeof( movie_state_t ));
|
||||
AVI_OpenVideo( Avi, fullpath, load_audio, false );
|
||||
|
||||
if( !AVI_IsActive( Avi ))
|
||||
{
|
||||
AVI_FreeVideo( Avi ); // something bad happens
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// all done
|
||||
return Avi;
|
||||
}
|
||||
|
||||
void AVI_FreeVideo( movie_state_t *state )
|
||||
{
|
||||
if( !state ) return;
|
||||
|
||||
if( Mem_IsAllocatedExt( cls.mempool, state ))
|
||||
{
|
||||
AVI_CloseVideo( state );
|
||||
Mem_Free( state );
|
||||
}
|
||||
}
|
||||
|
||||
qboolean AVI_Initailize( void )
|
||||
{
|
||||
if( Sys_CheckParm( "-noavi" ))
|
||||
{
|
||||
Con_Printf( "AVI: Disabled\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !Sys_LoadLibrary( &avifile_dll ))
|
||||
return false;
|
||||
|
||||
if( !Sys_LoadLibrary( &msvfw_dll ))
|
||||
{
|
||||
Sys_FreeLibrary( &avifile_dll );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !Sys_LoadLibrary( &msacm_dll ))
|
||||
{
|
||||
Sys_FreeLibrary( &avifile_dll );
|
||||
Sys_FreeLibrary( &msvfw_dll );
|
||||
return false;
|
||||
}
|
||||
|
||||
avi_initialized = true;
|
||||
pAVIFileInit();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AVI_Shutdown( void )
|
||||
{
|
||||
if( !avi_initialized ) return;
|
||||
|
||||
pAVIFileExit();
|
||||
|
||||
Sys_FreeLibrary( &avifile_dll );
|
||||
Sys_FreeLibrary( &msvfw_dll );
|
||||
Sys_FreeLibrary( &msacm_dll );
|
||||
avi_initialized = false;
|
||||
}
|
||||
#endif // _WIN32
|
||||
@@ -42,7 +42,8 @@ void CL_PlayVideo_f( void )
|
||||
switch( Cmd_Argc( ))
|
||||
{
|
||||
case 2: // simple user version
|
||||
Q_snprintf( path, sizeof( path ), "media/%s.avi", Cmd_Argv( 1 ));
|
||||
Q_snprintf( path, sizeof( path ), "media/%s", Cmd_Argv( 1 ));
|
||||
COM_DefaultExtension( path, ".avi", sizeof( path ));
|
||||
SCR_PlayCinematic( path );
|
||||
break;
|
||||
case 3: // sequenced cinematics used this
|
||||
|
||||
@@ -153,6 +153,7 @@ static void CL_WriteErrorMessage( int current_count, sizebuf_t *msg )
|
||||
|
||||
FS_Write( fp, &cls.starting_count, sizeof( int ));
|
||||
FS_Write( fp, ¤t_count, sizeof( int ));
|
||||
FS_Write( fp, &cls.legacymode, sizeof( cls.legacymode ));
|
||||
FS_Write( fp, MSG_GetData( msg ), MSG_GetMaxBytes( msg ));
|
||||
FS_Close( fp );
|
||||
|
||||
@@ -168,7 +169,7 @@ list last 32 messages for debugging net troubleshooting
|
||||
*/
|
||||
void CL_WriteMessageHistory( void )
|
||||
{
|
||||
oldcmd_t *old, *failcommand;
|
||||
oldcmd_t *old;
|
||||
sizebuf_t *msg = &net_message;
|
||||
int i, thecmd;
|
||||
|
||||
@@ -192,9 +193,8 @@ void CL_WriteMessageHistory( void )
|
||||
thecmd++;
|
||||
}
|
||||
|
||||
failcommand = &cls_message_debug.oldcmd[thecmd];
|
||||
Con_Printf( "BAD: %3i:%s\n", MSG_GetNumBytesRead( msg ) - 1, CL_MsgInfo( failcommand->command ));
|
||||
if( host_developer.value >= DEV_EXTENDED )
|
||||
CL_WriteErrorMessage( MSG_GetNumBytesRead( msg ) - 1, msg );
|
||||
old = &cls_message_debug.oldcmd[thecmd];
|
||||
Con_Printf( S_RED "BAD: " S_DEFAULT "%i %04i %s\n", old->frame_number, old->starting_offset, CL_MsgInfo( old->command ));
|
||||
CL_WriteErrorMessage( old->starting_offset, msg );
|
||||
cls_message_debug.parsing = false;
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ void CL_StartupDemoHeader( void )
|
||||
{
|
||||
CL_CloseDemoHeader();
|
||||
|
||||
cls.demoheader = FS_Open( "demoheader.tmp", "w+b", true );
|
||||
cls.demoheader = FS_Open( "demoheader.tmp", "w+bm", true );
|
||||
|
||||
if( !cls.demoheader )
|
||||
{
|
||||
@@ -373,7 +373,7 @@ CL_WriteDemoUserMessage
|
||||
Dumps the user message (demoaction)
|
||||
====================
|
||||
*/
|
||||
void CL_WriteDemoUserMessage( const byte *buffer, size_t size )
|
||||
void GAME_EXPORT CL_WriteDemoUserMessage( int size, byte *buffer )
|
||||
{
|
||||
if( !cls.demorecording || cls.demowaiting )
|
||||
return;
|
||||
@@ -624,11 +624,10 @@ static void CL_ReadDemoUserCmd( qboolean discard )
|
||||
|
||||
if( !discard )
|
||||
{
|
||||
usercmd_t nullcmd;
|
||||
const usercmd_t nullcmd = { 0 };
|
||||
sizebuf_t buf;
|
||||
demoangle_t *a;
|
||||
|
||||
memset( &nullcmd, 0, sizeof( nullcmd ));
|
||||
MSG_Init( &buf, "UserCmd", data, sizeof( data ));
|
||||
|
||||
// a1ba: I have no proper explanation why
|
||||
@@ -724,7 +723,7 @@ static void CL_DemoStartPlayback( int mode )
|
||||
{
|
||||
// NOTE: at this point demo is still valid
|
||||
CL_Disconnect();
|
||||
Host_ShutdownServer();
|
||||
SV_Shutdown( "Server was killed due to demo playback start\n" );
|
||||
|
||||
Con_FastClose();
|
||||
UI_SetActiveMenu( false );
|
||||
|
||||
@@ -127,8 +127,10 @@ static void R_SplitEntityOnNode( mnode_t *node )
|
||||
}
|
||||
|
||||
// recurse down the contacted sides
|
||||
if( sides & 1 ) R_SplitEntityOnNode( node->children[0] );
|
||||
if( sides & 2 ) R_SplitEntityOnNode( node->children[1] );
|
||||
if( sides & 1 )
|
||||
R_SplitEntityOnNode( node_child( node, 0, cl.worldmodel ));
|
||||
if( sides & 2 )
|
||||
R_SplitEntityOnNode( node_child( node, 1, cl.worldmodel ));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -2229,4 +2229,3 @@ void CL_ThinkParticle( double frametime, particle_t *p )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,6 @@ static const dllfunc_t cdll_exports[] =
|
||||
{ "IN_ClearStates", (void **)&clgame.dllFuncs.IN_ClearStates },
|
||||
{ "V_CalcRefdef", (void **)&clgame.dllFuncs.pfnCalcRefdef },
|
||||
{ "KB_Find", (void **)&clgame.dllFuncs.KB_Find },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
// optional exports
|
||||
@@ -91,7 +90,6 @@ static const dllfunc_t cdll_new_exports[] = // allowed only in SDK 2.3 and high
|
||||
{ "IN_ClientTouchEvent", (void **)&clgame.dllFuncs.pfnTouchEvent}, // Xash3D FWGS ext
|
||||
{ "IN_ClientMoveEvent", (void **)&clgame.dllFuncs.pfnMoveEvent}, // Xash3D FWGS ext
|
||||
{ "IN_ClientLookEvent", (void **)&clgame.dllFuncs.pfnLookEvent}, // Xash3D FWGS ext
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static void pfnSPR_DrawHoles( int frame, int x, int y, const wrect_t *prc );
|
||||
@@ -558,7 +556,7 @@ static void CL_InitTitles( const char *filename )
|
||||
|
||||
Q_snprintf( name, sizeof( name ), TEXT_MSGNAME, i );
|
||||
|
||||
cl_textmessage[i].pName = _copystring( clgame.mempool, name, __FILE__, __LINE__ );
|
||||
cl_textmessage[i].pName = copystringpool( clgame.mempool, name );
|
||||
cl_textmessage[i].pMessage = cl_textbuffer[i];
|
||||
}
|
||||
|
||||
@@ -976,7 +974,7 @@ static void CL_ClearUserMessage( char *pszName, int svc_num )
|
||||
int i;
|
||||
|
||||
for( i = 0; i < MAX_USER_MESSAGES && clgame.msg[i].name[0]; i++ )
|
||||
if( ( clgame.msg[i].number == svc_num ) && Q_strcmp( clgame.msg[i].name, pszName ) )
|
||||
if( ( clgame.msg[i].number == svc_num ) && Q_stricmp( clgame.msg[i].name, pszName ) )
|
||||
clgame.msg[i].number = 0;
|
||||
}
|
||||
|
||||
@@ -1046,7 +1044,7 @@ void CL_InitEdicts( int maxclients )
|
||||
cls.num_client_entities = CL_UPDATE_BACKUP * NUM_PACKET_ENTITIES;
|
||||
cls.packet_entities = Mem_Realloc( clgame.mempool, cls.packet_entities, sizeof( entity_state_t ) * cls.num_client_entities );
|
||||
clgame.entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * clgame.maxEntities );
|
||||
clgame.static_entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
|
||||
clgame.static_entities = NULL; // will be initialized later
|
||||
clgame.numStatics = 0;
|
||||
|
||||
if(( clgame.maxRemapInfos - 1 ) != clgame.maxEntities )
|
||||
@@ -1765,6 +1763,17 @@ static cvar_t *GAME_EXPORT pfnCvar_RegisterClientVariable( const char *szName, c
|
||||
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_CLIENTDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_CLIENTDLL ));
|
||||
}
|
||||
|
||||
static int GAME_EXPORT Cmd_AddClientCommand( const char *cmd_name, xcommand_t function )
|
||||
{
|
||||
int flags = CMD_CLIENTDLL;
|
||||
|
||||
// a1ba: try to mitigate outdated client.dll vulnerabilities
|
||||
if( !Q_stricmp( cmd_name, "motd_write" ))
|
||||
flags |= CMD_PRIVILEGED;
|
||||
|
||||
return Cmd_AddCommandEx( cmd_name, function, "client command", flags, __func__ );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnHookUserMsg
|
||||
@@ -2399,9 +2408,8 @@ CL_FindModelIndex
|
||||
*/
|
||||
static int GAME_EXPORT CL_FindModelIndex( const char *m )
|
||||
{
|
||||
char filepath[MAX_QPATH];
|
||||
static float lasttimewarn;
|
||||
int i;
|
||||
char filepath[MAX_QPATH];
|
||||
int i;
|
||||
|
||||
if( !COM_CheckString( m ))
|
||||
return 0;
|
||||
@@ -2418,13 +2426,6 @@ static int GAME_EXPORT CL_FindModelIndex( const char *m )
|
||||
return i+1;
|
||||
}
|
||||
|
||||
if( lasttimewarn < host.realtime )
|
||||
{
|
||||
// tell user about problem (but don't spam console)
|
||||
Con_DPrintf( S_ERROR "Could not find index for model %s: not precached\n", filepath );
|
||||
lasttimewarn = host.realtime + 1.0f;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2698,17 +2699,6 @@ static const char *pfnGetGameDirectory( void )
|
||||
return szGetGameDir;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Key_LookupBinding
|
||||
|
||||
=============
|
||||
*/
|
||||
static const char *Key_LookupBinding( const char *pBinding )
|
||||
{
|
||||
return Key_KeynumToString( Key_GetKey( pBinding ));
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnGetLevelName
|
||||
@@ -3358,28 +3348,6 @@ DemoApi implementation
|
||||
|
||||
=================
|
||||
*/
|
||||
/*
|
||||
=================
|
||||
Demo_IsRecording
|
||||
|
||||
=================
|
||||
*/
|
||||
static int GAME_EXPORT Demo_IsRecording( void )
|
||||
{
|
||||
return cls.demorecording;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Demo_IsPlayingback
|
||||
|
||||
=================
|
||||
*/
|
||||
static int GAME_EXPORT Demo_IsPlayingback( void )
|
||||
{
|
||||
return cls.demoplayback;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Demo_IsTimeDemo
|
||||
@@ -3391,17 +3359,6 @@ static int GAME_EXPORT Demo_IsTimeDemo( void )
|
||||
return cls.timedemo;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Demo_WriteBuffer
|
||||
|
||||
=================
|
||||
*/
|
||||
static void GAME_EXPORT Demo_WriteBuffer( int size, byte *buffer )
|
||||
{
|
||||
CL_WriteDemoUserMessage( buffer, size );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
NetworkApi implementation
|
||||
@@ -3587,28 +3544,6 @@ static int GAME_EXPORT NetAPI_CompareAdr( netadr_t *a, netadr_t *b )
|
||||
return NET_CompareAdr( *a, *b );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
NetAPI_StringToAdr
|
||||
|
||||
=================
|
||||
*/
|
||||
static int GAME_EXPORT NetAPI_StringToAdr( char *s, netadr_t *a )
|
||||
{
|
||||
return NET_StringToAdr( s, a );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
NetAPI_ValueForKey
|
||||
|
||||
=================
|
||||
*/
|
||||
static const char * GAME_EXPORT NetAPI_ValueForKey( const char *s, const char *key )
|
||||
{
|
||||
return Info_ValueForKey( s, key );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
NetAPI_RemoveKey
|
||||
@@ -3805,10 +3740,10 @@ static event_api_t gEventApi =
|
||||
|
||||
static demo_api_t gDemoApi =
|
||||
{
|
||||
Demo_IsRecording,
|
||||
Demo_IsPlayingback,
|
||||
(void *)CL_IsRecordDemo,
|
||||
(void *)CL_IsPlaybackDemo,
|
||||
Demo_IsTimeDemo,
|
||||
Demo_WriteBuffer,
|
||||
CL_WriteDemoUserMessage,
|
||||
};
|
||||
|
||||
net_api_t gNetApi =
|
||||
@@ -3820,8 +3755,8 @@ net_api_t gNetApi =
|
||||
NetAPI_CancelAllRequests,
|
||||
NetAPI_AdrToString,
|
||||
NetAPI_CompareAdr,
|
||||
NetAPI_StringToAdr,
|
||||
NetAPI_ValueForKey,
|
||||
(void *)NET_StringToAdr,
|
||||
Info_ValueForKey,
|
||||
NetAPI_RemoveKey,
|
||||
NetAPI_SetValueForKey,
|
||||
};
|
||||
@@ -4007,9 +3942,10 @@ void CL_UnloadProgs( void )
|
||||
qboolean CL_LoadProgs( const char *name )
|
||||
{
|
||||
static playermove_t gpMove;
|
||||
const dllfunc_t *func;
|
||||
CL_EXPORT_FUNCS GetClientAPI; // single export
|
||||
qboolean critical_exports = true;
|
||||
CL_EXPORT_FUNCS GetClientAPI; // single export
|
||||
qboolean valid_single_export = false;
|
||||
qboolean missed_exports = false;
|
||||
int i;
|
||||
|
||||
if( clgame.hInstance ) CL_UnloadProgs();
|
||||
|
||||
@@ -4020,36 +3956,19 @@ qboolean CL_LoadProgs( const char *name )
|
||||
clgame.mempool = Mem_AllocPool( "Client Edicts Zone" );
|
||||
clgame.entities = NULL;
|
||||
|
||||
|
||||
// a1ba: we need to check if client.dll has direct dependency on SDL2
|
||||
// and if so, disable relative mouse mode
|
||||
#if XASH_WIN32 && !XASH_64BIT
|
||||
if( ( clgame.client_dll_uses_sdl = COM_CheckLibraryDirectDependency( name, OS_LIB_PREFIX "SDL2." OS_LIB_EXT, false ) ) )
|
||||
{
|
||||
Con_Printf( S_NOTE "%s uses SDL2 for mouse input\n", name );
|
||||
}
|
||||
else
|
||||
{
|
||||
Con_Printf( S_NOTE "%s uses Windows API for mouse input\n", name );
|
||||
}
|
||||
#else
|
||||
// this doesn't mean other platforms uses SDL2 in any case
|
||||
// it just helps input code to stay platform-independent
|
||||
clgame.client_dll_uses_sdl = true;
|
||||
clgame.client_dll_uses_sdl = COM_CheckLibraryDirectDependency( name, OS_LIB_PREFIX "SDL2." OS_LIB_EXT, false );
|
||||
Con_Printf( S_NOTE "%s uses %s for mouse input\n", name, clgame.client_dll_uses_sdl ? "SDL2" : "Windows API" );
|
||||
#endif
|
||||
|
||||
// NOTE: important stuff!
|
||||
// vgui must startup BEFORE loading client.dll to avoid get error ERROR_NOACESS
|
||||
// during LoadLibrary
|
||||
// vgui must startup BEFORE loading client.dll to avoid get error ERROR_NOACESS during LoadLibrary
|
||||
if( !GI->internal_vgui_support && VGui_LoadProgs( NULL ))
|
||||
{
|
||||
VGui_Startup( refState.width, refState.height );
|
||||
}
|
||||
else
|
||||
{
|
||||
// we failed to load vgui_support, but let's probe client.dll for support anyway
|
||||
GI->internal_vgui_support = true;
|
||||
}
|
||||
GI->internal_vgui_support = true; // we failed to load vgui_support, but let's probe client.dll for support anyway
|
||||
|
||||
clgame.hInstance = COM_LoadLibrary( name, false, false );
|
||||
|
||||
@@ -4058,13 +3977,10 @@ qboolean CL_LoadProgs( const char *name )
|
||||
|
||||
// delayed vgui initialization for internal support
|
||||
if( GI->internal_vgui_support && VGui_LoadProgs( clgame.hInstance ))
|
||||
{
|
||||
VGui_Startup( refState.width, refState.height );
|
||||
}
|
||||
|
||||
// clear exports
|
||||
for( func = cdll_exports; func && func->name; func++ )
|
||||
*func->func = NULL;
|
||||
ClearExports( cdll_exports, ARRAYSIZE( cdll_exports ));
|
||||
|
||||
// trying to get single export
|
||||
if(( GetClientAPI = (void *)COM_GetProcAddress( clgame.hInstance, "GetClientAPI" )) != NULL )
|
||||
@@ -4082,56 +3998,44 @@ qboolean CL_LoadProgs( const char *name )
|
||||
CL_GetSecuredClientAPI( GetClientAPI );
|
||||
}
|
||||
|
||||
if ( GetClientAPI != NULL )
|
||||
{
|
||||
// check critical functions again
|
||||
for( func = cdll_exports; func && func->name; func++ )
|
||||
{
|
||||
if( func->func == NULL )
|
||||
break; // BAH critical function was missed
|
||||
}
|
||||
if( GetClientAPI != NULL ) // check critical functions again
|
||||
valid_single_export = ValidateExports( cdll_exports, ARRAYSIZE( cdll_exports ));
|
||||
|
||||
// because all the exports are loaded through function 'F"
|
||||
if( !func || !func->name )
|
||||
critical_exports = false;
|
||||
}
|
||||
|
||||
for( func = cdll_exports; func && func->name != NULL; func++ )
|
||||
for( i = 0; i < ARRAYSIZE( cdll_exports ); i++ )
|
||||
{
|
||||
if( *func->func != NULL )
|
||||
continue; // already get through 'F'
|
||||
if( *(cdll_exports[i].func) != NULL )
|
||||
continue; // already gott through 'F' or 'GetClientAPI'
|
||||
|
||||
// functions are cleared before all the extensions are evaluated
|
||||
if(( *func->func = (void *)COM_GetProcAddress( clgame.hInstance, func->name )) == NULL )
|
||||
if(( *(cdll_exports[i].func) = (void *)COM_GetProcAddress( clgame.hInstance, cdll_exports[i].name )) == NULL )
|
||||
{
|
||||
Con_Reportf( "%s: failed to get address of %s proc\n", __func__, func->name );
|
||||
Con_Reportf( S_ERROR "%s: failed to get address of %s proc\n", __func__, cdll_exports[i].name );
|
||||
|
||||
if( critical_exports )
|
||||
{
|
||||
COM_FreeLibrary( clgame.hInstance );
|
||||
clgame.hInstance = NULL;
|
||||
return false;
|
||||
}
|
||||
// print all not found exports at once, for debug
|
||||
missed_exports = true;
|
||||
}
|
||||
}
|
||||
|
||||
if( missed_exports )
|
||||
{
|
||||
COM_FreeLibrary( clgame.hInstance );
|
||||
clgame.hInstance = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// it may be loaded through 'GetClientAPI' so we don't need to clear them
|
||||
if( critical_exports )
|
||||
{
|
||||
// clear new exports
|
||||
for( func = cdll_new_exports; func && func->name; func++ )
|
||||
*func->func = NULL;
|
||||
}
|
||||
if( !valid_single_export )
|
||||
ClearExports( cdll_new_exports, ARRAYSIZE( cdll_new_exports ));
|
||||
|
||||
for( func = cdll_new_exports; func && func->name != NULL; func++ )
|
||||
for( i = 0; i < ARRAYSIZE( cdll_new_exports ); i++ )
|
||||
{
|
||||
if( *func->func != NULL )
|
||||
continue; // already get through 'F'
|
||||
if( *(cdll_new_exports[i].func) != NULL )
|
||||
continue; // already gott through 'F' or 'GetClientAPI'
|
||||
|
||||
// functions are cleared before all the extensions are evaluated
|
||||
// NOTE: new exports can be missed without stop the engine
|
||||
if(( *func->func = (void *)COM_GetProcAddress( clgame.hInstance, func->name )) == NULL )
|
||||
Con_Reportf( "%s: failed to get address of %s proc\n", __func__, func->name );
|
||||
if(( *(cdll_new_exports[i].func) = (void *)COM_GetProcAddress( clgame.hInstance, cdll_new_exports[i].name )) == NULL )
|
||||
Con_Reportf( S_WARN "%s: failed to get address of %s proc\n", __func__, cdll_new_exports[i].name );
|
||||
}
|
||||
|
||||
if( !clgame.dllFuncs.pfnInitialize( &gEngfuncs, CLDLL_INTERFACE_VERSION ))
|
||||
|
||||
@@ -302,14 +302,11 @@ void UI_ConnectionProgress_ParseServerInfo( const char *server )
|
||||
|
||||
static void GAME_EXPORT UI_DrawLogo( const char *filename, float x, float y, float width, float height )
|
||||
{
|
||||
static float cin_time;
|
||||
static int last_frame = -1;
|
||||
byte *cin_data = NULL;
|
||||
movie_state_t *cin_state;
|
||||
int cin_frame;
|
||||
qboolean redraw = false;
|
||||
|
||||
if( !gameui.drawLogo ) return;
|
||||
if( !gameui.drawLogo )
|
||||
return;
|
||||
|
||||
cin_state = AVI_GetState( CIN_LOGO );
|
||||
|
||||
if( !AVI_IsActive( cin_state ))
|
||||
@@ -336,37 +333,25 @@ static void GAME_EXPORT UI_DrawLogo( const char *filename, float x, float y, flo
|
||||
gameui.drawLogo = false;
|
||||
return;
|
||||
}
|
||||
|
||||
cin_time = 0.0f;
|
||||
last_frame = -1;
|
||||
}
|
||||
|
||||
if( width <= 0 || height <= 0 )
|
||||
{
|
||||
// precache call, don't draw
|
||||
cin_time = 0.0f;
|
||||
last_frame = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
// advances cinematic time (ignores maxfps and host_framerate settings)
|
||||
cin_time += host.realframetime;
|
||||
|
||||
// restarts the cinematic
|
||||
if( cin_time > gameui.logo_length )
|
||||
cin_time = 0.0f;
|
||||
AVI_SetParm( cin_state,
|
||||
AVI_RENDER_TEXNUM, 0,
|
||||
AVI_RENDER_X, (int)x,
|
||||
AVI_RENDER_Y, (int)y,
|
||||
AVI_RENDER_W, (int)width,
|
||||
AVI_RENDER_H, (int)height,
|
||||
AVI_PARM_LAST );
|
||||
|
||||
// read the next frame
|
||||
cin_frame = AVI_GetVideoFrameNumber( cin_state, cin_time );
|
||||
|
||||
if( cin_frame != last_frame )
|
||||
{
|
||||
cin_data = AVI_GetVideoFrame( cin_state, cin_frame );
|
||||
last_frame = cin_frame;
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
ref.dllFuncs.R_DrawStretchRaw( x, y, width, height, gameui.logo_xres, gameui.logo_yres, cin_data, redraw );
|
||||
if( !AVI_Think( cin_state ))
|
||||
AVI_SetParm( cin_state, AVI_REWIND, AVI_PARM_LAST );
|
||||
}
|
||||
|
||||
static int GAME_EXPORT UI_GetLogoWidth( void )
|
||||
@@ -694,6 +679,11 @@ static cvar_t *GAME_EXPORT pfnCvar_RegisterGameUIVariable( const char *szName, c
|
||||
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_GAMEUIDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_GAMEUIDLL ));
|
||||
}
|
||||
|
||||
static int GAME_EXPORT Cmd_AddGameUICommand( const char *cmd_name, xcommand_t function )
|
||||
{
|
||||
return Cmd_AddCommandEx( cmd_name, function, "gameui command", CMD_GAMEUIDLL, __func__ );
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
pfnClientCmd
|
||||
@@ -1109,7 +1099,7 @@ static void GAME_EXPORT UI_ShellExecute( const char *path, const char *parms, in
|
||||
Platform_ShellExecute( path, parms );
|
||||
|
||||
if( shouldExit )
|
||||
Sys_Quit();
|
||||
Sys_Quit( __func__ );
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -76,6 +76,7 @@ static CVAR_DEFINE_AUTO( cl_upmax, "1200", FCVAR_ARCHIVE, "max allowed incoming
|
||||
|
||||
CVAR_DEFINE_AUTO( cl_lw, "1", FCVAR_ARCHIVE|FCVAR_USERINFO, "enable client weapon predicting" );
|
||||
CVAR_DEFINE_AUTO( cl_charset, "utf-8", FCVAR_ARCHIVE, "1-byte charset to use (iconv style)" );
|
||||
CVAR_DEFINE_AUTO( cl_trace_consistency, "0", FCVAR_ARCHIVE, "enable consistency info tracing (good for developers)" );
|
||||
CVAR_DEFINE_AUTO( cl_trace_stufftext, "0", FCVAR_ARCHIVE, "enable stufftext (server-to-client console commands) tracing (good for developers)" );
|
||||
CVAR_DEFINE_AUTO( cl_trace_messages, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable message names tracing (good for developers)" );
|
||||
CVAR_DEFINE_AUTO( cl_trace_events, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable events tracing (good for developers)" );
|
||||
@@ -147,11 +148,6 @@ qboolean CL_IsRecordDemo( void )
|
||||
return cls.demorecording;
|
||||
}
|
||||
|
||||
qboolean CL_IsTimeDemo( void )
|
||||
{
|
||||
return cls.timedemo;
|
||||
}
|
||||
|
||||
qboolean CL_DisableVisibility( void )
|
||||
{
|
||||
return cls.envshot_disable_vis;
|
||||
@@ -598,7 +594,7 @@ CL_CreateCmd
|
||||
*/
|
||||
static void CL_CreateCmd( void )
|
||||
{
|
||||
usercmd_t nullcmd, *cmd;
|
||||
usercmd_t nullcmd = { 0 }, *cmd;
|
||||
runcmd_t *pcmd;
|
||||
qboolean active;
|
||||
double accurate_ms;
|
||||
@@ -650,7 +646,6 @@ static void CL_CreateCmd( void )
|
||||
}
|
||||
else
|
||||
{
|
||||
memset( &nullcmd, 0, sizeof( nullcmd ));
|
||||
cmd = &nullcmd;
|
||||
}
|
||||
|
||||
@@ -723,11 +718,20 @@ static void CL_WritePacket( void )
|
||||
int numbackup, maxbackup, maxcmds;
|
||||
const connprotocol_t proto = cls.legacymode;
|
||||
|
||||
// FIXME: on Xash protocol we don't send move commands until ca_active
|
||||
// to prevent outgoing_command outrun incoming_acknowledged
|
||||
// which is fatal for some buggy mods like TFC
|
||||
//
|
||||
// ... but GoldSrc don't have (real) ca_validate state, so we consider
|
||||
// ca_validate the same as ca_active, otherwise we don't pass validation
|
||||
// of server-side mods like ReAuthCheck
|
||||
const connstate_t min_state = proto == PROTO_GOLDSRC ? ca_validate : ca_active;
|
||||
|
||||
// don't send anything if playing back a demo
|
||||
if( cls.demoplayback || cls.state < ca_connected || cls.state == ca_cinematic )
|
||||
return;
|
||||
|
||||
if( cls.state <= ca_connected )
|
||||
if( cls.state < min_state )
|
||||
{
|
||||
Netchan_TransmitBits( &cls.netchan, 0, "" );
|
||||
return;
|
||||
@@ -825,7 +829,7 @@ static void CL_WritePacket( void )
|
||||
buf.pData[key] = CRC32_BlockSequence( &buf.pData[key + 1], size, cls.netchan.outgoing_sequence );
|
||||
COM_Munge( &buf.pData[key + 1], Q_min( size, 255 ), cls.netchan.outgoing_sequence );
|
||||
}
|
||||
else
|
||||
else if( !Host_IsLocalClient( ))
|
||||
{
|
||||
int size = MSG_GetRealBytesWritten( &buf ) - key - 1;
|
||||
buf.pData[key] = CRC32_BlockSequence( &buf.pData[key + 1], size, cls.netchan.outgoing_sequence );
|
||||
@@ -965,7 +969,7 @@ CL_Quit_f
|
||||
void CL_Quit_f( void )
|
||||
{
|
||||
CL_Disconnect();
|
||||
Sys_Quit();
|
||||
Sys_Quit( "command" );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1401,7 +1405,8 @@ static void CL_Connect_f( void )
|
||||
Q_strncpy( server, Cmd_Argv( 1 ), sizeof( server ));
|
||||
|
||||
// if running a local server, kill it and reissue
|
||||
if( SV_Active( )) Host_ShutdownServer();
|
||||
if( SV_Active( ))
|
||||
SV_Shutdown( "Server was killed due to connection to remote server\n" );
|
||||
NET_Config( true, !cl_nat.value ); // allow remote
|
||||
|
||||
Con_Printf( "server %s\n", server );
|
||||
@@ -1593,6 +1598,9 @@ void CL_SetupNetchanForProtocol( connprotocol_t proto )
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if( !Host_IsLocalClient( ))
|
||||
SetBits( flags, NETCHAN_USE_LZSS );
|
||||
|
||||
cls.extensions = Q_atoi( Info_ValueForKey( Cmd_Argv( 1 ), "ext" ));
|
||||
|
||||
if( FBitSet( cls.extensions, NET_EXT_SPLITSIZE ))
|
||||
@@ -1760,8 +1768,8 @@ static size_t NONNULL CL_BuildMasterServerScanRequest( char *buf, size_t size, u
|
||||
// let master know about client version
|
||||
Info_SetValueForKey( info, "clver", XASH_VERSION, remaining );
|
||||
Info_SetValueForKey( info, "nat", nat ? "1" : "0", remaining );
|
||||
Info_SetValueForKey( info, "commit", Q_buildcommit(), remaining );
|
||||
Info_SetValueForKey( info, "branch", Q_buildbranch(), remaining );
|
||||
Info_SetValueForKey( info, "commit", g_buildcommit, remaining );
|
||||
Info_SetValueForKey( info, "branch", g_buildbranch, remaining );
|
||||
Info_SetValueForKey( info, "os", Q_buildos(), remaining );
|
||||
Info_SetValueForKey( info, "arch", Q_buildarch(), remaining );
|
||||
|
||||
@@ -3326,6 +3334,22 @@ static void CL_Escape_f( void )
|
||||
else UI_SetActiveMenu( true );
|
||||
}
|
||||
|
||||
static void CL_ListMessages_f( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
Con_Printf( "num size name\n" );
|
||||
for( i = 0; i < MAX_USER_MESSAGES; i++ )
|
||||
{
|
||||
if( !COM_CheckStringEmpty( clgame.msg[i].name ))
|
||||
break;
|
||||
|
||||
Con_Printf( "%3d\t%3d\t%s\n", clgame.msg[i].number, clgame.msg[i].size, clgame.msg[i].name );
|
||||
}
|
||||
|
||||
Con_Printf( "Total %i messages\n", i );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_InitLocal
|
||||
@@ -3370,6 +3394,7 @@ static void CL_InitLocal( void )
|
||||
|
||||
Cvar_RegisterVariable( &rcon_address );
|
||||
|
||||
Cvar_RegisterVariable( &cl_trace_consistency );
|
||||
Cvar_RegisterVariable( &cl_trace_stufftext );
|
||||
Cvar_RegisterVariable( &cl_trace_messages );
|
||||
Cvar_RegisterVariable( &cl_trace_events );
|
||||
@@ -3483,6 +3508,7 @@ static void CL_InitLocal( void )
|
||||
Cmd_AddCommand( "richpresence_gamemode", Cmd_Null_f, "compatibility command, does nothing" );
|
||||
Cmd_AddCommand( "richpresence_update", Cmd_Null_f, "compatibility command, does nothing" );
|
||||
|
||||
Cmd_AddCommand( "cl_list_messages", CL_ListMessages_f, "list registered user messages" );
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
@@ -3640,6 +3666,8 @@ void CL_Init( void )
|
||||
if( !CL_LoadProgs( libpath ))
|
||||
Host_Error( "can't initialize %s: %s\n", libpath, COM_GetLibraryError( ));
|
||||
|
||||
ID_Init();
|
||||
|
||||
cls.build_num = 0;
|
||||
cls.initialized = true;
|
||||
cl.maxclients = 1; // allow to drawing player in menu
|
||||
|
||||
@@ -311,10 +311,13 @@ static client entity
|
||||
static void CL_ParseStaticEntity( sizebuf_t *msg )
|
||||
{
|
||||
int i, newnum;
|
||||
entity_state_t from, to;
|
||||
const entity_state_t from = { 0 };
|
||||
entity_state_t to;
|
||||
cl_entity_t *ent;
|
||||
|
||||
memset( &from, 0, sizeof( from ));
|
||||
if( !clgame.static_entities )
|
||||
clgame.static_entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
|
||||
|
||||
newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
|
||||
MSG_ReadDeltaEntity( msg, &from, &to, 0, DELTA_STATIC, cl.mtime[0] );
|
||||
|
||||
@@ -1322,11 +1325,11 @@ void CL_ParseLightStyle( sizebuf_t *msg, connprotocol_t proto )
|
||||
{
|
||||
int style;
|
||||
const char *s;
|
||||
float f = 0.0f;
|
||||
float f = cl.mtime[0];
|
||||
|
||||
style = MSG_ReadByte( msg );
|
||||
s = MSG_ReadString( msg );
|
||||
if( proto != PROTO_GOLDSRC )
|
||||
if( proto != PROTO_GOLDSRC && proto != PROTO_QUAKE )
|
||||
f = MSG_ReadFloat( msg );
|
||||
|
||||
CL_SetLightstyle( style, s, f );
|
||||
@@ -1424,37 +1427,31 @@ register new user message or update existing
|
||||
void CL_RegisterUserMessage( sizebuf_t *msg, connprotocol_t proto )
|
||||
{
|
||||
char *pszName;
|
||||
int svc_num, size, bits;
|
||||
|
||||
svc_num = MSG_ReadByte( msg );
|
||||
char szName[17];
|
||||
int size;
|
||||
int svc_num = MSG_ReadByte( msg );
|
||||
|
||||
if( proto == PROTO_LEGACY || proto == PROTO_GOLDSRC )
|
||||
{
|
||||
size = MSG_ReadByte( msg );
|
||||
bits = 8;
|
||||
if( size == UINT8_MAX )
|
||||
size = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = MSG_ReadWord( msg );
|
||||
bits = 16;
|
||||
if( size == UINT16_MAX )
|
||||
size = -1;
|
||||
}
|
||||
|
||||
if( proto == PROTO_GOLDSRC )
|
||||
{
|
||||
static char szName[17];
|
||||
|
||||
MSG_ReadBytes( msg, szName, sizeof( szName ) - 1 );
|
||||
szName[16] = 0;
|
||||
|
||||
pszName = szName;
|
||||
}
|
||||
else pszName = MSG_ReadString( msg );
|
||||
|
||||
// important stuff
|
||||
if( size == ( BIT( bits ) - 1 ) )
|
||||
size = -1;
|
||||
svc_num = bound( 0, svc_num, 255 );
|
||||
|
||||
CL_LinkUserMessage( pszName, svc_num, size );
|
||||
}
|
||||
|
||||
@@ -1593,17 +1590,23 @@ collect pings and packet lossage from clients
|
||||
*/
|
||||
void CL_UpdateUserPings( sizebuf_t *msg )
|
||||
{
|
||||
int i, slot;
|
||||
player_info_t *player;
|
||||
|
||||
for( i = 0; i < MAX_CLIENTS; i++ )
|
||||
// a1ba: there was a MAX_PLAYERS check but it doesn't make sense
|
||||
// because pings message always ends by null bit
|
||||
while( 1 )
|
||||
{
|
||||
if( !MSG_ReadOneBit( msg )) break; // end of message
|
||||
int slot;
|
||||
player_info_t *player;
|
||||
|
||||
if( !MSG_ReadOneBit( msg ))
|
||||
break; // end of message
|
||||
|
||||
slot = MSG_ReadUBitLong( msg, MAX_CLIENT_BITS );
|
||||
|
||||
if( slot >= MAX_CLIENTS )
|
||||
if( unlikely( slot >= MAX_CLIENTS ))
|
||||
{
|
||||
Host_Error( "%s: svc_pings > MAX_CLIENTS\n", __func__ );
|
||||
return;
|
||||
}
|
||||
|
||||
player = &cl.players[slot];
|
||||
player->ping = MSG_ReadUBitLong( msg, 12 );
|
||||
@@ -1611,6 +1614,23 @@ void CL_UpdateUserPings( sizebuf_t *msg )
|
||||
}
|
||||
}
|
||||
|
||||
static const char *CL_CheckTypeToString( int check_type )
|
||||
{
|
||||
// renamed so they have same width and look better in console output
|
||||
switch( check_type )
|
||||
{
|
||||
case force_exactfile:
|
||||
return "exactfile";
|
||||
case force_model_samebounds:
|
||||
return "samebounds";
|
||||
case force_model_specifybounds:
|
||||
return "specbounds";
|
||||
case force_model_specifybounds_if_avail:
|
||||
return "specbounds2";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static void CL_SendConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
|
||||
{
|
||||
qboolean user_changed_diskfile;
|
||||
@@ -1876,6 +1896,9 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
|
||||
return;
|
||||
}
|
||||
|
||||
if( cl_trace_consistency.value )
|
||||
Con_Printf( "Server wants consistency of the following resources:\n" );
|
||||
|
||||
skip_crc_change = NULL;
|
||||
lastcheck = 0;
|
||||
|
||||
@@ -1907,7 +1930,7 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
|
||||
pc = &cl.consistency_list[cl.num_consistency];
|
||||
cl.num_consistency++;
|
||||
|
||||
memset( pc, 0, sizeof( consistency_t ));
|
||||
memset( pc, 0, sizeof( *pc ));
|
||||
pc->filename = pResource->szFileName;
|
||||
pc->issound = (pResource->type == t_sound);
|
||||
pc->orig_index = delta;
|
||||
@@ -1920,6 +1943,9 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
|
||||
pc->check_type = pResource->rguc_reserved[0];
|
||||
}
|
||||
|
||||
if( cl_trace_consistency.value )
|
||||
Con_Printf( "%s\t%s\t%s\n", COM_ResourceTypeFromIndex( pResource->type ), CL_CheckTypeToString( pc->check_type ), pc->filename );
|
||||
|
||||
skip_crc_change = pResource;
|
||||
lastcheck = delta;
|
||||
}
|
||||
|
||||
@@ -33,10 +33,12 @@ static client entity
|
||||
static void CL_LegacyParseStaticEntity( sizebuf_t *msg )
|
||||
{
|
||||
int i;
|
||||
entity_state_t state;
|
||||
entity_state_t state = { 0 };
|
||||
cl_entity_t *ent;
|
||||
|
||||
memset( &state, 0, sizeof( state ));
|
||||
if( !clgame.static_entities )
|
||||
clgame.static_entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
|
||||
|
||||
state.modelindex = MSG_ReadShort( msg );
|
||||
state.sequence = MSG_ReadByte( msg );
|
||||
state.frame = MSG_ReadByte( msg );
|
||||
|
||||
@@ -91,11 +91,11 @@ static void CL_ParseNewMovevars( sizebuf_t *msg )
|
||||
|
||||
typedef struct delta_header_t
|
||||
{
|
||||
qboolean remove : 1;
|
||||
qboolean custom : 1;
|
||||
qboolean instanced : 1;
|
||||
uint instanced_baseline_index : 6;
|
||||
uint offset : 6;
|
||||
qboolean remove;
|
||||
qboolean custom;
|
||||
qboolean instanced;
|
||||
uint16_t instanced_baseline_index;
|
||||
uint16_t offset;
|
||||
} delta_header_t;
|
||||
|
||||
static int CL_ParseDeltaHeader( sizebuf_t *msg, qboolean delta, int oldnum, struct delta_header_t *hdr )
|
||||
@@ -160,33 +160,47 @@ static int CL_GetEntityDelta( const struct delta_header_t *hdr, int entnum )
|
||||
return DT_ENTITY_STATE_T;
|
||||
}
|
||||
|
||||
static void CL_FlushEntityPacketGS( frame_t *frame, sizebuf_t *msg )
|
||||
static int CL_FlushEntityPacketGS( frame_t *frame, sizebuf_t *msg )
|
||||
{
|
||||
int playerbytes = 0, numbase = 0;
|
||||
|
||||
frame->valid = false;
|
||||
cl.validsequence = 0; // can't render a frame
|
||||
|
||||
// read it all but ignore it
|
||||
while( 1 )
|
||||
{
|
||||
int num = 0;
|
||||
int newnum, bufstart;
|
||||
entity_state_t from = { 0 }, to;
|
||||
delta_header_t hdr;
|
||||
qboolean player;
|
||||
|
||||
if( MSG_ReadWord( msg ) != 0 )
|
||||
{
|
||||
MSG_SeekToBit( msg, -16, SEEK_CUR );
|
||||
num = CL_ParseDeltaHeader( msg, false, num, &hdr );
|
||||
numbase = newnum = CL_ParseDeltaHeader( msg, true, numbase, &hdr );
|
||||
}
|
||||
else break;
|
||||
|
||||
if( MSG_CheckOverflow( msg ))
|
||||
Host_Error( "%s: overflow\n", __func__ );
|
||||
|
||||
player = CL_IsPlayerIndex( newnum );
|
||||
bufstart = MSG_GetNumBytesRead( msg );
|
||||
|
||||
if( hdr.remove )
|
||||
continue;
|
||||
|
||||
Delta_ReadGSFields( msg, CL_GetEntityDelta( &hdr, num ), &from, &to, cl.mtime[0] );
|
||||
Delta_ReadGSFields( msg, CL_GetEntityDelta( &hdr, newnum ), &from, &to, cl.mtime[0] );
|
||||
|
||||
if( player )
|
||||
playerbytes += MSG_GetNumBytesRead( msg ) - bufstart;
|
||||
}
|
||||
|
||||
if( MSG_CheckOverflow( msg ))
|
||||
Host_Error( "%s: overflow\n", __func__ );
|
||||
|
||||
return playerbytes;
|
||||
}
|
||||
|
||||
static void CL_DeltaEntityGS( const delta_header_t *hdr, sizebuf_t *msg, frame_t *frame, int newnum, const entity_state_t *from )
|
||||
@@ -203,7 +217,7 @@ static void CL_DeltaEntityGS( const delta_header_t *hdr, sizebuf_t *msg, frame_t
|
||||
if(( newnum < 0 ) || ( newnum >= clgame.maxEntities ))
|
||||
{
|
||||
Con_DPrintf( S_ERROR "CL_DeltaEntity: invalid newnum: %d\n", newnum );
|
||||
Host_Error( "%s: bad delta entity number: %i", __func__, newnum );
|
||||
Host_Error( "%s: bad delta entity number: %i\n", __func__, newnum );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -267,7 +281,7 @@ static void CL_CopyPacketEntity( frame_t *frame, int num, const entity_state_t *
|
||||
static int CL_ParsePacketEntitiesGS( sizebuf_t *msg, qboolean delta )
|
||||
{
|
||||
frame_t *frame, *oldframe;
|
||||
int oldindex, newnum, oldnum, numbase = 0;
|
||||
int oldindex, oldnum, numbase = 0;
|
||||
entity_state_t *oldent;
|
||||
int count;
|
||||
int playerbytes = 0;
|
||||
@@ -314,7 +328,7 @@ static int CL_ParsePacketEntitiesGS( sizebuf_t *msg, qboolean delta )
|
||||
// read it all but ignore it
|
||||
while( 1 )
|
||||
{
|
||||
int bufstart;
|
||||
int bufstart, newnum;
|
||||
qboolean player;
|
||||
delta_header_t hdr;
|
||||
int val = MSG_ReadWord( msg );
|
||||
@@ -534,7 +548,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
|
||||
{
|
||||
if( MSG_CheckOverflow( msg ))
|
||||
{
|
||||
Host_Error( "CL_ParseServerMessage: overflow!\n" );
|
||||
Host_Error( "%s: overflow!\n", __func__ );
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -615,7 +629,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
|
||||
case svc_setangle:
|
||||
CL_ParseSetAngle( msg );
|
||||
break;
|
||||
case svc_goldsrc_serverinfo:
|
||||
case svc_serverdata:
|
||||
Cbuf_Execute(); // make sure any stuffed commands are done
|
||||
CL_ParseServerData( msg, PROTO_GOLDSRC );
|
||||
break;
|
||||
@@ -625,7 +639,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
|
||||
case svc_updateuserinfo:
|
||||
CL_UpdateUserinfo( msg, PROTO_GOLDSRC );
|
||||
break;
|
||||
case svc_goldsrc_deltadescription:
|
||||
case svc_deltatable:
|
||||
Delta_ParseTableField_GS( msg );
|
||||
break;
|
||||
case svc_clientdata:
|
||||
@@ -687,7 +701,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
|
||||
case svc_addangle:
|
||||
CL_ParseAddAngle( msg );
|
||||
break;
|
||||
case svc_goldsrc_newusermsg:
|
||||
case svc_usermessage:
|
||||
CL_RegisterUserMessage( msg, PROTO_GOLDSRC );
|
||||
break;
|
||||
case svc_packetentities:
|
||||
@@ -709,7 +723,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
|
||||
CL_ParseResourceList( msg, PROTO_GOLDSRC );
|
||||
MSG_EndBitWriting( msg );
|
||||
break;
|
||||
case svc_goldsrc_newmovevars:
|
||||
case svc_deltamovevars:
|
||||
CL_ParseNewMovevars( msg );
|
||||
break;
|
||||
case svc_resourcerequest:
|
||||
@@ -749,10 +763,10 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
|
||||
Con_Reportf( S_ERROR "%s: svc_goldsrc_timescale: implement me!\n", __func__ );
|
||||
MSG_ReadFloat( msg );
|
||||
break;
|
||||
case svc_goldsrc_sendcvarvalue:
|
||||
case svc_querycvarvalue:
|
||||
CL_ParseCvarValue( msg, false, PROTO_GOLDSRC );
|
||||
break;
|
||||
case svc_goldsrc_sendcvarvalue2:
|
||||
case svc_querycvarvalue2:
|
||||
CL_ParseCvarValue( msg, true, PROTO_GOLDSRC );
|
||||
break;
|
||||
case svc_exec:
|
||||
|
||||
@@ -628,11 +628,12 @@ CL_ParseStaticEntity
|
||||
*/
|
||||
static void CL_ParseQuakeStaticEntity( sizebuf_t *msg )
|
||||
{
|
||||
entity_state_t state;
|
||||
entity_state_t state = { 0 };
|
||||
cl_entity_t *ent;
|
||||
int i;
|
||||
|
||||
memset( &state, 0, sizeof( state ));
|
||||
if( !clgame.static_entities )
|
||||
clgame.static_entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * MAX_STATIC_ENTITIES );
|
||||
|
||||
state.modelindex = MSG_ReadByte( msg );
|
||||
state.frame = MSG_ReadByte( msg );
|
||||
@@ -969,9 +970,7 @@ void CL_ParseQuakeMessage( sizebuf_t *msg )
|
||||
CL_ParseQuakeServerInfo( msg );
|
||||
break;
|
||||
case svc_lightstyle:
|
||||
param1 = MSG_ReadByte( msg );
|
||||
str = MSG_ReadString( msg );
|
||||
CL_SetLightstyle( param1, str, cl.mtime[0] );
|
||||
CL_ParseLightStyle( msg, PROTO_QUAKE );
|
||||
break;
|
||||
case svc_updatename:
|
||||
param1 = MSG_ReadByte( msg );
|
||||
|
||||
@@ -138,10 +138,7 @@ intptr_t CL_RenderGetParm( const int parm, const int arg, const qboolean checkRe
|
||||
switch( parm )
|
||||
{
|
||||
case PARM_BSP2_SUPPORTED:
|
||||
#ifdef SUPPORT_BSP2_FORMAT
|
||||
return 1;
|
||||
#endif
|
||||
return 0;
|
||||
case PARAM_GAMEPAUSED:
|
||||
return cl.paused;
|
||||
case PARM_CLIENT_INGAME:
|
||||
@@ -236,6 +233,11 @@ static intptr_t pfnRenderGetParm( int parm, int arg )
|
||||
return CL_RenderGetParm( parm, arg, true );
|
||||
}
|
||||
|
||||
static void pfnAVI_StreamSound( movie_state_t *avi, int entnum, float fvol, float attn, float synctime )
|
||||
{
|
||||
return; // stub, use AVI_SetParm and AVI_Think to stream AVI sound
|
||||
}
|
||||
|
||||
static render_api_t gRenderAPI =
|
||||
{
|
||||
pfnRenderGetParm, // GL_RenderGetParm,
|
||||
@@ -261,16 +263,16 @@ static render_api_t gRenderAPI =
|
||||
NULL, // DrawSingleDecal,
|
||||
NULL, // R_DecalSetupVerts,
|
||||
NULL, // R_EntityRemoveDecals,
|
||||
(void*)AVI_LoadVideo,
|
||||
(void*)AVI_GetVideoInfo,
|
||||
(void*)AVI_GetVideoFrameNumber,
|
||||
(void*)AVI_GetVideoFrame,
|
||||
AVI_LoadVideo,
|
||||
AVI_GetVideoInfo,
|
||||
AVI_GetVideoFrameNumber,
|
||||
AVI_GetVideoFrame,
|
||||
NULL, // R_UploadStretchRaw,
|
||||
(void*)AVI_FreeVideo,
|
||||
(void*)AVI_IsActive,
|
||||
S_StreamAviSamples,
|
||||
NULL,
|
||||
NULL,
|
||||
AVI_FreeVideo,
|
||||
AVI_IsActive,
|
||||
pfnAVI_StreamSound,
|
||||
AVI_Think,
|
||||
AVI_SetParm,
|
||||
NULL, // GL_Bind,
|
||||
NULL, // GL_SelectTexture,
|
||||
NULL, // GL_LoadTexMatrixExt,
|
||||
|
||||
@@ -124,7 +124,7 @@ void SCR_DrawPos( void )
|
||||
if( cls.state != ca_active || !cl_showpos.value || cl.background )
|
||||
return;
|
||||
|
||||
ent = CL_EDICT_NUM( cl.playernum + 1 );
|
||||
ent = CL_GetLocalPlayer();
|
||||
speed = VectorLength( cl.simvel );
|
||||
|
||||
Q_snprintf( msg, MAX_SYSPATH,
|
||||
|
||||
@@ -567,57 +567,54 @@ R_FizzEffect
|
||||
Create a fizz effect
|
||||
==============
|
||||
*/
|
||||
void GAME_EXPORT R_FizzEffect( cl_entity_t *pent, int modelIndex, int density )
|
||||
void GAME_EXPORT R_FizzEffect( cl_entity_t *ent, int modelIndex, int density )
|
||||
{
|
||||
TEMPENTITY *pTemp;
|
||||
int i, width, depth;
|
||||
float angle, maxHeight, speed;
|
||||
float xspeed, yspeed, zspeed;
|
||||
vec3_t origin;
|
||||
model_t *mod;
|
||||
const float base_time = cl.time - 0.1f;
|
||||
model_t *mod = CL_ModelHandle( modelIndex );
|
||||
vec3_t volume, mins, maxs;
|
||||
vec2_t speed;
|
||||
int i;
|
||||
|
||||
if( !pent || !pent->model || !modelIndex )
|
||||
if( !ent || !ent->model || !modelIndex || !mod )
|
||||
return;
|
||||
|
||||
if(( mod = CL_ModelHandle( modelIndex )) == NULL )
|
||||
return;
|
||||
VectorCopy( ent->model->mins, mins );
|
||||
VectorCopy( ent->model->maxs, maxs );
|
||||
|
||||
maxHeight = pent->model->maxs[2] - pent->model->mins[2];
|
||||
width = pent->model->maxs[0] - pent->model->mins[0];
|
||||
depth = pent->model->maxs[1] - pent->model->mins[1];
|
||||
if( ent->angles[1] != 0.0f )
|
||||
{
|
||||
const float base_speed = ( ent->curstate.rendercolor.b ? -1.0f : 1.0f ) * ( ent->curstate.rendercolor.r * 256.0f + ent->curstate.rendercolor.g );
|
||||
SinCos( DEG2RAD( ent->angles[1] ), &speed[1], &speed[0] );
|
||||
speed[0] *= base_speed;
|
||||
speed[1] *= base_speed;
|
||||
}
|
||||
else speed[0] = speed[1] = 0.0f;
|
||||
|
||||
speed = ( pent->curstate.rendercolor.r<<8 | pent->curstate.rendercolor.g );
|
||||
if( pent->curstate.rendercolor.b )
|
||||
speed = -speed;
|
||||
|
||||
angle = DEG2RAD( pent->angles[YAW] );
|
||||
SinCos( angle, &yspeed, &xspeed );
|
||||
|
||||
xspeed *= speed;
|
||||
yspeed *= speed;
|
||||
VectorSubtract( maxs, mins, volume );
|
||||
|
||||
for( i = 0; i <= density; i++ )
|
||||
{
|
||||
origin[0] = mod->mins[0] + COM_RandomLong( 0, width - 1 );
|
||||
origin[1] = mod->mins[1] + COM_RandomLong( 0, depth - 1 );
|
||||
origin[2] = mod->mins[2];
|
||||
pTemp = CL_TempEntAlloc( origin, mod );
|
||||
TEMPENTITY *tent;
|
||||
vec3_t origin;
|
||||
|
||||
if ( !pTemp ) return;
|
||||
VectorCopy( mins, origin );
|
||||
origin[0] += COM_RandomLong( 0, (int)volume[0] - 1 );
|
||||
origin[1] += COM_RandomLong( 0, (int)volume[1] - 1 );
|
||||
|
||||
pTemp->flags |= FTENT_SINEWAVE;
|
||||
if( !( tent = CL_TempEntAlloc( origin, mod )))
|
||||
return;
|
||||
|
||||
pTemp->x = origin[0];
|
||||
pTemp->y = origin[1];
|
||||
tent->x = origin[0];
|
||||
tent->y = origin[1];
|
||||
tent->die = base_time;
|
||||
tent->flags |= FTENT_SINEWAVE;
|
||||
tent->entity.curstate.rendermode = kRenderTransAlpha;
|
||||
Vector2Copy( speed, tent->entity.baseline.origin );
|
||||
|
||||
zspeed = COM_RandomLong( 80, 140 );
|
||||
VectorSet( pTemp->entity.baseline.origin, xspeed, yspeed, zspeed );
|
||||
pTemp->die = cl.time + ( maxHeight / zspeed ) - 0.1f;
|
||||
pTemp->entity.curstate.frame = COM_RandomLong( 0, pTemp->frameMax );
|
||||
// Set sprite scale
|
||||
pTemp->entity.curstate.scale = 1.0f / COM_RandomFloat( 2.0f, 5.0f );
|
||||
pTemp->entity.curstate.rendermode = kRenderTransAlpha;
|
||||
pTemp->entity.curstate.renderamt = 255;
|
||||
tent->entity.baseline.origin[2] = COM_RandomLong( 80, 140 );
|
||||
tent->die += volume[2] / tent->entity.baseline.origin[2];
|
||||
tent->entity.curstate.frame = COM_RandomLong( 0, tent->frameMax );
|
||||
tent->entity.curstate.scale = 1.0f / COM_RandomFloat( 2.0f, 5.0f );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2427,18 +2424,18 @@ static void CL_ClearLightStyles( void )
|
||||
|
||||
void CL_SetLightstyle( int style, const char *s, float f )
|
||||
{
|
||||
int i, k;
|
||||
lightstyle_t *ls;
|
||||
float val1, val2;
|
||||
int i;
|
||||
lightstyle_t *ls;
|
||||
|
||||
Assert( s != NULL );
|
||||
Assert( style >= 0 && style < MAX_LIGHTSTYLES );
|
||||
if( unlikely( style < 0 || style >= MAX_LIGHTSTYLES ))
|
||||
{
|
||||
Con_Printf( S_WARN "%s: ignored invalid lightstyle id %d\n", style );
|
||||
return;
|
||||
}
|
||||
|
||||
ls = &cl.lightstyles[style];
|
||||
|
||||
Q_strncpy( ls->pattern, s, sizeof( ls->pattern ));
|
||||
|
||||
ls->length = Q_strlen( s );
|
||||
ls->length = Q_strncpy( ls->pattern, s, sizeof( ls->pattern ));
|
||||
ls->time = f; // set local time
|
||||
|
||||
for( i = 0; i < ls->length; i++ )
|
||||
@@ -2448,10 +2445,10 @@ void CL_SetLightstyle( int style, const char *s, float f )
|
||||
|
||||
// check for allow interpolate
|
||||
// NOTE: fast flickering styles looks ugly when interpolation is running
|
||||
for( k = 0; k < (ls->length - 1); k++ )
|
||||
for( i = 0; i < ( ls->length - 1 ); i++ )
|
||||
{
|
||||
val1 = ls->map[(k+0) % ls->length];
|
||||
val2 = ls->map[(k+1) % ls->length];
|
||||
float val1 = ls->map[( i + 0 ) % ls->length];
|
||||
float val2 = ls->map[( i + 1 ) % ls->length];
|
||||
|
||||
if( fabs( val1 - val2 ) > STYLE_LERPING_THRESHOLD )
|
||||
{
|
||||
@@ -2471,8 +2468,8 @@ DLIGHT MANAGEMENT
|
||||
|
||||
==============================================================
|
||||
*/
|
||||
dlight_t cl_dlights[MAX_DLIGHTS];
|
||||
dlight_t cl_elights[MAX_ELIGHTS];
|
||||
static dlight_t cl_dlights[MAX_DLIGHTS];
|
||||
static dlight_t cl_elights[MAX_ELIGHTS];
|
||||
|
||||
/*
|
||||
================
|
||||
|
||||
@@ -24,11 +24,6 @@ AVI PLAYING
|
||||
=================================================================
|
||||
*/
|
||||
|
||||
static int xres, yres;
|
||||
static float video_duration;
|
||||
static float cin_time;
|
||||
static int cin_frame;
|
||||
static wavdata_t cin_audio;
|
||||
static movie_state_t *cin_state;
|
||||
|
||||
/*
|
||||
@@ -88,7 +83,17 @@ void SCR_CheckStartupVids( void )
|
||||
char *pfile;
|
||||
string token;
|
||||
|
||||
if( Sys_CheckParm( "-nointro" ) || host_developer.value || cls.demonum != -1 || GameState->nextstate != STATE_RUNFRAME )
|
||||
#if 0
|
||||
if( host_developer.value )
|
||||
{
|
||||
// don't run movies where we in developer-mode
|
||||
cls.movienum = -1;
|
||||
CL_CheckStartupDemos();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( Sys_CheckParm( "-nointro" ) || cls.demonum != -1 || GameState->nextstate != STATE_RUNFRAME )
|
||||
{
|
||||
// don't run movies where we in developer-mode
|
||||
cls.movienum = -1;
|
||||
@@ -147,23 +152,9 @@ void SCR_RunCinematic( void )
|
||||
Key_SetKeyDest( key_menu );
|
||||
S_StopStreaming();
|
||||
cls.movienum = -1;
|
||||
cin_time = 0.0f;
|
||||
cls.signon = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// advances cinematic time (ignores maxfps and host_framerate settings)
|
||||
cin_time += host.realframetime;
|
||||
|
||||
// stop the video after it finishes
|
||||
if( cin_time > video_duration + 0.1f )
|
||||
{
|
||||
SCR_NextMovie( );
|
||||
return;
|
||||
}
|
||||
|
||||
// read the next frame
|
||||
cin_frame = AVI_GetVideoFrameNumber( cin_state, cin_time );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -176,21 +167,11 @@ should be skipped
|
||||
*/
|
||||
qboolean SCR_DrawCinematic( void )
|
||||
{
|
||||
static int last_frame = -1;
|
||||
qboolean redraw = false;
|
||||
byte *frame = NULL;
|
||||
|
||||
if( !ref.initialized || cin_time <= 0.0f )
|
||||
if( !ref.initialized )
|
||||
return false;
|
||||
|
||||
if( cin_frame != last_frame )
|
||||
{
|
||||
frame = AVI_GetVideoFrame( cin_state, cin_frame );
|
||||
last_frame = cin_frame;
|
||||
redraw = true;
|
||||
}
|
||||
|
||||
ref.dllFuncs.R_DrawStretchRaw( 0, 0, refState.width, refState.height, xres, yres, frame, redraw );
|
||||
if( !AVI_Think( cin_state ))
|
||||
return SCR_NextMovie();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -219,45 +200,28 @@ qboolean SCR_PlayCinematic( const char *arg )
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !( AVI_GetVideoInfo( cin_state, &xres, &yres, &video_duration ))) // couldn't open this at all.
|
||||
{
|
||||
AVI_CloseVideo( cin_state );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( AVI_GetAudioInfo( cin_state, &cin_audio ))
|
||||
if( AVI_HaveAudioTrack( cin_state ))
|
||||
{
|
||||
// begin streaming
|
||||
S_StopAllSounds( true );
|
||||
S_StartStreaming();
|
||||
}
|
||||
|
||||
AVI_SetParm( cin_state,
|
||||
AVI_RENDER_X, 0,
|
||||
AVI_RENDER_Y, 0,
|
||||
AVI_RENDER_W, -1,
|
||||
AVI_RENDER_H, -1,
|
||||
AVI_PARM_LAST );
|
||||
|
||||
UI_SetActiveMenu( false );
|
||||
cls.state = ca_cinematic;
|
||||
Con_FastClose();
|
||||
cin_time = 0.0f;
|
||||
cls.signon = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int SCR_GetAudioChunk( char *rawdata, int length )
|
||||
{
|
||||
int r;
|
||||
|
||||
r = AVI_GetAudioChunk( cin_state, rawdata, cin_audio.loopStart, length );
|
||||
cin_audio.loopStart += r; // advance play position
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
wavdata_t *SCR_GetMovieInfo( void )
|
||||
{
|
||||
if( AVI_IsActive( cin_state ))
|
||||
return &cin_audio;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
SCR_StopCinematic
|
||||
@@ -270,7 +234,6 @@ void SCR_StopCinematic( void )
|
||||
|
||||
AVI_CloseVideo( cin_state );
|
||||
S_StopStreaming();
|
||||
cin_time = 0.0f;
|
||||
|
||||
cls.state = ca_disconnected;
|
||||
cls.signon = 0;
|
||||
|
||||
@@ -466,8 +466,8 @@ static void R_ShowTree_r( mnode_t *node, float x, float y, float scale, int show
|
||||
R_DrawNodeConnection( x, y, x + scale, y + scale );
|
||||
}
|
||||
|
||||
R_ShowTree_r( node->children[1], x - scale, y + scale, downScale, shownodes, viewleaf );
|
||||
R_ShowTree_r( node->children[0], x + scale, y + scale, downScale, shownodes, viewleaf );
|
||||
R_ShowTree_r( node_child( node, 1, cl.worldmodel ), x - scale, y + scale, downScale, shownodes, viewleaf );
|
||||
R_ShowTree_r( node_child( node, 0, cl.worldmodel ), x + scale, y + scale, downScale, shownodes, viewleaf );
|
||||
|
||||
world.recursion_level--;
|
||||
}
|
||||
@@ -482,7 +482,7 @@ static void R_ShowTree( void )
|
||||
return;
|
||||
|
||||
world.recursion_level = 0;
|
||||
viewleaf = Mod_PointInLeaf( refState.vieworg, cl.worldmodel->nodes );
|
||||
viewleaf = Mod_PointInLeaf( refState.vieworg, cl.worldmodel->nodes, cl.worldmodel );
|
||||
|
||||
ref.dllFuncs.TriRenderMode( kRenderTransTexture );
|
||||
|
||||
|
||||
@@ -495,7 +495,9 @@ typedef struct
|
||||
|
||||
cl_entity_t viewent; // viewmodel
|
||||
|
||||
#if XASH_WIN32
|
||||
qboolean client_dll_uses_sdl;
|
||||
#endif
|
||||
} clgame_static_t;
|
||||
|
||||
typedef struct
|
||||
@@ -686,6 +688,7 @@ extern convar_t r_showtextures;
|
||||
extern convar_t cl_bmodelinterp;
|
||||
extern convar_t cl_lw; // local weapons
|
||||
extern convar_t cl_charset;
|
||||
extern convar_t cl_trace_consistency;
|
||||
extern convar_t cl_trace_stufftext;
|
||||
extern convar_t cl_trace_messages;
|
||||
extern convar_t cl_trace_events;
|
||||
@@ -765,7 +768,7 @@ void CL_StartupDemoHeader( void );
|
||||
void CL_DrawDemoRecording( void );
|
||||
void CL_WriteDemoUserCmd( int cmdnumber );
|
||||
void CL_WriteDemoMessage( qboolean startup, int start, sizebuf_t *msg );
|
||||
void CL_WriteDemoUserMessage( const byte *buffer, size_t size );
|
||||
void CL_WriteDemoUserMessage( int size, byte *buffer );
|
||||
qboolean CL_DemoReadMessage( byte *buffer, size_t *length );
|
||||
void CL_DemoInterpolateAngles( void );
|
||||
void CL_CheckStartupDemos( void );
|
||||
@@ -881,10 +884,12 @@ static inline qboolean CL_IsThirdPerson( void )
|
||||
|
||||
static inline cl_entity_t *CL_GetLocalPlayer( void )
|
||||
{
|
||||
cl_entity_t *player;
|
||||
cl_entity_t *player = CL_GetEntityByIndex( cl.playernum + 1 );
|
||||
|
||||
player = CL_EDICT_NUM( cl.playernum + 1 );
|
||||
Assert( player != NULL );
|
||||
// HACKHACK: GoldSrc doesn't do this, but some mods actually check it for null pointer
|
||||
// this is a lesser evil than changing semantics of HUD_VidInit and call it after entities are allocated
|
||||
if( !player )
|
||||
Con_Printf( S_WARN "%s: client entities are not initialized yet! Returning NULL...\n", __func__ );
|
||||
|
||||
return player;
|
||||
}
|
||||
@@ -1115,7 +1120,7 @@ void Con_PageUp( int lines );
|
||||
//
|
||||
// s_main.c
|
||||
//
|
||||
void S_StreamAviSamples( void *Avi, int entnum, float fvol, float attn, float synctime );
|
||||
typedef int sound_t;
|
||||
void S_StartBackgroundTrack( const char *intro, const char *loop, int position, qboolean fullpath );
|
||||
void S_StopBackgroundTrack( void );
|
||||
void S_StreamSetPause( int pause );
|
||||
@@ -1195,16 +1200,22 @@ void Key_Init( void );
|
||||
void Key_WriteBindings( file_t *f );
|
||||
const char *Key_GetBinding( int keynum );
|
||||
void Key_SetBinding( int keynum, const char *binding );
|
||||
const char *Key_LookupBinding( const char *pBinding );
|
||||
void Key_ClearStates( void );
|
||||
const char *Key_KeynumToString( int keynum );
|
||||
int Key_StringToKeynum( const char *str );
|
||||
int Key_GetKey( const char *binding );
|
||||
void Key_EnumCmds_f( void );
|
||||
void Key_SetKeyDest( int key_dest );
|
||||
void Key_EnableTextInput( qboolean enable, qboolean force );
|
||||
int Key_ToUpper( int key );
|
||||
void OSK_Draw( void );
|
||||
|
||||
//
|
||||
// identification.c
|
||||
//
|
||||
void ID_Init( void );
|
||||
const char *ID_GetMD5( void );
|
||||
void GAME_EXPORT ID_SetCustomClientID( const char *id );
|
||||
|
||||
extern rgba_t g_color_table[8];
|
||||
extern triangleapi_t gTriApi;
|
||||
extern net_api_t gNetApi;
|
||||
|
||||
@@ -611,7 +611,7 @@ void GAME_EXPORT ID_SetCustomClientID( const char *id )
|
||||
|
||||
void ID_Init( void )
|
||||
{
|
||||
MD5Context_t hash = {0};
|
||||
MD5Context_t hash = { 0 };
|
||||
byte md5[16];
|
||||
int i;
|
||||
|
||||
@@ -632,7 +632,7 @@ void ID_Init( void )
|
||||
#elif XASH_WIN32
|
||||
{
|
||||
CHAR szBuf[MAX_PATH];
|
||||
ID_GetKeyData( HKEY_CURRENT_USER, "Software\\Xash3D\\", "xash_id", szBuf, MAX_PATH );
|
||||
ID_GetKeyData( HKEY_CURRENT_USER, "Software\\"XASH_ENGINE_NAME"\\", "xash_id", szBuf, MAX_PATH );
|
||||
|
||||
sscanf(szBuf, "%016"PRIX64, &id);
|
||||
id ^= SYSTEM_XOR_MASK;
|
||||
@@ -686,7 +686,7 @@ void ID_Init( void )
|
||||
{
|
||||
CHAR Buf[MAX_PATH];
|
||||
sprintf( Buf, "%016"PRIX64, id^SYSTEM_XOR_MASK );
|
||||
ID_SetKeyData( HKEY_CURRENT_USER, "Software\\Xash3D\\", REG_SZ, "xash_id", Buf, Q_strlen(Buf) );
|
||||
ID_SetKeyData( HKEY_CURRENT_USER, "Software\\"XASH_ENGINE_NAME"\\", REG_SZ, "xash_id", Buf, Q_strlen(Buf) );
|
||||
}
|
||||
#else
|
||||
{
|
||||
@@ -266,7 +266,7 @@ static qboolean Touch_DumpConfig( const char *name, const char *profilename )
|
||||
}
|
||||
|
||||
FS_Printf( f, "//=======================================================================\n");
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\t\t\ttouchscreen config\n" );
|
||||
FS_Printf( f, "//=======================================================================\n" );
|
||||
FS_Printf( f, "\ntouch_config_file \"%s\"\n", profilename );
|
||||
@@ -902,9 +902,10 @@ static void Touch_AddButton_f( void )
|
||||
rgba_t color;
|
||||
int argc = Cmd_Argc( );
|
||||
touch_button_t *button = NULL;
|
||||
const char *name, *texture, *command;
|
||||
const char *name, *command;
|
||||
float x1, y1, x2, y2;
|
||||
qboolean privileged = Cmd_CurrentCommandIsPrivileged();
|
||||
string texture;
|
||||
|
||||
if( argc < 4 )
|
||||
{
|
||||
@@ -913,9 +914,18 @@ static void Touch_AddButton_f( void )
|
||||
}
|
||||
|
||||
name = Cmd_Argv( 1 );
|
||||
texture = Cmd_Argv( 2 );
|
||||
Q_strncpy( texture, Cmd_Argv( 2 ), sizeof( texture ));
|
||||
command = Cmd_Argv( 3 );
|
||||
|
||||
// HACKHACK: old engine specifically used .tga for touch buttons
|
||||
// and because new engine extras.pk3 don't have .tga textures
|
||||
// (which instead were converted to .png) strip extension to let
|
||||
// to let imagelib choose better format
|
||||
//
|
||||
// Remove this when old engine migration would be done
|
||||
if( Q_stricmp( COM_FileExtension( texture ), "tga" ))
|
||||
COM_StripExtension( texture );
|
||||
|
||||
if( argc < 8 )
|
||||
{
|
||||
x1 = y1 = 0.4f;
|
||||
@@ -1101,7 +1111,7 @@ void Touch_Init( void )
|
||||
Touch_AddDefaultButton( "duck", "touch_default/crouch", "+duck", 0.880000, 0.757428, 1.000000, 0.984656, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "tduck", "touch_default/tduck", ";+duck", 0.560000, 0.833171, 0.620000, 0.946785, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "edit", "touch_default/settings", "touch_enableedit", 0.420000, 0.000000, 0.500000, 0.151486, color, 2, 1, 32 );
|
||||
Touch_AddDefaultButton( "menu", "touch_default/menu", "escape", 0.000000, 0.833171, 0.080000, 0.984656, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "menu", "touch_default/menu", "cancelselect", 0.000000, 0.833171, 0.080000, 0.984656, color, 2, 1, 0 );
|
||||
Touch_AddDefaultButton( "spray", "touch_default/spray", "impulse 201", 0.680000, 0.000000, 0.760000, 0.142222, color, 2, 1, 8 );
|
||||
Touch_AddDefaultButton( "voicechat", "touch_default/microphone", "+voicerecord", 0.780000, 0.817778, 0.860000, 0.960000, color, 2, 1, 8 );
|
||||
|
||||
|
||||
@@ -633,8 +633,6 @@ Called every frame, even if not generating commands
|
||||
*/
|
||||
void Host_InputFrame( void )
|
||||
{
|
||||
Sys_SendKeyEvents ();
|
||||
|
||||
IN_Commands();
|
||||
|
||||
IN_MouseMove();
|
||||
|
||||
@@ -34,13 +34,13 @@ typedef struct keyname_s
|
||||
const char *binding; // default bind
|
||||
} keyname_t;
|
||||
|
||||
enginekey_t keys[256];
|
||||
static enginekey_t keys[256];
|
||||
|
||||
keyname_t keynames[] =
|
||||
static const keyname_t keynames[] =
|
||||
{
|
||||
{"TAB", K_TAB, "" },
|
||||
{"ENTER", K_ENTER, "" },
|
||||
{"ESCAPE", K_ESCAPE, "escape" }, // hardcoded
|
||||
{"ESCAPE", K_ESCAPE, "cancelselect" }, // hardcoded
|
||||
{"SPACE", K_SPACE, "+jump" },
|
||||
{"BACKSPACE", K_BACKSPACE, "" },
|
||||
{"UPARROW", K_UPARROW, "+forward" },
|
||||
@@ -51,7 +51,7 @@ keyname_t keynames[] =
|
||||
{"CTRL", K_CTRL, "+attack" },
|
||||
{"SHIFT", K_SHIFT, "+speed" },
|
||||
{"CAPSLOCK", K_CAPSLOCK, "" },
|
||||
{"SCROLLOCK", K_SCROLLOCK, "" },
|
||||
{"SCROLLOCK", K_SCROLLLOCK, "" },
|
||||
{"F1", K_F1, "cmd help" },
|
||||
{"F2", K_F2, "menu_savegame" },
|
||||
{"F3", K_F3, "menu_loadgame" },
|
||||
@@ -106,7 +106,7 @@ keyname_t keynames[] =
|
||||
{"Y_BUTTON", K_Y_BUTTON, "impulse 100"}, // Flashlight
|
||||
{"BACK", K_BACK_BUTTON, "pause"}, // Menu
|
||||
{"MODE", K_MODE_BUTTON, ""},
|
||||
{"START", K_START_BUTTON, "escape"},
|
||||
{"START", K_START_BUTTON, "cancelselect"},
|
||||
{"STICK1", K_LSTICK, "+speed"},
|
||||
{"STICK2", K_RSTICK, "+duck"},
|
||||
{"L1_BUTTON", K_L1_BUTTON, "+duck"},
|
||||
@@ -139,7 +139,6 @@ keyname_t keynames[] =
|
||||
|
||||
// raw semicolon seperates commands
|
||||
{"SEMICOLON", ';', "" },
|
||||
{NULL, 0, NULL },
|
||||
};
|
||||
|
||||
static void OSK_EnableTextInput( qboolean enable, qboolean force );
|
||||
@@ -172,48 +171,25 @@ the K_* names are matched up.
|
||||
to be configured even if they don't have defined names.
|
||||
===================
|
||||
*/
|
||||
int Key_StringToKeynum( const char *str )
|
||||
static int Key_StringToKeynum( const char *str )
|
||||
{
|
||||
keyname_t *kn;
|
||||
int i;
|
||||
|
||||
if( !str || !str[0] ) return -1;
|
||||
if( !str[1] ) return str[0];
|
||||
if( !str || !str[0] )
|
||||
return -1;
|
||||
|
||||
if( !str[1] )
|
||||
return str[0];
|
||||
|
||||
// check for hex code
|
||||
if( str[0] == '0' && str[1] == 'x' && Q_strlen( str ) == 4 )
|
||||
{
|
||||
int n1, n2;
|
||||
|
||||
n1 = str[2];
|
||||
if( n1 >= '0' && n1 <= '9' )
|
||||
{
|
||||
n1 -= '0';
|
||||
}
|
||||
else if( n1 >= 'a' && n1 <= 'f' )
|
||||
{
|
||||
n1 = n1 - 'a' + 10;
|
||||
}
|
||||
else n1 = 0;
|
||||
|
||||
n2 = str[3];
|
||||
if( n2 >= '0' && n2 <= '9' )
|
||||
{
|
||||
n2 -= '0';
|
||||
}
|
||||
else if( n2 >= 'a' && n2 <= 'f' )
|
||||
{
|
||||
n2 = n2 - 'a' + 10;
|
||||
}
|
||||
else n2 = 0;
|
||||
|
||||
return n1 * 16 + n2;
|
||||
}
|
||||
return COM_Nibble( str[2] ) << 4 | COM_Nibble( str[3] );
|
||||
|
||||
// scan for a text match
|
||||
for( kn = keynames; kn->name; kn++ )
|
||||
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
|
||||
{
|
||||
if( !Q_stricmp( str, kn->name ))
|
||||
return kn->keynum;
|
||||
if( !Q_stricmp( str, keynames[i].name ))
|
||||
return keynames[i].keynum;
|
||||
}
|
||||
|
||||
return -1;
|
||||
@@ -229,15 +205,17 @@ given keynum.
|
||||
*/
|
||||
const char *Key_KeynumToString( int keynum )
|
||||
{
|
||||
keyname_t *kn;
|
||||
static char tinystr[5];
|
||||
int i, j;
|
||||
|
||||
if ( keynum == -1 ) return "<KEY NOT FOUND>";
|
||||
if ( keynum < 0 || keynum > 255 ) return "<OUT OF RANGE>";
|
||||
if( keynum == -1 )
|
||||
return "<KEY NOT FOUND>";
|
||||
|
||||
if( keynum < 0 || keynum > 255 )
|
||||
return "<OUT OF RANGE>";
|
||||
|
||||
// check for printable ascii (don't use quote)
|
||||
if( keynum > 32 && keynum < 127 && keynum != '"' && keynum != ';' && keynum != K_SCROLLOCK )
|
||||
if( keynum > 32 && keynum < 127 && keynum != '"' && keynum != ';' && keynum != K_SCROLLLOCK )
|
||||
{
|
||||
tinystr[0] = keynum;
|
||||
tinystr[1] = 0;
|
||||
@@ -245,10 +223,10 @@ const char *Key_KeynumToString( int keynum )
|
||||
}
|
||||
|
||||
// check for a key string
|
||||
for( kn = keynames; kn->name; kn++ )
|
||||
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
|
||||
{
|
||||
if( keynum == kn->keynum )
|
||||
return kn->name;
|
||||
if( keynum == keynames[i].keynum )
|
||||
return keynames[i].name;
|
||||
}
|
||||
|
||||
// make a hex string
|
||||
@@ -301,7 +279,7 @@ const char *Key_GetBinding( int keynum )
|
||||
Key_GetKey
|
||||
===================
|
||||
*/
|
||||
int Key_GetKey( const char *pBinding )
|
||||
static int Key_GetKey( const char *pBinding )
|
||||
{
|
||||
int i, len;
|
||||
const char *p;
|
||||
@@ -327,6 +305,17 @@ int Key_GetKey( const char *pBinding )
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Key_LookupBinding
|
||||
|
||||
=============
|
||||
*/
|
||||
const char *Key_LookupBinding( const char *pBinding )
|
||||
{
|
||||
return Key_KeynumToString( Key_GetKey( pBinding ));
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
Key_Unbind_f
|
||||
@@ -350,6 +339,12 @@ static void Key_Unbind_f( void )
|
||||
return;
|
||||
}
|
||||
|
||||
if( b == K_ESCAPE )
|
||||
{
|
||||
Con_Printf( "Can't unbind ESCAPE key\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
Key_SetBinding( b, "" );
|
||||
}
|
||||
|
||||
@@ -369,8 +364,8 @@ static void Key_Unbindall_f( void )
|
||||
}
|
||||
|
||||
// set some defaults
|
||||
Key_SetBinding( K_ESCAPE, "escape" );
|
||||
Key_SetBinding( K_START_BUTTON, "escape" );
|
||||
Key_SetBinding( K_ESCAPE, "cancelselect" );
|
||||
Key_SetBinding( K_START_BUTTON, "cancelselect" );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -380,7 +375,6 @@ Key_Reset_f
|
||||
*/
|
||||
static void Key_Reset_f( void )
|
||||
{
|
||||
keyname_t *kn;
|
||||
int i;
|
||||
|
||||
// clear all keys first
|
||||
@@ -391,8 +385,8 @@ static void Key_Reset_f( void )
|
||||
}
|
||||
|
||||
// apply default values
|
||||
for( kn = keynames; kn->name; kn++ )
|
||||
Key_SetBinding( kn->keynum, kn->binding );
|
||||
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
|
||||
Key_SetBinding( keynames[i].keynum, keynames[i].binding );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -500,7 +494,7 @@ Key_Init
|
||||
*/
|
||||
void Key_Init( void )
|
||||
{
|
||||
keyname_t *kn;
|
||||
int i;
|
||||
|
||||
// register our functions
|
||||
Cmd_AddRestrictedCommand( "bind", Key_Bind_f, "binds a command to the specified key in bindmap" );
|
||||
@@ -511,7 +505,8 @@ void Key_Init( void )
|
||||
Cmd_AddCommand( "makehelp", Key_EnumCmds_f, "write help.txt that contains all console cvars and cmds" );
|
||||
|
||||
// setup default binding. "unbindall" from config.cfg will be reset it
|
||||
for( kn = keynames; kn->name; kn++ ) Key_SetBinding( kn->keynum, kn->binding );
|
||||
for( i = 0; i < ARRAYSIZE( keynames ); i++ )
|
||||
Key_SetBinding( keynames[i].keynum, keynames[i].binding );
|
||||
|
||||
Cvar_RegisterVariable( &osk_enable );
|
||||
Cvar_RegisterVariable( &key_rotate );
|
||||
@@ -748,18 +743,24 @@ void GAME_EXPORT Key_Event( int key, int down )
|
||||
|
||||
if( cls.key_dest == key_menu )
|
||||
{
|
||||
// only non printable keys passed
|
||||
// classic Xash3D menus don't have an extension that tells engine
|
||||
// to enable text input
|
||||
if( !gameui.use_extended_api )
|
||||
Key_EnableTextInput( true, false );
|
||||
//pass printable chars for old menus
|
||||
if( !gameui.use_extended_api && !host.textmode && down && ( key >= 32 ) && ( key <= 'z' ) )
|
||||
{
|
||||
if( Key_IsDown( K_SHIFT ) )
|
||||
// we don't know if menu wants text input or not
|
||||
// enable it unconditionally
|
||||
Key_EnableTextInput( true, false );
|
||||
|
||||
// pass this key to the menu, if printable
|
||||
if( !host.textmode && down && ( key >= 32 ) && ( key <= 'z' ))
|
||||
{
|
||||
key += 'A' - 'a';
|
||||
if( Key_IsDown( K_SHIFT ))
|
||||
key += 'A' - 'a';
|
||||
|
||||
UI_CharEvent( key );
|
||||
}
|
||||
UI_CharEvent( key );
|
||||
}
|
||||
|
||||
UI_KeyEvent( key, down );
|
||||
return;
|
||||
}
|
||||
@@ -855,11 +856,14 @@ void GAME_EXPORT Key_ClearStates( void )
|
||||
int i;
|
||||
|
||||
// don't clear keys during changelevel
|
||||
if( cls.changelevel ) return;
|
||||
if( cls.changelevel )
|
||||
return;
|
||||
|
||||
for( i = 0; i < 256; i++ )
|
||||
{
|
||||
if( keys[i].down )
|
||||
if( i >= K_MOUSE1 && i <= K_MOUSE5 )
|
||||
IN_MouseEvent( i - K_MOUSE1, false );
|
||||
else
|
||||
Key_Event( i, false );
|
||||
|
||||
keys[i].down = 0;
|
||||
@@ -909,17 +913,16 @@ A helper function if platform input doesn't support text mode properly
|
||||
*/
|
||||
int Key_ToUpper( int keynum )
|
||||
{
|
||||
keynum = Q_toupper( keynum );
|
||||
if( keynum == '-' )
|
||||
keynum = '_';
|
||||
return '_';
|
||||
if( keynum == '=' )
|
||||
keynum = '+';
|
||||
return '+';
|
||||
if( keynum == ';' )
|
||||
keynum = ':';
|
||||
return ':';
|
||||
if( keynum == '\'' )
|
||||
keynum = '"';
|
||||
return '"';
|
||||
|
||||
return keynum;
|
||||
return Q_toupper( keynum );
|
||||
}
|
||||
|
||||
/* On-screen keyboard:
|
||||
|
||||
@@ -470,16 +470,16 @@ out_free:
|
||||
* This is a stack of the clipnodes we have traversed
|
||||
* "sides" indicates which side we went down each time
|
||||
*/
|
||||
static mclipnode_t *node_stack[MAX_CLIPNODE_DEPTH];
|
||||
static int node_stack[MAX_CLIPNODE_DEPTH];
|
||||
static int side_stack[MAX_CLIPNODE_DEPTH];
|
||||
static uint node_stack_depth;
|
||||
|
||||
static void push_node( mclipnode_t *node, int side )
|
||||
static void push_node( int nodenum, int side )
|
||||
{
|
||||
if( node_stack_depth == MAX_CLIPNODE_DEPTH )
|
||||
Host_Error( "node stack overflow\n" );
|
||||
|
||||
node_stack[node_stack_depth] = node;
|
||||
node_stack[node_stack_depth] = nodenum;
|
||||
side_stack[node_stack_depth] = side;
|
||||
node_stack_depth++;
|
||||
}
|
||||
@@ -502,22 +502,27 @@ static void free_hull_polys( hullnode_t *hull_polys )
|
||||
}
|
||||
}
|
||||
|
||||
static void hull_windings_r( hull_t *hull, mclipnode_t *node, hullnode_t *polys, hull_model_t *model );
|
||||
static void hull_windings_r( hull_t *hull, int nodenum, hullnode_t *polys, hull_model_t *model );
|
||||
|
||||
static void do_hull_recursion( hull_t *hull, mclipnode_t *node, int side, hullnode_t *polys, hull_model_t *model )
|
||||
static void do_hull_recursion( hull_t *hull, int nodenum, int side, hullnode_t *polys, hull_model_t *model )
|
||||
{
|
||||
winding_t *w, *next;
|
||||
int childnum;
|
||||
|
||||
if( node->children[side] >= 0 )
|
||||
if( world.version == QBSP2_VERSION )
|
||||
childnum = hull->clipnodes32[nodenum].children[side];
|
||||
else
|
||||
childnum = hull->clipnodes16[nodenum].children[side];
|
||||
|
||||
if( childnum >= 0 )
|
||||
{
|
||||
mclipnode_t *child = hull->clipnodes + node->children[side];
|
||||
push_node( node, side );
|
||||
hull_windings_r( hull, child, polys, model );
|
||||
push_node( nodenum, side );
|
||||
hull_windings_r( hull, childnum, polys, model );
|
||||
pop_node();
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( node->children[side] )
|
||||
switch( childnum )
|
||||
{
|
||||
case CONTENTS_EMPTY:
|
||||
case CONTENTS_WATER:
|
||||
@@ -542,20 +547,25 @@ static void do_hull_recursion( hull_t *hull, mclipnode_t *node, int side, hullno
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Host_Error( "bad contents: %i\n", node->children[side] );
|
||||
Host_Error( "bad contents: %i\n", childnum );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void hull_windings_r( hull_t *hull, mclipnode_t *node, hullnode_t *polys, hull_model_t *model )
|
||||
static void hull_windings_r( hull_t *hull, int nodenum, hullnode_t *polys, hull_model_t *model )
|
||||
{
|
||||
mplane_t *plane = hull->planes + node->planenum;
|
||||
mplane_t *plane;
|
||||
hullnode_t frontlist = LIST_HEAD_INIT( frontlist );
|
||||
hullnode_t backlist = LIST_HEAD_INIT( backlist );
|
||||
winding_t *w, *next, *front, *back;
|
||||
int i;
|
||||
|
||||
if( world.version == QBSP2_VERSION )
|
||||
plane = hull->planes + hull->clipnodes32[nodenum].planenum;
|
||||
else
|
||||
plane = hull->planes + hull->clipnodes16[nodenum].planenum;
|
||||
|
||||
list_for_each_entry_safe( w, next, polys, chain )
|
||||
{
|
||||
// PARANIOA - PAIR CHECK
|
||||
@@ -601,7 +611,13 @@ static void hull_windings_r( hull_t *hull, mclipnode_t *node, hullnode_t *polys,
|
||||
|
||||
for( i = 0; w && i < node_stack_depth; i++ )
|
||||
{
|
||||
mplane_t *p = hull->planes + node_stack[i]->planenum;
|
||||
mplane_t *p;
|
||||
|
||||
if( world.version == QBSP2_VERSION )
|
||||
p = hull->planes + hull->clipnodes32[node_stack[i]].planenum;
|
||||
else
|
||||
p = hull->planes + hull->clipnodes16[node_stack[i]].planenum;
|
||||
|
||||
w = winding_clip( w, p, false, side_stack[i], 0.00001 );
|
||||
}
|
||||
|
||||
@@ -625,8 +641,8 @@ static void hull_windings_r( hull_t *hull, mclipnode_t *node, hullnode_t *polys,
|
||||
Con_Printf( S_WARN "new winding was clipped away!\n" );
|
||||
}
|
||||
|
||||
do_hull_recursion( hull, node, 0, &frontlist, model );
|
||||
do_hull_recursion( hull, node, 1, &backlist, model );
|
||||
do_hull_recursion( hull, nodenum, 0, &frontlist, model );
|
||||
do_hull_recursion( hull, nodenum, 1, &backlist, model );
|
||||
}
|
||||
|
||||
static void remove_paired_polys( hull_model_t *model )
|
||||
@@ -655,7 +671,7 @@ static void make_hull_windings( hull_t *hull, hull_model_t *model )
|
||||
|
||||
if( hull->planes != NULL )
|
||||
{
|
||||
hull_windings_r( hull, hull->clipnodes + hull->firstclipnode, &head, model );
|
||||
hull_windings_r( hull, hull->firstclipnode, &head, model );
|
||||
remove_paired_polys( model );
|
||||
}
|
||||
Con_Reportf( "%i hull polys\n", model->num_polys );
|
||||
|
||||
@@ -181,6 +181,11 @@ static void pfnCvar_FullSet( const char *var_name, const char *value, int flags
|
||||
Cvar_FullSet( var_name, value, flags | FCVAR_REFDLL );
|
||||
}
|
||||
|
||||
static int Cmd_AddRefCommand( const char *cmd_name, xcommand_t function, const char *description )
|
||||
{
|
||||
return Cmd_AddCommandEx( cmd_name, function, description, CMD_REFDLL, __func__ );
|
||||
}
|
||||
|
||||
static void pfnStudioEvent( const mstudioevent_t *event, const cl_entity_t *e )
|
||||
{
|
||||
clgame.dllFuncs.pfnStudioEvent( event, e );
|
||||
@@ -295,6 +300,12 @@ static qboolean R_Init_Video_( const int type )
|
||||
return R_Init_Video( type );
|
||||
}
|
||||
|
||||
static mleaf_t *pfnMod_PointInLeaf( const vec3_t p, mnode_t *node )
|
||||
{
|
||||
// FIXME: get rid of this on next RefAPI update
|
||||
return Mod_PointInLeaf( p, node, cl.models[1] );
|
||||
}
|
||||
|
||||
static const ref_api_t gEngfuncs =
|
||||
{
|
||||
pfnEngineGetParm,
|
||||
@@ -335,7 +346,7 @@ static const ref_api_t gEngfuncs =
|
||||
|
||||
Mod_SampleSizeForFace,
|
||||
Mod_BoxVisible,
|
||||
Mod_PointInLeaf,
|
||||
pfnMod_PointInLeaf,
|
||||
R_DrawWorldHull,
|
||||
R_DrawModelHull,
|
||||
|
||||
|
||||
@@ -312,7 +312,7 @@ static int DLY_Init( int idelay, float delay )
|
||||
|
||||
cur = &rgsxdly[idelay];
|
||||
cur->cdelaysamplesmax = ((int)(delay * idsp_dma_speed) << sxhires) + 1;
|
||||
cur->lpdelayline = (int *)Z_Calloc( cur->cdelaysamplesmax * sizeof( int ));
|
||||
cur->lpdelayline = (int *)Mem_Calloc( sndpool, cur->cdelaysamplesmax * sizeof( int ));
|
||||
cur->xfade = 0;
|
||||
|
||||
// init modulation
|
||||
|
||||
@@ -107,17 +107,18 @@ S_CreateDefaultSound
|
||||
*/
|
||||
static wavdata_t *S_CreateDefaultSound( void )
|
||||
{
|
||||
wavdata_t *sc;
|
||||
wavdata_t *sc;
|
||||
uint samples = SOUND_DMA_SPEED;
|
||||
uint channels = 1;
|
||||
uint width = 2;
|
||||
size_t size = samples * width * channels;
|
||||
|
||||
sc = Mem_Calloc( sndpool, sizeof( wavdata_t ));
|
||||
|
||||
sc->width = 2;
|
||||
sc->channels = 1;
|
||||
sc->loopStart = 0;
|
||||
sc = Mem_Calloc( sndpool, sizeof( wavdata_t ) + size );
|
||||
sc->width = width;
|
||||
sc->channels = channels;
|
||||
sc->rate = SOUND_DMA_SPEED;
|
||||
sc->samples = SOUND_DMA_SPEED;
|
||||
sc->size = sc->samples * sc->width * sc->channels;
|
||||
sc->buffer = Mem_Calloc( sndpool, sc->size );
|
||||
sc->samples = samples;
|
||||
sc->size = size;
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@ GNU General Public License for more details.
|
||||
#include "pm_local.h"
|
||||
#include "platform/platform.h"
|
||||
|
||||
#define SND_CLIP_DISTANCE 1000.0f
|
||||
|
||||
dma_t dma;
|
||||
poolhandle_t sndpool;
|
||||
static soundfade_t soundfade;
|
||||
@@ -996,7 +994,7 @@ static void S_UpdateAmbientSounds( void )
|
||||
// calc ambient sound levels
|
||||
if( !cl.worldmodel ) return;
|
||||
|
||||
leaf = Mod_PointInLeaf( s_listener.origin, cl.worldmodel->nodes );
|
||||
leaf = Mod_PointInLeaf( s_listener.origin, cl.worldmodel->nodes, cl.worldmodel );
|
||||
|
||||
if( !leaf || !s_ambient_level.value )
|
||||
{
|
||||
@@ -1111,7 +1109,7 @@ rawchan_t *S_FindRawChannel( int entnum, qboolean create )
|
||||
S_RawSamplesStereo
|
||||
===================
|
||||
*/
|
||||
static uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint max_samples, uint samples, uint rate, word width, word channels, const byte *data )
|
||||
uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint max_samples, uint samples, uint rate, word width, word channels, const byte *data )
|
||||
{
|
||||
uint fracstep, samplefrac;
|
||||
uint src, dst;
|
||||
@@ -1193,100 +1191,6 @@ void S_RawEntSamples( int entnum, uint samples, uint rate, word width, word chan
|
||||
ch->leftvol = ch->rightvol = snd_vol;
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
S_RawSamples
|
||||
===================
|
||||
*/
|
||||
void S_RawSamples( uint samples, uint rate, word width, word channels, const byte *data, int entnum )
|
||||
{
|
||||
int snd_vol = 128;
|
||||
|
||||
if( entnum < 0 ) snd_vol = 256; // bg track or movie track
|
||||
|
||||
S_RawEntSamples( entnum, samples, rate, width, channels, data, snd_vol );
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
S_PositionedRawSamples
|
||||
===================
|
||||
*/
|
||||
void S_StreamAviSamples( void *Avi, int entnum, float fvol, float attn, float synctime )
|
||||
{
|
||||
int bufferSamples;
|
||||
int fileSamples;
|
||||
byte raw[MAX_RAW_SAMPLES];
|
||||
float duration = 0.0f;
|
||||
int r, fileBytes;
|
||||
rawchan_t *ch = NULL;
|
||||
|
||||
if( !dma.initialized || s_listener.paused || !CL_IsInGame( ))
|
||||
return;
|
||||
|
||||
if( entnum < 0 || entnum >= GI->max_edicts )
|
||||
return;
|
||||
|
||||
if( !( ch = S_FindRawChannel( entnum, true )))
|
||||
return;
|
||||
|
||||
if( ch->sound_info.rate == 0 )
|
||||
{
|
||||
if( !AVI_GetAudioInfo( Avi, &ch->sound_info ))
|
||||
return; // no audiotrack
|
||||
}
|
||||
|
||||
ch->master_vol = bound( 0, fvol * 255, 255 );
|
||||
ch->dist_mult = (attn / SND_CLIP_DISTANCE);
|
||||
|
||||
// see how many samples should be copied into the raw buffer
|
||||
if( ch->s_rawend < soundtime )
|
||||
ch->s_rawend = soundtime;
|
||||
|
||||
// position is changed, synchronization is lost etc
|
||||
if( fabs( ch->oldtime - synctime ) > s_mixahead.value )
|
||||
ch->sound_info.loopStart = AVI_TimeToSoundPosition( Avi, synctime * 1000 );
|
||||
ch->oldtime = synctime; // keep actual time
|
||||
|
||||
while( ch->s_rawend < soundtime + ch->max_samples )
|
||||
{
|
||||
wavdata_t *info = &ch->sound_info;
|
||||
|
||||
bufferSamples = ch->max_samples - (ch->s_rawend - soundtime);
|
||||
|
||||
// decide how much data needs to be read from the file
|
||||
fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED );
|
||||
if( fileSamples <= 1 ) return; // no more samples need
|
||||
|
||||
// our max buffer size
|
||||
fileBytes = fileSamples * ( info->width * info->channels );
|
||||
|
||||
if( fileBytes > sizeof( raw ))
|
||||
{
|
||||
fileBytes = sizeof( raw );
|
||||
fileSamples = fileBytes / ( info->width * info->channels );
|
||||
}
|
||||
|
||||
// read audio stream
|
||||
r = AVI_GetAudioChunk( Avi, raw, info->loopStart, fileBytes );
|
||||
info->loopStart += r; // advance play position
|
||||
|
||||
if( r < fileBytes )
|
||||
{
|
||||
fileBytes = r;
|
||||
fileSamples = r / ( info->width * info->channels );
|
||||
}
|
||||
|
||||
if( r > 0 )
|
||||
{
|
||||
// add to raw buffer
|
||||
ch->s_rawend = S_RawSamplesStereo( ch->rawsamples, ch->s_rawend, ch->max_samples,
|
||||
fileSamples, info->rate, info->width, info->channels, raw );
|
||||
}
|
||||
else break; // no more samples for this frame
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
===================
|
||||
S_FreeIdleRawChannels
|
||||
@@ -1690,7 +1594,6 @@ void SND_UpdateSound( void )
|
||||
}
|
||||
|
||||
S_StreamBackgroundTrack ();
|
||||
S_StreamSoundTrack ();
|
||||
|
||||
// mix some sound
|
||||
S_UpdateChannels ();
|
||||
@@ -1944,7 +1847,8 @@ qboolean S_Init( void )
|
||||
Cmd_AddCommand( "play2", S_Play2_f, "playing a group of specified sound files" ); // nehahra stuff
|
||||
Cmd_AddCommand( "playvol", S_PlayVol_f, "playing a specified sound file with specified volume" );
|
||||
Cmd_AddCommand( "stopsound", S_StopSound_f, "stop all sounds" );
|
||||
Cmd_AddCommand( "music", S_Music_f, "starting a background track" );
|
||||
// HLU SDK have command with the same name
|
||||
Cmd_AddCommandWithFlags( "music", S_Music_f, "starting a background track", CMD_OVERRIDABLE );
|
||||
Cmd_AddCommand( "soundlist", S_SoundList_f, "display loaded sounds" );
|
||||
Cmd_AddCommand( "s_info", S_SoundInfo_f, "print sound system information" );
|
||||
Cmd_AddCommand( "s_fade", S_SoundFade_f, "fade all sounds then stop all" );
|
||||
@@ -1953,14 +1857,15 @@ qboolean S_Init( void )
|
||||
Cmd_AddCommand( "spk", S_SayReliable_f, "reliable play a specified sententce" );
|
||||
Cmd_AddCommand( "speak", S_Say_f, "playing a specified sententce" );
|
||||
|
||||
sndpool = Mem_AllocPool( "Sound Zone" );
|
||||
dma.backendName = "None";
|
||||
if( !SNDDMA_Init( ) )
|
||||
if( !SNDDMA_Init( ))
|
||||
{
|
||||
Con_Printf( "Audio: sound system can't be initialized\n" );
|
||||
Mem_FreePool( &sndpool );
|
||||
return false;
|
||||
}
|
||||
|
||||
sndpool = Mem_AllocPool( "Sound Zone" );
|
||||
soundtime = 0;
|
||||
paintedtime = 0;
|
||||
|
||||
@@ -1987,7 +1892,8 @@ void S_Shutdown( void )
|
||||
Cmd_RemoveCommand( "play" );
|
||||
Cmd_RemoveCommand( "playvol" );
|
||||
Cmd_RemoveCommand( "stopsound" );
|
||||
Cmd_RemoveCommand( "music" );
|
||||
if( Cmd_Exists( "music" ))
|
||||
Cmd_RemoveCommand( "music" );
|
||||
Cmd_RemoveCommand( "soundlist" );
|
||||
Cmd_RemoveCommand( "s_info" );
|
||||
Cmd_RemoveCommand( "s_fade" );
|
||||
|
||||
@@ -16,6 +16,7 @@ GNU General Public License for more details.
|
||||
#include "common.h"
|
||||
#include "sound.h"
|
||||
#include "client.h"
|
||||
#include "soundlib.h"
|
||||
|
||||
static bg_track_t s_bgTrack;
|
||||
static musicfade_t musicfade; // controlled by game dlls
|
||||
@@ -212,7 +213,7 @@ void S_StreamBackgroundTrack( void )
|
||||
|
||||
while( ch->s_rawend < soundtime + ch->max_samples )
|
||||
{
|
||||
wavdata_t *info = FS_StreamInfo( s_bgTrack.stream );
|
||||
const stream_t *info = s_bgTrack.stream;
|
||||
|
||||
bufferSamples = ch->max_samples - (ch->s_rawend - soundtime);
|
||||
|
||||
@@ -241,7 +242,7 @@ void S_StreamBackgroundTrack( void )
|
||||
if( r > 0 )
|
||||
{
|
||||
// add to raw buffer
|
||||
S_RawSamples( fileSamples, info->rate, info->width, info->channels, raw, S_RAW_SOUND_BACKGROUNDTRACK );
|
||||
S_RawEntSamples( S_RAW_SOUND_BACKGROUNDTRACK, fileSamples, info->rate, info->width, info->channels, raw, 255 );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -286,66 +287,3 @@ void S_StopStreaming( void )
|
||||
if( !dma.initialized ) return;
|
||||
s_listener.streaming = false;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
S_StreamSoundTrack
|
||||
=================
|
||||
*/
|
||||
void S_StreamSoundTrack( void )
|
||||
{
|
||||
int bufferSamples;
|
||||
int fileSamples;
|
||||
byte raw[MAX_RAW_SAMPLES];
|
||||
int r, fileBytes;
|
||||
rawchan_t *ch = NULL;
|
||||
|
||||
if( !dma.initialized || !s_listener.streaming || s_listener.paused )
|
||||
return;
|
||||
|
||||
ch = S_FindRawChannel( S_RAW_SOUND_SOUNDTRACK, true );
|
||||
|
||||
Assert( ch != NULL );
|
||||
|
||||
// see how many samples should be copied into the raw buffer
|
||||
if( ch->s_rawend < soundtime )
|
||||
ch->s_rawend = soundtime;
|
||||
|
||||
while( ch->s_rawend < soundtime + ch->max_samples )
|
||||
{
|
||||
wavdata_t *info = SCR_GetMovieInfo();
|
||||
|
||||
if( !info ) break; // bad soundtrack?
|
||||
|
||||
bufferSamples = ch->max_samples - (ch->s_rawend - soundtime);
|
||||
|
||||
// decide how much data needs to be read from the file
|
||||
fileSamples = bufferSamples * ((float)info->rate / SOUND_DMA_SPEED );
|
||||
if( fileSamples <= 1 ) return; // no more samples need
|
||||
|
||||
// our max buffer size
|
||||
fileBytes = fileSamples * ( info->width * info->channels );
|
||||
|
||||
if( fileBytes > sizeof( raw ))
|
||||
{
|
||||
fileBytes = sizeof( raw );
|
||||
fileSamples = fileBytes / ( info->width * info->channels );
|
||||
}
|
||||
|
||||
// read audio stream
|
||||
r = SCR_GetAudioChunk( raw, fileBytes );
|
||||
|
||||
if( r < fileBytes )
|
||||
{
|
||||
fileBytes = r;
|
||||
fileSamples = r / ( info->width * info->channels );
|
||||
}
|
||||
|
||||
if( r > 0 )
|
||||
{
|
||||
// add to raw buffer
|
||||
S_RawSamples( fileSamples, info->rate, info->width, info->channels, raw, S_RAW_SOUND_SOUNDTRACK );
|
||||
}
|
||||
else break; // no more samples for this frame
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,7 +557,7 @@ static void VOX_ReadSentenceFile_( byte *buf, fs_offset_t size )
|
||||
int index = cszrawsentences;
|
||||
int size = strlen( name ) + strlen( value ) + 2;
|
||||
|
||||
rgpszrawsentence[index] = Mem_Malloc( host.mempool, size );
|
||||
rgpszrawsentence[index] = Mem_Malloc( sndpool, size );
|
||||
memcpy( rgpszrawsentence[index], name, size );
|
||||
rgpszrawsentence[index][size - 1] = 0;
|
||||
cszrawsentences++;
|
||||
|
||||
@@ -114,7 +114,6 @@ typedef struct rawchan_s
|
||||
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[]; // variable sized
|
||||
} rawchan_t;
|
||||
@@ -171,12 +170,15 @@ typedef struct
|
||||
int source; // may be game, menu, etc
|
||||
} bg_track_t;
|
||||
|
||||
typedef int sound_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_RAW_SAMPLES 16384
|
||||
#define SND_CLIP_DISTANCE 1000.0f
|
||||
|
||||
extern sound_t ambient_sfx[NUM_AMBIENTS];
|
||||
extern qboolean snd_ambient;
|
||||
@@ -242,8 +244,8 @@ int S_GetCurrentStaticSounds( soundlist_t *pout, int size );
|
||||
int S_GetCurrentDynamicSounds( soundlist_t *pout, int size );
|
||||
sfx_t *S_GetSfxByHandle( sound_t handle );
|
||||
rawchan_t *S_FindRawChannel( int entnum, qboolean create );
|
||||
uint S_RawSamplesStereo( portable_samplepair_t *rawsamples, uint rawend, uint max_samples, uint samples, uint rate, word width, word channels, const byte *data );
|
||||
void S_RawEntSamples( int entnum, uint samples, uint rate, word width, word channels, const byte *data, int snd_vol );
|
||||
void S_RawSamples( uint samples, uint rate, word width, word channels, const byte *data, int entnum );
|
||||
void S_StopSound( int entnum, int channel, const char *soundname );
|
||||
void S_UpdateFrame( struct ref_viewpass_s *rvp );
|
||||
void S_StopAllSounds( qboolean ambient );
|
||||
@@ -263,7 +265,6 @@ void SND_ForceCloseMouth( int entnum );
|
||||
//
|
||||
// s_stream.c
|
||||
//
|
||||
void S_StreamSoundTrack( void );
|
||||
void S_StreamBackgroundTrack( void );
|
||||
void S_PrintBackgroundTrackState( void );
|
||||
void S_FadeMusicVolume( float fadePercent );
|
||||
|
||||
@@ -29,17 +29,20 @@ static void Sound_Reset( void )
|
||||
|
||||
static MALLOC_LIKE( FS_FreeSound, 1 ) wavdata_t *SoundPack( void )
|
||||
{
|
||||
wavdata_t *pack = Mem_Calloc( host.soundpool, sizeof( wavdata_t ));
|
||||
wavdata_t *pack = Mem_Malloc( host.soundpool, sizeof( *pack ) + sound.size );
|
||||
|
||||
pack->buffer = sound.wav;
|
||||
pack->width = sound.width;
|
||||
pack->rate = sound.rate;
|
||||
pack->type = sound.type;
|
||||
pack->size = sound.size;
|
||||
pack->loopStart = sound.loopstart;
|
||||
pack->samples = sound.samples;
|
||||
pack->channels = sound.channels;
|
||||
pack->type = sound.type;
|
||||
pack->flags = sound.flags;
|
||||
pack->rate = sound.rate;
|
||||
pack->width = sound.width;
|
||||
pack->channels = sound.channels;
|
||||
memcpy( pack->buffer, sound.wav, sound.size );
|
||||
|
||||
Mem_Free( sound.wav );
|
||||
sound.wav = NULL;
|
||||
|
||||
return pack;
|
||||
}
|
||||
@@ -132,7 +135,6 @@ free WAV buffer
|
||||
void FS_FreeSound( wavdata_t *pack )
|
||||
{
|
||||
if( !pack ) return;
|
||||
if( pack->buffer ) Mem_Free( pack->buffer );
|
||||
Mem_Free( pack );
|
||||
}
|
||||
|
||||
@@ -199,33 +201,6 @@ stream_t *FS_OpenStream( const char *filename )
|
||||
return stream;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FS_StreamInfo
|
||||
|
||||
get basic stream info
|
||||
================
|
||||
*/
|
||||
wavdata_t *FS_StreamInfo( stream_t *stream )
|
||||
{
|
||||
static wavdata_t info;
|
||||
|
||||
if( !stream ) return NULL;
|
||||
|
||||
// fill structure
|
||||
info.loopStart = 0;
|
||||
info.rate = stream->rate;
|
||||
info.width = stream->width;
|
||||
info.channels = stream->channels;
|
||||
info.flags = SOUND_STREAM;
|
||||
info.size = stream->size;
|
||||
info.buffer = NULL;
|
||||
info.samples = 0; // not actual for streams
|
||||
info.type = stream->type;
|
||||
|
||||
return &info;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FS_ReadStream
|
||||
|
||||
@@ -25,20 +25,29 @@ GNU General Public License for more details.
|
||||
|
||||
#define VGUI_MAX_TEXTURES 1024
|
||||
|
||||
typedef struct vgui_reusable_texture_s
|
||||
{
|
||||
int gl_texturenum;
|
||||
byte hash[16];
|
||||
} vgui_reusable_texture_t;
|
||||
|
||||
typedef struct vgui_static_s
|
||||
{
|
||||
qboolean initialized;
|
||||
VGUI_DefaultCursor cursor;
|
||||
vguiapi_t dllFuncs;
|
||||
|
||||
int textures[VGUI_MAX_TEXTURES];
|
||||
vgui_reusable_texture_t *textures;
|
||||
int texture_id;
|
||||
int max_textures;
|
||||
int bound_texture;
|
||||
byte color[4];
|
||||
qboolean enable_texture;
|
||||
|
||||
HINSTANCE hInstance;
|
||||
|
||||
poolhandle_t mempool;
|
||||
|
||||
enum VGUI_KeyCode virtualKeyTrans[256];
|
||||
} vgui_static_t;
|
||||
|
||||
@@ -49,9 +58,16 @@ static CVAR_DEFINE_AUTO( vgui_utf8, "0", FCVAR_ARCHIVE, "enable utf-8 support fo
|
||||
|
||||
static void GAME_EXPORT VGUI_DrawInit( void )
|
||||
{
|
||||
memset( vgui.textures, 0, sizeof( vgui.textures ));
|
||||
if( vgui.mempool )
|
||||
Mem_EmptyPool( vgui.mempool );
|
||||
else vgui.mempool = Mem_AllocPool( "VGui Support Pool" );
|
||||
|
||||
vgui.textures = NULL;
|
||||
|
||||
memset( vgui.color, 0, sizeof( vgui.color ));
|
||||
vgui.texture_id = vgui.bound_texture = 0;
|
||||
vgui.texture_id = 0;
|
||||
vgui.bound_texture = 0;
|
||||
vgui.max_textures = 0;
|
||||
vgui.enable_texture = true;
|
||||
}
|
||||
|
||||
@@ -60,28 +76,79 @@ static void GAME_EXPORT VGUI_DrawShutdown( void )
|
||||
int i;
|
||||
|
||||
for( i = 1; i < vgui.texture_id; i++ )
|
||||
ref.dllFuncs.GL_FreeTexture( vgui.textures[i] );
|
||||
ref.dllFuncs.GL_FreeTexture( vgui.textures[i].gl_texturenum );
|
||||
|
||||
Mem_FreePool( &vgui.mempool );
|
||||
vgui.textures = NULL;
|
||||
|
||||
memset( vgui.color, 0, sizeof( vgui.color ));
|
||||
vgui.texture_id = 0;
|
||||
vgui.bound_texture = 0;
|
||||
vgui.max_textures = 0;
|
||||
}
|
||||
|
||||
static int GAME_EXPORT VGUI_GenerateTexture( void )
|
||||
{
|
||||
if( ++vgui.texture_id >= VGUI_MAX_TEXTURES )
|
||||
Host_Error( "%s: VGUI_MAX_TEXTURES limit exceeded\n", __func__ );
|
||||
// allocate new
|
||||
if( vgui.texture_id + 1 >= vgui.max_textures )
|
||||
{
|
||||
if( vgui.max_textures + VGUI_MAX_TEXTURES >= VGUI_MAX_TEXTURES * VGUI_MAX_TEXTURES )
|
||||
{
|
||||
// in theory it might look up texture that hasn't been bound for a while and
|
||||
// reuse that but it will eventually overwrite some important textures anyway
|
||||
Con_Printf( S_ERROR "%s: Refusing resizing VGUI textures array due to memory leak\n", __func__ );
|
||||
return vgui.texture_id;
|
||||
}
|
||||
|
||||
return vgui.texture_id;
|
||||
vgui.max_textures += VGUI_MAX_TEXTURES;
|
||||
|
||||
// this potentially might leak memory if VGUI is used incorrectly!
|
||||
// (like in Cry of Fear)
|
||||
vgui.textures = Mem_Realloc( vgui.mempool, vgui.textures, sizeof( *vgui.textures ) * vgui.max_textures );
|
||||
|
||||
// warn mod developer
|
||||
if( vgui.max_textures >= VGUI_MAX_TEXTURES * 4 )
|
||||
Con_Printf( S_ERROR "%s: Potential memory leak in VGUI code is detected!\n", __func__ );
|
||||
}
|
||||
|
||||
return ++vgui.texture_id;
|
||||
}
|
||||
|
||||
static void GAME_EXPORT VGUI_UploadTexture( int id, const char *buffer, int width, int height )
|
||||
{
|
||||
rgbdata_t r_image = { 0 };
|
||||
char texName[32];
|
||||
MD5Context_t ctx;
|
||||
byte hash[16];
|
||||
|
||||
if( id <= 0 || id >= VGUI_MAX_TEXTURES )
|
||||
if( id <= 0 || id >= vgui.max_textures || width <= 0 || height <= 0 )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "%s: bad texture %i. Ignored\n", __func__, id );
|
||||
return;
|
||||
}
|
||||
|
||||
// need to do this as some mods tend to upload same texture over and over
|
||||
// exhausing engine-wide limit on textures and leaking vram
|
||||
MD5Init( &ctx );
|
||||
MD5Update( &ctx, buffer, width * height * 4 );
|
||||
MD5Final( hash, &ctx );
|
||||
|
||||
// it's a new texture, try to find a copy
|
||||
if( vgui.textures[id].gl_texturenum == 0 )
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 1; i < vgui.texture_id; i++ )
|
||||
{
|
||||
if( vgui.textures[i].gl_texturenum != 0 && !memcmp( vgui.textures[i].hash, hash, sizeof( hash )))
|
||||
{
|
||||
// copy data to new texture id
|
||||
vgui.textures[id] = vgui.textures[i];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Q_snprintf( texName, sizeof( texName ), "*vgui%i", id );
|
||||
|
||||
r_image.width = width;
|
||||
@@ -91,51 +158,29 @@ static void GAME_EXPORT VGUI_UploadTexture( int id, const char *buffer, int widt
|
||||
r_image.flags = IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA;
|
||||
r_image.buffer = (byte*)buffer;
|
||||
|
||||
vgui.textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE );
|
||||
vgui.textures[id].gl_texturenum = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE );
|
||||
memcpy( vgui.textures[id].hash, hash, sizeof( hash ));
|
||||
}
|
||||
|
||||
static void GAME_EXPORT VGUI_CreateTexture( int id, int width, int height )
|
||||
{
|
||||
rgbdata_t r_image = { 0 };
|
||||
char texName[32];
|
||||
// nothing uses it, it can be removed
|
||||
Host_Error( "%s: deprecated\n", __func__ );
|
||||
|
||||
if( id <= 0 || id >= VGUI_MAX_TEXTURES )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "%s: bad texture %i. Ignored\n", __func__, id );
|
||||
return;
|
||||
}
|
||||
|
||||
Q_snprintf( texName, sizeof( texName ), "*vgui%i", id );
|
||||
|
||||
r_image.width = width;
|
||||
r_image.height = height;
|
||||
r_image.type = PF_RGBA_32;
|
||||
r_image.size = width * height * 4;
|
||||
r_image.flags = IMAGE_HAS_COLOR|IMAGE_HAS_ALPHA;
|
||||
r_image.buffer = NULL;
|
||||
|
||||
vgui.textures[id] = GL_LoadTextureInternal( texName, &r_image, TF_IMAGE );
|
||||
vgui.bound_texture = id;
|
||||
}
|
||||
|
||||
static void GAME_EXPORT VGUI_UploadTextureBlock( int id, int drawX, int drawY, const byte *rgba, int blockWidth, int blockHeight )
|
||||
{
|
||||
if( id <= 0 || id >= VGUI_MAX_TEXTURES || vgui.textures[id] == 0 )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "%s: bad texture %i. Ignored\n", __func__, id );
|
||||
return;
|
||||
}
|
||||
|
||||
ref.dllFuncs.VGUI_UploadTextureBlock( drawX, drawY, rgba, blockWidth, blockHeight );
|
||||
vgui.bound_texture = id;
|
||||
// nothing uses it, it can be removed
|
||||
Host_Error( "%s: deprecated\n", __func__ );
|
||||
}
|
||||
|
||||
static void GAME_EXPORT VGUI_BindTexture( int id )
|
||||
{
|
||||
if( id <= 0 || id >= VGUI_MAX_TEXTURES || !vgui.textures[id] )
|
||||
if( id <= 0 || id >= vgui.max_textures || !vgui.textures[id].gl_texturenum )
|
||||
id = 1; // NOTE: same as bogus index 2700 in GoldSrc
|
||||
|
||||
ref.dllFuncs.GL_Bind( XASH_TEXTURE0, vgui.textures[id] );
|
||||
ref.dllFuncs.GL_Bind( XASH_TEXTURE0, vgui.textures[id].gl_texturenum );
|
||||
vgui.bound_texture = id;
|
||||
}
|
||||
|
||||
@@ -144,7 +189,7 @@ static void GAME_EXPORT VGUI_GetTextureSizes( int *w, int *h )
|
||||
int texnum;
|
||||
|
||||
if( vgui.bound_texture )
|
||||
texnum = vgui.textures[vgui.bound_texture];
|
||||
texnum = vgui.textures[vgui.bound_texture].gl_texturenum;
|
||||
else
|
||||
texnum = R_GetBuiltinTexture( REF_DEFAULT_TEXTURE );
|
||||
|
||||
@@ -187,7 +232,7 @@ static void GAME_EXPORT VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr )
|
||||
t2 = lr->coord[1];
|
||||
|
||||
ref.dllFuncs.Color4ub( vgui.color[0], vgui.color[1], vgui.color[2], vgui.color[3] );
|
||||
ref.dllFuncs.R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, vgui.textures[vgui.bound_texture] );
|
||||
ref.dllFuncs.R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, vgui.textures[vgui.bound_texture].gl_texturenum );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ GNU General Public License for more details.
|
||||
#include "base_cmd.h"
|
||||
#include "cdll_int.h"
|
||||
|
||||
#define HASH_SIZE 128 // 128 * 4 * 4 == 2048 bytes
|
||||
#define HASH_SIZE 64 // 64 * 4 * 4 == 1024 bytes
|
||||
|
||||
typedef struct base_command_hashmap_s base_command_hashmap_t;
|
||||
|
||||
@@ -26,10 +26,11 @@ struct base_command_hashmap_s
|
||||
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
|
||||
char name[]; // key for searching
|
||||
};
|
||||
|
||||
static base_command_hashmap_t *hashed_cmds[HASH_SIZE];
|
||||
static poolhandle_t basecmd_pool;
|
||||
|
||||
#define BaseCmd_HashKey( x ) COM_HashKey( name, HASH_SIZE )
|
||||
|
||||
@@ -42,11 +43,27 @@ Find base command in bucket
|
||||
*/
|
||||
static base_command_hashmap_t *BaseCmd_FindInBucket( base_command_hashmap_t *bucket, base_command_type_e type, const char *name )
|
||||
{
|
||||
base_command_hashmap_t *i = bucket;
|
||||
for( ; i && ( i->type != type || Q_stricmp( name, i->name ) ); // filter out
|
||||
i = i->next );
|
||||
base_command_hashmap_t *i;
|
||||
|
||||
return i;
|
||||
for( i = bucket; i != NULL; i = i->next )
|
||||
{
|
||||
int cmp;
|
||||
|
||||
if( i->type != type )
|
||||
continue;
|
||||
|
||||
cmp = Q_stricmp( i->name, name );
|
||||
|
||||
if( cmp < 0 )
|
||||
continue;
|
||||
|
||||
if( cmp > 0 )
|
||||
break;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -90,27 +107,31 @@ void BaseCmd_FindAll( const char *name, base_command_t **cmd, base_command_t **a
|
||||
base_command_hashmap_t *base = BaseCmd_GetBucket( name );
|
||||
base_command_hashmap_t *i = base;
|
||||
|
||||
ASSERT( cmd && alias && cvar );
|
||||
|
||||
*cmd = *alias = *cvar = NULL;
|
||||
|
||||
for( ; i; i = i->next )
|
||||
{
|
||||
if( !Q_stricmp( i->name, name ) )
|
||||
int cmp = Q_stricmp( i->name, name );
|
||||
|
||||
if( cmp < 0 )
|
||||
continue;
|
||||
|
||||
if( cmp > 0 )
|
||||
break;
|
||||
|
||||
switch( i->type )
|
||||
{
|
||||
switch( i->type )
|
||||
{
|
||||
case HM_CMD:
|
||||
*cmd = i->basecmd;
|
||||
break;
|
||||
case HM_CMDALIAS:
|
||||
*alias = i->basecmd;
|
||||
break;
|
||||
case HM_CVAR:
|
||||
*cvar = i->basecmd;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
case HM_CMD:
|
||||
*cmd = i->basecmd;
|
||||
break;
|
||||
case HM_CMDALIAS:
|
||||
*alias = i->basecmd;
|
||||
break;
|
||||
case HM_CVAR:
|
||||
*cvar = i->basecmd;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,14 +149,14 @@ void BaseCmd_Insert( base_command_type_e type, base_command_t *basecmd, const ch
|
||||
uint hash = BaseCmd_HashKey( name );
|
||||
size_t len = Q_strlen( name );
|
||||
|
||||
elem = Z_Malloc( sizeof( base_command_hashmap_t ) + len );
|
||||
elem = Mem_Malloc( basecmd_pool, sizeof( base_command_hashmap_t ) + len + 1 );
|
||||
elem->basecmd = basecmd;
|
||||
elem->type = type;
|
||||
Q_strncpy( elem->name, name, len + 1 );
|
||||
|
||||
// link the variable in alphanumerical order
|
||||
for( cur = NULL, find = hashed_cmds[hash];
|
||||
find && Q_strcmp( find->name, elem->name ) < 0;
|
||||
find && Q_stricmp( find->name, elem->name ) < 0;
|
||||
cur = find, find = find->next );
|
||||
|
||||
if( cur ) cur->next = elem;
|
||||
@@ -156,9 +177,23 @@ void BaseCmd_Remove( base_command_type_e type, const char *name )
|
||||
uint hash = BaseCmd_HashKey( name );
|
||||
base_command_hashmap_t *i, *prev;
|
||||
|
||||
for( prev = NULL, i = hashed_cmds[hash]; i &&
|
||||
( Q_strcmp( i->name, name ) || i->type != type); // filter out
|
||||
prev = i, i = i->next );
|
||||
for( prev = NULL, i = hashed_cmds[hash]; i != NULL; prev = i, i = i->next )
|
||||
{
|
||||
int cmp;
|
||||
|
||||
if( i->type != type )
|
||||
continue;
|
||||
|
||||
cmp = Q_stricmp( i->name, name );
|
||||
|
||||
if( cmp < 0 )
|
||||
continue;
|
||||
|
||||
if( cmp > 0 )
|
||||
i = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if( !i )
|
||||
{
|
||||
@@ -183,9 +218,15 @@ initialize base command hashmap system
|
||||
*/
|
||||
void BaseCmd_Init( void )
|
||||
{
|
||||
basecmd_pool = Mem_AllocPool( "BaseCmd" );
|
||||
memset( hashed_cmds, 0, sizeof( hashed_cmds ) );
|
||||
}
|
||||
|
||||
void BaseCmd_Shutdown( void )
|
||||
{
|
||||
Mem_FreePool( &basecmd_pool );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
BaseCmd_Stats_f
|
||||
|
||||
@@ -32,6 +32,7 @@ typedef enum base_command_type
|
||||
typedef void base_command_t;
|
||||
|
||||
void BaseCmd_Init( void );
|
||||
void BaseCmd_Shutdown( void );
|
||||
base_command_t *BaseCmd_Find( base_command_type_e type, const char *name );
|
||||
void BaseCmd_FindAll( const char *name,
|
||||
base_command_t **cmd, base_command_t **alias, base_command_t **cvar );
|
||||
|
||||
@@ -46,6 +46,7 @@ static cmdalias_t *cmd_alias;
|
||||
static uint cmd_condition;
|
||||
static int cmd_condlevel;
|
||||
static qboolean cmd_currentCommandIsPrivileged;
|
||||
static poolhandle_t cmd_pool;
|
||||
|
||||
static void Cmd_ExecuteStringWithPrivilegeCheck( const char *text, qboolean isPrivileged );
|
||||
|
||||
@@ -142,28 +143,33 @@ void Cbuf_AddFilteredText( const char *text )
|
||||
Cbuf_InsertText
|
||||
|
||||
Adds command text immediately after the current command
|
||||
Adds a \n to the text
|
||||
============
|
||||
*/
|
||||
static void Cbuf_InsertTextToBuffer( cmdbuf_t *buf, const char *text )
|
||||
static void Cbuf_InsertTextToBuffer( cmdbuf_t *buf, const char *text, size_t len, size_t requested_len )
|
||||
{
|
||||
int l = Q_strlen( text );
|
||||
|
||||
if(( buf->cursize + l ) >= buf->maxsize )
|
||||
if(( buf->cursize + requested_len ) >= buf->maxsize )
|
||||
{
|
||||
Con_Reportf( S_WARN "%s: overflow\n", __func__ );
|
||||
}
|
||||
else
|
||||
{
|
||||
memmove( buf->data + l, buf->data, buf->cursize );
|
||||
memcpy( buf->data, text, l );
|
||||
buf->cursize += l;
|
||||
memmove( buf->data + len, buf->data, buf->cursize );
|
||||
memcpy( buf->data, text, len );
|
||||
buf->cursize += len;
|
||||
}
|
||||
}
|
||||
|
||||
void Cbuf_InsertTextLen( const char *text, size_t len, size_t requested_len )
|
||||
{
|
||||
// sometimes we need to insert more data than we have
|
||||
// but also prevent overflow
|
||||
Cbuf_InsertTextToBuffer( &cmd_text, text, len, requested_len );
|
||||
}
|
||||
|
||||
void Cbuf_InsertText( const char *text )
|
||||
{
|
||||
Cbuf_InsertTextToBuffer( &cmd_text, text );
|
||||
size_t l = Q_strlen( text );
|
||||
Cbuf_InsertTextToBuffer( &cmd_text, text, l, l );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -263,10 +269,16 @@ Cbuf_Execute
|
||||
void Cbuf_Execute( void )
|
||||
{
|
||||
Cbuf_ExecuteCommandsFromBuffer( &cmd_text, true, -1 );
|
||||
// a1ba: unlimited commands for filtered buffer per frame
|
||||
|
||||
// a1ba: goldsrc limits unprivileged commands per frame to 1 here
|
||||
// I don't see any sense in restricting that at this moment
|
||||
// but in future we may limit this
|
||||
Cbuf_ExecuteCommandsFromBuffer( &filteredcmd_text, false, -1 );
|
||||
|
||||
// a1ba: there is little to no sense limit privileged commands in
|
||||
// local game, as client runs server code anyway
|
||||
// do this for singleplayer only though, to make it easier to catch
|
||||
// possible bugs during local multiplayer testing
|
||||
Cbuf_ExecuteCommandsFromBuffer( &filteredcmd_text, SV_Active() && SV_GetMaxClients() == 1, -1 );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -421,7 +433,7 @@ static void Cmd_Alias_f( void )
|
||||
{
|
||||
if( !Q_strcmp( s, a->name ))
|
||||
{
|
||||
Z_Free( a->value );
|
||||
Mem_Free( a->value );
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -430,7 +442,7 @@ static void Cmd_Alias_f( void )
|
||||
{
|
||||
cmdalias_t *cur, *prev;
|
||||
|
||||
a = Z_Malloc( sizeof( cmdalias_t ));
|
||||
a = Mem_Malloc( cmd_pool, sizeof( cmdalias_t ));
|
||||
|
||||
Q_strncpy( a->name, s, sizeof( a->name ));
|
||||
|
||||
@@ -458,7 +470,7 @@ static void Cmd_Alias_f( void )
|
||||
}
|
||||
|
||||
Q_strncat( cmd, "\n", sizeof( cmd ));
|
||||
a->value = copystring( cmd );
|
||||
a->value = copystringpool( cmd_pool, cmd );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -512,14 +524,14 @@ static void Cmd_UnAlias_f ( void )
|
||||
|
||||
=============================================================================
|
||||
*/
|
||||
typedef struct cmd_s
|
||||
struct cmd_s
|
||||
{
|
||||
struct cmd_s *next;
|
||||
char *name;
|
||||
xcommand_t function;
|
||||
int flags;
|
||||
char *desc;
|
||||
} cmd_t;
|
||||
char desc[];
|
||||
};
|
||||
|
||||
static int cmd_argc;
|
||||
static const char *cmd_args = NULL;
|
||||
@@ -625,7 +637,7 @@ void Cmd_TokenizeString( const char *text )
|
||||
|
||||
// clear the args from the last string
|
||||
for( i = 0; i < cmd_argc; i++ )
|
||||
Z_Free( cmd_argv[i] );
|
||||
Mem_Free( cmd_argv[i] );
|
||||
|
||||
cmd_argc = 0; // clear previous args
|
||||
cmd_args = NULL;
|
||||
@@ -659,7 +671,7 @@ void Cmd_TokenizeString( const char *text )
|
||||
|
||||
if( cmd_argc < MAX_CMD_TOKENS )
|
||||
{
|
||||
cmd_argv[cmd_argc] = copystring( cmd_token );
|
||||
cmd_argv[cmd_argc] = copystringpool( cmd_pool, cmd_token );
|
||||
cmd_argc++;
|
||||
}
|
||||
}
|
||||
@@ -670,10 +682,10 @@ void Cmd_TokenizeString( const char *text )
|
||||
Cmd_AddCommandEx
|
||||
============
|
||||
*/
|
||||
static int Cmd_AddCommandEx( const char *funcname, const char *cmd_name, xcommand_t function,
|
||||
const char *cmd_desc, int iFlags )
|
||||
int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd_desc, int iFlags, const char *funcname )
|
||||
{
|
||||
cmd_t *cmd, *cur, *prev;
|
||||
cmd_t *cmd, *cur, *prev;
|
||||
size_t desc_len;
|
||||
|
||||
if( !COM_CheckString( cmd_name ))
|
||||
{
|
||||
@@ -688,17 +700,35 @@ static int Cmd_AddCommandEx( const char *funcname, const char *cmd_name, xcomman
|
||||
return 0;
|
||||
}
|
||||
|
||||
// fail if the command already exists
|
||||
if( Cmd_Exists( cmd_name ))
|
||||
// fail if the command already exists and cannot be overriden
|
||||
cmd = Cmd_Exists( cmd_name );
|
||||
if( cmd )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "%s: %s already defined\n", funcname, cmd_name );
|
||||
return 0;
|
||||
// some mods register commands that share the name with some engine's commands
|
||||
// when they aren't critical to keep engine running, we can let mods to override them
|
||||
// unfortunately, we lose original command this way
|
||||
if( FBitSet( cmd->flags, CMD_OVERRIDABLE ))
|
||||
{
|
||||
desc_len = Q_strlen( cmd->desc ) + 1;
|
||||
Q_strncpy( cmd->desc, cmd_desc, desc_len );
|
||||
cmd->function = function;
|
||||
cmd->flags = iFlags;
|
||||
|
||||
Con_DPrintf( S_WARN "%s: %s already defined but is allowed to be overriden\n", funcname, cmd_name );
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Con_DPrintf( "%s%s: %s already defined\n", cmd->function == function ? S_WARN : S_ERROR, funcname, cmd_name );
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// use a small malloc to avoid zone fragmentation
|
||||
cmd = Z_Malloc( sizeof( cmd_t ) );
|
||||
cmd->name = copystring( cmd_name );
|
||||
cmd->desc = copystring( cmd_desc );
|
||||
desc_len = Q_strlen( cmd_desc ) + 1;
|
||||
cmd = Mem_Malloc( cmd_pool, sizeof( cmd_t ) + desc_len );
|
||||
cmd->name = copystringpool( cmd_pool, cmd_name );
|
||||
Q_strncpy( cmd->desc, cmd_desc, desc_len );
|
||||
cmd->function = function;
|
||||
cmd->flags = iFlags;
|
||||
|
||||
@@ -716,75 +746,6 @@ static int Cmd_AddCommandEx( const char *funcname, const char *cmd_name, xcomman
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_AddCommand
|
||||
============
|
||||
*/
|
||||
void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc )
|
||||
{
|
||||
Cmd_AddCommandEx( __func__, cmd_name, function, cmd_desc, 0 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_AddRestrictedCommand
|
||||
============
|
||||
*/
|
||||
void Cmd_AddRestrictedCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc )
|
||||
{
|
||||
Cmd_AddCommandEx( __func__, cmd_name, function, cmd_desc, CMD_PRIVILEGED );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_AddServerCommand
|
||||
============
|
||||
*/
|
||||
void GAME_EXPORT Cmd_AddServerCommand( const char *cmd_name, xcommand_t function )
|
||||
{
|
||||
Cmd_AddCommandEx( __func__, cmd_name, function, "server command", CMD_SERVERDLL );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_AddClientCommand
|
||||
============
|
||||
*/
|
||||
int GAME_EXPORT Cmd_AddClientCommand( const char *cmd_name, xcommand_t function )
|
||||
{
|
||||
int flags = CMD_CLIENTDLL;
|
||||
|
||||
// a1ba: try to mitigate outdated client.dll vulnerabilities
|
||||
if( !Q_stricmp( cmd_name, "motd_write" ))
|
||||
{
|
||||
flags |= CMD_PRIVILEGED;
|
||||
}
|
||||
|
||||
return Cmd_AddCommandEx( __func__, cmd_name, function, "client command", flags );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_AddGameUICommand
|
||||
============
|
||||
*/
|
||||
int GAME_EXPORT Cmd_AddGameUICommand( const char *cmd_name, xcommand_t function )
|
||||
{
|
||||
return Cmd_AddCommandEx( __func__, cmd_name, function, "gameui command", CMD_GAMEUIDLL );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_AddRefCommand
|
||||
============
|
||||
*/
|
||||
int Cmd_AddRefCommand( const char *cmd_name, xcommand_t function, const char *description )
|
||||
{
|
||||
return Cmd_AddCommandEx( __func__, cmd_name, function, description, CMD_REFDLL );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cmd_RemoveCommand
|
||||
@@ -814,9 +775,6 @@ void GAME_EXPORT Cmd_RemoveCommand( const char *cmd_name )
|
||||
if( cmd->name )
|
||||
Mem_Free( cmd->name );
|
||||
|
||||
if( cmd->desc )
|
||||
Mem_Free( cmd->desc );
|
||||
|
||||
Mem_Free( cmd );
|
||||
return;
|
||||
}
|
||||
@@ -853,19 +811,18 @@ void Cmd_LookupCmds( void *buffer, void *ptr, setpair_t callback )
|
||||
Cmd_Exists
|
||||
============
|
||||
*/
|
||||
qboolean Cmd_Exists( const char *cmd_name )
|
||||
cmd_t *Cmd_Exists( const char *cmd_name )
|
||||
{
|
||||
#if defined(XASH_HASHED_VARS)
|
||||
return BaseCmd_Find( HM_CMD, cmd_name ) != NULL;
|
||||
return BaseCmd_Find( HM_CMD, cmd_name );
|
||||
#else
|
||||
cmd_t *cmd;
|
||||
|
||||
for( cmd = cmd_functions; cmd; cmd = cmd->next )
|
||||
{
|
||||
if( !Q_strcmp( cmd_name, cmd->name ))
|
||||
return true;
|
||||
return cmd;
|
||||
}
|
||||
return false;
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1058,9 +1015,10 @@ static void Cmd_ExecuteStringWithPrivilegeCheck( const char *text, qboolean isPr
|
||||
|
||||
if( a )
|
||||
{
|
||||
size_t len = Q_strlen( a->value );
|
||||
Cbuf_InsertTextToBuffer(
|
||||
isPrivileged ? &cmd_text : &filteredcmd_text,
|
||||
a->value );
|
||||
a->value, len, len );
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1244,7 +1202,6 @@ void Cmd_Unlink( int group )
|
||||
*prev = cmd->next;
|
||||
|
||||
if( cmd->name ) Mem_Free( cmd->name );
|
||||
if( cmd->desc ) Mem_Free( cmd->desc );
|
||||
|
||||
Mem_Free( cmd );
|
||||
count++;
|
||||
@@ -1382,6 +1339,7 @@ Cmd_Init
|
||||
*/
|
||||
void Cmd_Init( void )
|
||||
{
|
||||
cmd_pool = Mem_AllocPool( "Console Commands" );
|
||||
cmd_functions = NULL;
|
||||
cmd_condition = 0;
|
||||
cmd_alias = NULL;
|
||||
@@ -1408,6 +1366,11 @@ void Cmd_Init( void )
|
||||
#endif
|
||||
}
|
||||
|
||||
void Cmd_Shutdown( void )
|
||||
{
|
||||
Mem_FreePool( &cmd_pool );
|
||||
}
|
||||
|
||||
#if XASH_ENGINE_TESTS
|
||||
#include "tests.h"
|
||||
|
||||
|
||||
@@ -72,8 +72,6 @@ GNU General Public License for more details.
|
||||
|
||||
#define CVAR_GLCONFIG_DESCRIPTION "enable or disable %s"
|
||||
|
||||
#define DEFAULT_BSP_BUILD_ERROR "%s can't be loaded in this build. Please rebuild engine with enabled SUPPORT_BSP2_FORMAT\n"
|
||||
|
||||
#define DEFAULT_UPDATE_PAGE "https://github.com/FWGS/xash3d-fwgs/releases/latest"
|
||||
|
||||
#define XASH_ENGINE_NAME "Xash3D FWGS"
|
||||
|
||||
@@ -612,7 +612,7 @@ COM_Nibble
|
||||
Returns the 4 bit nibble for a hex character
|
||||
==================
|
||||
*/
|
||||
static byte COM_Nibble( char c )
|
||||
byte COM_Nibble( char c )
|
||||
{
|
||||
if(( c >= '0' ) && ( c <= '9' ))
|
||||
{
|
||||
|
||||
@@ -108,14 +108,14 @@ typedef enum
|
||||
#include "com_model.h"
|
||||
#include "com_strings.h"
|
||||
#include "crtlib.h"
|
||||
#include "cvar.h"
|
||||
#include "con_nprint.h"
|
||||
#include "crclib.h"
|
||||
#include "ref_api.h"
|
||||
#define FSCALLBACK_OVERRIDE_OPEN
|
||||
#define FSCALLBACK_OVERRIDE_LOADFILE
|
||||
#define FSCALLBACK_OVERRIDE_MALLOC_LIKE
|
||||
#include "fscallback.h"
|
||||
#include "cvar.h"
|
||||
#include "con_nprint.h"
|
||||
#include "crclib.h"
|
||||
#include "ref_api.h"
|
||||
|
||||
// PERFORMANCE INFO
|
||||
#define MIN_FPS 20.0f // host minimum fps value for maxfps.
|
||||
@@ -146,6 +146,11 @@ typedef enum
|
||||
#define MAX_STATIC_ENTITIES 32 // static entities that moved on the client when level is spawn
|
||||
#endif
|
||||
|
||||
#define MAX_SERVERINFO_STRING 512 // server handles too many settings. expand to 1024?
|
||||
#define MAX_PRINT_MSG 8192 // how many symbols can handle single call of Con_Printf or Con_DPrintf
|
||||
#define MAX_TOKEN 2048 // parse token length
|
||||
#define MAX_USERMSG_LENGTH 2048 // don't modify it's relies on a client-side definitions
|
||||
|
||||
#define GameState (&host.game)
|
||||
|
||||
#define FORCE_DRAW_VERSION_TIME 5.0 // draw version for 5 seconds
|
||||
@@ -301,7 +306,6 @@ typedef struct host_parm_s
|
||||
poolhandle_t mempool; // static mempool for misc allocations
|
||||
poolhandle_t imagepool; // imagelib mempool
|
||||
poolhandle_t soundpool; // soundlib mempool
|
||||
string finalmsg; // server shutdown final message
|
||||
string downloadfile; // filename to be downloading
|
||||
int downloadcount; // how many files remain to downloading
|
||||
char deferred_cmd[128];// deferred commands
|
||||
@@ -362,12 +366,13 @@ typedef struct host_parm_s
|
||||
|
||||
extern host_parm_t host;
|
||||
|
||||
#define CMD_SERVERDLL BIT( 0 ) // added by server.dll
|
||||
#define CMD_CLIENTDLL BIT( 1 ) // added by client.dll
|
||||
#define CMD_GAMEUIDLL BIT( 2 ) // added by GameUI.dll
|
||||
#define CMD_PRIVILEGED BIT( 3 ) // only available in privileged mode
|
||||
#define CMD_FILTERABLE BIT( 4 ) // filtered in unprivileged mode if cl_filterstuffcmd is 1
|
||||
#define CMD_REFDLL BIT( 5 ) // added by ref.dll
|
||||
#define CMD_SERVERDLL BIT( 0 ) // added by server.dll
|
||||
#define CMD_CLIENTDLL BIT( 1 ) // added by client.dll
|
||||
#define CMD_GAMEUIDLL BIT( 2 ) // added by GameUI.dll
|
||||
#define CMD_PRIVILEGED BIT( 3 ) // only available in privileged mode
|
||||
#define CMD_FILTERABLE BIT( 4 ) // filtered in unprivileged mode if cl_filterstuffcmd is 1
|
||||
#define CMD_REFDLL BIT( 5 ) // added by ref.dll
|
||||
#define CMD_OVERRIDABLE BIT( 6 ) // can be removed by DLLs if name matches
|
||||
|
||||
typedef void (*xcommand_t)( void );
|
||||
|
||||
@@ -418,11 +423,13 @@ byte *FS_LoadDirectFile( const char *path, fs_offset_t *filesizeptr )
|
||||
//
|
||||
// cmd.c
|
||||
//
|
||||
typedef struct cmd_s cmd_t;
|
||||
void Cbuf_Clear( void );
|
||||
void Cbuf_AddText( const char *text );
|
||||
void Cbuf_AddTextf( const char *text, ... ) FORMAT_CHECK( 1 );
|
||||
void Cbuf_AddFilteredText( const char *text );
|
||||
void Cbuf_InsertText( const char *text );
|
||||
void Cbuf_InsertTextLen( const char *text, size_t len, size_t requested_len );
|
||||
void Cbuf_ExecStuffCmds( void );
|
||||
void Cbuf_Execute (void);
|
||||
qboolean Cmd_CurrentCommandIsPrivileged( void );
|
||||
@@ -430,15 +437,27 @@ int Cmd_Argc( void );
|
||||
const char *Cmd_Args( void ) RETURNS_NONNULL;
|
||||
const char *Cmd_Argv( int arg ) RETURNS_NONNULL;
|
||||
void Cmd_Init( void );
|
||||
void Cmd_Shutdown( void );
|
||||
void Cmd_Unlink( int group );
|
||||
void Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc );
|
||||
void Cmd_AddRestrictedCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc );
|
||||
void Cmd_AddServerCommand( const char *cmd_name, xcommand_t function );
|
||||
int Cmd_AddClientCommand( const char *cmd_name, xcommand_t function );
|
||||
int Cmd_AddGameUICommand( const char *cmd_name, xcommand_t function );
|
||||
int Cmd_AddRefCommand( const char *cmd_name, xcommand_t function, const char *description );
|
||||
int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd_desc, int flags, const char *funcname );
|
||||
|
||||
static inline int Cmd_AddCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc )
|
||||
{
|
||||
return Cmd_AddCommandEx( cmd_name, function, cmd_desc, 0, __func__ );
|
||||
}
|
||||
|
||||
static inline int Cmd_AddRestrictedCommand( const char *cmd_name, xcommand_t function, const char *cmd_desc )
|
||||
{
|
||||
return Cmd_AddCommandEx( cmd_name, function, cmd_desc, CMD_PRIVILEGED, __func__ );
|
||||
}
|
||||
|
||||
static inline int Cmd_AddCommandWithFlags( const char *cmd_name, xcommand_t function, const char *cmd_desc, int flags )
|
||||
{
|
||||
return Cmd_AddCommandEx( cmd_name, function, cmd_desc, flags, __func__ );
|
||||
}
|
||||
|
||||
void Cmd_RemoveCommand( const char *cmd_name );
|
||||
qboolean Cmd_Exists( const char *cmd_name );
|
||||
cmd_t *Cmd_Exists( const char *cmd_name );
|
||||
void Cmd_LookupCmds( void *buffer, void *ptr, setpair_t callback );
|
||||
int Cmd_ListMaps( search_t *t , char *lastmapname, size_t len );
|
||||
void Cmd_TokenizeString( const char *text );
|
||||
@@ -500,27 +519,27 @@ typedef enum
|
||||
|
||||
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)
|
||||
size_t size; // for bounds checking
|
||||
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
|
||||
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)
|
||||
byte buffer[]; // sound buffer
|
||||
} wavdata_t;
|
||||
|
||||
//
|
||||
// soundlib
|
||||
//
|
||||
typedef struct stream_s stream_t;
|
||||
void Sound_Init( void );
|
||||
void Sound_Shutdown( void );
|
||||
void FS_FreeSound( wavdata_t *pack );
|
||||
void FS_FreeStream( stream_t *stream );
|
||||
wavdata_t *FS_LoadSound( const char *filename, const byte *buffer, size_t size ) MALLOC_LIKE( FS_FreeSound, 1 ) WARN_UNUSED_RESULT;
|
||||
stream_t *FS_OpenStream( const char *filename ) MALLOC_LIKE( FS_FreeStream, 1 ) WARN_UNUSED_RESULT;
|
||||
wavdata_t *FS_StreamInfo( stream_t *stream );
|
||||
int FS_ReadStream( stream_t *stream, int bytes, void *buffer );
|
||||
int FS_SetStreamPos( stream_t *stream, int newpos );
|
||||
int FS_GetStreamPos( stream_t *stream );
|
||||
@@ -534,7 +553,7 @@ qboolean Sound_SupportedFileFormat( const char *fileext );
|
||||
typedef void( *pfnChangeGame )( const char *progname );
|
||||
|
||||
qboolean Host_IsQuakeCompatible( void );
|
||||
void EXPORT Host_Shutdown( void );
|
||||
void Host_ShutdownWithReason( const char *reason );
|
||||
int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGame, pfnChangeGame func );
|
||||
void Host_EndGame( qboolean abort, const char *message, ... ) FORMAT_CHECK( 2 );
|
||||
void Host_AbortCurrentFrame( void ) NORETURN;
|
||||
@@ -542,11 +561,11 @@ void Host_WriteServerConfig( const char *name );
|
||||
void Host_WriteOpenGLConfig( void );
|
||||
void Host_WriteVideoConfig( void );
|
||||
void Host_WriteConfig( void );
|
||||
void Host_ShutdownServer( void );
|
||||
void Host_Error( const char *error, ... ) FORMAT_CHECK( 1 );
|
||||
void Host_ValidateEngineFeatures( uint32_t mask, uint32_t features );
|
||||
void Host_Frame( double time );
|
||||
void Host_Credits( void );
|
||||
void Host_ExitInMain( void );
|
||||
|
||||
//
|
||||
// host_state.c
|
||||
@@ -565,11 +584,19 @@ CLIENT / SERVER SYSTEMS
|
||||
|
||||
==============================================================
|
||||
*/
|
||||
#if !XASH_DEDICATED
|
||||
void CL_Init( void );
|
||||
void CL_Shutdown( void );
|
||||
void Host_ClientBegin( void );
|
||||
void Host_ClientFrame( void );
|
||||
int CL_Active( void );
|
||||
#else
|
||||
static inline void CL_Init( void ) { }
|
||||
static inline void CL_Shutdown( void ) { }
|
||||
static inline void Host_ClientBegin( void ) { Cbuf_Execute(); }
|
||||
static inline void Host_ClientFrame( void ) { }
|
||||
static inline int CL_Active( void ) { return 0; }
|
||||
#endif
|
||||
|
||||
void SV_Init( void );
|
||||
void SV_Shutdown( const char *finalmsg );
|
||||
@@ -586,6 +613,7 @@ qboolean SV_Active( void );
|
||||
*/
|
||||
char *COM_MemFgets( byte *pMemFile, int fileSize, int *filePos, char *pBuffer, int bufferSize );
|
||||
void COM_HexConvert( const char *pszInput, int nInputLength, byte *pOutput );
|
||||
byte COM_Nibble( char c );
|
||||
int COM_SaveFile( const char *filename, const void *data, int len );
|
||||
byte *COM_LoadFileForMe( const char *filename, int *pLength ) MALLOC_LIKE( free, 1 );
|
||||
qboolean COM_IsSafeFileToDownload( const char *filename );
|
||||
@@ -606,6 +634,7 @@ int pfnNumberOfEntities( void );
|
||||
int pfnIsInGame( void );
|
||||
float pfnTime( void );
|
||||
#define copystring( s ) _copystring( host.mempool, s, __FILE__, __LINE__ )
|
||||
#define copystringpool( pool, s ) _copystring( pool, s, __FILE__, __LINE__ )
|
||||
#define SV_CopyString( s ) _copystring( svgame.stringspool, s, __FILE__, __LINE__ )
|
||||
#define freestring( s ) if( s != NULL ) { Mem_Free( s ); s = NULL; }
|
||||
char *_copystring( poolhandle_t mempool, const char *s, const char *filename, int fileline );
|
||||
@@ -656,6 +685,7 @@ int CSCR_WriteGameCVars( file_t *cfg, const char *scriptfilename );
|
||||
//
|
||||
// hpak.c
|
||||
//
|
||||
const char *COM_ResourceTypeFromIndex( int index );
|
||||
void HPAK_Init( void );
|
||||
qboolean HPAK_GetDataPointer( const char *filename, struct resource_s *pRes, byte **buffer, int *size );
|
||||
qboolean HPAK_ResourceForHash( const char *filename, byte *hash, struct resource_s *pRes );
|
||||
@@ -689,13 +719,32 @@ typedef enum connprotocol_e
|
||||
struct physent_s;
|
||||
struct sv_client_s;
|
||||
typedef struct sizebuf_s sizebuf_t;
|
||||
int SV_GetMaxClients( void );
|
||||
|
||||
#if !XASH_DEDICATED
|
||||
qboolean CL_Initialized( void );
|
||||
qboolean CL_IsInGame( void );
|
||||
qboolean CL_IsInConsole( void );
|
||||
qboolean CL_IsIntermission( void );
|
||||
qboolean CL_Initialized( void );
|
||||
qboolean CL_DisableVisibility( void );
|
||||
qboolean CL_IsRecordDemo( void );
|
||||
qboolean CL_IsPlaybackDemo( void );
|
||||
qboolean UI_CreditsActive( void );
|
||||
int CL_GetMaxClients( void );
|
||||
#else
|
||||
static inline qboolean CL_Initialized( void ) { return false; }
|
||||
static inline qboolean CL_IsInGame( void ) { return false; }
|
||||
static inline qboolean CL_IsInConsole( void ) { return false; }
|
||||
static inline qboolean CL_IsIntermission( void ) { return false; }
|
||||
static inline qboolean CL_DisableVisibility( void ) { return false; }
|
||||
static inline qboolean CL_IsRecordDemo( void ) { return false; }
|
||||
static inline qboolean CL_IsPlaybackDemo( void ) { return false; }
|
||||
static inline qboolean UI_CreditsActive( void ) { return false; }
|
||||
static inline int CL_GetMaxClients( void ) { return SV_GetMaxClients(); }
|
||||
#endif
|
||||
|
||||
char *CL_Userinfo( void );
|
||||
void CL_CharEvent( int key );
|
||||
qboolean CL_DisableVisibility( void );
|
||||
byte *COM_LoadFile( const char *filename, int usehunk, int *pLength ) MALLOC_LIKE( free, 1 );
|
||||
struct cmd_s *Cmd_GetFirstFunctionHandle( void );
|
||||
struct cmd_s *Cmd_GetNextFunctionHandle( struct cmd_s *cmd );
|
||||
@@ -713,13 +762,7 @@ const char *CL_MsgInfo( int cmd );
|
||||
void SV_DrawDebugTriangles( void );
|
||||
void SV_DrawOrthoTriangles( void );
|
||||
double CL_GetDemoFramerate( void );
|
||||
qboolean UI_CreditsActive( void );
|
||||
void CL_StopPlayback( void );
|
||||
int CL_GetMaxClients( void );
|
||||
int SV_GetMaxClients( void );
|
||||
qboolean CL_IsRecordDemo( void );
|
||||
qboolean CL_IsTimeDemo( void );
|
||||
qboolean CL_IsPlaybackDemo( void );
|
||||
qboolean SV_Initialized( void );
|
||||
void CL_ProcessFile( qboolean successfully_received, const char *filename );
|
||||
int SV_GetSaveComment( const char *savename, char *comment );
|
||||
@@ -741,8 +784,6 @@ void SCR_Init( void );
|
||||
void SCR_UpdateScreen( void );
|
||||
void SCR_BeginLoadingPlaque( qboolean is_background );
|
||||
void SCR_CheckStartupVids( void );
|
||||
int SCR_GetAudioChunk( char *rawdata, int length );
|
||||
wavdata_t *SCR_GetMovieInfo( void );
|
||||
void SCR_Shutdown( void );
|
||||
void Con_Print( const char *txt );
|
||||
void Con_NPrintf( int idx, const char *fmt, ... ) FORMAT_CHECK( 2 );
|
||||
@@ -832,13 +873,6 @@ void V_CheckGamma( void );
|
||||
void V_CheckGammaEnd( void );
|
||||
intptr_t V_GetGammaPtr( int parm );
|
||||
|
||||
//
|
||||
// identification.c
|
||||
//
|
||||
void ID_Init( void );
|
||||
const char *ID_GetMD5( void );
|
||||
void GAME_EXPORT ID_SetCustomClientID( const char *id );
|
||||
|
||||
//
|
||||
// masterlist.c
|
||||
//
|
||||
|
||||
@@ -1040,7 +1040,6 @@ static const autocomplete_list_t cmd_list[] =
|
||||
{ "map", 1, Cmd_GetMapList },
|
||||
{ "cd", 1, Cmd_GetCDList },
|
||||
{ "mp3", 1, Cmd_GetCDList },
|
||||
{ NULL }, // termiantor
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -1073,12 +1072,12 @@ for various cmds
|
||||
*/
|
||||
static qboolean Cmd_AutocompleteName( const char *source, int arg, char *buffer, size_t bufsize )
|
||||
{
|
||||
const autocomplete_list_t *list;
|
||||
int i;
|
||||
|
||||
for( list = cmd_list; list->name; list++ )
|
||||
for( i = 0; i < ARRAYSIZE( cmd_list ); i++ )
|
||||
{
|
||||
if( list->arg == arg && Cmd_CheckName( list->name ))
|
||||
return list->func( source, buffer, bufsize );
|
||||
if( cmd_list[i].arg == arg && Cmd_CheckName( cmd_list[i].name ))
|
||||
return cmd_list[i].func( source, buffer, bufsize );
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -1396,7 +1395,7 @@ void Host_WriteConfig( void )
|
||||
{
|
||||
Con_Reportf( "%s()\n", __func__ );
|
||||
FS_Printf( f, "//=======================================================================\n");
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\t\tconfig.cfg - archive of cvars\n" );
|
||||
FS_Printf( f, "//=======================================================================\n" );
|
||||
Key_WriteBindings( f );
|
||||
@@ -1444,7 +1443,7 @@ void GAME_EXPORT Host_WriteServerConfig( const char *name )
|
||||
if(( f = FS_Open( newconfigfile, "w", false )) != NULL )
|
||||
{
|
||||
FS_Printf( f, "//=======================================================================\n" );
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\t\tgame.cfg - multiplayer server temporare config\n" );
|
||||
FS_Printf( f, "//=======================================================================\n" );
|
||||
|
||||
@@ -1479,7 +1478,7 @@ void Host_WriteOpenGLConfig( void )
|
||||
{
|
||||
Con_Reportf( "%s()\n", __func__ );
|
||||
FS_Printf( f, "//=======================================================================\n" );
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\t\t%s - archive of renderer implementation cvars\n", name );
|
||||
FS_Printf( f, "//=======================================================================\n" );
|
||||
FS_Printf( f, "\n" );
|
||||
@@ -1509,7 +1508,7 @@ void Host_WriteVideoConfig( void )
|
||||
{
|
||||
Con_Reportf( "%s()\n", __func__ );
|
||||
FS_Printf( f, "//=======================================================================\n" );
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\t\tvideo.cfg - archive of renderer variables\n");
|
||||
FS_Printf( f, "//=======================================================================\n" );
|
||||
Cvar_WriteVariables( f, FCVAR_RENDERINFO );
|
||||
@@ -1535,7 +1534,7 @@ void Key_EnumCmds_f( void )
|
||||
if( f )
|
||||
{
|
||||
FS_Printf( f, "//=======================================================================\n");
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\tGenerated by "XASH_ENGINE_NAME" (%i, %s, %s, %s-%s)\n", Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
|
||||
FS_Printf( f, "//\t\thelp.txt - xash commands and console variables\n");
|
||||
FS_Printf( f, "//=======================================================================\n");
|
||||
|
||||
|
||||
@@ -1,558 +0,0 @@
|
||||
/*
|
||||
crashhandler.c - advanced crashhandler
|
||||
Copyright (C) 2016 Mittorn
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
================
|
||||
Sys_Crash
|
||||
|
||||
Crash handler, called from system
|
||||
================
|
||||
*/
|
||||
#if XASH_WIN32
|
||||
|
||||
#if DBGHELP
|
||||
|
||||
#pragma comment( lib, "dbghelp" )
|
||||
|
||||
#include <winnt.h>
|
||||
#include <dbghelp.h>
|
||||
#include <psapi.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef XASH_SDL
|
||||
typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
|
||||
#endif
|
||||
|
||||
static int Sys_ModuleName( HANDLE process, char *name, void *address, int len )
|
||||
{
|
||||
DWORD_PTR baseAddress = 0;
|
||||
static HMODULE *moduleArray;
|
||||
static unsigned int moduleCount;
|
||||
LPBYTE moduleArrayBytes;
|
||||
DWORD bytesRequired;
|
||||
int i;
|
||||
|
||||
if( len < 3 )
|
||||
return 0;
|
||||
|
||||
if( !moduleArray && EnumProcessModules( process, NULL, 0, &bytesRequired ) )
|
||||
{
|
||||
if ( bytesRequired )
|
||||
{
|
||||
moduleArrayBytes = (LPBYTE)LocalAlloc( LPTR, bytesRequired );
|
||||
|
||||
if( moduleArrayBytes && EnumProcessModules( process, (HMODULE *)moduleArrayBytes, bytesRequired, &bytesRequired ) )
|
||||
{
|
||||
moduleCount = bytesRequired / sizeof( HMODULE );
|
||||
moduleArray = (HMODULE *)moduleArrayBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for( i = 0; i < moduleCount; i++ )
|
||||
{
|
||||
MODULEINFO info;
|
||||
GetModuleInformation( process, moduleArray[i], &info, sizeof(MODULEINFO) );
|
||||
|
||||
if( ( address > info.lpBaseOfDll ) &&
|
||||
( (DWORD64)address < (DWORD64)info.lpBaseOfDll + (DWORD64)info.SizeOfImage ) )
|
||||
return GetModuleBaseName( process, moduleArray[i], name, len );
|
||||
}
|
||||
return Q_snprintf( name, len, "???" );
|
||||
}
|
||||
|
||||
static void Sys_StackTrace( PEXCEPTION_POINTERS pInfo )
|
||||
{
|
||||
char message[8192]; // match *nix Sys_Crash
|
||||
int len = 0;
|
||||
size_t i;
|
||||
HANDLE process = GetCurrentProcess();
|
||||
HANDLE thread = GetCurrentThread();
|
||||
IMAGEHLP_LINE64 line;
|
||||
DWORD dline = 0;
|
||||
DWORD options;
|
||||
CONTEXT context;
|
||||
STACKFRAME64 stackframe;
|
||||
DWORD image;
|
||||
|
||||
context = *pInfo->ContextRecord;
|
||||
|
||||
options = SymGetOptions();
|
||||
options |= SYMOPT_DEBUG;
|
||||
options |= SYMOPT_LOAD_LINES;
|
||||
SymSetOptions( options );
|
||||
|
||||
SymInitialize( process, NULL, TRUE );
|
||||
|
||||
ZeroMemory( &stackframe, sizeof( STACKFRAME64 ));
|
||||
|
||||
#ifdef _M_IX86
|
||||
image = IMAGE_FILE_MACHINE_I386;
|
||||
stackframe.AddrPC.Offset = context.Eip;
|
||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||
stackframe.AddrFrame.Offset = context.Ebp;
|
||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
||||
stackframe.AddrStack.Offset = context.Esp;
|
||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||
#elif _M_X64
|
||||
image = IMAGE_FILE_MACHINE_AMD64;
|
||||
stackframe.AddrPC.Offset = context.Rip;
|
||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||
stackframe.AddrFrame.Offset = context.Rsp;
|
||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
||||
stackframe.AddrStack.Offset = context.Rsp;
|
||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||
#elif _M_IA64
|
||||
image = IMAGE_FILE_MACHINE_IA64;
|
||||
stackframe.AddrPC.Offset = context.StIIP;
|
||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||
stackframe.AddrFrame.Offset = context.IntSp;
|
||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
||||
stackframe.AddrBStore.Offset = context.RsBSP;
|
||||
stackframe.AddrBStore.Mode = AddrModeFlat;
|
||||
stackframe.AddrStack.Offset = context.IntSp;
|
||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||
#elif _M_ARM
|
||||
image = IMAGE_FILE_MACHINE_ARMNT;
|
||||
stackframe.AddrPC.Offset = context.Pc;
|
||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||
stackframe.AddrFrame.Offset = context.R11;
|
||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
||||
stackframe.AddrStack.Offset = context.Sp;
|
||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||
#elif _M_ARM64
|
||||
image = IMAGE_FILE_MACHINE_ARM64;
|
||||
stackframe.AddrPC.Offset = context.Pc;
|
||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
||||
stackframe.AddrFrame.Offset = context.Fp;
|
||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
||||
stackframe.AddrStack.Offset = context.Sp;
|
||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||
#elif
|
||||
#error
|
||||
#endif
|
||||
|
||||
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n",
|
||||
Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch() );
|
||||
|
||||
len += Q_snprintf( message + len, 1024 - len, "Sys_Crash: address %p, code %p\n",
|
||||
pInfo->ExceptionRecord->ExceptionAddress, (void*)pInfo->ExceptionRecord->ExceptionCode );
|
||||
if( SymGetLineFromAddr64( process, (DWORD64)pInfo->ExceptionRecord->ExceptionAddress, &dline, &line ) )
|
||||
{
|
||||
len += Q_snprintf(message + len, 1024 - len, "Exception: %s:%d:%d\n",
|
||||
(char*)line.FileName, (int)line.LineNumber, (int)dline);
|
||||
}
|
||||
if( SymGetLineFromAddr64( process, stackframe.AddrPC.Offset, &dline, &line ) )
|
||||
{
|
||||
len += Q_snprintf(message + len, 1024 - len,"PC: %s:%d:%d\n",
|
||||
(char*)line.FileName, (int)line.LineNumber, (int)dline);
|
||||
}
|
||||
if( SymGetLineFromAddr64( process, stackframe.AddrFrame.Offset, &dline, &line ) )
|
||||
{
|
||||
len += Q_snprintf(message + len, 1024 - len,"Frame: %s:%d:%d\n",
|
||||
(char*)line.FileName, (int)line.LineNumber, (int)dline);
|
||||
}
|
||||
for( i = 0; i < 25; i++ )
|
||||
{
|
||||
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
|
||||
PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
|
||||
BOOL result = StackWalk64(
|
||||
image, process, thread,
|
||||
&stackframe, &context, NULL,
|
||||
SymFunctionTableAccess64, SymGetModuleBase64, NULL);
|
||||
DWORD64 displacement = 0;
|
||||
|
||||
if( !result )
|
||||
break;
|
||||
|
||||
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
symbol->MaxNameLen = MAX_SYM_NAME;
|
||||
|
||||
len += Q_snprintf( message + len, 1024 - len, "% 2d %p",
|
||||
i, (void*)stackframe.AddrPC.Offset );
|
||||
if( SymFromAddr( process, stackframe.AddrPC.Offset, &displacement, symbol ) )
|
||||
{
|
||||
len += Q_snprintf( message + len, 1024 - len, " %s ", symbol->Name );
|
||||
}
|
||||
if( SymGetLineFromAddr64( process, stackframe.AddrPC.Offset, &dline, &line ) )
|
||||
{
|
||||
len += Q_snprintf(message + len, 1024 - len,"(%s:%d:%d) ",
|
||||
(char*)line.FileName, (int)line.LineNumber, (int)dline);
|
||||
}
|
||||
len += Q_snprintf( message + len, 1024 - len, "(");
|
||||
len += Sys_ModuleName( process, message + len, (void*)stackframe.AddrPC.Offset, 1024 - len );
|
||||
len += Q_snprintf( message + len, 1024 - len, ")\n");
|
||||
}
|
||||
|
||||
#if XASH_SDL == 2
|
||||
if( host.type != HOST_DEDICATED ) // let system to restart server automaticly
|
||||
SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR, "Sys_Crash", message, host.hWnd );
|
||||
#endif
|
||||
|
||||
Sys_PrintLog( message );
|
||||
|
||||
SymCleanup( process );
|
||||
}
|
||||
|
||||
static void Sys_GetProcessName( char *processName, size_t bufferSize )
|
||||
{
|
||||
char fullpath[MAX_PATH];
|
||||
|
||||
GetModuleBaseName( GetCurrentProcess(), NULL, fullpath, sizeof( fullpath ) - 1 );
|
||||
COM_FileBase( fullpath, processName, bufferSize );
|
||||
}
|
||||
|
||||
static void Sys_GetMinidumpFileName( const char *processName, char *mdmpFileName, size_t bufferSize )
|
||||
{
|
||||
time_t currentUtcTime = time( NULL );
|
||||
struct tm *currentLocalTime = localtime( ¤tUtcTime );
|
||||
|
||||
Q_snprintf( mdmpFileName, bufferSize, "%s_%s_crash_%d%.2d%.2d_%.2d%.2d%.2d.mdmp",
|
||||
processName,
|
||||
Q_buildcommit(),
|
||||
currentLocalTime->tm_year + 1900,
|
||||
currentLocalTime->tm_mon + 1,
|
||||
currentLocalTime->tm_mday,
|
||||
currentLocalTime->tm_hour,
|
||||
currentLocalTime->tm_min,
|
||||
currentLocalTime->tm_sec);
|
||||
}
|
||||
|
||||
static qboolean Sys_WriteMinidump(PEXCEPTION_POINTERS exceptionInfo, MINIDUMP_TYPE minidumpType)
|
||||
{
|
||||
HRESULT errorCode;
|
||||
string processName;
|
||||
string mdmpFileName;
|
||||
MINIDUMP_EXCEPTION_INFORMATION minidumpInfo;
|
||||
|
||||
Sys_GetProcessName( processName, sizeof( processName ));
|
||||
Sys_GetMinidumpFileName( processName, mdmpFileName, sizeof( mdmpFileName ));
|
||||
|
||||
SetLastError( NOERROR );
|
||||
HANDLE fileHandle = CreateFile(
|
||||
mdmpFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
|
||||
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
errorCode = HRESULT_FROM_WIN32( GetLastError( ));
|
||||
if( !SUCCEEDED( errorCode )) {
|
||||
CloseHandle( fileHandle );
|
||||
return false;
|
||||
}
|
||||
|
||||
minidumpInfo.ThreadId = GetCurrentThreadId();
|
||||
minidumpInfo.ExceptionPointers = exceptionInfo;
|
||||
minidumpInfo.ClientPointers = FALSE;
|
||||
|
||||
qboolean status = MiniDumpWriteDump(
|
||||
GetCurrentProcess(), GetCurrentProcessId(), fileHandle,
|
||||
minidumpType, &minidumpInfo, NULL, NULL);
|
||||
|
||||
CloseHandle( fileHandle );
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif /* DBGHELP */
|
||||
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER oldFilter;
|
||||
static long _stdcall Sys_Crash( PEXCEPTION_POINTERS pInfo )
|
||||
{
|
||||
// save config
|
||||
if( host.status != HOST_CRASHED )
|
||||
{
|
||||
// check to avoid recursive call
|
||||
host.crashed = true;
|
||||
|
||||
#ifdef XASH_SDL
|
||||
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
|
||||
#endif // XASH_SDL
|
||||
|
||||
#if DBGHELP
|
||||
Sys_StackTrace( pInfo );
|
||||
#else
|
||||
Sys_Warn( "Sys_Crash: call %p at address %p", pInfo->ExceptionRecord->ExceptionAddress, pInfo->ExceptionRecord->ExceptionCode );
|
||||
#endif
|
||||
|
||||
if( host.type == HOST_NORMAL )
|
||||
CL_Crashed(); // tell client about crash
|
||||
else host.status = HOST_CRASHED;
|
||||
|
||||
#if DBGHELP
|
||||
if( Sys_CheckParm( "-minidumps" ))
|
||||
{
|
||||
int minidumpFlags = (
|
||||
MiniDumpWithDataSegs |
|
||||
MiniDumpWithCodeSegs |
|
||||
MiniDumpWithHandleData |
|
||||
MiniDumpWithFullMemory |
|
||||
MiniDumpWithFullMemoryInfo |
|
||||
MiniDumpWithIndirectlyReferencedMemory |
|
||||
MiniDumpWithThreadInfo |
|
||||
MiniDumpWithModuleHeaders);
|
||||
|
||||
if( !Sys_WriteMinidump( pInfo, (MINIDUMP_TYPE)minidumpFlags )) {
|
||||
// fallback method, create minidump with minimal info in it
|
||||
Sys_WriteMinidump( pInfo, MiniDumpWithDataSegs );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if( host_developer.value <= 0 )
|
||||
{
|
||||
// no reason to call debugger in release build - just exit
|
||||
Sys_Quit();
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
// all other states keep unchanged to let debugger find bug
|
||||
Sys_DestroyConsole();
|
||||
}
|
||||
|
||||
if( oldFilter )
|
||||
return oldFilter( pInfo );
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
void Sys_SetupCrashHandler( void )
|
||||
{
|
||||
SetErrorMode( SEM_FAILCRITICALERRORS ); // no abort/retry/fail errors
|
||||
oldFilter = SetUnhandledExceptionFilter( Sys_Crash );
|
||||
}
|
||||
|
||||
void Sys_RestoreCrashHandler( void )
|
||||
{
|
||||
// restore filter
|
||||
if( oldFilter ) SetUnhandledExceptionFilter( oldFilter );
|
||||
}
|
||||
|
||||
#elif XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX
|
||||
// Posix signal handler
|
||||
#ifndef XASH_OPENBSD
|
||||
#include <ucontext.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include <sys/mman.h>
|
||||
#include "library.h"
|
||||
|
||||
#define STACK_BACKTRACE_STR "Stack backtrace:\n"
|
||||
#define STACK_DUMP_STR "Stack dump:\n"
|
||||
|
||||
#define STACK_BACKTRACE_STR_LEN ( sizeof( STACK_BACKTRACE_STR ) - 1 )
|
||||
#define STACK_DUMP_STR_LEN ( sizeof( STACK_DUMP_STR ) - 1 )
|
||||
#define ALIGN( x, y ) (((uintptr_t) ( x ) + (( y ) - 1 )) & ~(( y ) - 1 ))
|
||||
|
||||
static struct sigaction oldFilter;
|
||||
|
||||
static int Sys_PrintFrame( char *buf, int len, int i, void *addr )
|
||||
{
|
||||
Dl_info dlinfo;
|
||||
if( len <= 0 )
|
||||
return 0; // overflow
|
||||
|
||||
if( dladdr( addr, &dlinfo ))
|
||||
{
|
||||
if( dlinfo.dli_sname )
|
||||
return Q_snprintf( buf, len, "%2d: %p <%s+%lu> (%s)\n", i, addr, dlinfo.dli_sname,
|
||||
(unsigned long)addr - (unsigned long)dlinfo.dli_saddr, dlinfo.dli_fname ); // print symbol, module and address
|
||||
|
||||
return Q_snprintf( buf, len, "%2d: %p (%s)\n", i, addr, dlinfo.dli_fname ); // print module and address
|
||||
}
|
||||
|
||||
return Q_snprintf( buf, len, "%2d: %p\n", i, addr ); // print only address
|
||||
}
|
||||
|
||||
static void Sys_Crash( int signal, siginfo_t *si, void *context)
|
||||
{
|
||||
void *pc = NULL, **bp = NULL, **sp = NULL; // this must be set for every OS!
|
||||
char message[8192];
|
||||
int len, logfd, i = 0;
|
||||
|
||||
#if XASH_OPENBSD
|
||||
struct sigcontext *ucontext = (struct sigcontext*)context;
|
||||
#else
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
#endif
|
||||
|
||||
#if XASH_AMD64
|
||||
#if XASH_FREEBSD
|
||||
pc = (void*)ucontext->uc_mcontext.mc_rip;
|
||||
bp = (void**)ucontext->uc_mcontext.mc_rbp;
|
||||
sp = (void**)ucontext->uc_mcontext.mc_rsp;
|
||||
#elif XASH_NETBSD
|
||||
pc = (void*)ucontext->uc_mcontext.__gregs[_REG_RIP];
|
||||
bp = (void**)ucontext->uc_mcontext.__gregs[_REG_RBP];
|
||||
sp = (void**)ucontext->uc_mcontext.__gregs[_REG_RSP];
|
||||
#elif XASH_OPENBSD
|
||||
pc = (void*)ucontext->sc_rip;
|
||||
bp = (void**)ucontext->sc_rbp;
|
||||
sp = (void**)ucontext->sc_rsp;
|
||||
#else
|
||||
pc = (void*)ucontext->uc_mcontext.gregs[REG_RIP];
|
||||
bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];
|
||||
sp = (void**)ucontext->uc_mcontext.gregs[REG_RSP];
|
||||
#endif
|
||||
#elif XASH_X86
|
||||
#if XASH_FREEBSD
|
||||
pc = (void*)ucontext->uc_mcontext.mc_eip;
|
||||
bp = (void**)ucontext->uc_mcontext.mc_ebp;
|
||||
sp = (void**)ucontext->uc_mcontext.mc_esp;
|
||||
#elif XASH_NETBSD
|
||||
pc = (void*)ucontext->uc_mcontext.__gregs[_REG_EIP];
|
||||
bp = (void**)ucontext->uc_mcontext.__gregs[_REG_EBP];
|
||||
sp = (void**)ucontext->uc_mcontext.__gregs[_REG_ESP];
|
||||
#elif XASH_OPENBSD
|
||||
pc = (void*)ucontext->sc_eip;
|
||||
bp = (void**)ucontext->sc_ebp;
|
||||
sp = (void**)ucontext->sc_esp;
|
||||
#else
|
||||
pc = (void*)ucontext->uc_mcontext.gregs[REG_EIP];
|
||||
bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];
|
||||
sp = (void**)ucontext->uc_mcontext.gregs[REG_ESP];
|
||||
#endif
|
||||
#elif XASH_ARM && XASH_64BIT
|
||||
pc = (void*)ucontext->uc_mcontext.pc;
|
||||
bp = (void*)ucontext->uc_mcontext.regs[29];
|
||||
sp = (void*)ucontext->uc_mcontext.sp;
|
||||
#elif XASH_ARM
|
||||
pc = (void*)ucontext->uc_mcontext.arm_pc;
|
||||
bp = (void*)ucontext->uc_mcontext.arm_fp;
|
||||
sp = (void*)ucontext->uc_mcontext.arm_sp;
|
||||
#endif
|
||||
|
||||
// safe actions first, stack and memory may be corrupted
|
||||
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n",
|
||||
Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch() );
|
||||
|
||||
#if !XASH_FREEBSD && !XASH_NETBSD && !XASH_OPENBSD
|
||||
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p %p\n", signal, si->si_errno, si->si_code, si->si_addr, si->si_ptr );
|
||||
#else
|
||||
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p\n", signal, si->si_errno, si->si_code, si->si_addr );
|
||||
#endif
|
||||
|
||||
write( STDERR_FILENO, message, len );
|
||||
|
||||
// flush buffers before writing directly to descriptors
|
||||
fflush( stdout );
|
||||
fflush( stderr );
|
||||
|
||||
// now get log fd and write trace directly to log
|
||||
logfd = Sys_LogFileNo();
|
||||
write( logfd, message, len );
|
||||
|
||||
if( pc && bp && sp )
|
||||
{
|
||||
size_t pagesize = sysconf( _SC_PAGESIZE );
|
||||
|
||||
// try to print backtrace
|
||||
write( STDERR_FILENO, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN );
|
||||
write( logfd, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN );
|
||||
Q_strncpy( message + len, STACK_BACKTRACE_STR, sizeof( message ) - len );
|
||||
len += STACK_BACKTRACE_STR_LEN;
|
||||
|
||||
// false on success, true on failure
|
||||
#define try_allow_read(pointer, pagesize) \
|
||||
((mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_WRITE | PROT_EXEC ) == -1) && \
|
||||
( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_EXEC ) == -1) && \
|
||||
( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_WRITE ) == -1) && \
|
||||
( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ ) == -1))
|
||||
|
||||
do
|
||||
{
|
||||
int line = Sys_PrintFrame( message + len, sizeof( message ) - len, ++i, pc);
|
||||
write( STDERR_FILENO, message + len, line );
|
||||
write( logfd, message + len, line );
|
||||
len += line;
|
||||
//if( !dladdr(bp,0) ) break; // only when bp is in module
|
||||
if( try_allow_read( bp, pagesize ) )
|
||||
break;
|
||||
if( try_allow_read( bp[0], pagesize ) )
|
||||
break;
|
||||
pc = bp[1];
|
||||
bp = (void**)bp[0];
|
||||
}
|
||||
while( bp && i < 128 );
|
||||
|
||||
// try to print stack
|
||||
write( STDERR_FILENO, STACK_DUMP_STR, STACK_DUMP_STR_LEN );
|
||||
write( logfd, STACK_DUMP_STR, STACK_DUMP_STR_LEN );
|
||||
Q_strncpy( message + len, STACK_DUMP_STR, sizeof( message ) - len );
|
||||
len += STACK_DUMP_STR_LEN;
|
||||
|
||||
if( !try_allow_read( sp, pagesize ) )
|
||||
{
|
||||
for( i = 0; i < 32; i++ )
|
||||
{
|
||||
int line = Sys_PrintFrame( message + len, sizeof( message ) - len, i, sp[i] );
|
||||
write( STDERR_FILENO, message + len, line );
|
||||
write( logfd, message + len, line );
|
||||
len += line;
|
||||
}
|
||||
}
|
||||
|
||||
#undef try_allow_read
|
||||
}
|
||||
|
||||
// put MessageBox as Sys_Error
|
||||
Msg( "%s\n", message );
|
||||
#ifdef XASH_SDL
|
||||
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
|
||||
#endif
|
||||
host.crashed = true;
|
||||
Platform_MessageBox( "Xash Error", message, false );
|
||||
|
||||
// log saved, now we can try to save configs and close log correctly, it may crash
|
||||
if( host.type == HOST_NORMAL )
|
||||
CL_Crashed();
|
||||
host.status = HOST_CRASHED;
|
||||
|
||||
|
||||
Sys_Quit();
|
||||
}
|
||||
|
||||
void Sys_SetupCrashHandler( void )
|
||||
{
|
||||
struct sigaction act = { 0 };
|
||||
act.sa_sigaction = Sys_Crash;
|
||||
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
sigaction( SIGSEGV, &act, &oldFilter );
|
||||
sigaction( SIGABRT, &act, &oldFilter );
|
||||
sigaction( SIGBUS, &act, &oldFilter );
|
||||
sigaction( SIGILL, &act, &oldFilter );
|
||||
}
|
||||
|
||||
void Sys_RestoreCrashHandler( void )
|
||||
{
|
||||
sigaction( SIGSEGV, &oldFilter, NULL );
|
||||
sigaction( SIGABRT, &oldFilter, NULL );
|
||||
sigaction( SIGBUS, &oldFilter, NULL );
|
||||
sigaction( SIGILL, &oldFilter, NULL );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void Sys_SetupCrashHandler( void )
|
||||
{
|
||||
// stub
|
||||
}
|
||||
|
||||
void Sys_RestoreCrashHandler( void )
|
||||
{
|
||||
// stub
|
||||
}
|
||||
#endif
|
||||
@@ -19,6 +19,7 @@ GNU General Public License for more details.
|
||||
#include "eiface.h" // ARRAYSIZE
|
||||
|
||||
static convar_t *cvar_vars = NULL; // head of list
|
||||
static poolhandle_t cvar_pool;
|
||||
CVAR_DEFINE_AUTO( cmd_scripting, "0", FCVAR_ARCHIVE|FCVAR_PRIVILEGED, "enable simple condition checking and variable operations" );
|
||||
|
||||
typedef struct cvar_filter_quirks_s
|
||||
@@ -432,7 +433,7 @@ convar_t *Cvar_Get( const char *name, const char *value, int flags, const char *
|
||||
{
|
||||
// directly set value
|
||||
freestring( var->string );
|
||||
var->string = copystring( value );
|
||||
var->string = copystringpool( cvar_pool, value );
|
||||
var->value = Q_atof( var->string );
|
||||
SetBits( var->flags, flags );
|
||||
|
||||
@@ -452,18 +453,18 @@ convar_t *Cvar_Get( const char *name, const char *value, int flags, const char *
|
||||
Con_Reportf( "%s change description from %s to %s\n", var->name, var->desc, var_desc );
|
||||
// update description if needs
|
||||
freestring( var->desc );
|
||||
var->desc = copystring( var_desc );
|
||||
var->desc = copystringpool( cvar_pool, var_desc );
|
||||
}
|
||||
|
||||
return var;
|
||||
}
|
||||
|
||||
// allocate a new cvar
|
||||
var = Z_Malloc( sizeof( *var ));
|
||||
var->name = copystring( name );
|
||||
var->string = copystring( value );
|
||||
var->def_string = copystring( value );
|
||||
var->desc = copystring( var_desc );
|
||||
var = Mem_Malloc( cvar_pool, sizeof( *var ));
|
||||
var->name = copystringpool( cvar_pool, name );
|
||||
var->string = copystringpool( cvar_pool, value );
|
||||
var->def_string = copystringpool( cvar_pool, value );
|
||||
var->desc = copystringpool( cvar_pool, var_desc );
|
||||
var->value = Q_atof( var->string );
|
||||
var->flags = flags|FCVAR_ALLOCATED;
|
||||
|
||||
@@ -549,7 +550,7 @@ void Cvar_RegisterVariable( convar_t *var )
|
||||
if( FBitSet( var->flags, FCVAR_EXTENDED ))
|
||||
var->def_string = var->string; // just swap pointers
|
||||
|
||||
var->string = copystring( var->string );
|
||||
var->string = copystringpool( cvar_pool, var->string );
|
||||
var->value = Q_atof( var->string );
|
||||
|
||||
// find the supposed position in chain (alphanumerical order)
|
||||
@@ -679,7 +680,7 @@ static convar_t *Cvar_Set2( const char *var_name, const char *value )
|
||||
|
||||
// and finally changed the cvar itself
|
||||
freestring( var->string );
|
||||
var->string = copystring( pszValue );
|
||||
var->string = copystringpool( cvar_pool, pszValue );
|
||||
var->value = Q_atof( var->string );
|
||||
|
||||
// tell engine about changes
|
||||
@@ -738,7 +739,7 @@ void GAME_EXPORT Cvar_DirectSet( convar_t *var, const char *value )
|
||||
|
||||
// and finally changed the cvar itself
|
||||
freestring( var->string );
|
||||
var->string = copystring( pszValue );
|
||||
var->string = copystringpool( cvar_pool, pszValue );
|
||||
var->value = Q_atof( var->string );
|
||||
|
||||
// tell engine about changes
|
||||
@@ -781,7 +782,7 @@ void Cvar_FullSet( const char *var_name, const char *value, int flags )
|
||||
}
|
||||
|
||||
freestring( var->string );
|
||||
var->string = copystring( value );
|
||||
var->string = copystringpool( cvar_pool, value );
|
||||
var->value = Q_atof( var->string );
|
||||
SetBits( var->flags, flags );
|
||||
|
||||
@@ -1189,6 +1190,7 @@ static void Cvar_List_f( void )
|
||||
for( var = cvar_vars; var; var = var->next )
|
||||
{
|
||||
char value[MAX_VA_STRING];
|
||||
char *p;
|
||||
|
||||
if( var->name[0] == '@' )
|
||||
continue; // never shows system cvars
|
||||
@@ -1196,7 +1198,9 @@ static void Cvar_List_f( void )
|
||||
if( match && !Q_strnicmpext( match, var->name, matchlen ))
|
||||
continue;
|
||||
|
||||
if( Q_colorstr( var->string ))
|
||||
p = Q_strchr( var->string, '^' );
|
||||
|
||||
if( IsColorString( p ))
|
||||
Q_snprintf( value, sizeof( value ), "\"%s\"", var->string );
|
||||
else Q_snprintf( value, sizeof( value ), "\"^2%s^7\"", var->string );
|
||||
|
||||
@@ -1257,7 +1261,7 @@ pending_cvar_t *Cvar_PrepareToUnlink( int group )
|
||||
continue;
|
||||
|
||||
namelen = Q_strlen( cv->name ) + 1;
|
||||
p = Mem_Malloc( host.mempool, sizeof( *list ) + namelen );
|
||||
p = Mem_Malloc( cvar_pool, sizeof( *list ) + namelen );
|
||||
p->next = NULL;
|
||||
p->cv_cur = cv;
|
||||
p->cv_next = cv->next;
|
||||
@@ -1333,6 +1337,7 @@ Reads in all archived cvars
|
||||
*/
|
||||
void Cvar_Init( void )
|
||||
{
|
||||
cvar_pool = Mem_AllocPool( "Console Variables" );
|
||||
cvar_vars = NULL;
|
||||
cvar_active_filter_quirks = NULL;
|
||||
Cvar_RegisterVariable( &cmd_scripting );
|
||||
@@ -1345,6 +1350,11 @@ void Cvar_Init( void )
|
||||
Cmd_AddCommand( "cvarlist", Cvar_List_f, "display all console variables beginning with the specified prefix" );
|
||||
}
|
||||
|
||||
void Cvar_Shutdown( void )
|
||||
{
|
||||
Mem_FreePool( &cvar_pool );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cvar_PostFSInit
|
||||
|
||||
@@ -30,6 +30,8 @@ typedef struct pending_cvar_s
|
||||
char cv_name[];
|
||||
} pending_cvar_t;
|
||||
|
||||
typedef void (*setpair_t)( const char *key, const void *value, const void *buffer, void *numpairs );
|
||||
|
||||
cvar_t *Cvar_GetList( void );
|
||||
#define Cvar_FindVar( name ) Cvar_FindVarExt( name, 0 )
|
||||
convar_t *Cvar_FindVarExt( const char *var_name, int ignore_group );
|
||||
@@ -52,6 +54,7 @@ void Cvar_Reset( const char *var_name );
|
||||
void Cvar_SetCheatState( void );
|
||||
qboolean Cvar_CommandWithPrivilegeCheck( convar_t *v, qboolean isPrivileged );
|
||||
void Cvar_Init( void );
|
||||
void Cvar_Shutdown( void );
|
||||
void Cvar_PostFSInit( void );
|
||||
void Cvar_Unlink( int group );
|
||||
|
||||
|
||||
@@ -49,52 +49,6 @@ const char *CL_MsgInfo( int cmd )
|
||||
return sz;
|
||||
}
|
||||
|
||||
int GAME_EXPORT CL_Active( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean CL_Initialized( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean CL_IsInGame( void )
|
||||
{
|
||||
return true; // always active for dedicated servers
|
||||
}
|
||||
|
||||
qboolean CL_IsInConsole( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean CL_IsIntermission( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean CL_IsPlaybackDemo( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean CL_IsRecordDemo( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
qboolean CL_DisableVisibility( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void CL_Init( void )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Key_Init( void )
|
||||
{
|
||||
|
||||
@@ -130,16 +84,6 @@ void CL_WriteMessageHistory( void )
|
||||
|
||||
}
|
||||
|
||||
void Host_ClientBegin( void )
|
||||
{
|
||||
Cbuf_Execute();
|
||||
}
|
||||
|
||||
void Host_ClientFrame( void )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void Host_InputFrame( void )
|
||||
{
|
||||
}
|
||||
@@ -159,11 +103,6 @@ void GAME_EXPORT S_StopSound(int entnum, int channel, const char *soundname)
|
||||
|
||||
}
|
||||
|
||||
int GAME_EXPORT CL_GetMaxClients( void )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void IN_TouchInitConfig( void )
|
||||
{
|
||||
|
||||
@@ -174,11 +113,6 @@ void CL_Disconnect( void )
|
||||
|
||||
}
|
||||
|
||||
void CL_Shutdown( void )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void R_ClearStaticEntities( void )
|
||||
{
|
||||
|
||||
@@ -189,11 +123,6 @@ void Host_Credits( void )
|
||||
|
||||
}
|
||||
|
||||
qboolean UI_CreditsActive( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void S_StopBackgroundTrack( void )
|
||||
{
|
||||
|
||||
@@ -204,11 +133,6 @@ void SCR_BeginLoadingPlaque( qboolean is_background )
|
||||
|
||||
}
|
||||
|
||||
int S_GetCurrentDynamicSounds( soundlist_t *pout, int size )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void S_StopAllSounds( qboolean ambient )
|
||||
{
|
||||
|
||||
|
||||
@@ -84,6 +84,11 @@ static void FS_Path_f_( void )
|
||||
FS_Path_f();
|
||||
}
|
||||
|
||||
static void FS_MakeGameInfo_f( void )
|
||||
{
|
||||
g_fsapi.MakeGameInfo();
|
||||
}
|
||||
|
||||
static const fs_interface_t fs_memfuncs =
|
||||
{
|
||||
Con_Printf,
|
||||
@@ -178,14 +183,23 @@ static qboolean FS_DetermineRootDirectory( char *out, size_t size )
|
||||
#elif XASH_PSVITA
|
||||
if( PSVita_GetBasePath( out, size ))
|
||||
return true;
|
||||
Sys_Error( "couldn't find Xash3D data directory" );
|
||||
Sys_Error( "couldn't find %s data directory", XASH_ENGINE_NAME );
|
||||
return false;
|
||||
#elif ( XASH_SDL == 2 ) && !XASH_NSWITCH // GetBasePath not impl'd in switch-sdl2
|
||||
path = SDL_GetBasePath();
|
||||
|
||||
#if XASH_APPLE
|
||||
if( path != NULL && Q_stristr( path, ".app" ))
|
||||
{
|
||||
SDL_free((void *)path );
|
||||
path = SDL_GetPrefPath( NULL, XASH_ENGINE_NAME );
|
||||
}
|
||||
#endif
|
||||
|
||||
if( path != NULL )
|
||||
{
|
||||
Q_strncpy( out, path, size );
|
||||
SDL_free(( void *)path );
|
||||
SDL_free((void *)path );
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -272,6 +286,7 @@ void FS_Init( const char *basedir )
|
||||
Cmd_AddRestrictedCommand( "fs_rescan", FS_Rescan_f, "rescan filesystem search pathes" );
|
||||
Cmd_AddRestrictedCommand( "fs_path", FS_Path_f_, "show filesystem search pathes" );
|
||||
Cmd_AddRestrictedCommand( "fs_clearpaths", FS_ClearPaths_f, "clear filesystem search pathes" );
|
||||
Cmd_AddRestrictedCommand( "fs_make_gameinfo", FS_MakeGameInfo_f, "create gameinfo.txt for current running game" );
|
||||
|
||||
if( !Sys_GetParmFromCmdLine( "-dll", host.gamedll ))
|
||||
host.gamedll[0] = 0;
|
||||
|
||||
@@ -43,6 +43,27 @@ GNU General Public License for more details.
|
||||
static pfnChangeGame pChangeGame = NULL;
|
||||
host_parm_t host; // host parms
|
||||
|
||||
#if XASH_ANDROID
|
||||
static jmp_buf return_from_main_buf;
|
||||
|
||||
/*
|
||||
===============
|
||||
Host_ExitInMain
|
||||
|
||||
On some platforms (e.g. Android) we can't exit with exit(3) as calling it would
|
||||
kill wrapper process (e.g. app_process) too early, before all resources would
|
||||
be freed, contexts released, files closed, etc, etc...
|
||||
|
||||
To fix this, we create jmp_buf in Host_Main function, when jumping into with
|
||||
non-zero value will immediately return from it with `error_on_exit`.
|
||||
===============
|
||||
*/
|
||||
void Host_ExitInMain( void )
|
||||
{
|
||||
longjmp( return_from_main_buf, 1 );
|
||||
}
|
||||
#endif // XASH_ANDROID
|
||||
|
||||
#ifdef XASH_ENGINE_TESTS
|
||||
struct tests_stats_s tests_stats;
|
||||
#endif
|
||||
@@ -209,7 +230,7 @@ static void Sys_PrintUsage( const char *exename )
|
||||
fprintf( stderr, usage_str, exename );
|
||||
#endif
|
||||
|
||||
Sys_Quit();
|
||||
Sys_Quit( NULL );
|
||||
}
|
||||
|
||||
static void Sys_PrintBugcompUsage( const char *exename )
|
||||
@@ -234,12 +255,7 @@ static void Sys_PrintBugcompUsage( const char *exename )
|
||||
fprintf( stderr, usage_str, exename );
|
||||
#endif
|
||||
|
||||
Sys_Quit();
|
||||
}
|
||||
|
||||
void Host_ShutdownServer( void )
|
||||
{
|
||||
SV_Shutdown( "Server was killed\n" );
|
||||
Sys_Quit( NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -367,9 +383,8 @@ static void Host_NewInstance( const char *name, const char *finalmsg )
|
||||
if( !pChangeGame ) return;
|
||||
|
||||
host.change_game = true;
|
||||
Q_strncpy( host.finalmsg, finalmsg, sizeof( host.finalmsg ));
|
||||
|
||||
if( !Sys_NewInstance( name ))
|
||||
if( !Sys_NewInstance( name, finalmsg ))
|
||||
pChangeGame( name ); // call from hl.exe
|
||||
}
|
||||
|
||||
@@ -423,8 +438,7 @@ static void Host_Exec_f( void )
|
||||
{
|
||||
string cfgpath;
|
||||
byte *f;
|
||||
char *txt;
|
||||
fs_offset_t len;
|
||||
fs_offset_t len;
|
||||
|
||||
if( Cmd_Argc() != 2 )
|
||||
{
|
||||
@@ -479,20 +493,29 @@ static void Host_Exec_f( void )
|
||||
return;
|
||||
}
|
||||
|
||||
// len is fs_offset_t, which can be larger than size_t
|
||||
if( len >= SIZE_MAX )
|
||||
{
|
||||
Con_Reportf( "%s: %s is too long\n", __func__, Cmd_Argv( 1 ));
|
||||
return;
|
||||
}
|
||||
|
||||
if( !Q_stricmp( "config.cfg", cfgpath ))
|
||||
host.config_executed = true;
|
||||
|
||||
// adds \n\0 at end of the file
|
||||
txt = Z_Calloc( len + 2 );
|
||||
memcpy( txt, f, len );
|
||||
txt[len] = '\n';
|
||||
txt[len + 1] = '\0';
|
||||
Mem_Free( f );
|
||||
|
||||
if( !host.apply_game_config )
|
||||
Con_Printf( "execing %s\n", Cmd_Argv( 1 ));
|
||||
Cbuf_InsertText( txt );
|
||||
Mem_Free( txt );
|
||||
|
||||
// adds \n at end of the file
|
||||
// FS_LoadFile always null terminates
|
||||
if( f[len - 1] != '\n' )
|
||||
{
|
||||
Cbuf_InsertTextLen( f, len, len + 1 );
|
||||
Cbuf_InsertTextLen( "\n", 1, 1 );
|
||||
}
|
||||
else Cbuf_InsertTextLen( f, len, len );
|
||||
|
||||
Mem_Free( f );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -595,7 +618,7 @@ static void Host_GetCommands( void )
|
||||
{
|
||||
char *cmd;
|
||||
|
||||
while( ( cmd = Sys_Input() ) )
|
||||
while( ( cmd = Platform_Input() ) )
|
||||
{
|
||||
Cbuf_AddText( cmd );
|
||||
Cbuf_Execute();
|
||||
@@ -814,11 +837,11 @@ void GAME_EXPORT Host_Error( const char *error, ... )
|
||||
}
|
||||
else
|
||||
{
|
||||
Con_Printf( "%s: %s", __func__, hosterror1 );
|
||||
if( host.allow_console )
|
||||
{
|
||||
UI_SetActiveMenu( false );
|
||||
Key_SetKeyDest( key_console );
|
||||
Con_Printf( "%s: %s", __func__, hosterror1 );
|
||||
}
|
||||
else Platform_MessageBox( "Host Error", hosterror1, true );
|
||||
}
|
||||
@@ -835,13 +858,12 @@ void GAME_EXPORT Host_Error( const char *error, ... )
|
||||
recursive = true;
|
||||
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 );
|
||||
|
||||
// clearing cmd buffer to prevent execute any commands
|
||||
COM_InitHostState();
|
||||
Cbuf_Clear();
|
||||
|
||||
Host_ShutdownServer();
|
||||
SV_Shutdown( "Server was killed due to an error\n" );
|
||||
CL_Drop(); // drop clients
|
||||
|
||||
// recreate world if needs
|
||||
@@ -920,7 +942,7 @@ static void Host_RunTests( int stage )
|
||||
#endif
|
||||
Msg( "Done! %d passed, %d failed\n", tests_stats.passed, tests_stats.failed );
|
||||
error_on_exit = tests_stats.failed > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
Sys_Quit();
|
||||
Sys_Quit( NULL );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1109,7 +1131,7 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
|
||||
#if XASH_DEDICATED
|
||||
Platform_SetupSigtermHandling();
|
||||
#endif
|
||||
Platform_Init( Host_IsDedicated( ) || developer >= DEV_EXTENDED );
|
||||
Platform_Init( Host_IsDedicated( ) || developer >= DEV_EXTENDED, basedir );
|
||||
FS_Init( basedir );
|
||||
|
||||
Sys_InitLog();
|
||||
@@ -1167,6 +1189,11 @@ static void Host_FreeCommon( void )
|
||||
FS_Shutdown();
|
||||
}
|
||||
|
||||
static void Sys_Quit_f( void )
|
||||
{
|
||||
Sys_Quit( "command" );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Host_Main
|
||||
@@ -1206,7 +1233,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||
|
||||
Cvar_Getf( "buildnum", FCVAR_READ_ONLY, "returns a current build number", "%i", Q_buildnum_compat());
|
||||
Cvar_Getf( "ver", FCVAR_READ_ONLY, "shows an engine version", "%i/%s (hw build %i)", PROTOCOL_VERSION, XASH_COMPAT_VERSION, Q_buildnum_compat());
|
||||
Cvar_Getf( "host_ver", FCVAR_READ_ONLY, "detailed info about this build", "%i " XASH_VERSION " %s %s %s", Q_buildnum(), Q_buildos(), Q_buildarch(), Q_buildcommit());
|
||||
Cvar_Getf( "host_ver", FCVAR_READ_ONLY, "detailed info about this build", "%i " XASH_VERSION " %s %s %s", Q_buildnum(), Q_buildos(), Q_buildarch(), g_buildcommit);
|
||||
Cvar_Getf( "host_lowmemorymode", FCVAR_READ_ONLY, "indicates if engine compiled for low RAM consumption (0 - normal, 1 - low engine limits, 2 - low protocol limits)", "%i", XASH_LOW_MEMORY );
|
||||
|
||||
Mod_Init();
|
||||
@@ -1229,7 +1256,6 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||
CL_Init();
|
||||
|
||||
HTTP_Init();
|
||||
ID_Init();
|
||||
SoundList_Init();
|
||||
|
||||
if( Host_IsDedicated( ))
|
||||
@@ -1241,8 +1267,8 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||
// disable texture replacements for dedicated
|
||||
Cvar_FullSet( "host_allow_materials", "0", FCVAR_READ_ONLY );
|
||||
|
||||
Cmd_AddRestrictedCommand( "quit", Sys_Quit, "quit the game" );
|
||||
Cmd_AddRestrictedCommand( "exit", Sys_Quit, "quit the game" );
|
||||
Cmd_AddRestrictedCommand( "quit", Sys_Quit_f, "quit the game" );
|
||||
Cmd_AddRestrictedCommand( "exit", Sys_Quit_f, "quit the game" );
|
||||
}
|
||||
else Cmd_AddRestrictedCommand( "minimize", Host_Minimize_f, "minimize main window to tray" );
|
||||
|
||||
@@ -1313,6 +1339,11 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||
// check after all configs were executed
|
||||
HPAK_CheckIntegrity( hpk_custom_file.string );
|
||||
|
||||
#if XASH_ANDROID
|
||||
if( setjmp( return_from_main_buf ))
|
||||
return error_on_exit;
|
||||
#endif // XASH_ANDROID
|
||||
|
||||
// main window message loop
|
||||
while( !host.crashed )
|
||||
{
|
||||
@@ -1325,20 +1356,31 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||
return 0;
|
||||
}
|
||||
|
||||
void EXPORT Host_Shutdown( void );
|
||||
void EXPORT Host_Shutdown( void )
|
||||
{
|
||||
Host_ShutdownWithReason( "launcher shutdown" );
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Host_Shutdown
|
||||
=================
|
||||
*/
|
||||
void EXPORT Host_Shutdown( void )
|
||||
void Host_ShutdownWithReason( const char *reason )
|
||||
{
|
||||
qboolean error = host.status == HOST_ERR_FATAL;
|
||||
|
||||
if( host.shutdown_issued ) return;
|
||||
if( host.shutdown_issued )
|
||||
return;
|
||||
|
||||
host.shutdown_issued = true;
|
||||
|
||||
if( host.status != HOST_ERR_FATAL ) host.status = HOST_SHUTDOWN; // prepare host to normal shutdown
|
||||
if( !host.change_game ) Q_strncpy( host.finalmsg, "Server shutdown", sizeof( host.finalmsg ));
|
||||
if( reason != NULL )
|
||||
Con_Printf( S_NOTE "Issuing host shutdown due to reason \"%s\"\n", reason );
|
||||
|
||||
if( host.status != HOST_ERR_FATAL )
|
||||
host.status = HOST_SHUTDOWN; // prepare host to normal shutdown
|
||||
|
||||
#if !XASH_DEDICATED
|
||||
if( host.type == HOST_NORMAL && !error )
|
||||
@@ -1357,10 +1399,14 @@ void EXPORT Host_Shutdown( void )
|
||||
Host_FreeCommon();
|
||||
Platform_Shutdown();
|
||||
|
||||
BaseCmd_Shutdown();
|
||||
Cmd_Shutdown();
|
||||
Cvar_Shutdown();
|
||||
|
||||
// must be last, console uses this
|
||||
Mem_FreePool( &host.mempool );
|
||||
|
||||
// restore filter
|
||||
Sys_RestoreCrashHandler();
|
||||
Sys_CloseLog();
|
||||
Sys_CloseLog( reason );
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ static void HPAK_MaxSize_f( void )
|
||||
Con_Printf( S_ERROR "hpk_maxsize is deprecated, use hpk_max_size\n" );
|
||||
}
|
||||
|
||||
static const char *HPAK_TypeFromIndex( int type )
|
||||
const char *COM_ResourceTypeFromIndex( int type )
|
||||
{
|
||||
switch( type )
|
||||
{
|
||||
@@ -104,7 +104,7 @@ static void HPAK_CreatePak( const char *filename, resource_t *pResource, byte *p
|
||||
string pakname;
|
||||
byte md5[16];
|
||||
file_t *fout;
|
||||
MD5Context_t ctx;
|
||||
MD5Context_t ctx = { 0 };
|
||||
|
||||
if( !COM_CheckString( filename ))
|
||||
return;
|
||||
@@ -125,7 +125,6 @@ static void HPAK_CreatePak( const char *filename, resource_t *pResource, byte *p
|
||||
}
|
||||
|
||||
// let's hash it.
|
||||
memset( &ctx, 0, sizeof( MD5Context_t ));
|
||||
MD5Init( &ctx );
|
||||
|
||||
if( pData == NULL )
|
||||
@@ -214,7 +213,7 @@ void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource,
|
||||
file_t *file_src;
|
||||
file_t *file_dst;
|
||||
byte md5[16];
|
||||
MD5Context_t ctx;
|
||||
MD5Context_t ctx = { 0 };
|
||||
|
||||
if( pData == NULL && pFile == NULL )
|
||||
return;
|
||||
@@ -226,7 +225,6 @@ void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource,
|
||||
}
|
||||
|
||||
// hash it
|
||||
memset( &ctx, 0, sizeof( MD5Context_t ));
|
||||
MD5Init( &ctx );
|
||||
|
||||
if( !pData )
|
||||
@@ -463,7 +461,7 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet, qboolean de
|
||||
|
||||
if( !quiet )
|
||||
{
|
||||
Con_Printf( "%i: %s %s %s: ", i, HPAK_TypeFromIndex( pRes->type ),
|
||||
Con_Printf( "%i: %s %s %s: ", i, COM_ResourceTypeFromIndex( pRes->type ),
|
||||
Q_pretifymem( pRes->nDownloadSize, 2 ), pRes->szFileName );
|
||||
}
|
||||
|
||||
@@ -944,7 +942,7 @@ static void HPAK_List_f( void )
|
||||
{
|
||||
entry = &directory.entries[nCurrent];
|
||||
COM_FileBase( entry->resource.szFileName, lumpname, sizeof( lumpname ));
|
||||
type = HPAK_TypeFromIndex( entry->resource.type );
|
||||
type = COM_ResourceTypeFromIndex( entry->resource.type );
|
||||
size = Q_memprint( entry->resource.nDownloadSize );
|
||||
|
||||
Con_Printf( "%i: %10s %s %s\n : %s\n", nCurrent + 1, type, size, lumpname, MD5_Print( entry->resource.rgucMD5_hash ));
|
||||
@@ -1039,7 +1037,7 @@ static void HPAK_Extract_f( void )
|
||||
continue;
|
||||
|
||||
COM_FileBase( entry->resource.szFileName, lumpname, sizeof( lumpname ) );
|
||||
type = HPAK_TypeFromIndex( entry->resource.type );
|
||||
type = COM_ResourceTypeFromIndex( entry->resource.type );
|
||||
size = Q_memprint( entry->resource.nDownloadSize );
|
||||
|
||||
Con_Printf( "Extracting %i: %10s %s %s\n", nCurrent + 1, type, size, lumpname );
|
||||
|
||||
@@ -15,6 +15,7 @@ GNU General Public License for more details.
|
||||
|
||||
#include <math.h>
|
||||
#include "imagelib.h"
|
||||
#include "eiface.h" // ARRAYSIZE
|
||||
|
||||
// global image variables
|
||||
imglib_t image;
|
||||
@@ -67,7 +68,6 @@ static const cubepack_t load_cubemap[] =
|
||||
{ "3Ds Sky1", skybox_qv1 },
|
||||
{ "3Ds Sky2", skybox_qv2 },
|
||||
{ "3Ds Cube", cubemap_v1 },
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
// soul of ImageLib - table of image format constants
|
||||
@@ -297,9 +297,8 @@ rgbdata_t *FS_LoadImage( const char *filename, const byte *buffer, size_t size )
|
||||
{
|
||||
const char *ext = COM_FileExtension( filename );
|
||||
string loadname;
|
||||
int i;
|
||||
int i, j;
|
||||
const loadpixformat_t *extfmt;
|
||||
const cubepack_t *cmap;
|
||||
|
||||
Q_strncpy( loadname, filename, sizeof( loadname ));
|
||||
Image_Reset(); // clear old image
|
||||
@@ -317,8 +316,10 @@ rgbdata_t *FS_LoadImage( const char *filename, const byte *buffer, size_t size )
|
||||
return ImagePack();
|
||||
|
||||
// check all cubemap sides with package suffix
|
||||
for( cmap = load_cubemap; cmap && cmap->type; cmap++ )
|
||||
for( j = 0; j < ARRAYSIZE( load_cubemap ); j++ )
|
||||
{
|
||||
const cubepack_t *cmap = &load_cubemap[j];
|
||||
|
||||
for( i = 0; i < 6; i++ )
|
||||
{
|
||||
if( Image_ProbeLoad( extfmt, loadname, cmap->type[i].suf, cmap->type[i].hint ))
|
||||
|
||||
@@ -28,12 +28,20 @@ Image_LoadPAL
|
||||
qboolean Image_LoadPAL( const char *name, const byte *buffer, fs_offset_t filesize )
|
||||
{
|
||||
int rendermode = LUMP_NORMAL;
|
||||
byte pal[768];
|
||||
|
||||
if( filesize != 768 )
|
||||
if( filesize > sizeof( pal ))
|
||||
{
|
||||
Con_DPrintf( S_ERROR "%s: (%s) have invalid size (%li should be %d)\n", __func__, name, (long)filesize, 768 );
|
||||
Con_DPrintf( S_ERROR "%s: (%s) have invalid size (%li should be less or equal than %d)\n", __func__, name, (long)filesize, sizeof( pal ));
|
||||
return false;
|
||||
}
|
||||
else if( filesize < sizeof( pal ) && buffer != NULL )
|
||||
{
|
||||
// palette might be truncated, fill it with zeros
|
||||
memset( pal, 0, sizeof( pal ));
|
||||
memcpy( pal, buffer, filesize );
|
||||
buffer = pal;
|
||||
}
|
||||
|
||||
if( name[0] == '#' )
|
||||
{
|
||||
|
||||
@@ -37,11 +37,7 @@ static char **szArgv;
|
||||
|
||||
static void Sys_ChangeGame( const char *progname )
|
||||
{
|
||||
// a1ba: may never be called within engine
|
||||
// if platform supports execv() function
|
||||
Q_strncpy( szGameDir, progname, sizeof( szGameDir ));
|
||||
Host_Shutdown( );
|
||||
exit( Host_Main( szArgc, szArgv, szGameDir, 1, &Sys_ChangeGame ) );
|
||||
// stub
|
||||
}
|
||||
|
||||
static int Sys_Start( void )
|
||||
|
||||
@@ -385,10 +385,7 @@ void NET_SaveMasters( void )
|
||||
master_t *m;
|
||||
|
||||
if( !ml.modified )
|
||||
{
|
||||
Con_Reportf( "Master server list not changed\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
f = FS_Open( "xashcomm.lst", "w", true );
|
||||
|
||||
|
||||
@@ -385,6 +385,35 @@ static const mlumpinfo_t extlumps[EXTRA_LUMPS] =
|
||||
},
|
||||
};
|
||||
|
||||
#define BOX_CLIPNODES_INITIALIZER \
|
||||
{ \
|
||||
.planenum = 0, \
|
||||
.children = { CONTENTS_EMPTY, 1 }, \
|
||||
}, \
|
||||
{ \
|
||||
.planenum = 1, \
|
||||
.children = { 2, CONTENTS_EMPTY }, \
|
||||
}, \
|
||||
{ \
|
||||
.planenum = 2, \
|
||||
.children = { CONTENTS_EMPTY, 3 }, \
|
||||
}, \
|
||||
{ \
|
||||
.planenum = 3, \
|
||||
.children = { 4, CONTENTS_EMPTY }, \
|
||||
}, \
|
||||
{ \
|
||||
.planenum = 4, \
|
||||
.children = { CONTENTS_EMPTY, 5 }, \
|
||||
}, \
|
||||
{ \
|
||||
.planenum = 5, \
|
||||
.children = { CONTENTS_SOLID, CONTENTS_EMPTY }, \
|
||||
}, \
|
||||
|
||||
const mclipnode16_t box_clipnodes16[6] = { BOX_CLIPNODES_INITIALIZER };
|
||||
const mclipnode32_t box_clipnodes32[6] = { BOX_CLIPNODES_INITIALIZER };
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
@@ -453,7 +482,7 @@ static int Mod_LoadTextureFromWadList( wadlist_t *list, const char *name, rgbdat
|
||||
return -1;
|
||||
}
|
||||
|
||||
static fs_offset_t Mod_CalculateMipTexSize( mip_t *mt, qboolean palette )
|
||||
static fs_offset_t Mod_CalculateMipTexSize( const mip_t *mt, qboolean palette )
|
||||
{
|
||||
if( !mt )
|
||||
return 0;
|
||||
@@ -856,7 +885,7 @@ Mod_PointInLeaf
|
||||
|
||||
==================
|
||||
*/
|
||||
mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node )
|
||||
mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node, model_t *mod )
|
||||
{
|
||||
Assert( node != NULL );
|
||||
|
||||
@@ -864,7 +893,7 @@ mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node )
|
||||
{
|
||||
if( node->contents < 0 )
|
||||
return (mleaf_t *)node;
|
||||
node = node->children[PlaneDiff( p, node->plane ) <= 0];
|
||||
node = node_child( node, PlaneDiff( p, node->plane ) <= 0, mod );
|
||||
}
|
||||
|
||||
// never reached
|
||||
@@ -885,7 +914,7 @@ byte *Mod_GetPVSForPoint( const vec3_t p )
|
||||
|
||||
ASSERT( worldmodel != NULL );
|
||||
|
||||
leaf = Mod_PointInLeaf( p, worldmodel->nodes );
|
||||
leaf = Mod_PointInLeaf( p, worldmodel->nodes, worldmodel );
|
||||
|
||||
if( leaf && leaf->cluster >= 0 )
|
||||
return Mod_DecompressPVS( leaf->compressed_vis, world.visbytes );
|
||||
@@ -905,14 +934,14 @@ static void Mod_FatPVS_RecursiveBSPNode( const vec3_t org, float radius, byte *v
|
||||
float d = PlaneDiff( org, node->plane );
|
||||
|
||||
if( d > radius )
|
||||
node = node->children[0];
|
||||
node = node_child( node, 0, worldmodel );
|
||||
else if( d < -radius )
|
||||
node = node->children[1];
|
||||
node = node_child( node, 1, worldmodel );
|
||||
else
|
||||
{
|
||||
// go down both sides
|
||||
Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, visbytes, node->children[0], phs );
|
||||
node = node->children[1];
|
||||
Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, visbytes, node_child( node, 0, worldmodel ), phs );
|
||||
node = node_child( node, 1, worldmodel );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -950,7 +979,7 @@ int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, q
|
||||
|
||||
ASSERT( worldmodel != NULL );
|
||||
|
||||
leaf = Mod_PointInLeaf( org, worldmodel->nodes );
|
||||
leaf = Mod_PointInLeaf( org, worldmodel->nodes, worldmodel );
|
||||
bytes = Q_min( bytes, visbytes );
|
||||
|
||||
// enable full visibility for some reasons
|
||||
@@ -1009,20 +1038,16 @@ static void Mod_BoxLeafnums_r( leaflist_t *ll, mnode_t *node )
|
||||
sides = BOX_ON_PLANE_SIDE( ll->mins, ll->maxs, node->plane );
|
||||
|
||||
if( sides == 1 )
|
||||
{
|
||||
node = node->children[0];
|
||||
}
|
||||
node = node_child( node, 0, worldmodel );
|
||||
else if( sides == 2 )
|
||||
{
|
||||
node = node->children[1];
|
||||
}
|
||||
node = node_child( node, 1, worldmodel );
|
||||
else
|
||||
{
|
||||
// go down both
|
||||
if( ll->topnode == -1 )
|
||||
ll->topnode = node - worldmodel->nodes;
|
||||
Mod_BoxLeafnums_r( ll, node->children[0] );
|
||||
node = node->children[1];
|
||||
Mod_BoxLeafnums_r( ll, node_child( node, 0, worldmodel ));
|
||||
node = node_child( node, 1, worldmodel );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1079,35 +1104,6 @@ qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbi
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
Mod_HeadnodeVisible
|
||||
=============
|
||||
*/
|
||||
qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, int *lastleaf )
|
||||
{
|
||||
if( !node || node->contents == CONTENTS_SOLID )
|
||||
return false;
|
||||
|
||||
if( node->contents < 0 )
|
||||
{
|
||||
if( !CHECKVISBIT( visbits, ((mleaf_t *)node)->cluster ))
|
||||
return false;
|
||||
|
||||
if( lastleaf )
|
||||
*lastleaf = ((mleaf_t *)node)->cluster;
|
||||
return true;
|
||||
}
|
||||
|
||||
if( Mod_HeadnodeVisible( node->children[0], visbits, lastleaf ))
|
||||
return true;
|
||||
|
||||
if( Mod_HeadnodeVisible( node->children[1], visbits, lastleaf ))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
Mod_FindModelOrigin
|
||||
@@ -1264,22 +1260,35 @@ Mod_GetFaceContents
|
||||
determine face contents by name
|
||||
==================
|
||||
*/
|
||||
static mvertex_t *Mod_GetVertexByNumber( model_t *mod, int surfedge )
|
||||
static mvertex_t *Mod_GetVertexByNumber( model_t *mod, int surfedge, const dbspmodel_t *bmod )
|
||||
{
|
||||
int lindex;
|
||||
medge_t *edge;
|
||||
int lindex = mod->surfedges[surfedge];
|
||||
|
||||
lindex = mod->surfedges[surfedge];
|
||||
|
||||
if( lindex > 0 )
|
||||
if( bmod->version == QBSP2_VERSION )
|
||||
{
|
||||
edge = &mod->edges[lindex];
|
||||
return &mod->vertexes[edge->v[0]];
|
||||
if( lindex > 0 )
|
||||
{
|
||||
medge32_t *edge = &mod->edges32[lindex];
|
||||
return &mod->vertexes[edge->v[0]];
|
||||
}
|
||||
else
|
||||
{
|
||||
medge32_t *edge = &mod->edges32[-lindex];
|
||||
return &mod->vertexes[edge->v[1]];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
edge = &mod->edges[-lindex];
|
||||
return &mod->vertexes[edge->v[1]];
|
||||
if( lindex > 0 )
|
||||
{
|
||||
medge16_t *edge = &mod->edges16[lindex];
|
||||
return &mod->vertexes[edge->v[0]];
|
||||
}
|
||||
else
|
||||
{
|
||||
medge16_t *edge = &mod->edges16[-lindex];
|
||||
return &mod->vertexes[edge->v[1]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1364,7 +1373,7 @@ Mod_CalcSurfaceExtents
|
||||
Fills in surf->texturemins[] and surf->extents[]
|
||||
=================
|
||||
*/
|
||||
static void Mod_CalcSurfaceExtents( model_t *mod, msurface_t *surf )
|
||||
static void Mod_CalcSurfaceExtents( model_t *mod, msurface_t *surf, const dbspmodel_t *bmod )
|
||||
{
|
||||
// this place is VERY critical to precision
|
||||
// keep it as float, don't use double, because it causes issues with lightmap
|
||||
@@ -1391,8 +1400,16 @@ static void Mod_CalcSurfaceExtents( model_t *mod, msurface_t *surf )
|
||||
if( e >= mod->numedges || e <= -mod->numedges )
|
||||
Host_Error( "%s: bad edge\n", __func__ );
|
||||
|
||||
if( e >= 0 ) v = &mod->vertexes[mod->edges[e].v[0]];
|
||||
else v = &mod->vertexes[mod->edges[-e].v[1]];
|
||||
if( bmod->version == QBSP2_VERSION )
|
||||
{
|
||||
if( e >= 0 ) v = &mod->vertexes[mod->edges32[e].v[0]];
|
||||
else v = &mod->vertexes[mod->edges32[-e].v[1]];
|
||||
}
|
||||
else
|
||||
{
|
||||
if( e >= 0 ) v = &mod->vertexes[mod->edges16[e].v[0]];
|
||||
else v = &mod->vertexes[mod->edges16[-e].v[1]];
|
||||
}
|
||||
|
||||
for( j = 0; j < 2; j++ )
|
||||
{
|
||||
@@ -1446,7 +1463,7 @@ Mod_CalcSurfaceBounds
|
||||
fills in surf->mins and surf->maxs
|
||||
=================
|
||||
*/
|
||||
static void Mod_CalcSurfaceBounds( model_t *mod, msurface_t *surf )
|
||||
static void Mod_CalcSurfaceBounds( model_t *mod, msurface_t *surf, const dbspmodel_t *bmod )
|
||||
{
|
||||
int i, e;
|
||||
mvertex_t *v;
|
||||
@@ -1460,8 +1477,16 @@ static void Mod_CalcSurfaceBounds( model_t *mod, msurface_t *surf )
|
||||
if( e >= mod->numedges || e <= -mod->numedges )
|
||||
Host_Error( "%s: bad edge\n", __func__ );
|
||||
|
||||
if( e >= 0 ) v = &mod->vertexes[mod->edges[e].v[0]];
|
||||
else v = &mod->vertexes[mod->edges[-e].v[1]];
|
||||
if( bmod->version == QBSP2_VERSION )
|
||||
{
|
||||
if( e >= 0 ) v = &mod->vertexes[mod->edges32[e].v[0]];
|
||||
else v = &mod->vertexes[mod->edges32[-e].v[1]];
|
||||
}
|
||||
else
|
||||
{
|
||||
if( e >= 0 ) v = &mod->vertexes[mod->edges16[e].v[0]];
|
||||
else v = &mod->vertexes[mod->edges16[-e].v[1]];
|
||||
}
|
||||
AddPointToBounds( v->position, surf->info->mins, surf->info->maxs );
|
||||
}
|
||||
|
||||
@@ -1473,7 +1498,7 @@ static void Mod_CalcSurfaceBounds( model_t *mod, msurface_t *surf )
|
||||
Mod_CreateFaceBevels
|
||||
=================
|
||||
*/
|
||||
static void Mod_CreateFaceBevels( model_t *mod, msurface_t *surf )
|
||||
static void Mod_CreateFaceBevels( model_t *mod, msurface_t *surf, const dbspmodel_t *bmod )
|
||||
{
|
||||
vec3_t delta, edgevec;
|
||||
byte *facebevel;
|
||||
@@ -1506,8 +1531,8 @@ static void Mod_CreateFaceBevels( model_t *mod, msurface_t *surf )
|
||||
{
|
||||
mplane_t *dest = &fb->edges[i];
|
||||
|
||||
v0 = Mod_GetVertexByNumber( mod, surf->firstedge + i );
|
||||
v1 = Mod_GetVertexByNumber( mod, surf->firstedge + (i + 1) % surf->numedges );
|
||||
v0 = Mod_GetVertexByNumber( mod, surf->firstedge + i, bmod );
|
||||
v1 = Mod_GetVertexByNumber( mod, surf->firstedge + (i + 1) % surf->numedges, bmod );
|
||||
VectorSubtract( v1->position, v0->position, edgevec );
|
||||
CrossProduct( faceNormal, edgevec, dest->normal );
|
||||
VectorNormalize( dest->normal );
|
||||
@@ -1521,7 +1546,7 @@ static void Mod_CreateFaceBevels( model_t *mod, msurface_t *surf )
|
||||
// compute face radius
|
||||
for( i = 0; i < surf->numedges; i++ )
|
||||
{
|
||||
v0 = Mod_GetVertexByNumber( mod, surf->firstedge + i );
|
||||
v0 = Mod_GetVertexByNumber( mod, surf->firstedge + i, bmod );
|
||||
VectorSubtract( v0->position, fb->origin, delta );
|
||||
radius = DotProduct( delta, delta );
|
||||
fb->radius = Q_max( radius, fb->radius );
|
||||
@@ -1533,13 +1558,15 @@ static void Mod_CreateFaceBevels( model_t *mod, msurface_t *surf )
|
||||
Mod_SetParent
|
||||
=================
|
||||
*/
|
||||
static void Mod_SetParent( mnode_t *node, mnode_t *parent )
|
||||
static void Mod_SetParent( model_t *mod, mnode_t *node, mnode_t *parent )
|
||||
{
|
||||
node->parent = parent;
|
||||
|
||||
if( node->contents < 0 ) return; // it's leaf
|
||||
Mod_SetParent( node->children[0], node );
|
||||
Mod_SetParent( node->children[1], node );
|
||||
if( node->contents < 0 )
|
||||
return; // it's leaf
|
||||
|
||||
Mod_SetParent( mod, node_child( node, 0, mod ), node );
|
||||
Mod_SetParent( mod, node_child( node, 1, mod ), node );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1547,7 +1574,7 @@ static void Mod_SetParent( mnode_t *node, mnode_t *parent )
|
||||
CountClipNodes_r
|
||||
==================
|
||||
*/
|
||||
static void CountClipNodes_r( mclipnode_t *src, hull_t *hull, int nodenum )
|
||||
static void CountClipNodes16_r( mclipnode16_t *src, hull_t *hull, int nodenum )
|
||||
{
|
||||
// leaf?
|
||||
if( nodenum < 0 ) return;
|
||||
@@ -1556,16 +1583,11 @@ static void CountClipNodes_r( mclipnode_t *src, hull_t *hull, int nodenum )
|
||||
Host_Error( "MAX_MAP_CLIPNODES limit exceeded\n" );
|
||||
hull->lastclipnode++;
|
||||
|
||||
CountClipNodes_r( src, hull, src[nodenum].children[0] );
|
||||
CountClipNodes_r( src, hull, src[nodenum].children[1] );
|
||||
CountClipNodes16_r( src, hull, src[nodenum].children[0] );
|
||||
CountClipNodes16_r( src, hull, src[nodenum].children[1] );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
CountClipNodes32_r
|
||||
==================
|
||||
*/
|
||||
static void CountClipNodes32_r( dclipnode32_t *src, hull_t *hull, int nodenum )
|
||||
static void CountClipNodes32_r( mclipnode32_t *src, hull_t *hull, int nodenum )
|
||||
{
|
||||
// leaf?
|
||||
if( nodenum < 0 ) return;
|
||||
@@ -1578,15 +1600,27 @@ static void CountClipNodes32_r( dclipnode32_t *src, hull_t *hull, int nodenum )
|
||||
CountClipNodes32_r( src, hull, src[nodenum].children[1] );
|
||||
}
|
||||
|
||||
static void CountDClipNodes_r( dclipnode32_t *src, hull_t *hull, int nodenum )
|
||||
{
|
||||
// leaf?
|
||||
if( nodenum < 0 ) return;
|
||||
|
||||
if( hull->lastclipnode == MAX_MAP_CLIPNODES )
|
||||
Host_Error( "MAX_MAP_CLIPNODES limit exceeded\n" );
|
||||
hull->lastclipnode++;
|
||||
|
||||
CountDClipNodes_r( src, hull, src[nodenum].children[0] );
|
||||
CountDClipNodes_r( src, hull, src[nodenum].children[1] );
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
RemapClipNodes_r
|
||||
==================
|
||||
*/
|
||||
static int RemapClipNodes_r( dclipnode32_t *srcnodes, hull_t *hull, int nodenum )
|
||||
static int RemapClipNodes_r( dbspmodel_t *bmod, dclipnode32_t *srcnodes, hull_t *hull, int nodenum )
|
||||
{
|
||||
dclipnode32_t *src;
|
||||
mclipnode_t *out;
|
||||
dclipnode32_t *src;
|
||||
int i, c;
|
||||
|
||||
// leaf?
|
||||
@@ -1599,13 +1633,22 @@ static int RemapClipNodes_r( dclipnode32_t *srcnodes, hull_t *hull, int nodenum
|
||||
src = srcnodes + nodenum;
|
||||
|
||||
c = hull->lastclipnode;
|
||||
out = &hull->clipnodes[c];
|
||||
hull->lastclipnode++;
|
||||
|
||||
out->planenum = src->planenum;
|
||||
|
||||
for( i = 0; i < 2; i++ )
|
||||
out->children[i] = RemapClipNodes_r( srcnodes, hull, src->children[i] );
|
||||
if( bmod->version == QBSP2_VERSION )
|
||||
{
|
||||
mclipnode32_t *out = &hull->clipnodes32[c];
|
||||
out->planenum = src->planenum;
|
||||
for( i = 0; i < 2; i++ )
|
||||
out->children[i] = RemapClipNodes_r( bmod, srcnodes, hull, src->children[i] );
|
||||
}
|
||||
else
|
||||
{
|
||||
mclipnode16_t *out = &hull->clipnodes16[c];
|
||||
out->planenum = src->planenum;
|
||||
for( i = 0; i < 2; i++ )
|
||||
out->children[i] = RemapClipNodes_r( bmod, srcnodes, hull, src->children[i] );
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
@@ -1617,34 +1660,64 @@ Mod_MakeHull0
|
||||
Duplicate the drawing hull structure as a clipping hull
|
||||
=================
|
||||
*/
|
||||
static void Mod_MakeHull0( model_t *mod )
|
||||
static void Mod_MakeHull0( model_t *mod, const dbspmodel_t *bmod )
|
||||
{
|
||||
mnode_t *in, *child;
|
||||
mclipnode_t *out;
|
||||
hull_t *hull;
|
||||
int i, j;
|
||||
|
||||
hull = &mod->hulls[0];
|
||||
hull->clipnodes = out = Mem_Malloc( mod->mempool, mod->numnodes * sizeof( *out ));
|
||||
in = mod->nodes;
|
||||
hull_t *hull = &mod->hulls[0];
|
||||
int i;
|
||||
|
||||
hull->firstclipnode = 0;
|
||||
hull->lastclipnode = mod->numnodes - 1;
|
||||
hull->planes = mod->planes;
|
||||
|
||||
for( i = 0; i < mod->numnodes; i++, out++, in++ )
|
||||
if( bmod->version == QBSP2_VERSION )
|
||||
{
|
||||
out->planenum = in->plane - mod->planes;
|
||||
mclipnode32_t *out;
|
||||
mnode_t *in = mod->nodes;
|
||||
|
||||
for( j = 0; j < 2; j++ )
|
||||
hull->clipnodes32 = out = Mem_Malloc( mod->mempool, mod->numnodes * sizeof( *hull->clipnodes32 ));
|
||||
|
||||
for( i = 0; i < mod->numnodes; i++, out++, in++ )
|
||||
{
|
||||
child = in->children[j];
|
||||
int j;
|
||||
|
||||
if( child->contents < 0 )
|
||||
out->children[j] = child->contents;
|
||||
else out->children[j] = child - mod->nodes;
|
||||
out->planenum = in->plane - mod->planes;
|
||||
|
||||
for( j = 0; j < 2; j++ )
|
||||
{
|
||||
mnode_t *child = node_child( in, j, mod );
|
||||
|
||||
if( child->contents < 0 )
|
||||
out->children[j] = child->contents;
|
||||
else
|
||||
out->children[j] = child - mod->nodes;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mclipnode16_t *out;
|
||||
mnode_t *in = mod->nodes;
|
||||
|
||||
hull->clipnodes16 = out = Mem_Malloc( mod->mempool, mod->numnodes * sizeof( *hull->clipnodes16 ));
|
||||
|
||||
for( i = 0; i < mod->numnodes; i++, out++, in++ )
|
||||
{
|
||||
int j;
|
||||
|
||||
out->planenum = in->plane - mod->planes;
|
||||
|
||||
for( j = 0; j < 2; j++ )
|
||||
{
|
||||
mnode_t *child = node_child( in, j, mod );
|
||||
|
||||
if( child->contents < 0 )
|
||||
out->children[j] = child->contents;
|
||||
else
|
||||
out->children[j] = child - mod->nodes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1688,15 +1761,18 @@ static void Mod_SetupHull( dbspmodel_t *bmod, model_t *mod, poolhandle_t mempool
|
||||
if( VectorIsNull( hull->clip_mins ) && VectorIsNull( hull->clip_maxs ))
|
||||
return; // no hull specified
|
||||
|
||||
CountClipNodes32_r( bmod->clipnodes_out, hull, headnode );
|
||||
CountDClipNodes_r( bmod->clipnodes_out, hull, headnode );
|
||||
|
||||
// fit array to real count
|
||||
hull->clipnodes = (mclipnode_t *)Mem_Malloc( mempool, sizeof( mclipnode_t ) * hull->lastclipnode );
|
||||
if( bmod->version == QBSP2_VERSION )
|
||||
hull->clipnodes32 = Mem_Malloc( mempool, sizeof( *hull->clipnodes32 ) * hull->lastclipnode );
|
||||
else
|
||||
hull->clipnodes16 = Mem_Malloc( mempool, sizeof( *hull->clipnodes16 ) * hull->lastclipnode );
|
||||
|
||||
hull->planes = mod->planes; // share planes
|
||||
hull->lastclipnode = 0; // restart counting
|
||||
|
||||
// remap clipnodes to 16-bit indexes
|
||||
RemapClipNodes_r( bmod->clipnodes_out, hull, headnode );
|
||||
RemapClipNodes_r( bmod, bmod->clipnodes_out, hull, headnode ); // remap clipnodes to 16-bit indexes
|
||||
}
|
||||
|
||||
static qboolean Mod_LoadLitfile( model_t *mod, const char *ext, size_t expected_size, color24 **out, size_t *outsize )
|
||||
@@ -1704,7 +1780,8 @@ static qboolean Mod_LoadLitfile( model_t *mod, const char *ext, size_t expected_
|
||||
char modelname[64], path[64];
|
||||
int iCompare;
|
||||
fs_offset_t datasize;
|
||||
byte *in;
|
||||
file_t *f;
|
||||
uint hdr[2];
|
||||
|
||||
COM_FileBase( mod->name, modelname, sizeof( modelname ));
|
||||
Q_snprintf( path, sizeof( path ), "maps/%s.%s", modelname, ext );
|
||||
@@ -1715,31 +1792,15 @@ static qboolean Mod_LoadLitfile( model_t *mod, const char *ext, size_t expected_
|
||||
if( iCompare < 0 ) // this may happens if level-designer used -onlyents key for hlcsg
|
||||
Con_Printf( S_WARN "%s probably is out of date\n", path );
|
||||
|
||||
in = FS_LoadFile( path, &datasize, false );
|
||||
f = FS_Open( path, "rb", false );
|
||||
|
||||
if( !in )
|
||||
if( !f )
|
||||
{
|
||||
Con_Printf( S_ERROR "couldn't load %s\n", path );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( datasize <= 8 ) // header + version
|
||||
{
|
||||
Con_Printf( S_ERROR "%s is too short\n", path );
|
||||
goto cleanup_and_error;
|
||||
}
|
||||
|
||||
if( LittleLong( ((uint *)in)[0] ) != IDDELUXEMAPHEADER )
|
||||
{
|
||||
Con_Printf( S_ERROR "%s is corrupted\n", path );
|
||||
goto cleanup_and_error;
|
||||
}
|
||||
|
||||
if( LittleLong( ((uint *)in)[1] ) != DELUXEMAP_VERSION )
|
||||
{
|
||||
Con_Printf( S_ERROR "has %s mismatched version (%u should be %u)\n", path, LittleLong( ((uint *)in)[1] ), DELUXEMAP_VERSION );
|
||||
goto cleanup_and_error;
|
||||
}
|
||||
datasize = FS_FileLength( f );
|
||||
|
||||
// skip header bytes
|
||||
datasize -= 8;
|
||||
@@ -1750,14 +1811,33 @@ static qboolean Mod_LoadLitfile( model_t *mod, const char *ext, size_t expected_
|
||||
goto cleanup_and_error;
|
||||
}
|
||||
|
||||
if( FS_Read( f, hdr, sizeof( hdr )) != sizeof( hdr ))
|
||||
{
|
||||
Con_Printf( S_ERROR "failed reading header from %s\n", path );
|
||||
goto cleanup_and_error;
|
||||
}
|
||||
|
||||
if( LittleLong( hdr[0] ) != IDDELUXEMAPHEADER )
|
||||
{
|
||||
Con_Printf( S_ERROR "%s is corrupted\n", path );
|
||||
goto cleanup_and_error;
|
||||
}
|
||||
|
||||
if( LittleLong( hdr[1] ) != DELUXEMAP_VERSION )
|
||||
{
|
||||
Con_Printf( S_ERROR "has %s mismatched version (%u should be %u)\n", path, LittleLong( hdr[1] ), DELUXEMAP_VERSION );
|
||||
goto cleanup_and_error;
|
||||
}
|
||||
|
||||
*out = Mem_Malloc( mod->mempool, datasize );
|
||||
memcpy( *out, in + 8, datasize );
|
||||
*outsize = datasize;
|
||||
Mem_Free( in );
|
||||
|
||||
FS_Read( f, *out, datasize );
|
||||
FS_Close( f );
|
||||
return true;
|
||||
|
||||
cleanup_and_error:
|
||||
Mem_Free( in );
|
||||
FS_Close( f );
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1772,6 +1852,7 @@ for embedded submodels
|
||||
static void Mod_SetupSubmodels( model_t *mod, dbspmodel_t *bmod )
|
||||
{
|
||||
qboolean colored = false;
|
||||
qboolean qbsp2 = false;
|
||||
poolhandle_t mempool;
|
||||
char *ents;
|
||||
dmodel_t *bm;
|
||||
@@ -1783,6 +1864,9 @@ static void Mod_SetupSubmodels( model_t *mod, dbspmodel_t *bmod )
|
||||
if( FBitSet( mod->flags, MODEL_COLORED_LIGHTING ))
|
||||
colored = true;
|
||||
|
||||
if( FBitSet( mod->flags, MODEL_QBSP2 ))
|
||||
qbsp2 = true;
|
||||
|
||||
mod->numframes = 2; // regular and alternate animation
|
||||
|
||||
// set up the submodels
|
||||
@@ -1795,7 +1879,10 @@ static void Mod_SetupSubmodels( model_t *mod, dbspmodel_t *bmod )
|
||||
mod->hulls[0].lastclipnode = bm->headnode[0]; // need to be real count
|
||||
|
||||
// counting a real number of clipnodes per each submodel
|
||||
CountClipNodes_r( mod->hulls[0].clipnodes, &mod->hulls[0], bm->headnode[0] );
|
||||
if( bmod->version == QBSP2_VERSION )
|
||||
CountClipNodes32_r( mod->hulls[0].clipnodes32, &mod->hulls[0], bm->headnode[0] );
|
||||
else
|
||||
CountClipNodes16_r( mod->hulls[0].clipnodes16, &mod->hulls[0], bm->headnode[0] );
|
||||
|
||||
// but hulls1-3 is build individually for a each given submodel
|
||||
for( j = 1; j < MAX_MAP_HULLS; j++ )
|
||||
@@ -1813,6 +1900,7 @@ static void Mod_SetupSubmodels( model_t *mod, dbspmodel_t *bmod )
|
||||
|
||||
// this bit will be shared between all the submodels include worldmodel
|
||||
if( colored ) SetBits( mod->flags, MODEL_COLORED_LIGHTING );
|
||||
if( qbsp2 ) SetBits( mod->flags, MODEL_QBSP2 );
|
||||
|
||||
if( i != 0 )
|
||||
{
|
||||
@@ -2135,15 +2223,15 @@ Mod_LoadEdges
|
||||
*/
|
||||
static void Mod_LoadEdges( model_t *mod, dbspmodel_t *bmod )
|
||||
{
|
||||
medge_t *out;
|
||||
int i;
|
||||
|
||||
mod->edges = out = Mem_Malloc( mod->mempool, bmod->numedges * sizeof( medge_t ));
|
||||
mod->numedges = bmod->numedges;
|
||||
|
||||
if( bmod->version == QBSP2_VERSION )
|
||||
{
|
||||
dedge32_t *in = (dedge32_t *)bmod->edges32;
|
||||
dedge32_t *in = bmod->edges32;
|
||||
medge32_t *out;
|
||||
mod->edges32 = out = Mem_Malloc( mod->mempool, bmod->numedges * sizeof( *out ));
|
||||
|
||||
for( i = 0; i < bmod->numedges; i++, in++, out++ )
|
||||
{
|
||||
@@ -2153,7 +2241,9 @@ static void Mod_LoadEdges( model_t *mod, dbspmodel_t *bmod )
|
||||
}
|
||||
else
|
||||
{
|
||||
dedge_t *in = (dedge_t *)bmod->edges;
|
||||
dedge_t *in = bmod->edges;
|
||||
medge16_t *out;
|
||||
mod->edges16 = out = Mem_Malloc( mod->mempool, bmod->numedges * sizeof( *out ));
|
||||
|
||||
for( i = 0; i < bmod->numedges; i++, in++, out++ )
|
||||
{
|
||||
@@ -2269,7 +2359,7 @@ static qboolean Mod_SearchForTextureReplacement( char *out, size_t size, const c
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Mod_InitSkyClouds( model_t *mod, mip_t *mt, texture_t *tx, qboolean custom_palette )
|
||||
static void Mod_InitSkyClouds( model_t *mod, const mip_t *mt, texture_t *tx, qboolean custom_palette )
|
||||
{
|
||||
#if !XASH_DEDICATED
|
||||
rgbdata_t r_temp, *r_sky;
|
||||
@@ -2426,9 +2516,6 @@ done:
|
||||
|
||||
static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureIndex )
|
||||
{
|
||||
texture_t *texture = NULL;
|
||||
mip_t *mipTex = NULL;
|
||||
qboolean usesCustomPalette = false;
|
||||
uint32_t txFlags = 0;
|
||||
char texpath[MAX_VA_STRING];
|
||||
char safemtname[16]; // only for external textures
|
||||
@@ -2436,12 +2523,10 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
|
||||
|
||||
// don't load texture data on dedicated server, as there is no renderer.
|
||||
// but count the wadusage for automatic precache
|
||||
//
|
||||
// FIXME: for ENGINE_IMPROVED_LINETRACE we need to load textures on server too
|
||||
// but there is no facility for this yet
|
||||
texture = mod->textures[textureIndex];
|
||||
mipTex = Mod_GetMipTexForTexture( bmod, textureIndex );
|
||||
usesCustomPalette = Mod_CalcMipTexUsesCustomPalette( mod, bmod, textureIndex );
|
||||
texture_t *texture = mod->textures[textureIndex];
|
||||
const mip_t *mipTex = Mod_GetMipTexForTexture( bmod, textureIndex );
|
||||
const qboolean usesCustomPalette = Mod_CalcMipTexUsesCustomPalette( mod, bmod, textureIndex );
|
||||
const qboolean iswater = Mod_LooksLikeWaterTexture( mipTex->name );
|
||||
|
||||
// check for multi-layered sky texture (quake1 specific)
|
||||
if( bmod->isworld && Q_strncmp( mipTex->name, "sky", 3 ) == 0 && ( mipTex->width / mipTex->height ) == 2 )
|
||||
@@ -2450,11 +2535,13 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: for ENGINE_IMPROVED_LINETRACE we need to load textures on server too
|
||||
// but there is no facility for this yet
|
||||
if( FBitSet( host.features, ENGINE_IMPROVED_LINETRACE ) && mipTex->name[0] == '{' )
|
||||
SetBits( txFlags, TF_KEEP_SOURCE ); // Paranoia2 texture alpha-tracing
|
||||
|
||||
// check if this is water to keep the source texture and expand it to RGBA (so ripple effect works)
|
||||
if( Mod_LooksLikeWaterTexture( mipTex->name ))
|
||||
if( iswater )
|
||||
SetBits( txFlags, TF_KEEP_SOURCE | TF_EXPAND_SOURCE );
|
||||
|
||||
// Texture loading order:
|
||||
@@ -2519,8 +2606,13 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
|
||||
texture->gl_texturenum = R_GetBuiltinTexture( REF_DEFAULT_TEXTURE );
|
||||
}
|
||||
|
||||
// Check for luma texture
|
||||
texture->fb_texturenum = 0;
|
||||
|
||||
// Check for luma texture
|
||||
// a1ba: ignore for water because fb_texturenum will be used to store ripple texture
|
||||
if( iswater )
|
||||
return;
|
||||
|
||||
if( load_external ) // external textures will not have TF_HAS_LUMA flag because it set only from WAD images loader
|
||||
{
|
||||
if( Mod_SearchForTextureReplacement( texpath, sizeof( texpath ), mod->name, safemtname, "_luma" ))
|
||||
@@ -2913,9 +3005,9 @@ static void Mod_LoadSurfaces( model_t *mod, dbspmodel_t *bmod )
|
||||
if( FBitSet( out->texinfo->flags, TEX_SPECIAL ))
|
||||
SetBits( out->flags, SURF_DRAWTILED );
|
||||
|
||||
Mod_CalcSurfaceBounds( mod, out );
|
||||
Mod_CalcSurfaceExtents( mod, out );
|
||||
Mod_CreateFaceBevels( mod, out );
|
||||
Mod_CalcSurfaceBounds( mod, out, bmod );
|
||||
Mod_CalcSurfaceExtents( mod, out, bmod );
|
||||
Mod_CreateFaceBevels( mod, out, bmod );
|
||||
|
||||
// grab the second sample to detect colored lighting
|
||||
if( test_lightsize > 0 && lightofs != -1 )
|
||||
@@ -2962,7 +3054,6 @@ static void Mod_LoadSurfaces( model_t *mod, dbspmodel_t *bmod )
|
||||
if( samples == 1 || samples == 3 )
|
||||
{
|
||||
bmod->lightmap_samples = (int)samples;
|
||||
Con_Reportf( "lighting: %s\n", (bmod->lightmap_samples == 1) ? "monochrome" : "colored" );
|
||||
bmod->lightmap_samples = Q_max( bmod->lightmap_samples, 1 ); // avoid division by zero
|
||||
}
|
||||
else Con_DPrintf( S_WARN "lighting invalid samplecount: %g, defaulting to %i\n", samples, bmod->lightmap_samples );
|
||||
@@ -2994,16 +3085,62 @@ static void Mod_LoadNodes( model_t *mod, dbspmodel_t *bmod )
|
||||
out->minmaxs[j+3] = in->maxs[j];
|
||||
}
|
||||
|
||||
#if !XASH_64BIT
|
||||
if( in->firstface >= BIT( 24 ))
|
||||
{
|
||||
Host_Error( "%s: face index limit exceeded on node %i\n", __func__, i );
|
||||
return;
|
||||
}
|
||||
|
||||
if( in->numfaces >= BIT( 24 ))
|
||||
{
|
||||
Host_Error( "%s: face count limit exceeded on node %i\n", __func__, i );
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
p = in->planenum;
|
||||
out->plane = mod->planes + p;
|
||||
out->firstsurface = in->firstface;
|
||||
out->numsurfaces = in->numfaces;
|
||||
out->firstsurface_0 = in->firstface & 0xFFFF;
|
||||
out->numsurfaces_0 = in->numfaces & 0xFFFF;
|
||||
|
||||
out->firstsurface_1 = in->firstface >> 16;
|
||||
out->numsurfaces_1 = in->numfaces >> 16;
|
||||
|
||||
for( j = 0; j < 2; j++ )
|
||||
{
|
||||
p = in->children[j];
|
||||
if( p >= 0 ) out->children[j] = mod->nodes + p;
|
||||
else out->children[j] = (mnode_t *)(mod->leafs + ( -1 - p ));
|
||||
#if XASH_64BIT
|
||||
if( p >= 0 ) out->children_[j] = mod->nodes + p;
|
||||
else out->children_[j] = (mnode_t *)(mod->leafs + ( -1 - p ));
|
||||
#else
|
||||
if( j == 0 )
|
||||
{
|
||||
if( p >= 0 )
|
||||
{
|
||||
out->child_0_leaf = 0;
|
||||
out->child_0_off = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
out->child_0_leaf = 1;
|
||||
out->child_0_off = -1 - p;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( p >= 0 )
|
||||
{
|
||||
out->child_1_leaf = 0;
|
||||
out->child_1_off = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
out->child_1_leaf = 1;
|
||||
out->child_1_off = -1 - p;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -3018,20 +3155,20 @@ static void Mod_LoadNodes( model_t *mod, dbspmodel_t *bmod )
|
||||
|
||||
p = in->planenum;
|
||||
out->plane = mod->planes + p;
|
||||
out->firstsurface = in->firstface;
|
||||
out->numsurfaces = in->numfaces;
|
||||
out->firstsurface_0 = in->firstface;
|
||||
out->numsurfaces_0 = in->numfaces;
|
||||
|
||||
for( j = 0; j < 2; j++ )
|
||||
{
|
||||
p = in->children[j];
|
||||
if( p >= 0 ) out->children[j] = mod->nodes + p;
|
||||
else out->children[j] = (mnode_t *)(mod->leafs + ( -1 - p ));
|
||||
if( p >= 0 ) out->children_[j] = mod->nodes + p;
|
||||
else out->children_[j] = (mnode_t *)(mod->leafs + ( -1 - p ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sets nodes and leafs
|
||||
Mod_SetParent( mod->nodes, NULL );
|
||||
Mod_SetParent( mod, mod->nodes, NULL );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3413,6 +3550,8 @@ static void Mod_LoadLighting( model_t *mod, dbspmodel_t *bmod )
|
||||
break;
|
||||
}
|
||||
|
||||
Con_Reportf( "lighting: %s\n", FBitSet( mod->flags, MODEL_COLORED_LIGHTING ) ? "colored" : "monochrome" );
|
||||
|
||||
// not supposed to be load ?
|
||||
if( FBitSet( host.features, ENGINE_LOAD_DELUXEDATA ))
|
||||
{
|
||||
@@ -3491,13 +3630,6 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, const byte *mod_base, qboolea
|
||||
Q_strncpy( loadstat.name, mod->name, sizeof( loadstat.name ));
|
||||
wadvalue[0] = '\0';
|
||||
|
||||
#ifndef SUPPORT_BSP2_FORMAT
|
||||
if( header->version == QBSP2_VERSION )
|
||||
{
|
||||
Con_Printf( S_ERROR DEFAULT_BSP_BUILD_ERROR, mod->name );
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
switch( header->version )
|
||||
{
|
||||
case HLBSP_VERSION:
|
||||
@@ -3520,6 +3652,9 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, const byte *mod_base, qboolea
|
||||
// everything else
|
||||
srclumps[0].lumpnumber = LUMP_ENTITIES;
|
||||
srclumps[1].lumpnumber = LUMP_PLANES;
|
||||
|
||||
if( header->version == QBSP2_VERSION )
|
||||
SetBits( mod->flags, MODEL_QBSP2 );
|
||||
break;
|
||||
default:
|
||||
Con_Printf( S_ERROR "%s has wrong version number (%i should be %i)\n", mod->name, header->version, HLBSP_VERSION );
|
||||
@@ -3570,7 +3705,7 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, const byte *mod_base, qboolea
|
||||
Mod_LoadClipnodes( mod, bmod );
|
||||
|
||||
// preform some post-initalization
|
||||
Mod_MakeHull0( mod );
|
||||
Mod_MakeHull0( mod, bmod );
|
||||
Mod_SetupSubmodels( mod, bmod );
|
||||
|
||||
if( isworld )
|
||||
@@ -3660,15 +3795,6 @@ qboolean Mod_TestBmodelLumps( file_t *f, const char *name, const byte *mod_base,
|
||||
if( silent )
|
||||
SetBits( flags, LUMP_SILENT );
|
||||
|
||||
#ifndef SUPPORT_BSP2_FORMAT
|
||||
if( header->version == QBSP2_VERSION )
|
||||
{
|
||||
if( !FBitSet( flags, LUMP_SILENT ))
|
||||
Con_Printf( S_ERROR DEFAULT_BSP_BUILD_ERROR, name );
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch( header->version )
|
||||
{
|
||||
case HLBSP_VERSION:
|
||||
|
||||
@@ -135,6 +135,8 @@ extern poolhandle_t com_studiocache;
|
||||
extern convar_t mod_studiocache;
|
||||
extern convar_t r_wadtextures;
|
||||
extern convar_t r_showhull;
|
||||
extern const mclipnode16_t box_clipnodes16[6];
|
||||
extern const mclipnode32_t box_clipnodes32[6];
|
||||
|
||||
//
|
||||
// model.c
|
||||
@@ -167,13 +169,12 @@ void Mod_LoadAliasModel( model_t *mod, const void *buffer, qboolean *loaded );
|
||||
//
|
||||
void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *loaded );
|
||||
qboolean Mod_TestBmodelLumps( file_t *f, const char *name, const byte *mod_base, qboolean silent, dlump_t *entities );
|
||||
qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, int *lastleaf );
|
||||
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis, qboolean false );
|
||||
qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbits );
|
||||
int Mod_CheckLump( const char *filename, const int lump, int *lumpsize );
|
||||
int Mod_ReadLump( const char *filename, const int lump, void **lumpdata, int *lumpsize );
|
||||
int Mod_SaveLump( const char *filename, const int lump, void *lumpdata, int lumpsize );
|
||||
mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node );
|
||||
mleaf_t *Mod_PointInLeaf( const vec3_t p, mnode_t *node, model_t *mod );
|
||||
int Mod_SampleSizeForFace( const msurface_t *surf );
|
||||
byte *Mod_GetPVSForPoint( const vec3_t p );
|
||||
void Mod_UnloadBrushModel( model_t *mod );
|
||||
|
||||
@@ -50,9 +50,8 @@ static matrix3x4 studio_bones[MAXSTUDIOBONES];
|
||||
static uint studio_hull_hitgroup[MAXSTUDIOBONES];
|
||||
static uint cache_hull_hitgroup[MAXSTUDIOBONES];
|
||||
static mstudiocache_t cache_studio[STUDIO_CACHESIZE];
|
||||
static mclipnode_t studio_clipnodes[6];
|
||||
static mplane_t studio_planes[768];
|
||||
static mplane_t cache_planes[768];
|
||||
static mplane_t studio_planes[MAXSTUDIOBONES * 6];
|
||||
static mplane_t cache_planes[MAXSTUDIOBONES * 6];
|
||||
|
||||
// current cache state
|
||||
static int cache_current;
|
||||
@@ -66,25 +65,14 @@ Mod_InitStudioHull
|
||||
*/
|
||||
void Mod_InitStudioHull( void )
|
||||
{
|
||||
int i, side;
|
||||
int i;
|
||||
|
||||
if( studio_hull[0].planes != NULL )
|
||||
return; // already initailized
|
||||
|
||||
for( i = 0; i < 6; i++ )
|
||||
{
|
||||
studio_clipnodes[i].planenum = i;
|
||||
|
||||
side = i & 1;
|
||||
|
||||
studio_clipnodes[i].children[side] = CONTENTS_EMPTY;
|
||||
if( i != 5 ) studio_clipnodes[i].children[side^1] = i + 1;
|
||||
else studio_clipnodes[i].children[side^1] = CONTENTS_SOLID;
|
||||
}
|
||||
|
||||
for( i = 0; i < MAXSTUDIOBONES; i++ )
|
||||
{
|
||||
studio_hull[i].clipnodes = studio_clipnodes;
|
||||
studio_hull[i].clipnodes16 = (mclipnode16_t *)box_clipnodes16;
|
||||
studio_hull[i].planes = &studio_planes[i*6];
|
||||
studio_hull[i].firstclipnode = 0;
|
||||
studio_hull[i].lastclipnode = 5;
|
||||
@@ -270,6 +258,11 @@ hull_t *Mod_HullForStudio( model_t *model, float frame, int sequence, vec3_t ang
|
||||
|
||||
for( i = j = 0; i < mod_studiohdr->numhitboxes; i++, j += 6 )
|
||||
{
|
||||
if( world.version == QBSP2_VERSION )
|
||||
studio_hull[i].clipnodes32 = (mclipnode32_t *)box_clipnodes32;
|
||||
else
|
||||
studio_hull[i].clipnodes16 = (mclipnode16_t *)box_clipnodes16;
|
||||
|
||||
if( bSkipShield && i == 21 )
|
||||
continue; // CS stuff
|
||||
|
||||
@@ -875,7 +868,7 @@ void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded )
|
||||
mod->type = mod_studio;
|
||||
|
||||
phdr = R_StudioLoadHeader( mod, buffer );
|
||||
if( !phdr )
|
||||
if( !phdr || phdr->length < sizeof( studiohdr_t )) // garbage value in length
|
||||
return; // bad model
|
||||
|
||||
#if !XASH_DEDICATED
|
||||
|
||||
@@ -258,7 +258,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
||||
{
|
||||
char tempname[MAX_QPATH];
|
||||
fs_offset_t length = 0;
|
||||
qboolean loaded;
|
||||
qboolean loaded, loaded2 = false;
|
||||
byte *buf;
|
||||
model_info_t *p;
|
||||
|
||||
@@ -279,7 +279,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
||||
|
||||
buf = FS_LoadFile( tempname, &length, false );
|
||||
|
||||
if( !buf )
|
||||
if( !buf || length < sizeof( uint ))
|
||||
{
|
||||
memset( mod, 0, sizeof( model_t ));
|
||||
|
||||
@@ -329,11 +329,12 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
||||
// let the server.dll load custom data
|
||||
svgame.physFuncs.Mod_ProcessUserData( mod, true, buf );
|
||||
}
|
||||
loaded2 = true;
|
||||
}
|
||||
#if !XASH_DEDICATED
|
||||
else
|
||||
{
|
||||
loaded = ref.dllFuncs.Mod_ProcessRenderData( mod, true, buf );
|
||||
loaded2 = ref.dllFuncs.Mod_ProcessRenderData( mod, true, buf );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -345,7 +346,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
||||
hdr->pposeverts = NULL;
|
||||
}
|
||||
|
||||
if( !loaded )
|
||||
if( !loaded || !loaded2 )
|
||||
{
|
||||
Mod_FreeModel( mod );
|
||||
Mem_Free( buf );
|
||||
@@ -610,3 +611,41 @@ void Mod_NeedCRC( const char *name, qboolean needCRC )
|
||||
if( needCRC ) SetBits( p->flags, FCRC_SHOULD_CHECKSUM );
|
||||
else ClearBits( p->flags, FCRC_SHOULD_CHECKSUM );
|
||||
}
|
||||
|
||||
#if XASH_ENGINE_TESTS
|
||||
|
||||
static const uint8_t *fuzz_data;
|
||||
static size_t fuzz_size;
|
||||
|
||||
static byte *Fuzz_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
|
||||
{
|
||||
byte *buf = Mem_Malloc( host.mempool, fuzz_size );
|
||||
memcpy( buf, fuzz_data, fuzz_size );
|
||||
*filesizeptr = fuzz_size;
|
||||
return buf;
|
||||
}
|
||||
|
||||
int EXPORT Fuzz_Mod_LoadModel( const uint8_t *Data, size_t Size );
|
||||
int EXPORT Fuzz_Mod_LoadModel( const uint8_t *Data, size_t Size )
|
||||
{
|
||||
model_t mod = { .name = "test", .needload = NL_NEEDS_LOADED };
|
||||
|
||||
Memory_Init();
|
||||
|
||||
host.type = HOST_DEDICATED;
|
||||
host.mempool = Mem_AllocPool( "fuzzing pool" );
|
||||
fuzz_data = Data;
|
||||
fuzz_size = Size;
|
||||
refState.draw_surfaces = NULL;
|
||||
|
||||
g_fsapi.LoadFile = Fuzz_LoadFile;
|
||||
|
||||
if( Mod_LoadModel( &mod, false ) && mod.mempool )
|
||||
Mem_FreePool( &mod.mempool );
|
||||
|
||||
Mem_FreePool( &host.mempool );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // XASH_ENGINE_TESTS
|
||||
|
||||
@@ -18,11 +18,177 @@ GNU General Public License for more details.
|
||||
#include "net_buffer.h"
|
||||
#include "xash3d_mathlib.h"
|
||||
|
||||
// precalculated bit masks for WriteUBitLong.
|
||||
// Using these tables instead of doing the calculations
|
||||
// gives a 33% speedup in WriteUBitLong.
|
||||
static uint32_t BitWriteMasks[32][33];
|
||||
static uint32_t ExtraMasks[32];
|
||||
static const uint32_t BitWriteMasks[32][32] =
|
||||
{ {
|
||||
0xfffffffe, 0xfffffffc, 0xfffffff8, 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80, 0xffffff00,
|
||||
0xfffffe00, 0xfffffc00, 0xfffff800, 0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000,
|
||||
0xfffe0000, 0xfffc0000, 0xfff80000, 0xfff00000, 0xffe00000, 0xffc00000, 0xff800000, 0xff000000,
|
||||
0xfe000000, 0xfc000000, 0xf8000000, 0xf0000000, 0xe0000000, 0xc0000000, 0x80000000, 0x00000000,
|
||||
}, {
|
||||
0xfffffffd, 0xfffffff9, 0xfffffff1, 0xffffffe1, 0xffffffc1, 0xffffff81, 0xffffff01, 0xfffffe01,
|
||||
0xfffffc01, 0xfffff801, 0xfffff001, 0xffffe001, 0xffffc001, 0xffff8001, 0xffff0001, 0xfffe0001,
|
||||
0xfffc0001, 0xfff80001, 0xfff00001, 0xffe00001, 0xffc00001, 0xff800001, 0xff000001, 0xfe000001,
|
||||
0xfc000001, 0xf8000001, 0xf0000001, 0xe0000001, 0xc0000001, 0x80000001, 0x00000001, 0x00000001,
|
||||
}, {
|
||||
0xfffffffb, 0xfffffff3, 0xffffffe3, 0xffffffc3, 0xffffff83, 0xffffff03, 0xfffffe03, 0xfffffc03,
|
||||
0xfffff803, 0xfffff003, 0xffffe003, 0xffffc003, 0xffff8003, 0xffff0003, 0xfffe0003, 0xfffc0003,
|
||||
0xfff80003, 0xfff00003, 0xffe00003, 0xffc00003, 0xff800003, 0xff000003, 0xfe000003, 0xfc000003,
|
||||
0xf8000003, 0xf0000003, 0xe0000003, 0xc0000003, 0x80000003, 0x00000003, 0x00000003, 0x00000003,
|
||||
}, {
|
||||
0xfffffff7, 0xffffffe7, 0xffffffc7, 0xffffff87, 0xffffff07, 0xfffffe07, 0xfffffc07, 0xfffff807,
|
||||
0xfffff007, 0xffffe007, 0xffffc007, 0xffff8007, 0xffff0007, 0xfffe0007, 0xfffc0007, 0xfff80007,
|
||||
0xfff00007, 0xffe00007, 0xffc00007, 0xff800007, 0xff000007, 0xfe000007, 0xfc000007, 0xf8000007,
|
||||
0xf0000007, 0xe0000007, 0xc0000007, 0x80000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007,
|
||||
}, {
|
||||
0xffffffef, 0xffffffcf, 0xffffff8f, 0xffffff0f, 0xfffffe0f, 0xfffffc0f, 0xfffff80f, 0xfffff00f,
|
||||
0xffffe00f, 0xffffc00f, 0xffff800f, 0xffff000f, 0xfffe000f, 0xfffc000f, 0xfff8000f, 0xfff0000f,
|
||||
0xffe0000f, 0xffc0000f, 0xff80000f, 0xff00000f, 0xfe00000f, 0xfc00000f, 0xf800000f, 0xf000000f,
|
||||
0xe000000f, 0xc000000f, 0x8000000f, 0x0000000f, 0x0000000f, 0x0000000f, 0x0000000f, 0x0000000f,
|
||||
}, {
|
||||
0xffffffdf, 0xffffff9f, 0xffffff1f, 0xfffffe1f, 0xfffffc1f, 0xfffff81f, 0xfffff01f, 0xffffe01f,
|
||||
0xffffc01f, 0xffff801f, 0xffff001f, 0xfffe001f, 0xfffc001f, 0xfff8001f, 0xfff0001f, 0xffe0001f,
|
||||
0xffc0001f, 0xff80001f, 0xff00001f, 0xfe00001f, 0xfc00001f, 0xf800001f, 0xf000001f, 0xe000001f,
|
||||
0xc000001f, 0x8000001f, 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f, 0x0000001f,
|
||||
}, {
|
||||
0xffffffbf, 0xffffff3f, 0xfffffe3f, 0xfffffc3f, 0xfffff83f, 0xfffff03f, 0xffffe03f, 0xffffc03f,
|
||||
0xffff803f, 0xffff003f, 0xfffe003f, 0xfffc003f, 0xfff8003f, 0xfff0003f, 0xffe0003f, 0xffc0003f,
|
||||
0xff80003f, 0xff00003f, 0xfe00003f, 0xfc00003f, 0xf800003f, 0xf000003f, 0xe000003f, 0xc000003f,
|
||||
0x8000003f, 0x0000003f, 0x0000003f, 0x0000003f, 0x0000003f, 0x0000003f, 0x0000003f, 0x0000003f,
|
||||
}, {
|
||||
0xffffff7f, 0xfffffe7f, 0xfffffc7f, 0xfffff87f, 0xfffff07f, 0xffffe07f, 0xffffc07f, 0xffff807f,
|
||||
0xffff007f, 0xfffe007f, 0xfffc007f, 0xfff8007f, 0xfff0007f, 0xffe0007f, 0xffc0007f, 0xff80007f,
|
||||
0xff00007f, 0xfe00007f, 0xfc00007f, 0xf800007f, 0xf000007f, 0xe000007f, 0xc000007f, 0x8000007f,
|
||||
0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f, 0x0000007f,
|
||||
}, {
|
||||
0xfffffeff, 0xfffffcff, 0xfffff8ff, 0xfffff0ff, 0xffffe0ff, 0xffffc0ff, 0xffff80ff, 0xffff00ff,
|
||||
0xfffe00ff, 0xfffc00ff, 0xfff800ff, 0xfff000ff, 0xffe000ff, 0xffc000ff, 0xff8000ff, 0xff0000ff,
|
||||
0xfe0000ff, 0xfc0000ff, 0xf80000ff, 0xf00000ff, 0xe00000ff, 0xc00000ff, 0x800000ff, 0x000000ff,
|
||||
0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff,
|
||||
}, {
|
||||
0xfffffdff, 0xfffff9ff, 0xfffff1ff, 0xffffe1ff, 0xffffc1ff, 0xffff81ff, 0xffff01ff, 0xfffe01ff,
|
||||
0xfffc01ff, 0xfff801ff, 0xfff001ff, 0xffe001ff, 0xffc001ff, 0xff8001ff, 0xff0001ff, 0xfe0001ff,
|
||||
0xfc0001ff, 0xf80001ff, 0xf00001ff, 0xe00001ff, 0xc00001ff, 0x800001ff, 0x000001ff, 0x000001ff,
|
||||
0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff, 0x000001ff,
|
||||
}, {
|
||||
0xfffffbff, 0xfffff3ff, 0xffffe3ff, 0xffffc3ff, 0xffff83ff, 0xffff03ff, 0xfffe03ff, 0xfffc03ff,
|
||||
0xfff803ff, 0xfff003ff, 0xffe003ff, 0xffc003ff, 0xff8003ff, 0xff0003ff, 0xfe0003ff, 0xfc0003ff,
|
||||
0xf80003ff, 0xf00003ff, 0xe00003ff, 0xc00003ff, 0x800003ff, 0x000003ff, 0x000003ff, 0x000003ff,
|
||||
0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff, 0x000003ff,
|
||||
}, {
|
||||
0xfffff7ff, 0xffffe7ff, 0xffffc7ff, 0xffff87ff, 0xffff07ff, 0xfffe07ff, 0xfffc07ff, 0xfff807ff,
|
||||
0xfff007ff, 0xffe007ff, 0xffc007ff, 0xff8007ff, 0xff0007ff, 0xfe0007ff, 0xfc0007ff, 0xf80007ff,
|
||||
0xf00007ff, 0xe00007ff, 0xc00007ff, 0x800007ff, 0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff,
|
||||
0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff, 0x000007ff,
|
||||
}, {
|
||||
0xffffefff, 0xffffcfff, 0xffff8fff, 0xffff0fff, 0xfffe0fff, 0xfffc0fff, 0xfff80fff, 0xfff00fff,
|
||||
0xffe00fff, 0xffc00fff, 0xff800fff, 0xff000fff, 0xfe000fff, 0xfc000fff, 0xf8000fff, 0xf0000fff,
|
||||
0xe0000fff, 0xc0000fff, 0x80000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff,
|
||||
0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff, 0x00000fff,
|
||||
}, {
|
||||
0xffffdfff, 0xffff9fff, 0xffff1fff, 0xfffe1fff, 0xfffc1fff, 0xfff81fff, 0xfff01fff, 0xffe01fff,
|
||||
0xffc01fff, 0xff801fff, 0xff001fff, 0xfe001fff, 0xfc001fff, 0xf8001fff, 0xf0001fff, 0xe0001fff,
|
||||
0xc0001fff, 0x80001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff,
|
||||
0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff, 0x00001fff,
|
||||
}, {
|
||||
0xffffbfff, 0xffff3fff, 0xfffe3fff, 0xfffc3fff, 0xfff83fff, 0xfff03fff, 0xffe03fff, 0xffc03fff,
|
||||
0xff803fff, 0xff003fff, 0xfe003fff, 0xfc003fff, 0xf8003fff, 0xf0003fff, 0xe0003fff, 0xc0003fff,
|
||||
0x80003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff,
|
||||
0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff, 0x00003fff,
|
||||
}, {
|
||||
0xffff7fff, 0xfffe7fff, 0xfffc7fff, 0xfff87fff, 0xfff07fff, 0xffe07fff, 0xffc07fff, 0xff807fff,
|
||||
0xff007fff, 0xfe007fff, 0xfc007fff, 0xf8007fff, 0xf0007fff, 0xe0007fff, 0xc0007fff, 0x80007fff,
|
||||
0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff,
|
||||
0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff, 0x00007fff,
|
||||
}, {
|
||||
0xfffeffff, 0xfffcffff, 0xfff8ffff, 0xfff0ffff, 0xffe0ffff, 0xffc0ffff, 0xff80ffff, 0xff00ffff,
|
||||
0xfe00ffff, 0xfc00ffff, 0xf800ffff, 0xf000ffff, 0xe000ffff, 0xc000ffff, 0x8000ffff, 0x0000ffff,
|
||||
0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff,
|
||||
0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff,
|
||||
}, {
|
||||
0xfffdffff, 0xfff9ffff, 0xfff1ffff, 0xffe1ffff, 0xffc1ffff, 0xff81ffff, 0xff01ffff, 0xfe01ffff,
|
||||
0xfc01ffff, 0xf801ffff, 0xf001ffff, 0xe001ffff, 0xc001ffff, 0x8001ffff, 0x0001ffff, 0x0001ffff,
|
||||
0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff,
|
||||
0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff, 0x0001ffff,
|
||||
}, {
|
||||
0xfffbffff, 0xfff3ffff, 0xffe3ffff, 0xffc3ffff, 0xff83ffff, 0xff03ffff, 0xfe03ffff, 0xfc03ffff,
|
||||
0xf803ffff, 0xf003ffff, 0xe003ffff, 0xc003ffff, 0x8003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff,
|
||||
0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff,
|
||||
0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff, 0x0003ffff,
|
||||
}, {
|
||||
0xfff7ffff, 0xffe7ffff, 0xffc7ffff, 0xff87ffff, 0xff07ffff, 0xfe07ffff, 0xfc07ffff, 0xf807ffff,
|
||||
0xf007ffff, 0xe007ffff, 0xc007ffff, 0x8007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff,
|
||||
0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff,
|
||||
0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff, 0x0007ffff,
|
||||
}, {
|
||||
0xffefffff, 0xffcfffff, 0xff8fffff, 0xff0fffff, 0xfe0fffff, 0xfc0fffff, 0xf80fffff, 0xf00fffff,
|
||||
0xe00fffff, 0xc00fffff, 0x800fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff,
|
||||
0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff,
|
||||
0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff, 0x000fffff,
|
||||
}, {
|
||||
0xffdfffff, 0xff9fffff, 0xff1fffff, 0xfe1fffff, 0xfc1fffff, 0xf81fffff, 0xf01fffff, 0xe01fffff,
|
||||
0xc01fffff, 0x801fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff,
|
||||
0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff,
|
||||
0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff, 0x001fffff,
|
||||
}, {
|
||||
0xffbfffff, 0xff3fffff, 0xfe3fffff, 0xfc3fffff, 0xf83fffff, 0xf03fffff, 0xe03fffff, 0xc03fffff,
|
||||
0x803fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff,
|
||||
0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff,
|
||||
0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff,
|
||||
}, {
|
||||
0xff7fffff, 0xfe7fffff, 0xfc7fffff, 0xf87fffff, 0xf07fffff, 0xe07fffff, 0xc07fffff, 0x807fffff,
|
||||
0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff,
|
||||
0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff,
|
||||
0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff, 0x007fffff,
|
||||
}, {
|
||||
0xfeffffff, 0xfcffffff, 0xf8ffffff, 0xf0ffffff, 0xe0ffffff, 0xc0ffffff, 0x80ffffff, 0x00ffffff,
|
||||
0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
|
||||
0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
|
||||
0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff, 0x00ffffff,
|
||||
}, {
|
||||
0xfdffffff, 0xf9ffffff, 0xf1ffffff, 0xe1ffffff, 0xc1ffffff, 0x81ffffff, 0x01ffffff, 0x01ffffff,
|
||||
0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
|
||||
0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
|
||||
0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff,
|
||||
}, {
|
||||
0xfbffffff, 0xf3ffffff, 0xe3ffffff, 0xc3ffffff, 0x83ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff,
|
||||
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff,
|
||||
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff,
|
||||
0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff, 0x03ffffff,
|
||||
}, {
|
||||
0xf7ffffff, 0xe7ffffff, 0xc7ffffff, 0x87ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff,
|
||||
0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff,
|
||||
0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff,
|
||||
0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff, 0x07ffffff,
|
||||
}, {
|
||||
0xefffffff, 0xcfffffff, 0x8fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff,
|
||||
0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff,
|
||||
0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff,
|
||||
0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff, 0x0fffffff,
|
||||
}, {
|
||||
0xdfffffff, 0x9fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff,
|
||||
0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff,
|
||||
0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff,
|
||||
0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff,
|
||||
}, {
|
||||
0xbfffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff,
|
||||
0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff,
|
||||
0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff,
|
||||
0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff, 0x3fffffff,
|
||||
}, {
|
||||
0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff,
|
||||
0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff,
|
||||
0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff,
|
||||
0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff,
|
||||
} };
|
||||
|
||||
static const uint32_t ExtraMasks[32] =
|
||||
{
|
||||
0x00000000, 0x00000001, 0x00000003, 0x00000007, 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
|
||||
0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
|
||||
0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
|
||||
0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
|
||||
};
|
||||
|
||||
const char *const svc_strings[svc_lastmsg+1] =
|
||||
{
|
||||
"svc_bad",
|
||||
@@ -101,20 +267,14 @@ const char *const svc_legacy_strings[svc_lastmsg+1] =
|
||||
const char *const 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",
|
||||
};
|
||||
|
||||
const char *const svc_quake_strings[svc_lastmsg+1] =
|
||||
@@ -138,65 +298,41 @@ const char *const svc_quake_strings[svc_lastmsg+1] =
|
||||
[svc_fog] = "svc_quake_fog",
|
||||
};
|
||||
|
||||
void MSG_InitMasks( void )
|
||||
{
|
||||
uint startbit, endbit;
|
||||
uint maskBit, nBitsLeft;
|
||||
|
||||
for( startbit = 0; startbit < 32; startbit++ )
|
||||
{
|
||||
for( nBitsLeft = 0; nBitsLeft < 33; nBitsLeft++ )
|
||||
{
|
||||
endbit = startbit + nBitsLeft;
|
||||
|
||||
BitWriteMasks[startbit][nBitsLeft] = (uint)BIT( startbit ) - 1;
|
||||
if( endbit < 32 ) BitWriteMasks[startbit][nBitsLeft] |= ~((uint)BIT( endbit ) - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
for( maskBit = 0; maskBit < 32; maskBit++ )
|
||||
ExtraMasks[maskBit] = (uint)BIT( maskBit ) - 1;
|
||||
}
|
||||
|
||||
void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits )
|
||||
{
|
||||
Assert( numbits >= 0 && numbits <= 32 );
|
||||
int nBitsLeft = numbits;
|
||||
int iCurBit = sb->iCurBit;
|
||||
uint iDWord = iCurBit >> 5; // Mask in a dword.
|
||||
uint32_t iCurBitMasked;
|
||||
int nBitsWritten;
|
||||
|
||||
Assert( numbits >= 1 && numbits <= 32 );
|
||||
|
||||
// bounds checking..
|
||||
if(( sb->iCurBit + numbits ) > sb->nDataBits )
|
||||
if( MSG_Overflow( sb, numbits ))
|
||||
{
|
||||
sb->bOverflow = true;
|
||||
sb->iCurBit = sb->nDataBits;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
int nBitsLeft = numbits;
|
||||
int iCurBit = sb->iCurBit;
|
||||
uint iDWord = iCurBit >> 5; // Mask in a dword.
|
||||
uint32_t iCurBitMasked;
|
||||
int nBitsWritten;
|
||||
|
||||
Assert(( iDWord * 4 + sizeof( int )) <= (uint)MSG_GetMaxBytes( sb ));
|
||||
iCurBitMasked = iCurBit & 31;
|
||||
((uint32_t *)sb->pData)[iDWord] &= BitWriteMasks[iCurBitMasked][nBitsLeft-1];
|
||||
((uint32_t *)sb->pData)[iDWord] |= curData << iCurBitMasked;
|
||||
|
||||
// did it span a dword?
|
||||
nBitsWritten = 32 - iCurBitMasked;
|
||||
|
||||
if( nBitsWritten < nBitsLeft )
|
||||
{
|
||||
nBitsLeft -= nBitsWritten;
|
||||
iCurBit += nBitsWritten;
|
||||
curData >>= nBitsWritten;
|
||||
|
||||
iCurBitMasked = iCurBit & 31;
|
||||
((uint32_t *)sb->pData)[iDWord] &= BitWriteMasks[iCurBitMasked][nBitsLeft];
|
||||
((uint32_t *)sb->pData)[iDWord] |= curData << iCurBitMasked;
|
||||
|
||||
// did it span a dword?
|
||||
nBitsWritten = 32 - iCurBitMasked;
|
||||
|
||||
if( nBitsWritten < nBitsLeft )
|
||||
{
|
||||
nBitsLeft -= nBitsWritten;
|
||||
iCurBit += nBitsWritten;
|
||||
curData >>= nBitsWritten;
|
||||
|
||||
iCurBitMasked = iCurBit & 31;
|
||||
((uint32_t *)sb->pData)[iDWord+1] &= BitWriteMasks[iCurBitMasked][nBitsLeft];
|
||||
((uint32_t *)sb->pData)[iDWord+1] |= curData << iCurBitMasked;
|
||||
}
|
||||
sb->iCurBit += numbits;
|
||||
((uint32_t *)sb->pData)[iDWord+1] &= BitWriteMasks[iCurBitMasked][nBitsLeft-1];
|
||||
((uint32_t *)sb->pData)[iDWord+1] |= curData << iCurBitMasked;
|
||||
}
|
||||
sb->iCurBit += numbits;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -244,7 +380,7 @@ qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits )
|
||||
int nBitsLeft = nBits;
|
||||
|
||||
// get output dword-aligned.
|
||||
while((( uint32_t )pOut & 3 ) != 0 && nBitsLeft >= 8 )
|
||||
while((( uintptr_t )pOut & 3 ) != 0 && nBitsLeft >= 8 )
|
||||
{
|
||||
MSG_WriteUBitLong( sb, *pOut, 8 );
|
||||
|
||||
@@ -281,16 +417,14 @@ qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits )
|
||||
|
||||
void MSG_WriteBitAngle( sizebuf_t *sb, float fAngle, int numbits )
|
||||
{
|
||||
uint mask, shift;
|
||||
const uint shift = ( 1 << numbits );
|
||||
const uint mask = shift - 1;
|
||||
int d;
|
||||
|
||||
// clamp the angle before receiving
|
||||
fAngle = fmod( fAngle, 360.0f );
|
||||
if( fAngle < 0 ) fAngle += 360.0f;
|
||||
|
||||
shift = ( 1 << numbits );
|
||||
mask = shift - 1;
|
||||
|
||||
d = (int)(( fAngle * shift ) / 360.0f );
|
||||
d &= mask;
|
||||
|
||||
@@ -444,9 +578,8 @@ uint MSG_ReadUBitLong( sizebuf_t *sb, int numbits )
|
||||
return 0; // end of message
|
||||
}
|
||||
|
||||
if(( sb->iCurBit + numbits ) > sb->nDataBits )
|
||||
if( MSG_Overflow( sb, numbits ))
|
||||
{
|
||||
sb->bOverflow = true;
|
||||
sb->iCurBit = sb->nDataBits;
|
||||
return 0;
|
||||
}
|
||||
@@ -519,13 +652,9 @@ qboolean MSG_ReadBits( sizebuf_t *sb, void *pOutData, int nBits )
|
||||
|
||||
float MSG_ReadBitAngle( sizebuf_t *sb, int numbits )
|
||||
{
|
||||
float fReturn, shift;
|
||||
int i;
|
||||
|
||||
shift = (float)( 1 << numbits );
|
||||
|
||||
i = MSG_ReadUBitLong( sb, numbits );
|
||||
fReturn = (float)i * ( 360.0f / shift );
|
||||
float shift = (float)( 1 << numbits );
|
||||
int i = MSG_ReadUBitLong( sb, numbits );
|
||||
float fReturn = (float)i * ( 360.0f / shift );
|
||||
|
||||
// clamp the finale angle
|
||||
if( fReturn < -180.0f ) fReturn += 360.0f;
|
||||
@@ -537,11 +666,11 @@ float MSG_ReadBitAngle( sizebuf_t *sb, int numbits )
|
||||
// Append numbits least significant bits from data to the current bit stream
|
||||
int MSG_ReadSBitLong( sizebuf_t *sb, int numbits )
|
||||
{
|
||||
int r, sign;
|
||||
int r;
|
||||
|
||||
if( sb->iAlternateSign )
|
||||
{
|
||||
sign = MSG_ReadOneBit( sb );
|
||||
int sign = MSG_ReadOneBit( sb );
|
||||
r = MSG_ReadUBitLong( sb, numbits - 1 );
|
||||
|
||||
if( sign )
|
||||
@@ -550,9 +679,7 @@ int MSG_ReadSBitLong( sizebuf_t *sb, int numbits )
|
||||
else
|
||||
{
|
||||
r = MSG_ReadUBitLong( sb, numbits - 1 );
|
||||
sign = MSG_ReadOneBit( sb );
|
||||
|
||||
if( sign )
|
||||
if( MSG_ReadOneBit( sb ))
|
||||
r = -( BIT( numbits - 1 ) - r );
|
||||
}
|
||||
|
||||
@@ -673,12 +800,12 @@ qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes )
|
||||
static char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
|
||||
{
|
||||
static char string[4096];
|
||||
int l = 0, c;
|
||||
int l = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// use MSG_ReadByte so -1 is out of bounds
|
||||
c = MSG_ReadByte( sb );
|
||||
int c = MSG_ReadByte( sb );
|
||||
|
||||
if( c == 0 ) break;
|
||||
else if( bLine && c == '\n' )
|
||||
@@ -871,8 +998,6 @@ static void Test_Buffer_ExciseBits( void )
|
||||
|
||||
void Test_RunBuffer( void )
|
||||
{
|
||||
MSG_InitMasks();
|
||||
|
||||
TRUN( Test_Buffer_BitByte( ));
|
||||
TRUN( Test_Buffer_Write( ));
|
||||
TRUN( Test_Buffer_Read( ));
|
||||
|
||||
@@ -193,7 +193,6 @@ static inline void MSG_StartBitWriting( sizebuf_t *sb )
|
||||
sb->iAlternateSign++;
|
||||
}
|
||||
|
||||
void MSG_InitMasks( void ); // called once at startup engine
|
||||
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
|
||||
|
||||
// Bit-write functions
|
||||
|
||||
@@ -272,8 +272,6 @@ void Netchan_Init( void )
|
||||
Cvar_FullSet( net_qport.name, buf, net_qport.flags );
|
||||
|
||||
net_mempool = Mem_AllocPool( "Network Pool" );
|
||||
|
||||
MSG_InitMasks(); // initialize bit-masks
|
||||
}
|
||||
|
||||
void Netchan_Shutdown( void )
|
||||
@@ -343,6 +341,7 @@ void Netchan_Setup( netsrc_t sock, netchan_t *chan, netadr_t adr, int qport, voi
|
||||
chan->split = FBitSet( flags, NETCHAN_USE_LEGACY_SPLIT ) ? true : false;
|
||||
chan->use_munge = FBitSet( flags, NETCHAN_USE_MUNGE ) ? true : false;
|
||||
chan->use_bz2 = FBitSet( flags, NETCHAN_USE_BZIP2 ) ? true : false;
|
||||
chan->use_lzss = FBitSet( flags, NETCHAN_USE_LZSS ) ? true : false;
|
||||
chan->gs_netchan = FBitSet( flags, NETCHAN_GOLDSRC ) ? true : false;
|
||||
|
||||
MSG_Init( &chan->message, "NetData", chan->message_buf, sizeof( chan->message_buf ));
|
||||
@@ -768,7 +767,7 @@ static void Netchan_CreateFragments_( netchan_t *chan, sizebuf_t *msg )
|
||||
Host_Error( "%s: BZ2 compression is not supported for server", __func__ );
|
||||
#endif
|
||||
}
|
||||
else if( !chan->use_bz2 && !LZSS_IsCompressed( MSG_GetData( msg ), MSG_GetMaxBytes( msg )))
|
||||
else if( chan->use_lzss && !LZSS_IsCompressed( MSG_GetData( msg ), MSG_GetMaxBytes( msg )))
|
||||
{
|
||||
uint uCompressedSize = 0;
|
||||
uint uSourceSize = MSG_GetNumBytesWritten( msg );
|
||||
@@ -1175,7 +1174,7 @@ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *l
|
||||
p = n;
|
||||
}
|
||||
|
||||
if( chan->use_bz2 && !memcmp( MSG_GetData( msg ), "BZ2", 4 ) )
|
||||
if( chan->use_bz2 && !memcmp( MSG_GetData( msg ), "BZ2", 4 ))
|
||||
{
|
||||
#if !XASH_DEDICATED
|
||||
byte buf[0x10000];
|
||||
@@ -1196,7 +1195,7 @@ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *l
|
||||
Host_Error( "%s: BZ2 compression is not supported for server\n", __func__ );
|
||||
#endif
|
||||
}
|
||||
else if( !chan->use_bz2 && LZSS_IsCompressed( MSG_GetData( msg ), size ))
|
||||
else if( chan->use_lzss && LZSS_IsCompressed( MSG_GetData( msg ), size ))
|
||||
{
|
||||
uint uDecompressedLen = LZSS_GetActualSize( MSG_GetData( msg ), size );
|
||||
byte buf[NET_MAX_MESSAGE];
|
||||
@@ -1347,7 +1346,7 @@ qboolean Netchan_CopyFileFragments( netchan_t *chan, sizebuf_t *msg )
|
||||
Host_Error( "%s: BZ2 compression is not supported for server", __func__ );
|
||||
#endif
|
||||
}
|
||||
else if( LZSS_IsCompressed( buffer, nsize + 1 ))
|
||||
else if( chan->use_lzss && LZSS_IsCompressed( buffer, nsize + 1 ))
|
||||
{
|
||||
byte *uncompressedBuffer;
|
||||
|
||||
|
||||
@@ -39,8 +39,6 @@ GNU General Public License for more details.
|
||||
#define DT_SIGNED BIT( 8 ) // sign modificator
|
||||
#define DT_SIGNED_GS BIT( 31 ) // GoldSrc-specific sign modificator
|
||||
|
||||
#define NUM_FIELDS( x ) ((sizeof( x ) / sizeof( x[0] )) - 1)
|
||||
|
||||
// helper macroses
|
||||
#define ENTS_DEF( x ) #x, offsetof( entity_state_t, x ), sizeof( ((entity_state_t *)0)->x )
|
||||
#define UCMD_DEF( x ) #x, offsetof( usercmd_t, x ), sizeof( ((usercmd_t *)0)->x )
|
||||
@@ -71,7 +69,6 @@ static const delta_field_t cmd_fields[] =
|
||||
{ UCMD_DEF( impact_position[0] ) },
|
||||
{ UCMD_DEF( impact_position[1] ) },
|
||||
{ UCMD_DEF( impact_position[2] ) },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const delta_field_t pm_fields[] =
|
||||
@@ -107,7 +104,6 @@ static const delta_field_t pm_fields[] =
|
||||
{ PHYS_DEF( skydir_y ) },
|
||||
{ PHYS_DEF( skydir_z ) },
|
||||
{ PHYS_DEF( skyangle ) },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const delta_field_t ev_fields[] =
|
||||
@@ -130,7 +126,6 @@ static const delta_field_t ev_fields[] =
|
||||
{ EVNT_DEF( iparam2 ) },
|
||||
{ EVNT_DEF( bparam1 ) },
|
||||
{ EVNT_DEF( bparam2 ) },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const delta_field_t wd_fields[] =
|
||||
@@ -157,7 +152,6 @@ static const delta_field_t wd_fields[] =
|
||||
{ WPDT_DEF( fuser2 ) },
|
||||
{ WPDT_DEF( fuser3 ) },
|
||||
{ WPDT_DEF( fuser4 ) },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const delta_field_t cd_fields[] =
|
||||
@@ -218,7 +212,6 @@ static const delta_field_t cd_fields[] =
|
||||
{ CLDT_DEF( vuser4[0] ) },
|
||||
{ CLDT_DEF( vuser4[1] ) },
|
||||
{ CLDT_DEF( vuser4[2] ) },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const delta_field_t ent_fields[] =
|
||||
@@ -314,7 +307,6 @@ static const delta_field_t ent_fields[] =
|
||||
{ ENTS_DEF( vuser4[0] ) },
|
||||
{ ENTS_DEF( vuser4[1] ) },
|
||||
{ ENTS_DEF( vuser4[2] ) },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const delta_field_t meta_fields[] =
|
||||
@@ -326,7 +318,6 @@ static const delta_field_t meta_fields[] =
|
||||
{ DESC_DEF( significant_bits ), },
|
||||
{ DESC_DEF( premultiply ), },
|
||||
{ DESC_DEF( postmultiply ), },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
#if XASH_ENGINE_TESTS
|
||||
@@ -362,24 +353,22 @@ static const delta_field_t test_fields[] =
|
||||
{ TEST_DEF( dt_short_unsigned ) },
|
||||
{ TEST_DEF( dt_byte_signed ) },
|
||||
{ TEST_DEF( dt_byte_unsigned ) },
|
||||
{ NULL },
|
||||
};
|
||||
#endif
|
||||
|
||||
static delta_info_t dt_info[] =
|
||||
{
|
||||
[DT_EVENT_T] = { "event_t", ev_fields, NUM_FIELDS( ev_fields ) },
|
||||
[DT_MOVEVARS_T] = { "movevars_t", pm_fields, NUM_FIELDS( pm_fields ) },
|
||||
[DT_USERCMD_T] = { "usercmd_t", cmd_fields, NUM_FIELDS( cmd_fields ) },
|
||||
[DT_CLIENTDATA_T] = { "clientdata_t", cd_fields, NUM_FIELDS( cd_fields ) },
|
||||
[DT_WEAPONDATA_T] = { "weapon_data_t", wd_fields, NUM_FIELDS( wd_fields ) },
|
||||
[DT_ENTITY_STATE_T] = { "entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||
[DT_ENTITY_STATE_PLAYER_T] = { "entity_state_player_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||
[DT_CUSTOM_ENTITY_STATE_T] = { "custom_entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||
[DT_EVENT_T] = { "event_t", ev_fields, ARRAYSIZE( ev_fields ) },
|
||||
[DT_MOVEVARS_T] = { "movevars_t", pm_fields, ARRAYSIZE( pm_fields ) },
|
||||
[DT_USERCMD_T] = { "usercmd_t", cmd_fields, ARRAYSIZE( cmd_fields ) },
|
||||
[DT_CLIENTDATA_T] = { "clientdata_t", cd_fields, ARRAYSIZE( cd_fields ) },
|
||||
[DT_WEAPONDATA_T] = { "weapon_data_t", wd_fields, ARRAYSIZE( wd_fields ) },
|
||||
[DT_ENTITY_STATE_T] = { "entity_state_t", ent_fields, ARRAYSIZE( ent_fields ) },
|
||||
[DT_ENTITY_STATE_PLAYER_T] = { "entity_state_player_t", ent_fields, ARRAYSIZE( ent_fields ) },
|
||||
[DT_CUSTOM_ENTITY_STATE_T] = { "custom_entity_state_t", ent_fields, ARRAYSIZE( ent_fields ) },
|
||||
#if XASH_ENGINE_TESTS
|
||||
[DT_DELTA_TEST_STRUCT_T] = { "delta_test_struct_t", test_fields, NUM_FIELDS( test_fields ) },
|
||||
[DT_DELTA_TEST_STRUCT_T] = { "delta_test_struct_t", test_fields, ARRAYSIZE( test_fields ) },
|
||||
#endif
|
||||
[DT_STRUCT_COUNT] = { NULL },
|
||||
};
|
||||
|
||||
// meta description is special, it cannot be overriden
|
||||
@@ -387,9 +376,9 @@ static const delta_info_t dt_goldsrc_meta =
|
||||
{
|
||||
.pName = "goldsrc_delta_t",
|
||||
.pInfo = meta_fields,
|
||||
.maxFields = NUM_FIELDS( meta_fields ),
|
||||
.numFields = NUM_FIELDS( meta_fields ),
|
||||
.pFields = (delta_t[NUM_FIELDS( meta_fields )])
|
||||
.maxFields = ARRAYSIZE( meta_fields ),
|
||||
.numFields = ARRAYSIZE( meta_fields ),
|
||||
.pFields = (delta_t[ARRAYSIZE( meta_fields )])
|
||||
{
|
||||
{
|
||||
DESC_DEF( fieldType ),
|
||||
@@ -451,7 +440,7 @@ static delta_info_t *Delta_FindStruct( const char *name )
|
||||
if( !COM_CheckString( name ))
|
||||
return NULL;
|
||||
|
||||
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
|
||||
for( i = 0; i < ARRAYSIZE( dt_info ); i++ )
|
||||
{
|
||||
if( !Q_stricmp( dt_info[i].pName, name ))
|
||||
return &dt_info[i];
|
||||
@@ -465,7 +454,7 @@ static delta_info_t *Delta_FindStruct( const char *name )
|
||||
|
||||
static int Delta_NumTables( void )
|
||||
{
|
||||
return NUM_FIELDS( dt_info );
|
||||
return ARRAYSIZE( dt_info );
|
||||
}
|
||||
|
||||
static delta_info_t *Delta_FindStructByIndex( int index )
|
||||
@@ -480,7 +469,7 @@ static delta_info_t *Delta_FindStructByEncoder( const char *encoderName )
|
||||
if( !COM_CheckString( encoderName ) )
|
||||
return NULL;
|
||||
|
||||
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
|
||||
for( i = 0; i < ARRAYSIZE( dt_info ); i++ )
|
||||
{
|
||||
if( !Q_stricmp( dt_info[i].funcName, encoderName ))
|
||||
return &dt_info[i];
|
||||
@@ -495,7 +484,7 @@ static delta_info_t *Delta_FindStructByDelta( const delta_t *pFields )
|
||||
|
||||
if( !pFields ) return NULL;
|
||||
|
||||
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
|
||||
for( i = 0; i < ARRAYSIZE( dt_info ); i++ )
|
||||
{
|
||||
if( dt_info[i].pFields == pFields )
|
||||
return &dt_info[i];
|
||||
@@ -518,29 +507,32 @@ static void Delta_CustomEncode( delta_info_t *dt, const void *from, const void *
|
||||
dt->userCallback( dt->pFields, from, to );
|
||||
}
|
||||
|
||||
static delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName )
|
||||
static const delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName, int maxFields )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( !fieldName || !*fieldName )
|
||||
return NULL;
|
||||
|
||||
for( ; pInfo->name; pInfo++ )
|
||||
for( i = 0; i < maxFields; i++ )
|
||||
{
|
||||
if( !Q_strcmp( pInfo->name, fieldName ))
|
||||
return (delta_field_t *)pInfo;
|
||||
if( !Q_strcmp( pInfo[i].name, fieldName ))
|
||||
return &pInfo[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int Delta_IndexForFieldInfo( const delta_field_t *pInfo, const char *fieldName )
|
||||
static int Delta_IndexForFieldInfo( const delta_field_t *pInfo, const char *fieldName, int maxFields )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( !fieldName || !*fieldName )
|
||||
return -1;
|
||||
|
||||
for( i = 0; pInfo->name; i++, pInfo++ )
|
||||
for( i = 0; i < maxFields; i++ )
|
||||
{
|
||||
if( !Q_strcmp( pInfo->name, fieldName ))
|
||||
if( !Q_strcmp( pInfo[i].name, fieldName ))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
@@ -548,7 +540,7 @@ static int Delta_IndexForFieldInfo( const delta_field_t *pInfo, const char *fiel
|
||||
|
||||
static qboolean Delta_AddField( delta_info_t *dt, const char *pName, int flags, int bits, float mul, float post_mul )
|
||||
{
|
||||
delta_field_t *pFieldInfo;
|
||||
const delta_field_t *pFieldInfo;
|
||||
delta_t *pField;
|
||||
int i;
|
||||
|
||||
@@ -567,7 +559,7 @@ static qboolean Delta_AddField( delta_info_t *dt, const char *pName, int flags,
|
||||
}
|
||||
|
||||
// find field description
|
||||
pFieldInfo = Delta_FindFieldInfo( dt->pInfo, pName );
|
||||
pFieldInfo = Delta_FindFieldInfo( dt->pInfo, pName, dt->maxFields );
|
||||
if( !pFieldInfo )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "%s: couldn't find description for %s->%s\n", __func__, dt->pName, pName );
|
||||
@@ -610,7 +602,7 @@ static void Delta_WriteTableField( sizebuf_t *msg, int tableIndex, const delta_t
|
||||
dt = Delta_FindStructByIndex( tableIndex );
|
||||
Assert( dt && dt->bInitialized );
|
||||
|
||||
nameIndex = Delta_IndexForFieldInfo( dt->pInfo, pField->name );
|
||||
nameIndex = Delta_IndexForFieldInfo( dt->pInfo, pField->name, dt->maxFields );
|
||||
Assert( nameIndex >= 0 && nameIndex < dt->maxFields );
|
||||
|
||||
MSG_BeginServerCmd( msg, svc_deltatable );
|
||||
@@ -681,10 +673,10 @@ void Delta_ParseTableField( sizebuf_t *msg )
|
||||
Delta_AddField( dt, pName, flags, bits, mul, post_mul );
|
||||
}
|
||||
|
||||
static qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInfo, delta_t *pField, qboolean bPost )
|
||||
static qboolean Delta_ParseField( char **delta_script, const delta_info_t *dt, delta_t *pField, qboolean bPost )
|
||||
{
|
||||
const delta_field_t *pFieldInfo;
|
||||
string token;
|
||||
delta_field_t *pFieldInfo;
|
||||
char *oldpos;
|
||||
|
||||
*delta_script = COM_ParseFile( *delta_script, token, sizeof( token ));
|
||||
@@ -701,7 +693,7 @@ static qboolean Delta_ParseField( char **delta_script, const delta_field_t *pInf
|
||||
return false;
|
||||
}
|
||||
|
||||
pFieldInfo = Delta_FindFieldInfo( pInfo, token );
|
||||
pFieldInfo = Delta_FindFieldInfo( dt->pInfo, token, dt->maxFields );
|
||||
if( !pFieldInfo )
|
||||
{
|
||||
Con_DPrintf( S_ERROR "%s: unable to find field %s\n", __func__, token );
|
||||
@@ -825,13 +817,11 @@ static void Delta_ParseTable( char **delta_script, delta_info_t *dt, const char
|
||||
{
|
||||
string token;
|
||||
delta_t *pField;
|
||||
const delta_field_t *pInfo;
|
||||
|
||||
// allocate the delta-structures
|
||||
if( !dt->pFields ) dt->pFields = (delta_t *)Z_Calloc( dt->maxFields * sizeof( delta_t ));
|
||||
|
||||
pField = dt->pFields;
|
||||
pInfo = dt->pInfo;
|
||||
dt->numFields = 0;
|
||||
|
||||
// assume we have handled '{'
|
||||
@@ -841,12 +831,12 @@ static void Delta_ParseTable( char **delta_script, delta_info_t *dt, const char
|
||||
|
||||
if( !Q_strcmp( token, "DEFINE_DELTA" ))
|
||||
{
|
||||
if( Delta_ParseField( delta_script, pInfo, &pField[dt->numFields], false ))
|
||||
if( Delta_ParseField( delta_script, dt, &pField[dt->numFields], false ))
|
||||
dt->numFields++;
|
||||
}
|
||||
else if( !Q_strcmp( token, "DEFINE_DELTA_POST" ))
|
||||
{
|
||||
if( Delta_ParseField( delta_script, pInfo, &pField[dt->numFields], true ))
|
||||
if( Delta_ParseField( delta_script, dt, &pField[dt->numFields], true ))
|
||||
dt->numFields++;
|
||||
}
|
||||
else if( token[0] == '}' )
|
||||
@@ -963,7 +953,7 @@ void Delta_Init( void )
|
||||
Delta_AddField( dt, "skyvec_z", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f );
|
||||
Delta_AddField( dt, "wateralpha", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f );
|
||||
Delta_AddField( dt, "fog_settings", DT_INTEGER, 32, 1.0f, 1.0f );
|
||||
dt->numFields = NUM_FIELDS( pm_fields ) - 4;
|
||||
dt->numFields = ARRAYSIZE( pm_fields ) - 4;
|
||||
|
||||
// now done
|
||||
dt->bInitialized = true;
|
||||
@@ -976,7 +966,7 @@ void Delta_InitClient( void )
|
||||
// already initalized
|
||||
if( delta_init ) return;
|
||||
|
||||
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
|
||||
for( i = 0; i < ARRAYSIZE( dt_info ); i++ )
|
||||
{
|
||||
if( dt_info[i].numFields > 0 )
|
||||
{
|
||||
@@ -994,7 +984,7 @@ void Delta_Shutdown( void )
|
||||
|
||||
if( !delta_init ) return;
|
||||
|
||||
for( i = 0; i < NUM_FIELDS( dt_info ); i++ )
|
||||
for( i = 0; i < ARRAYSIZE( dt_info ); i++ )
|
||||
{
|
||||
dt_info[i].numFields = 0;
|
||||
dt_info[i].customEncode = CUSTOM_NONE;
|
||||
@@ -2292,10 +2282,6 @@ void Test_RunDelta( void )
|
||||
char buffer[4096] = { 0 };
|
||||
const double timebase = 123.123;
|
||||
|
||||
// a1ba: netbuffer bitmasks are initialized in netchan for some reason
|
||||
// initialize it ourselves just in case
|
||||
MSG_InitMasks(); // initialize bit-masks
|
||||
|
||||
Delta_AddField( dt, "dt_string", DT_STRING, 1, 1.0f, 1.0f );
|
||||
Delta_AddField( dt, "dt_timewindow_big", DT_TIMEWINDOW_BIG, 24, 1000.f, 1.0f );
|
||||
Delta_AddField( dt, "dt_timewindow_8", DT_TIMEWINDOW_8, 8, 1.0f, 1.0f );
|
||||
|
||||
@@ -46,7 +46,6 @@ enum
|
||||
#if XASH_ENGINE_TESTS
|
||||
DT_DELTA_TEST_STRUCT_T,
|
||||
#endif
|
||||
DT_STRUCT_COUNT
|
||||
};
|
||||
|
||||
// struct info (filled by engine)
|
||||
|
||||
@@ -326,7 +326,7 @@ static int HTTP_FileConnect( httpfile_t *file )
|
||||
if( !COM_CheckStringEmpty( http_useragent.string ) || !Q_strcmp( http_useragent.string, "xash3d" ))
|
||||
{
|
||||
Q_snprintf( useragent, sizeof( useragent ), "%s/%s (%s-%s; build %d; %s)",
|
||||
XASH_ENGINE_NAME, XASH_VERSION, Q_buildos( ), Q_buildarch( ), Q_buildnum( ), Q_buildcommit( ));
|
||||
XASH_ENGINE_NAME, XASH_VERSION, Q_buildos( ), Q_buildarch( ), Q_buildnum( ), g_buildcommit );
|
||||
}
|
||||
else Q_strncpy( useragent, http_useragent.string, sizeof( useragent ));
|
||||
|
||||
@@ -505,11 +505,14 @@ static int HTTP_FileDecompress( httpfile_t *file )
|
||||
|
||||
if( zlib_result == Z_OK || zlib_result == Z_STREAM_END )
|
||||
{
|
||||
Mem_Free( data_in );
|
||||
g_fsapi.WriteFile( name, data_out, decompressed_len );
|
||||
HTTP_FreeFile( file, false );
|
||||
}
|
||||
else HTTP_FreeFile( file, true );
|
||||
|
||||
Mem_Free( data_in );
|
||||
Mem_Free( data_out );
|
||||
|
||||
g_fsapi.WriteFile( name, data_out, decompressed_len );
|
||||
HTTP_FreeFile( file, false );
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -214,6 +214,7 @@ typedef enum netchan_flags_e
|
||||
NETCHAN_USE_MUNGE = BIT( 1 ),
|
||||
NETCHAN_USE_BZIP2 = BIT( 2 ),
|
||||
NETCHAN_GOLDSRC = BIT( 3 ),
|
||||
NETCHAN_USE_LZSS = BIT( 4 ), // mutually exclusive with bzip2
|
||||
} netchan_flags_t;
|
||||
|
||||
// Network Connection Channel
|
||||
@@ -285,6 +286,7 @@ typedef struct netchan_s
|
||||
qboolean split;
|
||||
qboolean use_munge;
|
||||
qboolean use_bz2;
|
||||
qboolean use_lzss;
|
||||
qboolean gs_netchan;
|
||||
} netchan_t;
|
||||
|
||||
|
||||
@@ -112,6 +112,9 @@ msurface_t *PM_RecursiveSurfCheck( model_t *mod, mnode_t *node, vec3_t p1, vec3_
|
||||
int i, side;
|
||||
msurface_t *surf;
|
||||
vec3_t mid;
|
||||
mnode_t *children[2];
|
||||
int numsurfaces, firstsurface;
|
||||
|
||||
loc0:
|
||||
if( node->contents < 0 )
|
||||
return NULL;
|
||||
@@ -119,15 +122,17 @@ loc0:
|
||||
t1 = PlaneDiff( p1, node->plane );
|
||||
t2 = PlaneDiff( p2, node->plane );
|
||||
|
||||
node_children( children, node, mod );
|
||||
|
||||
if( t1 >= -FRAC_EPSILON && t2 >= -FRAC_EPSILON )
|
||||
{
|
||||
node = node->children[0];
|
||||
node = children[0];
|
||||
goto loc0;
|
||||
}
|
||||
|
||||
if( t1 < FRAC_EPSILON && t2 < FRAC_EPSILON )
|
||||
{
|
||||
node = node->children[1];
|
||||
node = children[1];
|
||||
goto loc0;
|
||||
}
|
||||
|
||||
@@ -137,13 +142,15 @@ loc0:
|
||||
|
||||
VectorLerp( p1, frac, p2, mid );
|
||||
|
||||
if(( surf = PM_RecursiveSurfCheck( mod, node->children[side], p1, mid )) != NULL )
|
||||
if(( surf = PM_RecursiveSurfCheck( mod, children[side], p1, mid )) != NULL )
|
||||
return surf;
|
||||
|
||||
// walk through real faces
|
||||
for( i = 0; i < node->numsurfaces; i++ )
|
||||
numsurfaces = node_numsurfaces( node, mod );
|
||||
firstsurface = node_firstsurface( node, mod );
|
||||
for( i = 0; i < numsurfaces; i++ )
|
||||
{
|
||||
msurface_t *surf = &mod->surfaces[node->firstsurface + i];
|
||||
msurface_t *surf = &mod->surfaces[firstsurface + i];
|
||||
mextrasurf_t *info = surf->info;
|
||||
mfacebevel_t *fb = info->bevel;
|
||||
int j, contents;
|
||||
@@ -172,7 +179,7 @@ loc0:
|
||||
return NULL; // through the fence
|
||||
}
|
||||
|
||||
return PM_RecursiveSurfCheck( mod, node->children[side^1], mid, p2 );
|
||||
return PM_RecursiveSurfCheck( mod, children[side^1], mid, p2 );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -227,6 +234,9 @@ static int PM_TestLine_r( model_t *mod, mnode_t *node, vec_t p1f, vec_t p2f, con
|
||||
float frac, midf;
|
||||
int i, r, side;
|
||||
vec3_t mid;
|
||||
mnode_t *children[2];
|
||||
int numsurfaces, firstsurface;
|
||||
|
||||
loc0:
|
||||
if( node->contents < 0 )
|
||||
{
|
||||
@@ -242,15 +252,17 @@ loc0:
|
||||
front = PlaneDiff( start, node->plane );
|
||||
back = PlaneDiff( stop, node->plane );
|
||||
|
||||
node_children( children, node, mod );
|
||||
|
||||
if( front >= -FRAC_EPSILON && back >= -FRAC_EPSILON )
|
||||
{
|
||||
node = node->children[0];
|
||||
node = children[0];
|
||||
goto loc0;
|
||||
}
|
||||
|
||||
if( front < FRAC_EPSILON && back < FRAC_EPSILON )
|
||||
{
|
||||
node = node->children[1];
|
||||
node = children[1];
|
||||
goto loc0;
|
||||
}
|
||||
|
||||
@@ -261,7 +273,7 @@ loc0:
|
||||
VectorLerp( start, frac, stop, mid );
|
||||
midf = p1f + ( p2f - p1f ) * frac;
|
||||
|
||||
r = PM_TestLine_r( mod, node->children[side], p1f, midf, start, mid, trace );
|
||||
r = PM_TestLine_r( mod, children[side], p1f, midf, start, mid, trace );
|
||||
|
||||
if( r != CONTENTS_EMPTY )
|
||||
{
|
||||
@@ -272,9 +284,11 @@ loc0:
|
||||
}
|
||||
|
||||
// walk through real faces
|
||||
for( i = 0; i < node->numsurfaces; i++ )
|
||||
numsurfaces = node_numsurfaces( node, mod );
|
||||
firstsurface = node_firstsurface( node, mod );
|
||||
for( i = 0; i < numsurfaces; i++ )
|
||||
{
|
||||
msurface_t *surf = &mod->surfaces[node->firstsurface + i];
|
||||
msurface_t *surf = &mod->surfaces[firstsurface + i];
|
||||
mextrasurf_t *info = surf->info;
|
||||
mfacebevel_t *fb = info->bevel;
|
||||
int j, contents;
|
||||
@@ -308,7 +322,7 @@ loc0:
|
||||
return contents;
|
||||
}
|
||||
|
||||
return PM_TestLine_r( mod, node->children[!side], midf, p2f, mid, stop, trace );
|
||||
return PM_TestLine_r( mod, children[!side], midf, p2f, mid, stop, trace );
|
||||
}
|
||||
|
||||
int PM_TestLineExt( playermove_t *pmove, physent_t *ents, int numents, const vec3_t start, const vec3_t end, int flags )
|
||||
|
||||
@@ -25,8 +25,7 @@ GNU General Public License for more details.
|
||||
#define PM_AllowHitBoxTrace( model, hull ) ( model && model->type == mod_studio && ( FBitSet( model->flags, STUDIO_TRACE_HITBOX ) || hull == 2 ))
|
||||
|
||||
static mplane_t pm_boxplanes[6];
|
||||
static mclipnode_t pm_boxclipnodes[6];
|
||||
static hull_t pm_boxhull;
|
||||
static hull_t pm_boxhull;
|
||||
|
||||
// default hullmins
|
||||
static const vec3_t pm_hullmins[MAX_MAP_HULLS] =
|
||||
@@ -65,23 +64,15 @@ can just be stored out and get a proper hull_t structure.
|
||||
*/
|
||||
void PM_InitBoxHull( void )
|
||||
{
|
||||
int i, side;
|
||||
int i;
|
||||
|
||||
pm_boxhull.clipnodes = pm_boxclipnodes;
|
||||
pm_boxhull.clipnodes16 = (mclipnode16_t *)box_clipnodes16;
|
||||
pm_boxhull.planes = pm_boxplanes;
|
||||
pm_boxhull.firstclipnode = 0;
|
||||
pm_boxhull.lastclipnode = 5;
|
||||
|
||||
for( i = 0; i < 6; i++ )
|
||||
{
|
||||
pm_boxclipnodes[i].planenum = i;
|
||||
|
||||
side = i & 1;
|
||||
|
||||
pm_boxclipnodes[i].children[side] = CONTENTS_EMPTY;
|
||||
if( i != 5 ) pm_boxclipnodes[i].children[side^1] = i + 1;
|
||||
else pm_boxclipnodes[i].children[side^1] = CONTENTS_SOLID;
|
||||
|
||||
pm_boxplanes[i].type = i>>1;
|
||||
pm_boxplanes[i].normal[i>>1] = 1.0f;
|
||||
pm_boxplanes[i].signbits = 0;
|
||||
@@ -106,6 +97,11 @@ static hull_t *PM_HullForBox( const vec3_t mins, const vec3_t maxs )
|
||||
pm_boxplanes[4].dist = maxs[2];
|
||||
pm_boxplanes[5].dist = mins[2];
|
||||
|
||||
if( world.version == QBSP2_VERSION )
|
||||
pm_boxhull.clipnodes32 = (mclipnode32_t *)box_clipnodes32;
|
||||
else
|
||||
pm_boxhull.clipnodes16 = (mclipnode16_t *)box_clipnodes16;
|
||||
|
||||
return &pm_boxhull;
|
||||
}
|
||||
|
||||
@@ -122,10 +118,21 @@ int GAME_EXPORT PM_HullPointContents( hull_t *hull, int num, const vec3_t p )
|
||||
if( !hull || !hull->planes ) // fantom bmodels?
|
||||
return CONTENTS_NONE;
|
||||
|
||||
while( num >= 0 )
|
||||
if( world.version == QBSP2_VERSION )
|
||||
{
|
||||
plane = &hull->planes[hull->clipnodes[num].planenum];
|
||||
num = hull->clipnodes[num].children[PlaneDiff( p, plane ) < 0];
|
||||
while( num >= 0 )
|
||||
{
|
||||
plane = &hull->planes[hull->clipnodes32[num].planenum];
|
||||
num = hull->clipnodes32[num].children[PlaneDiff( p, plane ) < 0];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while( num >= 0 )
|
||||
{
|
||||
plane = &hull->planes[hull->clipnodes16[num].planenum];
|
||||
num = hull->clipnodes16[num].children[PlaneDiff( p, plane ) < 0];
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
@@ -193,7 +200,7 @@ PM_RecursiveHullCheck
|
||||
*/
|
||||
qboolean PM_RecursiveHullCheck( hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, pmtrace_t *trace )
|
||||
{
|
||||
mclipnode_t *node;
|
||||
int children[2];
|
||||
mplane_t *plane;
|
||||
float t1, t2;
|
||||
float frac, midf;
|
||||
@@ -226,21 +233,31 @@ loc0:
|
||||
Host_Error( "%s: bad node number %i\n", __func__, num );
|
||||
|
||||
// find the point distances
|
||||
node = hull->clipnodes + num;
|
||||
plane = hull->planes + node->planenum;
|
||||
if( world.version == QBSP2_VERSION )
|
||||
{
|
||||
children[0] = hull->clipnodes32[num].children[0];
|
||||
children[1] = hull->clipnodes32[num].children[1];
|
||||
plane = hull->planes + hull->clipnodes32[num].planenum;
|
||||
}
|
||||
else
|
||||
{
|
||||
children[0] = hull->clipnodes16[num].children[0];
|
||||
children[1] = hull->clipnodes16[num].children[1];
|
||||
plane = hull->planes + hull->clipnodes16[num].planenum;
|
||||
}
|
||||
|
||||
t1 = PlaneDiff( p1, plane );
|
||||
t2 = PlaneDiff( p2, plane );
|
||||
|
||||
if( t1 >= 0.0f && t2 >= 0.0f )
|
||||
{
|
||||
num = node->children[0];
|
||||
num = children[0];
|
||||
goto loc0;
|
||||
}
|
||||
|
||||
if( t1 < 0.0f && t2 < 0.0f )
|
||||
{
|
||||
num = node->children[1];
|
||||
num = children[1];
|
||||
goto loc0;
|
||||
}
|
||||
|
||||
@@ -257,14 +274,14 @@ loc0:
|
||||
VectorLerp( p1, frac, p2, mid );
|
||||
|
||||
// move up to the node
|
||||
if( !PM_RecursiveHullCheck( hull, node->children[side], p1f, midf, p1, mid, trace ))
|
||||
if( !PM_RecursiveHullCheck( hull, children[side], p1f, midf, p1, mid, trace ))
|
||||
return false;
|
||||
|
||||
// this recursion can not be optimized because mid would need to be duplicated on a stack
|
||||
if( PM_HullPointContents( hull, node->children[side^1], mid ) != CONTENTS_SOLID )
|
||||
if( PM_HullPointContents( hull, children[side^1], mid ) != CONTENTS_SOLID )
|
||||
{
|
||||
// go past the node
|
||||
return PM_RecursiveHullCheck( hull, node->children[side^1], midf, p2f, mid, p2, trace );
|
||||
return PM_RecursiveHullCheck( hull, children[side^1], midf, p2f, mid, p2, trace );
|
||||
}
|
||||
|
||||
// never got out of the solid area
|
||||
|
||||
@@ -324,20 +324,14 @@ extern const char *const clc_strings[clc_lastmsg+1];
|
||||
#define PROTOCOL_GOLDSRC_VERSION 48
|
||||
|
||||
#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
|
||||
|
||||
@@ -89,16 +89,6 @@ void Sound_Shutdown( void )
|
||||
Mem_FreePool( &host.soundpool );
|
||||
}
|
||||
|
||||
static byte *Sound_Copy( size_t size )
|
||||
{
|
||||
byte *out;
|
||||
|
||||
out = Mem_Realloc( host.soundpool, sound.tempbuffer, size );
|
||||
sound.tempbuffer = NULL;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
uint GAME_EXPORT Sound_GetApproxWavePlayLen( const char *filepath )
|
||||
{
|
||||
string name;
|
||||
@@ -378,6 +368,7 @@ static qboolean Sound_ResampleInternal( wavdata_t *sc, int outrate, int outwidth
|
||||
const int inwidth = sc->width;
|
||||
const int inchannels = sc->channels;
|
||||
const int incount = sc->samples;
|
||||
const int insize = sc->size;
|
||||
qboolean handled = false;
|
||||
double stepscale;
|
||||
double t1, t2;
|
||||
@@ -431,22 +422,30 @@ static qboolean Sound_ResampleInternal( wavdata_t *sc, int outrate, int outwidth
|
||||
else // upsample case, w/ interpolation
|
||||
handled = Sound_ConvertUpsample( sc, inwidth, inchannels, incount, outwidth, outchannels, outcount, stepscale );
|
||||
|
||||
t2 = Sys_DoubleTime();
|
||||
|
||||
if( handled )
|
||||
if( !handled )
|
||||
{
|
||||
if( t2 - t1 > 0.01f ) // critical, report to mod developer
|
||||
Con_Printf( S_WARN "%s: from [%d bit %d Hz %dch] to [%d bit %d Hz %dch] (took %.3fs)\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels, t2 - t1 );
|
||||
else
|
||||
Con_Reportf( "%s: from [%d bit %d Hz %dch] to [%d bit %d Hz %dch] (took %.3fs)\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels, t2 - t1 );
|
||||
}
|
||||
else
|
||||
// restore previously changed data
|
||||
sc->rate = inrate;
|
||||
sc->width = inwidth;
|
||||
sc->channels = inchannels;
|
||||
sc->samples = incount;
|
||||
sc->size = insize;
|
||||
|
||||
Con_Printf( S_ERROR "%s: unsupported from [%d bit %d Hz %dch] to [%d bit %d Hz %dch]\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
t2 = Sys_DoubleTime();
|
||||
sc->rate = outrate;
|
||||
sc->width = outwidth;
|
||||
|
||||
return handled;
|
||||
if( t2 - t1 > 0.01f ) // critical, report to mod developer
|
||||
Con_Printf( S_WARN "%s: from [%d bit %d Hz %dch] to [%d bit %d Hz %dch] (took %.3fs)\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels, t2 - t1 );
|
||||
else
|
||||
Con_Reportf( "%s: from [%d bit %d Hz %dch] to [%d bit %d Hz %dch] (took %.3fs)\n", __func__, inwidth * 8, inrate, inchannels, outwidth * 8, outrate, outchannels, t2 - t1 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
qboolean Sound_Process( wavdata_t **wav, int rate, int width, int channels, uint flags )
|
||||
@@ -464,8 +463,11 @@ qboolean Sound_Process( wavdata_t **wav, int rate, int width, int channels, uint
|
||||
|
||||
if( result )
|
||||
{
|
||||
Mem_Free( snd->buffer ); // free original image buffer
|
||||
snd->buffer = Sound_Copy( snd->size ); // unzone buffer
|
||||
snd = Mem_Realloc( host.soundpool, snd, sizeof( *snd ) + snd->size );
|
||||
memcpy( snd->buffer, sound.tempbuffer, snd->size );
|
||||
|
||||
Mem_Free( sound.tempbuffer );
|
||||
sound.tempbuffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,7 @@ GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#if XASH_WIN32
|
||||
#define STDOUT_FILENO 1
|
||||
#include <io.h>
|
||||
#elif XASH_ANDROID
|
||||
#if XASH_ANDROID
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
@@ -25,20 +22,13 @@ GNU General Public License for more details.
|
||||
#if XASH_IRIX
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#include "xash3d_mathlib.h"
|
||||
|
||||
// do not waste precious CPU cycles on mobiles or low memory devices
|
||||
#if !XASH_WIN32 && !XASH_MOBILE_PLATFORM && !XASH_LOW_MEMORY
|
||||
#define XASH_COLORIZE_CONSOLE true
|
||||
// use with caution, running engine in Qt Creator may cause a freeze in read() call
|
||||
// I have never encountered this bug anywhere else, so still enable by default
|
||||
#define XASH_USE_SELECT 1
|
||||
#define XASH_COLORIZE_CONSOLE 1
|
||||
#else
|
||||
#define XASH_COLORIZE_CONSOLE false
|
||||
#endif
|
||||
|
||||
#if XASH_USE_SELECT
|
||||
// non-blocking console input
|
||||
#include <sys/select.h>
|
||||
#define XASH_COLORIZE_CONSOLE 0
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
@@ -51,41 +41,6 @@ typedef struct {
|
||||
|
||||
static LogData s_ld;
|
||||
|
||||
char *Sys_Input( void )
|
||||
{
|
||||
#if XASH_USE_SELECT
|
||||
if( Host_IsDedicated( ))
|
||||
{
|
||||
fd_set rfds;
|
||||
static char line[1024];
|
||||
static int len;
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO( &rfds );
|
||||
FD_SET( 0, &rfds); // stdin
|
||||
while( select( 1, &rfds, NULL, NULL, &tv ) > 0 )
|
||||
{
|
||||
if( read( 0, &line[len], 1 ) != 1 )
|
||||
break;
|
||||
if( line[len] == '\n' || len > 1022 )
|
||||
{
|
||||
line[ ++len ] = 0;
|
||||
len = 0;
|
||||
return line;
|
||||
}
|
||||
len++;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if XASH_WIN32
|
||||
return Wcon_Input();
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Sys_DestroyConsole( void )
|
||||
{
|
||||
// last text message into console or log
|
||||
@@ -154,48 +109,48 @@ void Sys_InitLog( void )
|
||||
|
||||
// fit to 80 columns for easier read on standard terminal
|
||||
fputs( "================================================================================\n", s_ld.logfile );
|
||||
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
|
||||
fprintf( s_ld.logfile, "Game started at %s\n", Q_timestamp( TIME_FULL ));
|
||||
fputs( "================================================================================\n", s_ld.logfile );
|
||||
fflush( s_ld.logfile );
|
||||
}
|
||||
}
|
||||
|
||||
void Sys_CloseLog( void )
|
||||
void Sys_CloseLog( const char *finalmsg )
|
||||
{
|
||||
char event_name[64];
|
||||
|
||||
// continue logged
|
||||
switch( host.status )
|
||||
{
|
||||
case HOST_CRASHED:
|
||||
Q_strncpy( event_name, "crashed", sizeof( event_name ));
|
||||
break;
|
||||
case HOST_ERR_FATAL:
|
||||
Q_strncpy( event_name, "stopped with error", sizeof( event_name ));
|
||||
break;
|
||||
default:
|
||||
if( !host.change_game ) Q_strncpy( event_name, "stopped", sizeof( event_name ));
|
||||
else Q_strncpy( event_name, host.finalmsg, sizeof( event_name ));
|
||||
break;
|
||||
}
|
||||
|
||||
Sys_FlushStdout(); // flush to stdout to ensure all data was written
|
||||
|
||||
if( s_ld.logfile )
|
||||
if( !s_ld.logfile )
|
||||
return;
|
||||
|
||||
// continue logged
|
||||
if( !finalmsg )
|
||||
{
|
||||
fputc( '\n', s_ld.logfile );
|
||||
fputs( "================================================================================\n", s_ld.logfile );
|
||||
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
||||
fprintf( s_ld.logfile, "Stopped with reason \"%s\" at %s\n", event_name, Q_timestamp( TIME_FULL ));
|
||||
fputs( "================================================================================\n", s_ld.logfile );
|
||||
fclose( s_ld.logfile );
|
||||
s_ld.logfile = NULL;
|
||||
switch( host.status )
|
||||
{
|
||||
case HOST_CRASHED:
|
||||
finalmsg = "crashed";
|
||||
break;
|
||||
case HOST_ERR_FATAL:
|
||||
finalmsg = "stopped with error";
|
||||
break;
|
||||
default:
|
||||
finalmsg = "stopped";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fputc( '\n', s_ld.logfile );
|
||||
fputs( "================================================================================\n", s_ld.logfile );
|
||||
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), g_buildcommit, g_buildbranch, Q_buildos(), Q_buildarch());
|
||||
fprintf( s_ld.logfile, "Stopped with reason \"%s\" at %s\n", finalmsg, Q_timestamp( TIME_FULL ));
|
||||
fputs( "================================================================================\n", s_ld.logfile );
|
||||
fclose( s_ld.logfile );
|
||||
s_ld.logfile = NULL;
|
||||
}
|
||||
|
||||
#if XASH_COLORIZE_CONSOLE == true
|
||||
static void Sys_WriteEscapeSequenceForColorcode( int fd, int c )
|
||||
#if XASH_COLORIZE_CONSOLE
|
||||
static qboolean Sys_WriteEscapeSequenceForColorcode( int fd, int c )
|
||||
{
|
||||
static const char *q3ToAnsi[ 8 ] =
|
||||
{
|
||||
@@ -210,19 +165,26 @@ static void Sys_WriteEscapeSequenceForColorcode( int fd, int c )
|
||||
};
|
||||
const char *esc = q3ToAnsi[c];
|
||||
|
||||
if( c == 7 )
|
||||
write( fd, esc, 4 );
|
||||
else write( fd, esc, 7 );
|
||||
return write( fd, esc, c == 7 ? 4 : 7 ) < 0 ? false : true;
|
||||
}
|
||||
#else
|
||||
static void Sys_WriteEscapeSequenceForColorcode( int fd, int c ) {}
|
||||
static qboolean Sys_WriteEscapeSequenceForColorcode( int fd, int c )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void Sys_PrintLogfile( const int fd, const char *logtime, const char *msg, const qboolean colorize )
|
||||
static void Sys_PrintLogfile( const int fd, const char *logtime, size_t logtime_len, const char *msg, const int colorize )
|
||||
{
|
||||
const char *p = msg;
|
||||
|
||||
write( fd, logtime, Q_strlen( logtime ) );
|
||||
if( logtime_len != 0 )
|
||||
{
|
||||
if( write( fd, logtime, logtime_len ) < 0 )
|
||||
{
|
||||
// not critical for us
|
||||
}
|
||||
}
|
||||
|
||||
while( p && *p )
|
||||
{
|
||||
@@ -262,7 +224,7 @@ static void Sys_PrintLogfile( const int fd, const char *logtime, const char *msg
|
||||
Sys_WriteEscapeSequenceForColorcode( fd, 7 );
|
||||
}
|
||||
|
||||
static void Sys_PrintStdout( const char *logtime, const char *msg )
|
||||
static void Sys_PrintStdout( const char *logtime, size_t logtime_len, const char *msg )
|
||||
{
|
||||
#if XASH_MOBILE_PLATFORM
|
||||
static char buf[MAX_PRINT_MSG];
|
||||
@@ -294,7 +256,7 @@ static void Sys_PrintStdout( const char *logtime, const char *msg )
|
||||
#endif
|
||||
|
||||
#elif !XASH_WIN32 // Wcon does the job
|
||||
Sys_PrintLogfile( STDOUT_FILENO, logtime, msg, XASH_COLORIZE_CONSOLE );
|
||||
Sys_PrintLogfile( STDOUT_FILENO, logtime, logtime_len, msg, XASH_COLORIZE_CONSOLE );
|
||||
Sys_FlushStdout();
|
||||
#endif
|
||||
}
|
||||
@@ -305,33 +267,44 @@ void Sys_PrintLog( const char *pMsg )
|
||||
const struct tm *crt_tm;
|
||||
char logtime[32] = "";
|
||||
static char lastchar;
|
||||
size_t len;
|
||||
qboolean print_time = true;
|
||||
size_t len, logtime_len = 0;
|
||||
|
||||
time( &crt_time );
|
||||
crt_tm = localtime( &crt_time );
|
||||
if( !lastchar || lastchar == '\n' )
|
||||
{
|
||||
if( time( &crt_time ) >= 0 )
|
||||
{
|
||||
crt_tm = localtime( &crt_time );
|
||||
if( crt_tm == NULL )
|
||||
print_time = false;
|
||||
}
|
||||
}
|
||||
else print_time = false;
|
||||
|
||||
if( !lastchar || lastchar == '\n')
|
||||
strftime( logtime, sizeof( logtime ), "[%H:%M:%S] ", crt_tm ); //short time
|
||||
if( print_time )
|
||||
{
|
||||
logtime_len = strftime( logtime, sizeof( logtime ), "[%H:%M:%S] ", crt_tm ); // short time
|
||||
logtime_len = Q_min( logtime_len, sizeof( logtime ) - 1 ); // just in case
|
||||
}
|
||||
|
||||
// spew to stdout
|
||||
Sys_PrintStdout( logtime, pMsg );
|
||||
Sys_PrintStdout( logtime, logtime_len, pMsg );
|
||||
|
||||
len = Q_strlen( pMsg );
|
||||
|
||||
if( !s_ld.logfile )
|
||||
{
|
||||
// save last char to detect when line was not ended
|
||||
lastchar = len > 0 ? pMsg[len - 1] : 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if( !lastchar || lastchar == '\n')
|
||||
strftime( logtime, sizeof( logtime ), "[%Y:%m:%d|%H:%M:%S] ", crt_tm ); //full time
|
||||
|
||||
// save last char to detect when line was not ended
|
||||
lastchar = len > 0 ? pMsg[len - 1] : 0;
|
||||
|
||||
Sys_PrintLogfile( s_ld.logfileno, logtime, pMsg, false );
|
||||
if( !s_ld.logfile )
|
||||
return;
|
||||
|
||||
if( print_time )
|
||||
{
|
||||
logtime_len = strftime( logtime, sizeof( logtime ), "[%Y:%m:%d|%H:%M:%S] ", crt_tm ); //full time
|
||||
logtime_len = Q_min( logtime_len, sizeof( logtime ) - 1 ); // just in case
|
||||
}
|
||||
|
||||
Sys_PrintLogfile( s_ld.logfileno, logtime, logtime_len, pMsg, false );
|
||||
Sys_FlushLogfile();
|
||||
}
|
||||
|
||||
|
||||
@@ -234,28 +234,12 @@ qboolean Sys_GetIntFromCmdLine( const char* argName, int *out )
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sys_SendKeyEvents( void )
|
||||
{
|
||||
#if XASH_WIN32
|
||||
MSG msg;
|
||||
|
||||
while( PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ))
|
||||
{
|
||||
if( !GetMessage( &msg, NULL, 0, 0 ))
|
||||
Sys_Quit ();
|
||||
|
||||
TranslateMessage( &msg );
|
||||
DispatchMessage( &msg );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// DLL'S MANAGER SYSTEM
|
||||
//=======================================================================
|
||||
qboolean Sys_LoadLibrary( dll_info_t *dll )
|
||||
{
|
||||
const dllfunc_t *func;
|
||||
size_t i;
|
||||
string errorstring;
|
||||
|
||||
// check errors
|
||||
@@ -267,12 +251,8 @@ qboolean Sys_LoadLibrary( dll_info_t *dll )
|
||||
|
||||
Con_Reportf( "%s: Loading %s", __func__, dll->name );
|
||||
|
||||
if( dll->fcts )
|
||||
{
|
||||
// lookup export table
|
||||
for( func = dll->fcts; func && func->name != NULL; func++ )
|
||||
*func->func = NULL;
|
||||
}
|
||||
if( dll->fcts ) // lookup export table
|
||||
ClearExports( dll->fcts, dll->num_fcts );
|
||||
|
||||
if( !dll->link )
|
||||
dll->link = COM_LoadLibrary( dll->name, false, true ); // environment pathes
|
||||
@@ -285,9 +265,10 @@ qboolean Sys_LoadLibrary( dll_info_t *dll )
|
||||
}
|
||||
|
||||
// Get the function adresses
|
||||
for( func = dll->fcts; func && func->name != NULL; func++ )
|
||||
for( i = 0; i < dll->num_fcts; i++ )
|
||||
{
|
||||
if( !( *func->func = Sys_GetProcAddress( dll, func->name )))
|
||||
const dllfunc_t *func = &dll->fcts[i];
|
||||
if( !( *func->func = COM_GetProcAddress( dll->link, func->name )))
|
||||
{
|
||||
Q_snprintf( errorstring, sizeof( errorstring ), "Sys_LoadLibrary: %s missing or invalid function (%s)\n", dll->name, func->name );
|
||||
goto error;
|
||||
@@ -300,19 +281,11 @@ error:
|
||||
Con_Reportf( " - failed\n" );
|
||||
Sys_FreeLibrary( dll ); // trying to free
|
||||
if( dll->crash ) Sys_Error( "%s", errorstring );
|
||||
else Con_Reportf( S_ERROR "%s", errorstring );
|
||||
else Con_Reportf( S_ERROR "%s", errorstring );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void* Sys_GetProcAddress( dll_info_t *dll, const char* name )
|
||||
{
|
||||
if( !dll || !dll->link ) // invalid desc
|
||||
return NULL;
|
||||
|
||||
return (void *)COM_GetProcAddress( dll->link, name );
|
||||
}
|
||||
|
||||
qboolean Sys_FreeLibrary( dll_info_t *dll )
|
||||
{
|
||||
// invalid desc or alredy freed
|
||||
@@ -330,6 +303,8 @@ qboolean Sys_FreeLibrary( dll_info_t *dll )
|
||||
COM_FreeLibrary( dll->link );
|
||||
dll->link = NULL;
|
||||
|
||||
ClearExports( dll->fcts, dll->num_fcts );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -437,7 +412,7 @@ void Sys_Error( const char *error, ... )
|
||||
Sys_WaitForQuit();
|
||||
}
|
||||
|
||||
Sys_Quit();
|
||||
Sys_Quit( "caught an error" );
|
||||
}
|
||||
|
||||
#if XASH_EMSCRIPTEN
|
||||
@@ -445,6 +420,12 @@ void Sys_Error( const char *error, ... )
|
||||
_exit->_Exit->asm._exit->_exit
|
||||
As we do not need atexit(), just throw hidden exception
|
||||
*/
|
||||
|
||||
// Hey, you, making an Emscripten port!
|
||||
// What if we're not supposed to use exit() on Emscripten and instead we should
|
||||
// exit from the main() function? Would this fix this bug? Test this case, pls.
|
||||
#error "Read the comment above"
|
||||
|
||||
#include <emscripten.h>
|
||||
#define exit my_exit
|
||||
void my_exit(int ret)
|
||||
@@ -460,10 +441,14 @@ void my_exit(int ret)
|
||||
Sys_Quit
|
||||
================
|
||||
*/
|
||||
void Sys_Quit( void )
|
||||
void Sys_Quit( const char *reason )
|
||||
{
|
||||
Host_Shutdown();
|
||||
Host_ShutdownWithReason( reason );
|
||||
#if XASH_ANDROID
|
||||
Host_ExitInMain();
|
||||
#else
|
||||
exit( error_on_exit );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -554,7 +539,7 @@ but since engine will be unloaded during this call
|
||||
it explicitly doesn't use internal allocation or string copy utils
|
||||
==================
|
||||
*/
|
||||
qboolean Sys_NewInstance( const char *gamedir )
|
||||
qboolean Sys_NewInstance( const char *gamedir, const char *finalmsg )
|
||||
{
|
||||
#if XASH_NSWITCH
|
||||
char newargs[4096];
|
||||
@@ -565,7 +550,7 @@ qboolean Sys_NewInstance( const char *gamedir )
|
||||
// just restart the entire thing
|
||||
printf( "envSetNextLoad exe: `%s`\n", exe );
|
||||
printf( "envSetNextLoad argv:\n`%s`\n", newargs );
|
||||
Host_Shutdown( );
|
||||
Host_ShutdownWithReason( finalmsg );
|
||||
envSetNextLoad( exe, newargs );
|
||||
exit( 0 );
|
||||
#else
|
||||
@@ -603,7 +588,7 @@ qboolean Sys_NewInstance( const char *gamedir )
|
||||
#if XASH_PSVITA
|
||||
// under normal circumstances it's always going to be the same path
|
||||
exe = strdup( "app0:/eboot.bin" );
|
||||
Host_Shutdown( );
|
||||
Host_ShutdownWithReason( finalmsg );
|
||||
sceAppMgrLoadExec( exe, newargs, NULL );
|
||||
#else
|
||||
exelen = wai_getExecutablePath( NULL, 0, NULL );
|
||||
@@ -611,7 +596,7 @@ qboolean Sys_NewInstance( const char *gamedir )
|
||||
wai_getExecutablePath( exe, exelen, NULL );
|
||||
exe[exelen] = 0;
|
||||
|
||||
Host_Shutdown();
|
||||
Host_ShutdownWithReason( finalmsg );
|
||||
|
||||
execv( exe, newargs );
|
||||
#endif
|
||||
|
||||
@@ -41,6 +41,15 @@ NOTE: never change this structure because all dll descriptions in xash code
|
||||
writes into struct by offsets not names
|
||||
========================================================================
|
||||
*/
|
||||
typedef struct dll_info_s
|
||||
{
|
||||
const char *name; // name of library
|
||||
const dllfunc_t *fcts; // list of dll exports
|
||||
const size_t num_fcts;
|
||||
qboolean crash; // crash if dll not found
|
||||
void *link; // hinstance of loading library
|
||||
} dll_info_t;
|
||||
|
||||
extern int error_on_exit;
|
||||
double Sys_DoubleTime( void );
|
||||
char *Sys_GetClipboardData( void );
|
||||
@@ -49,22 +58,15 @@ int Sys_CheckParm( const char *parm );
|
||||
void Sys_Warn( const char *format, ... ) FORMAT_CHECK( 1 );
|
||||
void Sys_Error( const char *error, ... ) FORMAT_CHECK( 1 );
|
||||
qboolean Sys_LoadLibrary( dll_info_t *dll );
|
||||
void* Sys_GetProcAddress( dll_info_t *dll, const char* name );
|
||||
qboolean Sys_FreeLibrary( dll_info_t *dll );
|
||||
void Sys_ParseCommandLine( int argc, char **argv );
|
||||
void Sys_SetupCrashHandler( void );
|
||||
void Sys_RestoreCrashHandler( void );
|
||||
void Sys_DebugBreak( void );
|
||||
#define Sys_GetParmFromCmdLine( parm, out ) _Sys_GetParmFromCmdLine( parm, out, sizeof( out ))
|
||||
qboolean _Sys_GetParmFromCmdLine( const char *parm, char *out, size_t size );
|
||||
qboolean Sys_GetIntFromCmdLine( const char *parm, int *out );
|
||||
void Sys_SendKeyEvents( void );
|
||||
void Sys_Print( const char *pMsg );
|
||||
void Sys_PrintLog( const char *pMsg );
|
||||
void Sys_InitLog( void );
|
||||
void Sys_CloseLog( void );
|
||||
void Sys_Quit( void ) NORETURN;
|
||||
qboolean Sys_NewInstance( const char *gamedir );
|
||||
void Sys_Quit( const char *reason ) NORETURN;
|
||||
qboolean Sys_NewInstance( const char *gamedir, const char *finalmsg );
|
||||
void *Sys_GetNativeObject( const char *obj );
|
||||
|
||||
//
|
||||
@@ -72,7 +74,7 @@ void *Sys_GetNativeObject( const char *obj );
|
||||
//
|
||||
char *Sys_Input( void );
|
||||
void Sys_DestroyConsole( void );
|
||||
void Sys_CloseLog( void );
|
||||
void Sys_CloseLog( const char *finalmsg );
|
||||
void Sys_InitLog( void );
|
||||
void Sys_PrintLog( const char *pMsg );
|
||||
int Sys_LogFileNo( void );
|
||||
|
||||
@@ -68,7 +68,13 @@ extern "C" {
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
#if (_MSC_VER >= 1900)
|
||||
#include <stdbool.h>
|
||||
#else
|
||||
#define bool int
|
||||
#define false 0
|
||||
#define true 1
|
||||
#endif
|
||||
|
||||
static int WAI_PREFIX(getModulePath_)(HMODULE module, char* out, int capacity, int* dirname_length)
|
||||
{
|
||||
@@ -243,6 +249,11 @@ int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(WAI_STRINGIZE)
|
||||
#define WAI_STRINGIZE(s)
|
||||
#define WAI_STRINGIZE_(s) #s
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__) || defined(ANDROID)
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
@@ -265,20 +276,20 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char buffer[PATH_MAX < 1024 ? 1024 : PATH_MAX];
|
||||
uint64_t low, high;
|
||||
char buffer[128 + PATH_MAX];
|
||||
uintptr_t low, high;
|
||||
char perms[5];
|
||||
uint64_t offset;
|
||||
uint32_t major, minor;
|
||||
char path[PATH_MAX];
|
||||
uint32_t inode;
|
||||
uint32_t major, minor, inode;
|
||||
char path[PATH_MAX + 1];
|
||||
|
||||
if (!fgets(buffer, sizeof(buffer), maps))
|
||||
break;
|
||||
|
||||
if (sscanf(buffer, "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " %x:%x %u %s\n", &low, &high, perms, &offset, &major, &minor, &inode, path) == 8)
|
||||
if (sscanf(buffer, "%" SCNxPTR "-%" SCNxPTR " %s %" SCNx64 " %x:%x %u %" WAI_STRINGIZE(PATH_MAX) "[^\n]\n", &low, &high, perms, &offset, &major, &minor, &inode, path) == 8)
|
||||
{
|
||||
uint64_t addr = (uintptr_t)WAI_RETURN_ADDRESS();
|
||||
void* _addr = WAI_RETURN_ADDRESS();
|
||||
uintptr_t addr = (uintptr_t)_addr;
|
||||
if (low <= addr && addr <= high)
|
||||
{
|
||||
char* resolved;
|
||||
|
||||
@@ -31,7 +31,8 @@ extern "C" {
|
||||
* @param out destination buffer, optional
|
||||
* @param capacity destination buffer capacity
|
||||
* @param dirname_length optional recipient for the length of the dirname part
|
||||
* of the path.
|
||||
* of the path. Available only when `capacity` is large enough to retrieve the
|
||||
* path.
|
||||
*
|
||||
* @return the length of the executable path on success (without a terminal NUL
|
||||
* character), otherwise `-1`
|
||||
@@ -52,7 +53,8 @@ int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length);
|
||||
* @param out destination buffer, optional
|
||||
* @param capacity destination buffer capacity
|
||||
* @param dirname_length optional recipient for the length of the dirname part
|
||||
* of the path.
|
||||
* of the path. Available only when `capacity` is large enough to retrieve the
|
||||
* path.
|
||||
*
|
||||
* @return the length of the module path on success (without a terminal NUL
|
||||
* character), otherwise `-1`
|
||||
|
||||
@@ -18,7 +18,7 @@ GNU General Public License for more details.
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define MEMHEADER_SENTINEL1 0xDEADF00DU
|
||||
#define MEMHEADER_SENTINEL1 0xA1BAU
|
||||
#define MEMHEADER_SENTINEL2 0xDFU
|
||||
|
||||
#ifdef XASH_CUSTOM_SWAP
|
||||
@@ -51,31 +51,29 @@ static void *Q_realloc( void *mem, size_t size )
|
||||
#define Q_realloc realloc
|
||||
#endif
|
||||
|
||||
// keep this structure as compact as possible while keeping it aligned
|
||||
// on ILP32 it's 24 bytes, which is aligned to 8 byte boundary
|
||||
// on LP64 it's 40 bytes, which is also aligned to 8 byte boundary
|
||||
typedef struct memheader_s
|
||||
{
|
||||
struct memheader_s *next; // next and previous memheaders in chain belonging to pool
|
||||
struct memheader_s *prev;
|
||||
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
|
||||
#endif
|
||||
uint32_t sentinel1; // should always be MEMHEADER_SENTINEL1
|
||||
|
||||
struct memheader_s *next, *prev; // next and previous memheaders in chain belonging to pool
|
||||
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
|
||||
uint16_t fileline;
|
||||
uint16_t sentinel1; // must be equal to MEMHEADER_SENTINEL1
|
||||
// immediately followed by data, which is followed by a MEMHEADER_SENTINEL2 byte
|
||||
} memheader_t;
|
||||
|
||||
typedef struct mempool_s
|
||||
{
|
||||
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
|
||||
const char *filename; // file name and line where Mem_AllocPool was called
|
||||
int fileline;
|
||||
char name[64]; // name of the pool
|
||||
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
|
||||
const char *filename; // file name and line where Mem_AllocPool was called
|
||||
int fileline;
|
||||
char name[64]; // name of the pool
|
||||
} mempool_t;
|
||||
|
||||
static mempool_t *poolchain = NULL; // critical stuff
|
||||
@@ -521,4 +519,5 @@ Memory_Init
|
||||
void Memory_Init( void )
|
||||
{
|
||||
poolchain = NULL; // init mem chain
|
||||
poolcount = 0;
|
||||
}
|
||||
|
||||
@@ -16,11 +16,8 @@
|
||||
#ifndef EDICT_H
|
||||
#define EDICT_H
|
||||
|
||||
#ifdef SUPPORT_BSP2_FORMAT
|
||||
#define MAX_ENT_LEAFS 24 // Orignally was 16
|
||||
#else
|
||||
#define MAX_ENT_LEAFS 48
|
||||
#endif
|
||||
#define MAX_ENT_LEAFS_32 24 // Orignally was 16
|
||||
#define MAX_ENT_LEAFS_16 48
|
||||
|
||||
#include "progdefs.h"
|
||||
|
||||
@@ -33,11 +30,12 @@ struct edict_s
|
||||
int headnode; // -1 to use normal leaf check
|
||||
|
||||
int num_leafs;
|
||||
#ifdef SUPPORT_BSP2_FORMAT
|
||||
int leafnums[MAX_ENT_LEAFS];
|
||||
#else
|
||||
short leafnums[MAX_ENT_LEAFS];
|
||||
#endif
|
||||
union
|
||||
{
|
||||
int leafnums32[MAX_ENT_LEAFS_32];
|
||||
short leafnums16[MAX_ENT_LEAFS_16];
|
||||
};
|
||||
|
||||
float freetime; // sv.time when the object was freed
|
||||
|
||||
void* pvPrivateData; // Alloced and freed by engine, used by DLLs
|
||||
|
||||
300
engine/keydefs.h
300
engine/keydefs.h
@@ -1,186 +1,164 @@
|
||||
/***
|
||||
*
|
||||
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
|
||||
*
|
||||
* This product contains software technology licensed from Id
|
||||
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Use, distribution, and modification of this source code and/or resulting
|
||||
* object code is restricted to non-commercial enhancements to products from
|
||||
* Valve LLC. All other use, distribution, or modification is prohibited
|
||||
* without written permission from Valve LLC.
|
||||
*
|
||||
****/
|
||||
/*
|
||||
Copyright (C) 1997-2001 Id Software, Inc.
|
||||
|
||||
#ifndef KEYDEFS_H
|
||||
#define KEYDEFS_H
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
// taken from Quake-2 source code and modified for GoldSrc compatibility
|
||||
|
||||
//
|
||||
// these are the key numbers that should be passed to Key_Event
|
||||
//
|
||||
#define K_TAB 9
|
||||
#define K_ENTER 13
|
||||
#define K_ESCAPE 27
|
||||
#define K_SPACE 32
|
||||
#define K_SCROLLOCK 70
|
||||
|
||||
// normal keys should be passed as lowercased ascii
|
||||
//
|
||||
#define K_TAB 9
|
||||
#define K_ENTER 13
|
||||
#define K_ESCAPE 27
|
||||
#define K_SPACE 32
|
||||
#define K_SCROLLLOCK 70
|
||||
#define K_BACKSPACE 127
|
||||
#define K_UPARROW 128
|
||||
#define K_DOWNARROW 129
|
||||
#define K_LEFTARROW 130
|
||||
#define K_RIGHTARROW 131
|
||||
#define K_ALT 132
|
||||
#define K_CTRL 133
|
||||
#define K_SHIFT 134
|
||||
#define K_F1 135
|
||||
#define K_F2 136
|
||||
#define K_F3 137
|
||||
#define K_F4 138
|
||||
#define K_F5 139
|
||||
#define K_F6 140
|
||||
#define K_F7 141
|
||||
#define K_F8 142
|
||||
#define K_F9 143
|
||||
#define K_F10 144
|
||||
#define K_F11 145
|
||||
#define K_F12 146
|
||||
#define K_INS 147
|
||||
#define K_DEL 148
|
||||
#define K_PGDN 149
|
||||
#define K_PGUP 150
|
||||
#define K_HOME 151
|
||||
#define K_END 152
|
||||
|
||||
#define K_BACKSPACE 127
|
||||
#define K_UPARROW 128
|
||||
#define K_DOWNARROW 129
|
||||
#define K_LEFTARROW 130
|
||||
#define K_RIGHTARROW 131
|
||||
|
||||
#define K_ALT 132
|
||||
#define K_CTRL 133
|
||||
#define K_SHIFT 134
|
||||
#define K_F1 135
|
||||
#define K_F2 136
|
||||
#define K_F3 137
|
||||
#define K_F4 138
|
||||
#define K_F5 139
|
||||
#define K_F6 140
|
||||
#define K_F7 141
|
||||
#define K_F8 142
|
||||
#define K_F9 143
|
||||
#define K_F10 144
|
||||
#define K_F11 145
|
||||
#define K_F12 146
|
||||
#define K_INS 147
|
||||
#define K_DEL 148
|
||||
#define K_PGDN 149
|
||||
#define K_PGUP 150
|
||||
#define K_HOME 151
|
||||
#define K_END 152
|
||||
|
||||
#define K_KP_HOME 160
|
||||
#define K_KP_UPARROW 161
|
||||
#define K_KP_PGUP 162
|
||||
#define K_KP_LEFTARROW 163
|
||||
#define K_KP_5 164
|
||||
#define K_KP_HOME 160
|
||||
#define K_KP_UPARROW 161
|
||||
#define K_KP_PGUP 162
|
||||
#define K_KP_LEFTARROW 163
|
||||
#define K_KP_5 164
|
||||
#define K_KP_RIGHTARROW 165
|
||||
#define K_KP_END 166
|
||||
#define K_KP_DOWNARROW 167
|
||||
#define K_KP_PGDN 168
|
||||
#define K_KP_ENTER 169
|
||||
#define K_KP_INS 170
|
||||
#define K_KP_DEL 171
|
||||
#define K_KP_SLASH 172
|
||||
#define K_KP_MINUS 173
|
||||
#define K_KP_PLUS 174
|
||||
#define K_CAPSLOCK 175
|
||||
#define K_KP_MUL 176
|
||||
#define K_WIN 177
|
||||
#define K_KP_NUMLOCK 178
|
||||
#define K_KP_END 166
|
||||
#define K_KP_DOWNARROW 167
|
||||
#define K_KP_PGDN 168
|
||||
#define K_KP_ENTER 169
|
||||
#define K_KP_INS 170
|
||||
#define K_KP_DEL 171
|
||||
#define K_KP_SLASH 172
|
||||
#define K_KP_MINUS 173
|
||||
#define K_KP_PLUS 174
|
||||
#define K_CAPSLOCK 175
|
||||
#define K_KP_MUL 176
|
||||
#define K_WIN 177
|
||||
#define K_KP_NUMLOCK 178
|
||||
|
||||
//
|
||||
// joystick buttons
|
||||
//
|
||||
#define K_JOY1 203 // LTRIGGER (L2)
|
||||
#define K_JOY2 204 // RTRIGGER (R2)
|
||||
#define K_JOY3 205
|
||||
#define K_JOY4 206
|
||||
#define K_JOY1 203
|
||||
#define K_JOY2 204
|
||||
#define K_JOY3 205
|
||||
#define K_JOY4 206
|
||||
|
||||
//
|
||||
// aux keys are for multi-buttoned joysticks to generate so they can use
|
||||
// the normal binding process
|
||||
//
|
||||
#define K_AUX1 207
|
||||
#define K_A_BUTTON K_AUX1
|
||||
#define K_AUX1 207
|
||||
#define K_AUX2 208
|
||||
#define K_AUX3 209
|
||||
#define K_AUX4 210
|
||||
#define K_AUX5 211
|
||||
#define K_AUX6 212
|
||||
#define K_AUX7 213
|
||||
#define K_AUX8 214
|
||||
#define K_AUX9 215
|
||||
#define K_AUX10 216
|
||||
#define K_AUX11 217
|
||||
#define K_AUX12 218
|
||||
#define K_AUX13 219
|
||||
#define K_AUX14 220
|
||||
#define K_AUX15 221
|
||||
#define K_AUX16 222
|
||||
#define K_AUX17 223
|
||||
#define K_AUX18 224
|
||||
#define K_AUX19 225
|
||||
#define K_AUX20 226
|
||||
#define K_AUX21 227
|
||||
#define K_AUX22 228
|
||||
#define K_AUX23 229
|
||||
#define K_AUX24 230
|
||||
#define K_AUX25 231
|
||||
#define K_AUX26 232
|
||||
#define K_AUX27 233
|
||||
#define K_AUX28 234
|
||||
#define K_AUX29 235
|
||||
#define K_AUX30 236
|
||||
#define K_AUX31 237
|
||||
#define K_AUX32 238
|
||||
|
||||
#define K_AUX2 208
|
||||
#define K_B_BUTTON K_AUX2
|
||||
|
||||
#define K_AUX3 209
|
||||
#define K_X_BUTTON K_AUX3
|
||||
|
||||
#define K_AUX4 210
|
||||
#define K_Y_BUTTON K_AUX4
|
||||
|
||||
#define K_AUX5 211
|
||||
#define K_L1_BUTTON K_AUX5
|
||||
|
||||
#define K_AUX6 212
|
||||
#define K_R1_BUTTON K_AUX6
|
||||
|
||||
#define K_AUX7 213
|
||||
#define K_BACK_BUTTON K_AUX7
|
||||
|
||||
#define K_AUX8 214
|
||||
#define K_MODE_BUTTON K_AUX8
|
||||
|
||||
#define K_AUX9 215
|
||||
#define K_START_BUTTON K_AUX9
|
||||
|
||||
#define K_AUX10 216
|
||||
#define K_LSTICK K_AUX10
|
||||
|
||||
#define K_AUX11 217
|
||||
#define K_RSTICK K_AUX11
|
||||
|
||||
#define K_AUX12 218
|
||||
#define K_L2_BUTTON K_AUX12
|
||||
|
||||
#define K_AUX13 219
|
||||
#define K_R2_BUTTON K_AUX13
|
||||
|
||||
#define K_AUX14 220
|
||||
#define K_C_BUTTON K_AUX14
|
||||
|
||||
#define K_AUX15 221
|
||||
#define K_Z_BUTTON K_AUX15
|
||||
|
||||
#define K_AUX16 222
|
||||
#define K_DPAD_UP K_AUX16
|
||||
|
||||
#define K_AUX17 223
|
||||
#define K_DPAD_DOWN K_AUX17
|
||||
|
||||
#define K_AUX18 224
|
||||
#define K_DPAD_LEFT K_AUX18
|
||||
|
||||
#define K_AUX19 225
|
||||
#define K_DPAD_RIGHT K_AUX19
|
||||
|
||||
#define K_AUX20 226
|
||||
#define K_MISC_BUTTON K_AUX20 // Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button
|
||||
|
||||
#define K_AUX21 227
|
||||
#define K_PADDLE1_BUTTON K_AUX21 // Xbox Elite paddle P1-P4
|
||||
|
||||
#define K_AUX22 228
|
||||
//
|
||||
// button names for game pads
|
||||
//
|
||||
#define K_A_BUTTON K_AUX1
|
||||
#define K_B_BUTTON K_AUX2
|
||||
#define K_X_BUTTON K_AUX3
|
||||
#define K_Y_BUTTON K_AUX4
|
||||
#define K_L1_BUTTON K_AUX5
|
||||
#define K_R1_BUTTON K_AUX6
|
||||
#define K_BACK_BUTTON K_AUX7
|
||||
#define K_MODE_BUTTON K_AUX8
|
||||
#define K_START_BUTTON K_AUX9
|
||||
#define K_LSTICK K_AUX10
|
||||
#define K_RSTICK K_AUX11
|
||||
#define K_L2_BUTTON K_AUX12
|
||||
#define K_R2_BUTTON K_AUX13
|
||||
#define K_C_BUTTON K_AUX14
|
||||
#define K_Z_BUTTON K_AUX15
|
||||
#define K_DPAD_UP K_AUX16
|
||||
#define K_DPAD_DOWN K_AUX17
|
||||
#define K_DPAD_LEFT K_AUX18
|
||||
#define K_DPAD_RIGHT K_AUX19
|
||||
#define K_MISC_BUTTON K_AUX20
|
||||
#define K_PADDLE1_BUTTON K_AUX21
|
||||
#define K_PADDLE2_BUTTON K_AUX22
|
||||
|
||||
#define K_AUX23 229
|
||||
#define K_PADDLE3_BUTTON K_AUX23
|
||||
|
||||
#define K_AUX24 230
|
||||
#define K_PADDLE4_BUTTON K_AUX24
|
||||
|
||||
#define K_AUX25 231
|
||||
#define K_TOUCHPAD K_AUX25 // PS4/PS5 touchpad button
|
||||
|
||||
#define K_AUX26 232
|
||||
#define K_AUX27 233
|
||||
#define K_AUX28 234
|
||||
#define K_AUX29 235
|
||||
#define K_AUX30 236
|
||||
#define K_AUX31 237
|
||||
#define K_AUX32 238
|
||||
#define K_MWHEELDOWN 239
|
||||
#define K_MWHEELUP 240
|
||||
|
||||
#define K_PAUSE 255
|
||||
#define K_TOUCHPAD K_AUX25
|
||||
|
||||
//
|
||||
// mouse buttons generate virtual keys
|
||||
//
|
||||
#define K_MOUSE1 241
|
||||
#define K_MOUSE2 242
|
||||
#define K_MOUSE3 243
|
||||
#define K_MOUSE4 244
|
||||
#define K_MOUSE5 245
|
||||
#define K_MWHEELDOWN 239
|
||||
#define K_MWHEELUP 240
|
||||
#define K_MOUSE1 241
|
||||
#define K_MOUSE2 242
|
||||
#define K_MOUSE3 243
|
||||
#define K_MOUSE4 244
|
||||
#define K_MOUSE5 245
|
||||
|
||||
#endif//KEYDEFS_H
|
||||
#define K_PAUSE 255
|
||||
|
||||
@@ -184,7 +184,7 @@ qboolean SNDDMA_Init( void )
|
||||
return false;
|
||||
}
|
||||
|
||||
dma.buffer = Z_Malloc( samples * 2 ); //allocate pcm frame buffer
|
||||
dma.buffer = Mem_Malloc( sndpool, samples * 2 ); //allocate pcm frame buffer
|
||||
dma.samplepos = 0;
|
||||
dma.samples = samples;
|
||||
dma.format.width = 2;
|
||||
|
||||
@@ -34,6 +34,7 @@ long pathconf( const char *path, int name ) { return -1; }
|
||||
|
||||
// part of libunwind; required by any dynamic lib that uses C++ exceptions
|
||||
extern void *_Unwind_Resume;
|
||||
extern void *_Unwind_GetIPInfo;
|
||||
|
||||
// these are macros in our libc, so we need to wrap them
|
||||
static int tolower_fn( int c ) { return tolower( c ); }
|
||||
@@ -55,6 +56,7 @@ static const solder_export_t aux_exports[] =
|
||||
SOLDER_EXPORT_SYMBOL( strchrnul ),
|
||||
SOLDER_EXPORT_SYMBOL( stpcpy ),
|
||||
SOLDER_EXPORT_SYMBOL( _Unwind_Resume ),
|
||||
SOLDER_EXPORT_SYMBOL( _Unwind_GetIPInfo ),
|
||||
};
|
||||
|
||||
const solder_export_t *__solder_aux_exports = aux_exports;
|
||||
|
||||
@@ -51,10 +51,11 @@ void IOS_LaunchDialog( void );
|
||||
#if XASH_POSIX
|
||||
void Posix_Daemonize( void );
|
||||
void Posix_SetupSigtermHandling( void );
|
||||
char *Posix_Input( void );
|
||||
#endif
|
||||
|
||||
#if XASH_SDL
|
||||
void SDLash_Init( void );
|
||||
void SDLash_Init( const char *basedir );
|
||||
void SDLash_Shutdown( void );
|
||||
#endif
|
||||
|
||||
@@ -103,7 +104,7 @@ void Linux_SetTimer( float time );
|
||||
int Linux_GetProcessID( void );
|
||||
#endif
|
||||
|
||||
static inline void Platform_Init( qboolean con_showalways )
|
||||
static inline void Platform_Init( qboolean con_showalways, const char *basedir )
|
||||
{
|
||||
#if XASH_POSIX
|
||||
// daemonize as early as possible, because we need to close our file descriptors
|
||||
@@ -111,7 +112,7 @@ static inline void Platform_Init( qboolean con_showalways )
|
||||
#endif
|
||||
|
||||
#if XASH_SDL
|
||||
SDLash_Init( );
|
||||
SDLash_Init( basedir );
|
||||
#endif
|
||||
|
||||
#if XASH_ANDROID
|
||||
@@ -177,6 +178,20 @@ static inline void Platform_Sleep( int msec )
|
||||
#endif
|
||||
}
|
||||
|
||||
#if XASH_WIN32 || XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX
|
||||
void Sys_SetupCrashHandler( void );
|
||||
void Sys_RestoreCrashHandler( void );
|
||||
#else
|
||||
static inline void Sys_SetupCrashHandler( void )
|
||||
{
|
||||
}
|
||||
|
||||
static inline void Sys_RestoreCrashHandler( void )
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
@@ -227,6 +242,17 @@ static inline void Platform_SetTimer( float time )
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline char *Platform_Input( void )
|
||||
{
|
||||
#if XASH_WIN32
|
||||
return Wcon_Input();
|
||||
#elif XASH_POSIX && !XASH_MOBILE_PLATFORM && !XASH_LOW_MEMORY
|
||||
return Posix_Input();
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
|
||||
52
engine/platform/posix/con_posix.c
Normal file
52
engine/platform/posix/con_posix.c
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
con_posix.c - reading from stdin
|
||||
Copyright (C) 2024 Flying With Gauss
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "platform/platform.h"
|
||||
|
||||
#if !XASH_MOBILE_PLATFORM && !XASH_LOW_MEMORY
|
||||
// use with caution, running engine in Qt Creator may cause a freeze in read() call
|
||||
// I have never encountered this bug anywhere else, so still enable by default
|
||||
#include <sys/select.h>
|
||||
|
||||
char *Posix_Input( void )
|
||||
{
|
||||
fd_set rfds;
|
||||
static char line[1024];
|
||||
static int len;
|
||||
struct timeval tv = { 0 };
|
||||
|
||||
if( !Host_IsDedicated( ))
|
||||
return NULL;
|
||||
|
||||
FD_ZERO( &rfds );
|
||||
FD_SET( 0, &rfds); // stdin
|
||||
while( select( 1, &rfds, NULL, NULL, &tv ) > 0 )
|
||||
{
|
||||
if( read( 0, &line[len], 1 ) != 1 )
|
||||
break;
|
||||
if( line[len] == '\n' || len > ( sizeof( line ) - 2 ))
|
||||
{
|
||||
line[ ++len ] = 0;
|
||||
len = 0;
|
||||
return line;
|
||||
}
|
||||
len++;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif // !XASH_MOBILE_PLATFORM && !XASH_LOW_MEMORY
|
||||
222
engine/platform/posix/crash_posix.c
Normal file
222
engine/platform/posix/crash_posix.c
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
crashhandler.c - advanced crashhandler
|
||||
Copyright (C) 2016 Mittorn
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
// while this is mostly POSIX-compatible functions
|
||||
// the contents of ucontext_t is platform-dependent
|
||||
// before adding new OS here, check platform.h
|
||||
#if XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX
|
||||
#ifndef XASH_OPENBSD
|
||||
#include <ucontext.h>
|
||||
#endif
|
||||
#include <signal.h>
|
||||
#include <sys/mman.h>
|
||||
#include "library.h"
|
||||
|
||||
#define STACK_BACKTRACE_STR "Stack backtrace:\n"
|
||||
#define STACK_DUMP_STR "Stack dump:\n"
|
||||
|
||||
#define STACK_BACKTRACE_STR_LEN ( sizeof( STACK_BACKTRACE_STR ) - 1 )
|
||||
#define STACK_DUMP_STR_LEN ( sizeof( STACK_DUMP_STR ) - 1 )
|
||||
#define ALIGN( x, y ) (((uintptr_t) ( x ) + (( y ) - 1 )) & ~(( y ) - 1 ))
|
||||
|
||||
static struct sigaction oldFilter;
|
||||
|
||||
static int Sys_PrintFrame( char *buf, int len, int i, void *addr )
|
||||
{
|
||||
Dl_info dlinfo;
|
||||
if( len <= 0 )
|
||||
return 0; // overflow
|
||||
|
||||
if( dladdr( addr, &dlinfo ))
|
||||
{
|
||||
if( dlinfo.dli_sname )
|
||||
return Q_snprintf( buf, len, "%2d: %p <%s+%lu> (%s)\n", i, addr, dlinfo.dli_sname,
|
||||
(unsigned long)addr - (unsigned long)dlinfo.dli_saddr, dlinfo.dli_fname ); // print symbol, module and address
|
||||
|
||||
return Q_snprintf( buf, len, "%2d: %p (%s)\n", i, addr, dlinfo.dli_fname ); // print module and address
|
||||
}
|
||||
|
||||
return Q_snprintf( buf, len, "%2d: %p\n", i, addr ); // print only address
|
||||
}
|
||||
|
||||
static void Sys_Crash( int signal, siginfo_t *si, void *context)
|
||||
{
|
||||
void *pc = NULL, **bp = NULL, **sp = NULL; // this must be set for every OS!
|
||||
char message[8192];
|
||||
int len, logfd, i = 0;
|
||||
|
||||
#if XASH_OPENBSD
|
||||
struct sigcontext *ucontext = (struct sigcontext*)context;
|
||||
#else
|
||||
ucontext_t *ucontext = (ucontext_t*)context;
|
||||
#endif
|
||||
|
||||
#if XASH_AMD64
|
||||
#if XASH_FREEBSD
|
||||
pc = (void*)ucontext->uc_mcontext.mc_rip;
|
||||
bp = (void**)ucontext->uc_mcontext.mc_rbp;
|
||||
sp = (void**)ucontext->uc_mcontext.mc_rsp;
|
||||
#elif XASH_NETBSD
|
||||
pc = (void*)ucontext->uc_mcontext.__gregs[_REG_RIP];
|
||||
bp = (void**)ucontext->uc_mcontext.__gregs[_REG_RBP];
|
||||
sp = (void**)ucontext->uc_mcontext.__gregs[_REG_RSP];
|
||||
#elif XASH_OPENBSD
|
||||
pc = (void*)ucontext->sc_rip;
|
||||
bp = (void**)ucontext->sc_rbp;
|
||||
sp = (void**)ucontext->sc_rsp;
|
||||
#else
|
||||
pc = (void*)ucontext->uc_mcontext.gregs[REG_RIP];
|
||||
bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];
|
||||
sp = (void**)ucontext->uc_mcontext.gregs[REG_RSP];
|
||||
#endif
|
||||
#elif XASH_X86
|
||||
#if XASH_FREEBSD
|
||||
pc = (void*)ucontext->uc_mcontext.mc_eip;
|
||||
bp = (void**)ucontext->uc_mcontext.mc_ebp;
|
||||
sp = (void**)ucontext->uc_mcontext.mc_esp;
|
||||
#elif XASH_NETBSD
|
||||
pc = (void*)ucontext->uc_mcontext.__gregs[_REG_EIP];
|
||||
bp = (void**)ucontext->uc_mcontext.__gregs[_REG_EBP];
|
||||
sp = (void**)ucontext->uc_mcontext.__gregs[_REG_ESP];
|
||||
#elif XASH_OPENBSD
|
||||
pc = (void*)ucontext->sc_eip;
|
||||
bp = (void**)ucontext->sc_ebp;
|
||||
sp = (void**)ucontext->sc_esp;
|
||||
#else
|
||||
pc = (void*)ucontext->uc_mcontext.gregs[REG_EIP];
|
||||
bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];
|
||||
sp = (void**)ucontext->uc_mcontext.gregs[REG_ESP];
|
||||
#endif
|
||||
#elif XASH_ARM && XASH_64BIT
|
||||
pc = (void*)ucontext->uc_mcontext.pc;
|
||||
bp = (void*)ucontext->uc_mcontext.regs[29];
|
||||
sp = (void*)ucontext->uc_mcontext.sp;
|
||||
#elif XASH_ARM
|
||||
pc = (void*)ucontext->uc_mcontext.arm_pc;
|
||||
bp = (void*)ucontext->uc_mcontext.arm_fp;
|
||||
sp = (void*)ucontext->uc_mcontext.arm_sp;
|
||||
#endif
|
||||
|
||||
// safe actions first, stack and memory may be corrupted
|
||||
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n",
|
||||
Q_buildnum(), g_buildcommit, Q_buildos(), Q_buildarch() );
|
||||
|
||||
#if !XASH_FREEBSD && !XASH_NETBSD && !XASH_OPENBSD
|
||||
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p %p\n", signal, si->si_errno, si->si_code, si->si_addr, si->si_ptr );
|
||||
#else
|
||||
len += Q_snprintf( message + len, sizeof( message ) - len, "Crash: signal %d errno %d with code %d at %p\n", signal, si->si_errno, si->si_code, si->si_addr );
|
||||
#endif
|
||||
|
||||
write( STDERR_FILENO, message, len );
|
||||
|
||||
// flush buffers before writing directly to descriptors
|
||||
fflush( stdout );
|
||||
fflush( stderr );
|
||||
|
||||
// now get log fd and write trace directly to log
|
||||
logfd = Sys_LogFileNo();
|
||||
write( logfd, message, len );
|
||||
|
||||
if( pc && bp && sp )
|
||||
{
|
||||
size_t pagesize = sysconf( _SC_PAGESIZE );
|
||||
|
||||
// try to print backtrace
|
||||
write( STDERR_FILENO, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN );
|
||||
write( logfd, STACK_BACKTRACE_STR, STACK_BACKTRACE_STR_LEN );
|
||||
Q_strncpy( message + len, STACK_BACKTRACE_STR, sizeof( message ) - len );
|
||||
len += STACK_BACKTRACE_STR_LEN;
|
||||
|
||||
// false on success, true on failure
|
||||
#define try_allow_read(pointer, pagesize) \
|
||||
(( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_WRITE | PROT_EXEC ) == -1 ) && \
|
||||
( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_EXEC ) == -1 ) && \
|
||||
( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ | PROT_WRITE ) == -1 ) && \
|
||||
( mprotect( (char *)ALIGN( (pointer), (pagesize) ), (pagesize), PROT_READ ) == -1 ))
|
||||
|
||||
do
|
||||
{
|
||||
int line = Sys_PrintFrame( message + len, sizeof( message ) - len, ++i, pc);
|
||||
write( STDERR_FILENO, message + len, line );
|
||||
write( logfd, message + len, line );
|
||||
len += line;
|
||||
//if( !dladdr(bp,0) ) break; // only when bp is in module
|
||||
if( try_allow_read( bp, pagesize ) )
|
||||
break;
|
||||
if( try_allow_read( bp[0], pagesize ) )
|
||||
break;
|
||||
pc = bp[1];
|
||||
bp = (void**)bp[0];
|
||||
}
|
||||
while( bp && i < 128 );
|
||||
|
||||
// try to print stack
|
||||
write( STDERR_FILENO, STACK_DUMP_STR, STACK_DUMP_STR_LEN );
|
||||
write( logfd, STACK_DUMP_STR, STACK_DUMP_STR_LEN );
|
||||
Q_strncpy( message + len, STACK_DUMP_STR, sizeof( message ) - len );
|
||||
len += STACK_DUMP_STR_LEN;
|
||||
|
||||
if( !try_allow_read( sp, pagesize ) )
|
||||
{
|
||||
for( i = 0; i < 32; i++ )
|
||||
{
|
||||
int line = Sys_PrintFrame( message + len, sizeof( message ) - len, i, sp[i] );
|
||||
write( STDERR_FILENO, message + len, line );
|
||||
write( logfd, message + len, line );
|
||||
len += line;
|
||||
}
|
||||
}
|
||||
|
||||
#undef try_allow_read
|
||||
}
|
||||
|
||||
// put MessageBox as Sys_Error
|
||||
Msg( "%s\n", message );
|
||||
#ifdef XASH_SDL
|
||||
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
|
||||
#endif
|
||||
host.crashed = true;
|
||||
Platform_MessageBox( "Xash Error", message, false );
|
||||
|
||||
// log saved, now we can try to save configs and close log correctly, it may crash
|
||||
if( host.type == HOST_NORMAL )
|
||||
CL_Crashed();
|
||||
host.status = HOST_CRASHED;
|
||||
|
||||
Sys_Quit( "crashed" );
|
||||
}
|
||||
|
||||
void Sys_SetupCrashHandler( void )
|
||||
{
|
||||
struct sigaction act = { 0 };
|
||||
act.sa_sigaction = Sys_Crash;
|
||||
act.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
sigaction( SIGSEGV, &act, &oldFilter );
|
||||
sigaction( SIGABRT, &act, &oldFilter );
|
||||
sigaction( SIGBUS, &act, &oldFilter );
|
||||
sigaction( SIGILL, &act, &oldFilter );
|
||||
}
|
||||
|
||||
void Sys_RestoreCrashHandler( void )
|
||||
{
|
||||
sigaction( SIGSEGV, &oldFilter, NULL );
|
||||
sigaction( SIGABRT, &oldFilter, NULL );
|
||||
sigaction( SIGBUS, &oldFilter, NULL );
|
||||
sigaction( SIGILL, &oldFilter, NULL );
|
||||
}
|
||||
|
||||
#endif // XASH_FREEBSD || XASH_NETBSD || XASH_OPENBSD || XASH_ANDROID || XASH_LINUX
|
||||
@@ -148,7 +148,9 @@ void Posix_Daemonize( void )
|
||||
|
||||
static void Posix_SigtermCallback( int signal )
|
||||
{
|
||||
Sys_Quit();
|
||||
string reason;
|
||||
Con_Printf( reason, sizeof( reason ), "caught signal %d", signal );
|
||||
Sys_Quit( reason );
|
||||
}
|
||||
|
||||
void Posix_SetupSigtermHandling( void )
|
||||
|
||||
@@ -265,7 +265,7 @@ static void SDLash_KeyEvent( SDL_KeyboardEvent key )
|
||||
break;
|
||||
}
|
||||
case SDL_SCANCODE_PAUSE: keynum = K_PAUSE; break;
|
||||
case SDL_SCANCODE_SCROLLLOCK: keynum = K_SCROLLOCK; break;
|
||||
case SDL_SCANCODE_SCROLLLOCK: keynum = K_SCROLLLOCK; break;
|
||||
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
|
||||
case SDL_SCANCODE_APPLICATION: keynum = K_WIN; break; // (compose key) ???
|
||||
// don't console spam on known functional buttons, not used in engine
|
||||
@@ -396,8 +396,12 @@ static void SDLash_ActiveEvent( int gain )
|
||||
}
|
||||
#endif
|
||||
host.status = HOST_NOFOCUS;
|
||||
|
||||
if( cls.key_dest == key_game )
|
||||
{
|
||||
Key_ClearStates();
|
||||
IN_DeactivateMouse();
|
||||
}
|
||||
|
||||
host.force_draw_version_time = host.realtime + 2.0;
|
||||
VID_RestoreScreenResolution();
|
||||
@@ -498,7 +502,7 @@ static void SDLash_EventHandler( SDL_Event *event )
|
||||
break;
|
||||
|
||||
case SDL_QUIT:
|
||||
Sys_Quit();
|
||||
Sys_Quit( "caught SDL_QUIT" );
|
||||
break;
|
||||
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
|
||||
case SDL_MOUSEWHEEL:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user