Compare commits

...

107 Commits

Author SHA1 Message Date
Alibek Omarov
004af02e99 engine: avi: comment out debug messages 2025-01-29 11:13:29 +03:00
Alibek Omarov
8ad56eb085 Merge branch 'master' into avi 2025-01-29 11:12:38 +03:00
Alibek Omarov
578a77518f engine: client: fix clearing keyboard buttons caused by typical brain fart 2025-01-29 10:04:47 +03:00
Alibek Omarov
2457ecf226 filesystem: fix recursive basedir possible cyclic dependency when default game directory uses a basedir that's base directory is undefined
That could happen when default game directory depends on base directory that don't have gameinfo.txt.
Because all game directories with liblist.gam automatically have dependency on default game directory, it causes cyclic dependency.
2025-01-29 09:49:29 +03:00
Alibek Omarov
8cd99885f1 filesystem: clean added status for game folders when purging search paths 2025-01-29 09:46:18 +03:00
Alibek Omarov
684e229ac8 engine: client: get rid of absolutely useless bitfields 2025-01-26 23:34:04 +03:00
SNMetamorph
c0f1d8c647 engine: model: fixed incorrect check in Mod_LoadModel 2025-01-26 23:27:18 +03:00
SNMetamorph
c3b8696957 engine: platform: win32: disable initializing console in case of regular game startup 2025-01-26 23:02:24 +03:00
Tom Kidd
3ca413dbab Fixed path calc for extras on Mac 2025-01-26 22:25:08 +03:00
Alibek Omarov
92dc04ff3c engine: client: minor change, add forgotten newline in CL_DeltaEntityGS Host_Error call 2025-01-25 17:51:48 +03:00
Alibek Omarov
ad6db91285 engine: move xashid stuff onto client 2025-01-25 17:51:48 +03:00
David DeGraw
90a0f74087 undo change to mod link 2025-01-25 08:23:04 +03:00
David DeGraw
4f7f5288a1 more nits 2025-01-25 08:23:04 +03:00
David DeGraw
c23b4bfe61 nits 2025-01-25 08:23:04 +03:00
David DeGraw
4780f70ea2 Improve mod installation instructions
Also improved uplink setup and used a better source for mod files.
2025-01-25 08:23:04 +03:00
NightFox
98a04c7764 FIx Matrix*x4_LoadIdentity (xash3d_mathlib.h) 2025-01-25 08:21:21 +03:00
Alibek Omarov
7da9772143 engine: check for macOS bundle in SDL_GetBasePath, and fallback to SDL_GetPrefPath for our directory 2025-01-23 22:58:19 +03:00
Alibek Omarov
32def35408 engine: avi: remove stub file 2025-01-23 18:56:44 +03:00
Alibek Omarov
952ccb1247 engine: avi: very dumb pause 2025-01-23 18:55:48 +03:00
Alibek Omarov
6f0fb594e7 Merge branch 'master' 2025-01-23 18:42:00 +03:00
Alibek Omarov
f0b29bac1b engine: client: add cl_trace_consistency used to print which resources server wants to check 2025-01-23 13:57:17 +03:00
Alibek Omarov
7b5ff606bd 3rdparty: extras: enable compression of extras.pk3 2025-01-23 13:08:53 +03:00
Alibek Omarov
3e22ee64ae scripts: waifulib: zip: add support for passing compression level on Python 3.7. Exclude PNG files from compression 2025-01-23 13:08:21 +03:00
Alibek Omarov
c86c45503f engine: replace few more Xash3D strings by XASH_ENGINE_NAME macro 2025-01-23 10:33:22 +03:00
Alibek Omarov
ef75a4c28d engine: rename pref path on Mac to Xash3D FWGS by allowing for custom branding through XASH_ENGINE_NAME macro 2025-01-23 10:24:55 +03:00
Alibek Omarov
bccd3f2271 engine: pass launcher's default game directory all the way down to Platform_Init, so we mount correct extras.pk3 on Mac 2025-01-23 10:22:53 +03:00
Tom Kidd
7bbc3e8238 Made modifications for Mac App Bundle
- Looks for game data in SDL pref path (Application Support)
- Sets XASH3D_EXTRAS_PAK1 to SDL base path (Resources dir in App Bundle
- Added option to force search for SDL dylib via pkgconfig on Darwin instead of Framework (option for Mac Source Ports build process)
2025-01-23 10:15:47 +03:00
Alibek Omarov
c34e0c66d9 engine: add fuzzing target for Mod_LoadModel 2025-01-23 10:12:32 +03:00
Alibek Omarov
e5d80878b8 scripts: waifulib: add asan-only build type 2025-01-23 10:11:56 +03:00
Alibek Omarov
1e075d25b7 engine: make LZSS compression optional for 49 protocol, disable it for local clients (singleplayer) 2025-01-22 21:18:19 +03:00
Alibek Omarov
d29e53481d engine: client: remove unused S_StreamAviSamples 2025-01-22 20:01:11 +03:00
Alibek Omarov
d23a2fd2df engine: client: stub AVI_StreamSound RenderAPI call, it is not used in ffmpeg-based video playback code 2025-01-22 20:00:50 +03:00
Alibek Omarov
f6f15cc204 engine: mod_studio: validate studio self-reported length before loading model 2025-01-22 20:00:13 +03:00
Alibek Omarov
4f2249ed8e ref: support loading sprites with truncated palette 2025-01-22 19:24:00 +03:00
Alibek Omarov
9f322df498 engine: imagelib: handle loading truncated palette files, by filling remaining bytes with zeros 2025-01-22 19:21:51 +03:00
Alibek Omarov
b554d7e215 ref: properly handle unloading sprites that aren't loaded completely 2025-01-22 19:20:20 +03:00
Alibek Omarov
719093c10b ref: properly return false to the engine if renderer refuses to load the model for some reason 2025-01-22 19:13:23 +03:00
Alibek Omarov
c2da140ccc engine: model: do not crash if renderer refused to load this model 2025-01-22 19:12:43 +03:00
Alibek Omarov
375998dffb Cleanup xash3d_types.h from engine-specific macros and types 2025-01-22 15:10:18 +03:00
Alibek Omarov
787444f63d engine: simplify sound fx allocation 2025-01-22 14:46:40 +03:00
Alibek Omarov
0c50076ff0 engine: zone: ensure poolcount is zero on Memory_Init 2025-01-22 13:49:51 +03:00
Alibek Omarov
8ce01c38c7 engine: http: ensure we don't write broken decompressed files 2025-01-22 13:49:24 +03:00
Alibek Omarov
cac6206984 engine: client: allocate everything related to sounds in the sound pool 2025-01-22 13:49:02 +03:00
Alibek Omarov
a5c88bdda9 engine: touch: allow smoother migration from old engine touch configs by stripping .tga extension 2025-01-22 13:40:47 +03:00
Alibek Omarov
fc017286a6 engine: base_cmd: slightly faster search based on assumption that list is always ordered 2025-01-22 05:41:52 +03:00
Alibek Omarov
20d4e3e719 engine: fix flexible array member usage in case of null terminated strings
(woops)
2025-01-22 05:41:52 +03:00
Alibek Omarov
4eaa32fc10 engine: whereami: sync with upstream 2025-01-21 20:03:20 +03:00
Alibek Omarov
b7c025b167 filesystem: android: request buffer for Android asset LoadFile implementation
Might be better than asking for random access and then only reading forward.
2025-01-21 19:50:14 +03:00
Alibek Omarov
f29c588e0f filesystem: take code from DarkPlaces to properly read compressed files 2025-01-21 18:47:42 +03:00
Alibek Omarov
2065ef143a engine: server: fix ent_create under PrimeXT 2025-01-21 16:09:56 +03:00
Alibek Omarov
a5c02c85f0 filesystem: wad: get rid of sentinel value at the end of wad_types array 2025-01-21 15:26:06 +03:00
Alibek Omarov
9a8761f1d8 engine: client: remove unused NetAPI_ValueForKey function 2025-01-21 15:17:03 +03:00
Alibek Omarov
273990d292 engine: cmd: store command description in flexible array member 2025-01-21 15:06:08 +03:00
Alibek Omarov
0e27d8717c ref: remove servercount from texture struct, Xash don't use it (and it's also harmful anyway) 2025-01-21 14:36:42 +03:00
Alibek Omarov
8a9b209db0 engine: zone: optimize memory usage a bit by compressing memheader_t better while keeping it efficient
It saves about 40 kilobytes of memory.
2025-01-21 14:04:33 +03:00
Alibek Omarov
232d1f8583 engine: make separate mempools for cmds, cvars and basecmd 2025-01-21 11:26:35 +03:00
Alibek Omarov
6cfa5877a4 engine: base_cmd: decrease base cmd hash size 2025-01-21 11:25:33 +03:00
Alibek Omarov
154df00f94 filesystem: don't create full path to rwdir, as cwd is always equal to rwdir
Fixes updating gameinfo.txt.
2025-01-20 19:53:04 +03:00
Alibek Omarov
c5649c94d5 engine: client: fix delta entity packet flush on GoldSrc protocol
Implement counting playerbytes for more accurate net_graph, even if we're
skipping this delta frame.
2025-01-20 19:38:44 +03:00
Alibek Omarov
a1da10fe38 filesystem: set default values for quick/autosave aged count 2025-01-20 16:06:57 +03:00
Andrey Akhmichin
17a71ffc96 ci: upgrade freebsd tasks. 2025-01-19 04:36:07 +03:00
Andrey Akhmichin
4609fbc0c5 Documentation: supported-mod-list.md: update links. 2025-01-19 04:35:17 +03:00
Andrey Akhmichin
d278d3bdd7 engine: common: fix clang build. 2025-01-19 04:33:06 +03:00
Alibek Omarov
7811b60292 engine: common: fix build for apple and freebsd-15 2025-01-18 10:40:12 +03:00
Alibek Omarov
870fad5606 public: tests: remove Q_colorstr tests 2025-01-18 10:36:11 +03:00
Alibek Omarov
3e93aa459d engine: net_buffer: turn bit write and read masks into predefined arrays, so we don't have to call InitMasks
In future, net_buffer might get moved to libpublic.

Also, get rid of 32-th bit write mask, it's only get used when we're trying to
write zero bits value which is nonsense.
2025-01-18 09:54:11 +03:00
Alibek Omarov
626c5e44f6 engine: client: use existing engine functions for some client API functions 2025-01-18 09:44:21 +03:00
Alibek Omarov
c906aa0106 ref: gl: make DrawGLPoly and R_TextureAnimation private to brush rendering code 2025-01-18 08:39:31 +03:00
Alibek Omarov
0a41b70e44 ref: gl: store ripple texture in texture's fb_texturenum as it's only used for water and water don't have luma 2025-01-18 08:38:43 +03:00
Alibek Omarov
ea338adc46 ref: gl: make GL_FrustumSetPlanme private to the frustum implementation 2025-01-18 08:34:25 +03:00
Alibek Omarov
5fa777578b ref: gl: fix detail texture leak, fix texture leak when texture have default texture set (in which case it still might have other textures set) 2025-01-18 08:33:20 +03:00
Alibek Omarov
5b9db5940b engine: mod_bmodel: don't try to load luma/fullbright texture for water, as no renderers support it anyway, and instead we will use that field for rippletexture 2025-01-18 08:30:59 +03:00
Alibek Omarov
4b1b3aa13c public: remove Q_colorstr, as it's completely useless and checking for color string is easy actually 2025-01-18 08:29:36 +03:00
Alibek Omarov
2d51d23d89 engine: client: don't send commands until ca_active on Xash protocol 2025-01-17 15:06:59 +03:00
Alibek Omarov
b5b6dad39c engine: fix a typo in scroll lock (missing L) 2025-01-15 23:49:13 +03:00
Alibek Omarov
a5619e9960 engine: take keydefs header from Quake-2 source code (client/keys.h) 2025-01-15 23:47:55 +03:00
Alibek Omarov
a75666a3cd engine: common: fix dedicated build by defining SV_GetMaxClients before CL_GetMaxClients stub (that redirects to it)
Also remove CL_Shutdown from dedicated stub lists.
2025-01-14 13:10:02 +03:00
Alibek Omarov
49426721d8 engine: use zero initializers instead of memset 2025-01-14 12:11:27 +03:00
Alibek Omarov
04125284a3 engine: dedicated: make some stubs inlined 2025-01-14 12:10:31 +03:00
Alibek Omarov
1d4f7b2f94 engine: server: slight refactoring, make SV_ModelHandle inlined, move PlayerIsFrozen to sv_client, fix packet loss data type 2025-01-14 12:09:23 +03:00
Alibek Omarov
38c82a3f76 engine: don't bother calculating crc32 for local clients for better performance (thanks @tyabus for the idea) 2025-01-14 11:55:28 +03:00
Alibek Omarov
785632a437 filesystem: minor refactoring in MD5_HashFile, use initializer instead of memset, limit buffer variable scope 2025-01-14 11:36:13 +03:00
Alibek Omarov
4be75af214 engine: client: always write buffer.dat so we will be able to request it from users. Append protocol number to it 2025-01-14 11:31:10 +03:00
Alibek Omarov
dcdca01e86 ref: gl: declare VBO globals static 2025-01-14 11:30:35 +03:00
Alibek Omarov
201d9c8f80 public: split VCS info to separate file for slightly better compilation speeds 2025-01-13 20:02:59 +03:00
Alibek Omarov
69341e36a3 public: expose commit and branch as global variables instead of functions 2025-01-13 20:02:59 +03:00
Alibek Omarov
3532a77643 public: move git commit and branch private to libpublic 2025-01-13 20:02:59 +03:00
Alibek Omarov
35dc072b26 filesystem: on Android, assume all paths are case-sensitive because doing Linux-specific ioctl check crashes FUSE driver and kills our app 2025-01-13 13:56:15 +03:00
Alibek Omarov
f92a3695b3 filesystem: fix fd leak in Platform_GetDirectoryCaseSensitivity 2025-01-13 13:54:42 +03:00
Alibek Omarov
a7b776f3b9 Revert "wscript: disable /showIncludes based msvcdeps for now, it causes issues with non-English locales"
Add option --enable-msvcdeps that we only enable on CI.

This reverts commit e58007aab3.
2025-01-10 21:48:43 +03:00
Alibek Omarov
f2fb668c9e android: now run exit() from Java side, as the next engine run is expected to be clean 2025-01-09 21:29:01 +03:00
Alibek Omarov
90e493fa3a engine: common: add Host_ExitInMain function that will force engine return from Host_Main() function, essentially making engine gracefully exit on Android
In future, this might be used everywhere, so users would be able to add custom
cleanup in some advanced game_launch implementation, on any platform.
2025-01-09 20:31:26 +03:00
Alibek Omarov
692bcc4073 engine: client: cl_tent: rewrite fizz effect, fix incorrect positoning along the way 2025-01-09 19:23:40 +03:00
Alibek Omarov
823642b10d readme: add link to ipa-reader.com for Xash word pronounciation [skip ci] 2025-01-09 17:13:56 +03:00
Alibek Omarov
07189ca2f5 engine: client: remove spammy message about not precached model on client side
Recently, mods (Brutal Half-Life v3 and MMod) started to call this function
every frame as a hacky way to detect presence of some model on the level. I
don't know why they do that, but users (who co-incidentally run engine with
-dev) has been complaining about console spam.

This is why we can't have things.
2025-01-09 17:10:54 +03:00
Alibek Omarov
0d55441830 engine: properly pass shutdown reason down to close log, helps to finally get rid of global finalmsg 2025-01-09 08:04:18 +03:00
Alibek Omarov
8b4b0479c8 ci: enable ffmpeg by default for Windows and Linux x86 targets 2024-12-13 03:04:32 +03:00
Alibek Omarov
c8bf7e5630 engine: avi: get rid of stubs file, temporarily put these stubs into avi_ffmpeg.c 2024-12-13 03:04:32 +03:00
Alibek Omarov
4987080e1e engine: client: remove unused S_RawSamples wrapper function 2024-12-13 03:04:32 +03:00
Alibek Omarov
1d78e400ff engine: sound: increase MAX_RAW_SAMPLES to 16384 to fit an audio track coming from the movies 2024-12-13 03:04:32 +03:00
Alibek Omarov
2d1a885954 common: render_api: use movie_state_s in AVI functions for easier type checking 2024-12-13 03:04:32 +03:00
Alibek Omarov
43ba2e747b engine: avi: mention SDL3 and FTEQW developers which ffmpeg integrations in their projects helped me to understand the ffmpeg API 2024-12-13 03:04:32 +03:00
Alibek Omarov
eefb823ee2 engine: client: remove legacy movie audio track streaming functions 2024-12-13 03:04:32 +03:00
Alibek Omarov
a3c33e0fa9 engine: client: sound: make S_RawSampleStereo public to other parts of engine 2024-12-13 03:04:32 +03:00
Alibek Omarov
16fe6b1b1a engine: client: avi: remove VFW-based player 2024-12-13 03:04:32 +03:00
Alibek Omarov
4275829bd5 engine: client: partially rework how AVI playback works in Xash. Add ffmpeg-based player.
This intentionally will not build without --enable-ffmpeg for now.

We add new functions to the RenderAPI called AVI_Think and AVI_SetParm. Game
developer is supposed to call AVI_Think each frame and set video playback
parameters through AVI_SetParm function.

What's tested:
* Intro cinematics.
* Looping videos.
* Playing back an hour long video.
* API extension (PrimeXT's avi branch at https://github.com/a1batross/PrimeXT).

What's broken:
* There is no way to seek a video file, only rewind to the start.
2024-12-13 03:04:32 +03:00
Alibek Omarov
1884f0a3ce engine: client: avi: add new macro XASH_AVI and corresponding backend select macros (AVI_NULL and AVI_FFMPEG) 2024-12-09 00:27:40 +03:00
118 changed files with 3090 additions and 2824 deletions

View File

@@ -1,10 +1,10 @@
task: task:
name: freebsd-14-amd64 name: freebsd-14-amd64
freebsd_instance: freebsd_instance:
image_family: freebsd-14-0 image_family: freebsd-14-2
setup_script: setup_script:
- pkg update - pkg update
- pkg install -y pkgconf git sdl2 python fontconfig opus - pkg install -y pkgconf git sdl2 python fontconfig libvorbis opusfile bzip2
- git submodule update --init --recursive - git submodule update --init --recursive
test_script: test_script:
- ./scripts/cirrus/build_freebsd.sh dedicated - ./scripts/cirrus/build_freebsd.sh dedicated
@@ -16,7 +16,7 @@ task:
image_family: freebsd-15-0-snap image_family: freebsd-15-0-snap
setup_script: setup_script:
- pkg update - pkg update
- pkg install -y pkgconf git sdl2 python fontconfig opus - pkg install -y pkgconf git sdl2 python fontconfig libvorbis opusfile bzip2
- git submodule update --init --recursive - git submodule update --init --recursive
test_script: test_script:
- ./scripts/cirrus/build_freebsd.sh dedicated - ./scripts/cirrus/build_freebsd.sh dedicated

View File

@@ -67,7 +67,9 @@ jobs:
targetarch: amd64 targetarch: amd64
env: env:
SDL_VERSION: 2.30.11 SDL_VERSION: 2.30.11
FFMPEG_VERSION: 7.1
GH_CPU_ARCH: ${{ matrix.targetarch }} GH_CPU_ARCH: ${{ matrix.targetarch }}
GH_CPU_OS: ${{ matrix.targetos }}
GH_CROSSCOMPILING: ${{ matrix.cross }} GH_CROSSCOMPILING: ${{ matrix.cross }}
steps: steps:
- name: Checkout - name: Checkout

View File

@@ -25,5 +25,4 @@ def build(bld):
name = 'extras.pk3', name = 'extras.pk3',
files = srcdir.ant_glob('**/*'), files = srcdir.ant_glob('**/*'),
relative_to = srcdir, relative_to = srcdir,
compresslevel = 0,
install_path = install_path) install_path = install_path)

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
[![builds.sr.ht status](https://builds.sr.ht/~a1batross/xash3d-fwgs.svg)](https://builds.sr.ht/~a1batross/xash3d-fwgs?) [![GitHub Actions Status](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml/badge.svg)](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml) [![FreeBSD Build Status](https://img.shields.io/cirrus/github/FWGS/xash3d-fwgs?label=freebsd%20build)](https://cirrus-ci.com/github/FWGS/xash3d-fwgs) [![Discord Server](https://img.shields.io/discord/355697768582610945.svg)](http://fwgsdiscord.mentality.rip/) \ [![builds.sr.ht status](https://builds.sr.ht/~a1batross/xash3d-fwgs.svg)](https://builds.sr.ht/~a1batross/xash3d-fwgs?) [![GitHub Actions Status](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml/badge.svg)](https://github.com/FWGS/xash3d-fwgs/actions/workflows/c-cpp.yml) [![FreeBSD Build Status](https://img.shields.io/cirrus/github/FWGS/xash3d-fwgs?label=freebsd%20build)](https://cirrus-ci.com/github/FWGS/xash3d-fwgs) [![Discord Server](https://img.shields.io/discord/355697768582610945.svg)](http://fwgsdiscord.mentality.rip/) \
[![Download Stable](https://img.shields.io/badge/download-stable-yellow)](https://github.com/FWGS/xash3d-fwgs/releases/latest) [![Download Testing](https://img.shields.io/badge/downloads-testing-orange)](https://github.com/FWGS/xash3d-fwgs/releases/tag/continuous) [![Download Stable](https://img.shields.io/badge/download-stable-yellow)](https://github.com/FWGS/xash3d-fwgs/releases/latest) [![Download Testing](https://img.shields.io/badge/downloads-testing-orange)](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. Xash3D FWGS is a heavily modified fork of an original [Xash3D Engine](https://www.moddb.com/engines/xash3d-engine) by Unkle Mike.

View File

@@ -30,6 +30,18 @@ public class XashActivity extends SDLActivity {
AndroidBug5497Workaround.assistActivity(this); 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 @Override
protected String[] getLibraries() { protected String[] getLibraries() {
return new String[]{"SDL2", "xash"}; return new String[]{"SDL2", "xash"};

View File

@@ -50,4 +50,8 @@ GNU General Public License for more details.
#define LIB_WIN32 2 #define LIB_WIN32 2
#define LIB_STATIC 3 #define LIB_STATIC 3
// movies (XASH_AVI)
#define AVI_NULL 0
#define AVI_FFMPEG 1
#endif /* BACKENDS_H */ #endif /* BACKENDS_H */

View File

@@ -78,7 +78,6 @@ SETUP BACKENDS DEFINITIONS
// usually only 10-20 fds availiable // usually only 10-20 fds availiable
#define XASH_REDUCE_FD #define XASH_REDUCE_FD
#endif #endif
#endif // XASH_DEDICATED #endif // XASH_DEDICATED
// //
@@ -105,6 +104,17 @@ SETUP BACKENDS DEFINITIONS
#endif // !XASH_WIN32 #endif // !XASH_WIN32
#endif #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 #ifdef XASH_STATIC_LIBS
#define XASH_LIB LIB_STATIC #define XASH_LIB LIB_STATIC
#define XASH_INTERNAL_GAMELIBS #define XASH_INTERNAL_GAMELIBS

View File

@@ -157,6 +157,23 @@ typedef struct decallist_s
modelstate_t studio_state; // studio decals only modelstate_t studio_state; // studio decals only
} decallist_t; } 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; struct ref_viewpass_s;
typedef struct render_api_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) void (*R_EntityRemoveDecals)( struct model_s *mod ); // remove all the decals from specified entity (BSP only)
// AVIkit support // AVIkit support
void *(*AVI_LoadVideo)( const char *filename, qboolean load_audio ); struct movie_state_s *(*AVI_LoadVideo)( const char *filename, qboolean load_audio );
int (*AVI_GetVideoInfo)( void *Avi, int *xres, int *yres, float *duration ); // a1ba: changed longs to int qboolean (*AVI_GetVideoInfo)( struct movie_state_s *Avi, int *xres, int *yres, float *duration ); // a1ba: changed longs to int
int (*AVI_GetVideoFrameNumber)( void *Avi, float time ); int (*AVI_GetVideoFrameNumber)( struct movie_state_s *Avi, float time );
byte *(*AVI_GetVideoFrame)( void *Avi, int frame ); 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_UploadRawFrame)( int texture, int cols, int rows, int width, int height, const byte *data );
void (*AVI_FreeVideo)( void *Avi ); void (*AVI_FreeVideo)( struct movie_state_s *Avi );
int (*AVI_IsActive)( void *Avi ); qboolean (*AVI_IsActive)( struct movie_state_s *Avi );
void (*AVI_StreamSound)( void *Avi, int entnum, float fvol, float attn, float synctime ); void (*AVI_StreamSound)( struct movie_state_s *Avi, int entnum, float fvol, float attn, float synctime );
void (*AVI_Reserved0)( void ); // for potential interface expansion without broken compatibility qboolean (*AVI_Think)( struct movie_state_s *Avi );
void (*AVI_Reserved1)( void ); 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) // 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 ); void (*GL_Bind)( int tmu, unsigned int texnum );

View File

@@ -16,19 +16,17 @@
#include STDINT_H #include STDINT_H
#include <assert.h> #include <assert.h>
typedef unsigned char byte; typedef uint8_t byte;
typedef int sound_t; typedef float vec_t;
typedef float vec_t; typedef vec_t vec2_t[2];
typedef vec_t vec2_t[2]; typedef vec_t vec3_t[3];
typedef vec_t vec3_t[3]; typedef vec_t vec4_t[4];
typedef vec_t vec4_t[4]; typedef vec_t quat_t[4];
typedef vec_t quat_t[4]; typedef byte rgba_t[4]; // unsigned byte colorpack
typedef byte rgba_t[4]; // unsigned byte colorpack typedef byte rgb_t[3]; // unsigned byte colorpack
typedef byte rgb_t[3]; // unsigned byte colorpack typedef vec_t matrix3x4[3][4];
typedef vec_t matrix3x4[3][4]; typedef vec_t matrix4x4[4][4];
typedef vec_t matrix4x4[4][4]; typedef uint32_t poolhandle_t;
typedef uint32_t poolhandle_t;
#undef true #undef true
#undef false #undef false
@@ -39,18 +37,10 @@ typedef enum { false, true } qboolean;
typedef int qboolean; typedef int qboolean;
#endif #endif
typedef uint64_t longtime_t; #define MAX_STRING 256 // generic string
#define MAX_VA_STRING 1024 // compatibility macro
#define MAX_STRING 256 // generic string #define MAX_SYSPATH 1024 // system filepath
#define MAX_INFO_STRING 256 // infostrings are transmitted across network #define MAX_MODS 512 // environment games that engine can keep visible
#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 BIT( n ) ( 1U << ( n )) #define BIT( n ) ( 1U << ( n ))
#define BIT64( n ) ( 1ULL << ( n )) #define BIT64( n ) ( 1ULL << ( n ))
@@ -209,35 +199,16 @@ _inline float LittleFloat( float f )
#endif #endif
typedef unsigned int dword; typedef unsigned int dword;
typedef unsigned int uint; typedef unsigned int uint;
typedef unsigned long ulong; typedef char string[MAX_STRING];
typedef char string[MAX_STRING]; typedef off_t fs_offset_t;
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;
#if XASH_WIN32 #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 */ #else /* !XASH_WIN32 */
typedef ssize_t fs_size_t; typedef ssize_t fs_size_t;
#endif /* !XASH_WIN32 */ #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
const size_t num_fcts;
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 * ); typedef void *(*pfnCreateInterface_t)( const char *, int * );
// config strings are a general means of communication from // config strings are a general means of communication from

View File

@@ -18,12 +18,11 @@ GNU General Public License for more details.
// //
// avikit.c // 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 ); int AVI_GetVideoFrameNumber( movie_state_t *Avi, float time );
byte *AVI_GetVideoFrame( movie_state_t *Avi, int frame ); byte *AVI_GetVideoFrame( movie_state_t *Avi, int frame );
qboolean AVI_GetVideoInfo( movie_state_t *Avi, int *xres, int *yres, float *duration ); qboolean AVI_GetVideoInfo( movie_state_t *Avi, int *xres, int *yres, float *duration );
qboolean AVI_GetAudioInfo( movie_state_t *Avi, wavdata_t *snd_info ); qboolean AVI_HaveAudioTrack( const movie_state_t *Avi );
int AVI_GetAudioChunk( movie_state_t *Avi, char *audiodata, int offset, int length );
void AVI_OpenVideo( movie_state_t *Avi, const char *filename, qboolean load_audio, int quiet ); 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 ); movie_state_t *AVI_LoadVideo( const char *filename, qboolean load_audio );
int AVI_TimeToSoundPosition( movie_state_t *Avi, int time ); int AVI_TimeToSoundPosition( movie_state_t *Avi, int time );
@@ -34,4 +33,7 @@ movie_state_t *AVI_GetState( int num );
qboolean AVI_Initailize( void ); qboolean AVI_Initailize( void );
void AVI_Shutdown( 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 #endif // AVI_H

View 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 );
}

View File

@@ -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

View File

@@ -1,732 +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 },
};
dll_info_t msvfw_dll = { "msvfw32.dll", msvfw_funcs, ARRAYSIZE( 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 },
};
dll_info_t msacm_dll = { "msacm32.dll", msacm_funcs, ARRAYSIZE( 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 },
};
dll_info_t avifile_dll = { "avifil32.dll", avifile_funcs, ARRAYSIZE( 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

View File

@@ -42,7 +42,8 @@ void CL_PlayVideo_f( void )
switch( Cmd_Argc( )) switch( Cmd_Argc( ))
{ {
case 2: // simple user version 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 ); SCR_PlayCinematic( path );
break; break;
case 3: // sequenced cinematics used this case 3: // sequenced cinematics used this

View File

@@ -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, &cls.starting_count, sizeof( int ));
FS_Write( fp, &current_count, sizeof( int )); FS_Write( fp, &current_count, sizeof( int ));
FS_Write( fp, &cls.legacymode, sizeof( cls.legacymode ));
FS_Write( fp, MSG_GetData( msg ), MSG_GetMaxBytes( msg )); FS_Write( fp, MSG_GetData( msg ), MSG_GetMaxBytes( msg ));
FS_Close( fp ); FS_Close( fp );
@@ -168,7 +169,7 @@ list last 32 messages for debugging net troubleshooting
*/ */
void CL_WriteMessageHistory( void ) void CL_WriteMessageHistory( void )
{ {
oldcmd_t *old, *failcommand; oldcmd_t *old;
sizebuf_t *msg = &net_message; sizebuf_t *msg = &net_message;
int i, thecmd; int i, thecmd;
@@ -192,9 +193,8 @@ void CL_WriteMessageHistory( void )
thecmd++; thecmd++;
} }
failcommand = &cls_message_debug.oldcmd[thecmd]; old = &cls_message_debug.oldcmd[thecmd];
Con_Printf( "BAD: %3i:%s\n", MSG_GetNumBytesRead( msg ) - 1, CL_MsgInfo( failcommand->command )); Con_Printf( S_RED "BAD: " S_DEFAULT "%i %04i %s\n", old->frame_number, old->starting_offset, CL_MsgInfo( old->command ));
if( host_developer.value >= DEV_EXTENDED ) CL_WriteErrorMessage( old->starting_offset, msg );
CL_WriteErrorMessage( MSG_GetNumBytesRead( msg ) - 1, msg );
cls_message_debug.parsing = false; cls_message_debug.parsing = false;
} }

View File

@@ -373,7 +373,7 @@ CL_WriteDemoUserMessage
Dumps the user message (demoaction) 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 ) if( !cls.demorecording || cls.demowaiting )
return; return;
@@ -624,11 +624,10 @@ static void CL_ReadDemoUserCmd( qboolean discard )
if( !discard ) if( !discard )
{ {
usercmd_t nullcmd; const usercmd_t nullcmd = { 0 };
sizebuf_t buf; sizebuf_t buf;
demoangle_t *a; demoangle_t *a;
memset( &nullcmd, 0, sizeof( nullcmd ));
MSG_Init( &buf, "UserCmd", data, sizeof( data )); MSG_Init( &buf, "UserCmd", data, sizeof( data ));
// a1ba: I have no proper explanation why // a1ba: I have no proper explanation why

View File

@@ -2229,4 +2229,3 @@ void CL_ThinkParticle( double frametime, particle_t *p )
break; break;
} }
} }

View File

@@ -556,7 +556,7 @@ static void CL_InitTitles( const char *filename )
Q_snprintf( name, sizeof( name ), TEXT_MSGNAME, i ); 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]; cl_textmessage[i].pMessage = cl_textbuffer[i];
} }
@@ -2408,9 +2408,8 @@ CL_FindModelIndex
*/ */
static int GAME_EXPORT CL_FindModelIndex( const char *m ) static int GAME_EXPORT CL_FindModelIndex( const char *m )
{ {
char filepath[MAX_QPATH]; char filepath[MAX_QPATH];
static float lasttimewarn; int i;
int i;
if( !COM_CheckString( m )) if( !COM_CheckString( m ))
return 0; return 0;
@@ -2427,13 +2426,6 @@ static int GAME_EXPORT CL_FindModelIndex( const char *m )
return i+1; 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; return 0;
} }
@@ -3356,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 Demo_IsTimeDemo
@@ -3389,17 +3359,6 @@ static int GAME_EXPORT Demo_IsTimeDemo( void )
return cls.timedemo; return cls.timedemo;
} }
/*
=================
Demo_WriteBuffer
=================
*/
static void GAME_EXPORT Demo_WriteBuffer( int size, byte *buffer )
{
CL_WriteDemoUserMessage( buffer, size );
}
/* /*
================= =================
NetworkApi implementation NetworkApi implementation
@@ -3585,28 +3544,6 @@ static int GAME_EXPORT NetAPI_CompareAdr( netadr_t *a, netadr_t *b )
return NET_CompareAdr( *a, *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 NetAPI_RemoveKey
@@ -3803,10 +3740,10 @@ static event_api_t gEventApi =
static demo_api_t gDemoApi = static demo_api_t gDemoApi =
{ {
Demo_IsRecording, (void *)CL_IsRecordDemo,
Demo_IsPlayingback, (void *)CL_IsPlaybackDemo,
Demo_IsTimeDemo, Demo_IsTimeDemo,
Demo_WriteBuffer, CL_WriteDemoUserMessage,
}; };
net_api_t gNetApi = net_api_t gNetApi =
@@ -3818,8 +3755,8 @@ net_api_t gNetApi =
NetAPI_CancelAllRequests, NetAPI_CancelAllRequests,
NetAPI_AdrToString, NetAPI_AdrToString,
NetAPI_CompareAdr, NetAPI_CompareAdr,
NetAPI_StringToAdr, (void *)NET_StringToAdr,
NetAPI_ValueForKey, Info_ValueForKey,
NetAPI_RemoveKey, NetAPI_RemoveKey,
NetAPI_SetValueForKey, NetAPI_SetValueForKey,
}; };

View File

@@ -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 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; 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 ); cin_state = AVI_GetState( CIN_LOGO );
if( !AVI_IsActive( cin_state )) 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; gameui.drawLogo = false;
return; return;
} }
cin_time = 0.0f;
last_frame = -1;
} }
if( width <= 0 || height <= 0 ) if( width <= 0 || height <= 0 )
{ {
// precache call, don't draw // precache call, don't draw
cin_time = 0.0f;
last_frame = -1;
return; return;
} }
// advances cinematic time (ignores maxfps and host_framerate settings) AVI_SetParm( cin_state,
cin_time += host.realframetime; AVI_RENDER_TEXNUM, 0,
AVI_RENDER_X, (int)x,
// restarts the cinematic AVI_RENDER_Y, (int)y,
if( cin_time > gameui.logo_length ) AVI_RENDER_W, (int)width,
cin_time = 0.0f; AVI_RENDER_H, (int)height,
AVI_PARM_LAST );
// read the next frame // read the next frame
cin_frame = AVI_GetVideoFrameNumber( cin_state, cin_time ); if( !AVI_Think( cin_state ))
AVI_SetParm( cin_state, AVI_REWIND, AVI_PARM_LAST );
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 );
} }
static int GAME_EXPORT UI_GetLogoWidth( void ) static int GAME_EXPORT UI_GetLogoWidth( void )

View File

@@ -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_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_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_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_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)" ); 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; return cls.demorecording;
} }
qboolean CL_IsTimeDemo( void )
{
return cls.timedemo;
}
qboolean CL_DisableVisibility( void ) qboolean CL_DisableVisibility( void )
{ {
return cls.envshot_disable_vis; return cls.envshot_disable_vis;
@@ -598,7 +594,7 @@ CL_CreateCmd
*/ */
static void CL_CreateCmd( void ) static void CL_CreateCmd( void )
{ {
usercmd_t nullcmd, *cmd; usercmd_t nullcmd = { 0 }, *cmd;
runcmd_t *pcmd; runcmd_t *pcmd;
qboolean active; qboolean active;
double accurate_ms; double accurate_ms;
@@ -650,7 +646,6 @@ static void CL_CreateCmd( void )
} }
else else
{ {
memset( &nullcmd, 0, sizeof( nullcmd ));
cmd = &nullcmd; cmd = &nullcmd;
} }
@@ -723,11 +718,20 @@ static void CL_WritePacket( void )
int numbackup, maxbackup, maxcmds; int numbackup, maxbackup, maxcmds;
const connprotocol_t proto = cls.legacymode; 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 // don't send anything if playing back a demo
if( cls.demoplayback || cls.state < ca_connected || cls.state == ca_cinematic ) if( cls.demoplayback || cls.state < ca_connected || cls.state == ca_cinematic )
return; return;
if( cls.state <= ca_connected ) if( cls.state < min_state )
{ {
Netchan_TransmitBits( &cls.netchan, 0, "" ); Netchan_TransmitBits( &cls.netchan, 0, "" );
return; return;
@@ -825,7 +829,7 @@ static void CL_WritePacket( void )
buf.pData[key] = CRC32_BlockSequence( &buf.pData[key + 1], size, cls.netchan.outgoing_sequence ); 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 ); 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; int size = MSG_GetRealBytesWritten( &buf ) - key - 1;
buf.pData[key] = CRC32_BlockSequence( &buf.pData[key + 1], size, cls.netchan.outgoing_sequence ); buf.pData[key] = CRC32_BlockSequence( &buf.pData[key + 1], size, cls.netchan.outgoing_sequence );
@@ -1594,6 +1598,9 @@ void CL_SetupNetchanForProtocol( connprotocol_t proto )
} }
break; break;
default: default:
if( !Host_IsLocalClient( ))
SetBits( flags, NETCHAN_USE_LZSS );
cls.extensions = Q_atoi( Info_ValueForKey( Cmd_Argv( 1 ), "ext" )); cls.extensions = Q_atoi( Info_ValueForKey( Cmd_Argv( 1 ), "ext" ));
if( FBitSet( cls.extensions, NET_EXT_SPLITSIZE )) if( FBitSet( cls.extensions, NET_EXT_SPLITSIZE ))
@@ -1761,8 +1768,8 @@ static size_t NONNULL CL_BuildMasterServerScanRequest( char *buf, size_t size, u
// let master know about client version // let master know about client version
Info_SetValueForKey( info, "clver", XASH_VERSION, remaining ); Info_SetValueForKey( info, "clver", XASH_VERSION, remaining );
Info_SetValueForKey( info, "nat", nat ? "1" : "0", remaining ); Info_SetValueForKey( info, "nat", nat ? "1" : "0", remaining );
Info_SetValueForKey( info, "commit", Q_buildcommit(), remaining ); Info_SetValueForKey( info, "commit", g_buildcommit, remaining );
Info_SetValueForKey( info, "branch", Q_buildbranch(), remaining ); Info_SetValueForKey( info, "branch", g_buildbranch, remaining );
Info_SetValueForKey( info, "os", Q_buildos(), remaining ); Info_SetValueForKey( info, "os", Q_buildos(), remaining );
Info_SetValueForKey( info, "arch", Q_buildarch(), remaining ); Info_SetValueForKey( info, "arch", Q_buildarch(), remaining );
@@ -3387,6 +3394,7 @@ static void CL_InitLocal( void )
Cvar_RegisterVariable( &rcon_address ); Cvar_RegisterVariable( &rcon_address );
Cvar_RegisterVariable( &cl_trace_consistency );
Cvar_RegisterVariable( &cl_trace_stufftext ); Cvar_RegisterVariable( &cl_trace_stufftext );
Cvar_RegisterVariable( &cl_trace_messages ); Cvar_RegisterVariable( &cl_trace_messages );
Cvar_RegisterVariable( &cl_trace_events ); Cvar_RegisterVariable( &cl_trace_events );
@@ -3658,6 +3666,8 @@ void CL_Init( void )
if( !CL_LoadProgs( libpath )) if( !CL_LoadProgs( libpath ))
Host_Error( "can't initialize %s: %s\n", libpath, COM_GetLibraryError( )); Host_Error( "can't initialize %s: %s\n", libpath, COM_GetLibraryError( ));
ID_Init();
cls.build_num = 0; cls.build_num = 0;
cls.initialized = true; cls.initialized = true;
cl.maxclients = 1; // allow to drawing player in menu cl.maxclients = 1; // allow to drawing player in menu

View File

@@ -1614,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 ) static void CL_SendConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
{ {
qboolean user_changed_diskfile; qboolean user_changed_diskfile;
@@ -1879,6 +1896,9 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
return; return;
} }
if( cl_trace_consistency.value )
Con_Printf( "Server wants consistency of the following resources:\n" );
skip_crc_change = NULL; skip_crc_change = NULL;
lastcheck = 0; lastcheck = 0;
@@ -1910,7 +1930,7 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
pc = &cl.consistency_list[cl.num_consistency]; pc = &cl.consistency_list[cl.num_consistency];
cl.num_consistency++; cl.num_consistency++;
memset( pc, 0, sizeof( consistency_t )); memset( pc, 0, sizeof( *pc ));
pc->filename = pResource->szFileName; pc->filename = pResource->szFileName;
pc->issound = (pResource->type == t_sound); pc->issound = (pResource->type == t_sound);
pc->orig_index = delta; pc->orig_index = delta;
@@ -1923,6 +1943,9 @@ static void CL_ParseConsistencyInfo( sizebuf_t *msg, connprotocol_t proto )
pc->check_type = pResource->rguc_reserved[0]; 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; skip_crc_change = pResource;
lastcheck = delta; lastcheck = delta;
} }

View File

@@ -91,11 +91,11 @@ static void CL_ParseNewMovevars( sizebuf_t *msg )
typedef struct delta_header_t typedef struct delta_header_t
{ {
qboolean remove : 1; qboolean remove;
qboolean custom : 1; qboolean custom;
qboolean instanced : 1; qboolean instanced;
uint instanced_baseline_index : 6; uint16_t instanced_baseline_index;
uint offset : 6; uint16_t offset;
} delta_header_t; } delta_header_t;
static int CL_ParseDeltaHeader( sizebuf_t *msg, qboolean delta, int oldnum, struct delta_header_t *hdr ) 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; 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; frame->valid = false;
cl.validsequence = 0; // can't render a frame cl.validsequence = 0; // can't render a frame
// read it all but ignore it // read it all but ignore it
while( 1 ) while( 1 )
{ {
int num = 0; int newnum, bufstart;
entity_state_t from = { 0 }, to; entity_state_t from = { 0 }, to;
delta_header_t hdr; delta_header_t hdr;
qboolean player;
if( MSG_ReadWord( msg ) != 0 ) if( MSG_ReadWord( msg ) != 0 )
{ {
MSG_SeekToBit( msg, -16, SEEK_CUR ); MSG_SeekToBit( msg, -16, SEEK_CUR );
num = CL_ParseDeltaHeader( msg, false, num, &hdr ); numbase = newnum = CL_ParseDeltaHeader( msg, true, numbase, &hdr );
} }
else break; else break;
if( MSG_CheckOverflow( msg )) if( MSG_CheckOverflow( msg ))
Host_Error( "%s: overflow\n", __func__ ); Host_Error( "%s: overflow\n", __func__ );
player = CL_IsPlayerIndex( newnum );
bufstart = MSG_GetNumBytesRead( msg );
if( hdr.remove ) if( hdr.remove )
continue; 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 ) 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 )) if(( newnum < 0 ) || ( newnum >= clgame.maxEntities ))
{ {
Con_DPrintf( S_ERROR "CL_DeltaEntity: invalid newnum: %d\n", newnum ); 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; 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 ) static int CL_ParsePacketEntitiesGS( sizebuf_t *msg, qboolean delta )
{ {
frame_t *frame, *oldframe; frame_t *frame, *oldframe;
int oldindex, newnum, oldnum, numbase = 0; int oldindex, oldnum, numbase = 0;
entity_state_t *oldent; entity_state_t *oldent;
int count; int count;
int playerbytes = 0; int playerbytes = 0;
@@ -314,7 +328,7 @@ static int CL_ParsePacketEntitiesGS( sizebuf_t *msg, qboolean delta )
// read it all but ignore it // read it all but ignore it
while( 1 ) while( 1 )
{ {
int bufstart; int bufstart, newnum;
qboolean player; qboolean player;
delta_header_t hdr; delta_header_t hdr;
int val = MSG_ReadWord( msg ); int val = MSG_ReadWord( msg );
@@ -534,7 +548,7 @@ void CL_ParseGoldSrcServerMessage( sizebuf_t *msg )
{ {
if( MSG_CheckOverflow( msg )) if( MSG_CheckOverflow( msg ))
{ {
Host_Error( "CL_ParseServerMessage: overflow!\n" ); Host_Error( "%s: overflow!\n", __func__ );
return; return;
} }

View File

@@ -233,6 +233,11 @@ static intptr_t pfnRenderGetParm( int parm, int arg )
return CL_RenderGetParm( parm, arg, true ); 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 = static render_api_t gRenderAPI =
{ {
pfnRenderGetParm, // GL_RenderGetParm, pfnRenderGetParm, // GL_RenderGetParm,
@@ -258,16 +263,16 @@ static render_api_t gRenderAPI =
NULL, // DrawSingleDecal, NULL, // DrawSingleDecal,
NULL, // R_DecalSetupVerts, NULL, // R_DecalSetupVerts,
NULL, // R_EntityRemoveDecals, NULL, // R_EntityRemoveDecals,
(void*)AVI_LoadVideo, AVI_LoadVideo,
(void*)AVI_GetVideoInfo, AVI_GetVideoInfo,
(void*)AVI_GetVideoFrameNumber, AVI_GetVideoFrameNumber,
(void*)AVI_GetVideoFrame, AVI_GetVideoFrame,
NULL, // R_UploadStretchRaw, NULL, // R_UploadStretchRaw,
(void*)AVI_FreeVideo, AVI_FreeVideo,
(void*)AVI_IsActive, AVI_IsActive,
S_StreamAviSamples, pfnAVI_StreamSound,
NULL, AVI_Think,
NULL, AVI_SetParm,
NULL, // GL_Bind, NULL, // GL_Bind,
NULL, // GL_SelectTexture, NULL, // GL_SelectTexture,
NULL, // GL_LoadTexMatrixExt, NULL, // GL_LoadTexMatrixExt,

View File

@@ -567,57 +567,54 @@ R_FizzEffect
Create a fizz effect 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; const float base_time = cl.time - 0.1f;
int i, width, depth; model_t *mod = CL_ModelHandle( modelIndex );
float angle, maxHeight, speed; vec3_t volume, mins, maxs;
float xspeed, yspeed, zspeed; vec2_t speed;
vec3_t origin; int i;
model_t *mod;
if( !pent || !pent->model || !modelIndex ) if( !ent || !ent->model || !modelIndex || !mod )
return; return;
if(( mod = CL_ModelHandle( modelIndex )) == NULL ) VectorCopy( ent->model->mins, mins );
return; VectorCopy( ent->model->maxs, maxs );
maxHeight = pent->model->maxs[2] - pent->model->mins[2]; if( ent->angles[1] != 0.0f )
width = pent->model->maxs[0] - pent->model->mins[0]; {
depth = pent->model->maxs[1] - pent->model->mins[1]; 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 ); VectorSubtract( maxs, mins, volume );
if( pent->curstate.rendercolor.b )
speed = -speed;
angle = DEG2RAD( pent->angles[YAW] );
SinCos( angle, &yspeed, &xspeed );
xspeed *= speed;
yspeed *= speed;
for( i = 0; i <= density; i++ ) for( i = 0; i <= density; i++ )
{ {
origin[0] = mod->mins[0] + COM_RandomLong( 0, width - 1 ); TEMPENTITY *tent;
origin[1] = mod->mins[1] + COM_RandomLong( 0, depth - 1 ); vec3_t origin;
origin[2] = mod->mins[2];
pTemp = CL_TempEntAlloc( origin, mod );
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]; tent->x = origin[0];
pTemp->y = origin[1]; 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 ); tent->entity.baseline.origin[2] = COM_RandomLong( 80, 140 );
VectorSet( pTemp->entity.baseline.origin, xspeed, yspeed, zspeed ); tent->die += volume[2] / tent->entity.baseline.origin[2];
pTemp->die = cl.time + ( maxHeight / zspeed ) - 0.1f; tent->entity.curstate.frame = COM_RandomLong( 0, tent->frameMax );
pTemp->entity.curstate.frame = COM_RandomLong( 0, pTemp->frameMax ); tent->entity.curstate.scale = 1.0f / COM_RandomFloat( 2.0f, 5.0f );
// 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;
} }
} }

View File

@@ -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; static movie_state_t *cin_state;
/* /*
@@ -88,7 +83,17 @@ void SCR_CheckStartupVids( void )
char *pfile; char *pfile;
string token; 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 // don't run movies where we in developer-mode
cls.movienum = -1; cls.movienum = -1;
@@ -147,23 +152,9 @@ void SCR_RunCinematic( void )
Key_SetKeyDest( key_menu ); Key_SetKeyDest( key_menu );
S_StopStreaming(); S_StopStreaming();
cls.movienum = -1; cls.movienum = -1;
cin_time = 0.0f;
cls.signon = 0; cls.signon = 0;
return; 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 ) qboolean SCR_DrawCinematic( void )
{ {
static int last_frame = -1; if( !ref.initialized )
qboolean redraw = false;
byte *frame = NULL;
if( !ref.initialized || cin_time <= 0.0f )
return false; return false;
if( cin_frame != last_frame ) if( !AVI_Think( cin_state ))
{ return SCR_NextMovie();
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 );
return true; return true;
} }
@@ -219,45 +200,28 @@ qboolean SCR_PlayCinematic( const char *arg )
return false; return false;
} }
if( !( AVI_GetVideoInfo( cin_state, &xres, &yres, &video_duration ))) // couldn't open this at all. if( AVI_HaveAudioTrack( cin_state ))
{
AVI_CloseVideo( cin_state );
return false;
}
if( AVI_GetAudioInfo( cin_state, &cin_audio ))
{ {
// begin streaming // begin streaming
S_StopAllSounds( true ); S_StopAllSounds( true );
S_StartStreaming(); 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 ); UI_SetActiveMenu( false );
cls.state = ca_cinematic; cls.state = ca_cinematic;
Con_FastClose(); Con_FastClose();
cin_time = 0.0f;
cls.signon = 0; cls.signon = 0;
return true; 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 SCR_StopCinematic
@@ -270,7 +234,6 @@ void SCR_StopCinematic( void )
AVI_CloseVideo( cin_state ); AVI_CloseVideo( cin_state );
S_StopStreaming(); S_StopStreaming();
cin_time = 0.0f;
cls.state = ca_disconnected; cls.state = ca_disconnected;
cls.signon = 0; cls.signon = 0;

View File

@@ -688,6 +688,7 @@ extern convar_t r_showtextures;
extern convar_t cl_bmodelinterp; extern convar_t cl_bmodelinterp;
extern convar_t cl_lw; // local weapons extern convar_t cl_lw; // local weapons
extern convar_t cl_charset; extern convar_t cl_charset;
extern convar_t cl_trace_consistency;
extern convar_t cl_trace_stufftext; extern convar_t cl_trace_stufftext;
extern convar_t cl_trace_messages; extern convar_t cl_trace_messages;
extern convar_t cl_trace_events; extern convar_t cl_trace_events;
@@ -767,7 +768,7 @@ void CL_StartupDemoHeader( void );
void CL_DrawDemoRecording( void ); void CL_DrawDemoRecording( void );
void CL_WriteDemoUserCmd( int cmdnumber ); void CL_WriteDemoUserCmd( int cmdnumber );
void CL_WriteDemoMessage( qboolean startup, int start, sizebuf_t *msg ); 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 ); qboolean CL_DemoReadMessage( byte *buffer, size_t *length );
void CL_DemoInterpolateAngles( void ); void CL_DemoInterpolateAngles( void );
void CL_CheckStartupDemos( void ); void CL_CheckStartupDemos( void );
@@ -1119,7 +1120,7 @@ void Con_PageUp( int lines );
// //
// s_main.c // 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_StartBackgroundTrack( const char *intro, const char *loop, int position, qboolean fullpath );
void S_StopBackgroundTrack( void ); void S_StopBackgroundTrack( void );
void S_StreamSetPause( int pause ); void S_StreamSetPause( int pause );
@@ -1208,6 +1209,13 @@ void Key_EnableTextInput( qboolean enable, qboolean force );
int Key_ToUpper( int key ); int Key_ToUpper( int key );
void OSK_Draw( void ); 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 rgba_t g_color_table[8];
extern triangleapi_t gTriApi; extern triangleapi_t gTriApi;
extern net_api_t gNetApi; extern net_api_t gNetApi;

View File

@@ -611,7 +611,7 @@ void GAME_EXPORT ID_SetCustomClientID( const char *id )
void ID_Init( void ) void ID_Init( void )
{ {
MD5Context_t hash = {0}; MD5Context_t hash = { 0 };
byte md5[16]; byte md5[16];
int i; int i;
@@ -632,7 +632,7 @@ void ID_Init( void )
#elif XASH_WIN32 #elif XASH_WIN32
{ {
CHAR szBuf[MAX_PATH]; 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); sscanf(szBuf, "%016"PRIX64, &id);
id ^= SYSTEM_XOR_MASK; id ^= SYSTEM_XOR_MASK;
@@ -686,7 +686,7 @@ void ID_Init( void )
{ {
CHAR Buf[MAX_PATH]; CHAR Buf[MAX_PATH];
sprintf( Buf, "%016"PRIX64, id^SYSTEM_XOR_MASK ); 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 #else
{ {

View File

@@ -266,7 +266,7 @@ static qboolean Touch_DumpConfig( const char *name, const char *profilename )
} }
FS_Printf( f, "//=======================================================================\n"); 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, "//\t\t\ttouchscreen config\n" );
FS_Printf( f, "//=======================================================================\n" ); FS_Printf( f, "//=======================================================================\n" );
FS_Printf( f, "\ntouch_config_file \"%s\"\n", profilename ); FS_Printf( f, "\ntouch_config_file \"%s\"\n", profilename );
@@ -902,9 +902,10 @@ static void Touch_AddButton_f( void )
rgba_t color; rgba_t color;
int argc = Cmd_Argc( ); int argc = Cmd_Argc( );
touch_button_t *button = NULL; touch_button_t *button = NULL;
const char *name, *texture, *command; const char *name, *command;
float x1, y1, x2, y2; float x1, y1, x2, y2;
qboolean privileged = Cmd_CurrentCommandIsPrivileged(); qboolean privileged = Cmd_CurrentCommandIsPrivileged();
string texture;
if( argc < 4 ) if( argc < 4 )
{ {
@@ -913,9 +914,18 @@ static void Touch_AddButton_f( void )
} }
name = Cmd_Argv( 1 ); name = Cmd_Argv( 1 );
texture = Cmd_Argv( 2 ); Q_strncpy( texture, Cmd_Argv( 2 ), sizeof( texture ));
command = Cmd_Argv( 3 ); 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 ) if( argc < 8 )
{ {
x1 = y1 = 0.4f; x1 = y1 = 0.4f;

View File

@@ -51,7 +51,7 @@ static const keyname_t keynames[] =
{"CTRL", K_CTRL, "+attack" }, {"CTRL", K_CTRL, "+attack" },
{"SHIFT", K_SHIFT, "+speed" }, {"SHIFT", K_SHIFT, "+speed" },
{"CAPSLOCK", K_CAPSLOCK, "" }, {"CAPSLOCK", K_CAPSLOCK, "" },
{"SCROLLOCK", K_SCROLLOCK, "" }, {"SCROLLOCK", K_SCROLLLOCK, "" },
{"F1", K_F1, "cmd help" }, {"F1", K_F1, "cmd help" },
{"F2", K_F2, "menu_savegame" }, {"F2", K_F2, "menu_savegame" },
{"F3", K_F3, "menu_loadgame" }, {"F3", K_F3, "menu_loadgame" },
@@ -215,7 +215,7 @@ const char *Key_KeynumToString( int keynum )
return "<OUT OF RANGE>"; return "<OUT OF RANGE>";
// check for printable ascii (don't use quote) // 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[0] = keynum;
tinystr[1] = 0; tinystr[1] = 0;
@@ -861,7 +861,9 @@ void GAME_EXPORT Key_ClearStates( void )
for( i = 0; i < 256; i++ ) for( i = 0; i < 256; i++ )
{ {
if( keys[i].down && i < K_MOUSE1 && i > K_MOUSE5 ) if( i >= K_MOUSE1 && i <= K_MOUSE5 )
IN_MouseEvent( i - K_MOUSE1, false );
else
Key_Event( i, false ); Key_Event( i, false );
keys[i].down = 0; keys[i].down = 0;
@@ -869,9 +871,6 @@ void GAME_EXPORT Key_ClearStates( void )
keys[i].gamedown = 0; keys[i].gamedown = 0;
} }
for( i = K_MOUSE1; i < K_MOUSE5; i++ ) // from K_MOUSE1 to K_MOUSE5
IN_MouseEvent( i - K_MOUSE1, false );
if( clgame.hInstance ) if( clgame.hInstance )
clgame.dllFuncs.IN_ClearStates(); clgame.dllFuncs.IN_ClearStates();
} }

View File

@@ -312,7 +312,7 @@ static int DLY_Init( int idelay, float delay )
cur = &rgsxdly[idelay]; cur = &rgsxdly[idelay];
cur->cdelaysamplesmax = ((int)(delay * idsp_dma_speed) << sxhires) + 1; 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; cur->xfade = 0;
// init modulation // init modulation

View File

@@ -107,17 +107,18 @@ S_CreateDefaultSound
*/ */
static wavdata_t *S_CreateDefaultSound( void ) 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 = Mem_Calloc( sndpool, sizeof( wavdata_t ) + size );
sc->width = width;
sc->width = 2; sc->channels = channels;
sc->channels = 1;
sc->loopStart = 0;
sc->rate = SOUND_DMA_SPEED; sc->rate = SOUND_DMA_SPEED;
sc->samples = SOUND_DMA_SPEED; sc->samples = samples;
sc->size = sc->samples * sc->width * sc->channels; sc->size = size;
sc->buffer = Mem_Calloc( sndpool, sc->size );
return sc; return sc;
} }

View File

@@ -20,8 +20,6 @@ GNU General Public License for more details.
#include "pm_local.h" #include "pm_local.h"
#include "platform/platform.h" #include "platform/platform.h"
#define SND_CLIP_DISTANCE 1000.0f
dma_t dma; dma_t dma;
poolhandle_t sndpool; poolhandle_t sndpool;
static soundfade_t soundfade; static soundfade_t soundfade;
@@ -1111,7 +1109,7 @@ rawchan_t *S_FindRawChannel( int entnum, qboolean create )
S_RawSamplesStereo 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 fracstep, samplefrac;
uint src, dst; 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; 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 S_FreeIdleRawChannels
@@ -1690,7 +1594,6 @@ void SND_UpdateSound( void )
} }
S_StreamBackgroundTrack (); S_StreamBackgroundTrack ();
S_StreamSoundTrack ();
// mix some sound // mix some sound
S_UpdateChannels (); S_UpdateChannels ();
@@ -1954,14 +1857,15 @@ qboolean S_Init( void )
Cmd_AddCommand( "spk", S_SayReliable_f, "reliable play a specified sententce" ); Cmd_AddCommand( "spk", S_SayReliable_f, "reliable play a specified sententce" );
Cmd_AddCommand( "speak", S_Say_f, "playing a specified sententce" ); Cmd_AddCommand( "speak", S_Say_f, "playing a specified sententce" );
sndpool = Mem_AllocPool( "Sound Zone" );
dma.backendName = "None"; dma.backendName = "None";
if( !SNDDMA_Init( ) ) if( !SNDDMA_Init( ))
{ {
Con_Printf( "Audio: sound system can't be initialized\n" ); Con_Printf( "Audio: sound system can't be initialized\n" );
Mem_FreePool( &sndpool );
return false; return false;
} }
sndpool = Mem_AllocPool( "Sound Zone" );
soundtime = 0; soundtime = 0;
paintedtime = 0; paintedtime = 0;

View File

@@ -16,6 +16,7 @@ GNU General Public License for more details.
#include "common.h" #include "common.h"
#include "sound.h" #include "sound.h"
#include "client.h" #include "client.h"
#include "soundlib.h"
static bg_track_t s_bgTrack; static bg_track_t s_bgTrack;
static musicfade_t musicfade; // controlled by game dlls static musicfade_t musicfade; // controlled by game dlls
@@ -212,7 +213,7 @@ void S_StreamBackgroundTrack( void )
while( ch->s_rawend < soundtime + ch->max_samples ) 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); bufferSamples = ch->max_samples - (ch->s_rawend - soundtime);
@@ -241,7 +242,7 @@ void S_StreamBackgroundTrack( void )
if( r > 0 ) if( r > 0 )
{ {
// add to raw buffer // 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 else
{ {
@@ -286,66 +287,3 @@ void S_StopStreaming( void )
if( !dma.initialized ) return; if( !dma.initialized ) return;
s_listener.streaming = false; 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
}
}

View File

@@ -557,7 +557,7 @@ static void VOX_ReadSentenceFile_( byte *buf, fs_offset_t size )
int index = cszrawsentences; int index = cszrawsentences;
int size = strlen( name ) + strlen( value ) + 2; 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 ); memcpy( rgpszrawsentence[index], name, size );
rgpszrawsentence[index][size - 1] = 0; rgpszrawsentence[index][size - 1] = 0;
cszrawsentences++; cszrawsentences++;

View File

@@ -114,7 +114,6 @@ typedef struct rawchan_s
vec3_t origin; // only use if fixed_origin is set vec3_t origin; // only use if fixed_origin is set
volatile uint s_rawend; volatile uint s_rawend;
float oldtime; // catch time jumps float oldtime; // catch time jumps
wavdata_t sound_info; // advance play position
size_t max_samples; // buffer length size_t max_samples; // buffer length
portable_samplepair_t rawsamples[]; // variable sized portable_samplepair_t rawsamples[]; // variable sized
} rawchan_t; } rawchan_t;
@@ -171,12 +170,15 @@ typedef struct
int source; // may be game, menu, etc int source; // may be game, menu, etc
} bg_track_t; } bg_track_t;
typedef int sound_t;
//==================================================================== //====================================================================
#define MAX_DYNAMIC_CHANNELS (60 + NUM_AMBIENTS) #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_CHANNELS (256 + MAX_DYNAMIC_CHANNELS) // Scourge Of Armagon has too many static sounds on hip2m4.bsp
#define MAX_RAW_CHANNELS 48 #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 sound_t ambient_sfx[NUM_AMBIENTS];
extern qboolean snd_ambient; extern qboolean snd_ambient;
@@ -242,8 +244,8 @@ int S_GetCurrentStaticSounds( soundlist_t *pout, int size );
int S_GetCurrentDynamicSounds( soundlist_t *pout, int size ); int S_GetCurrentDynamicSounds( soundlist_t *pout, int size );
sfx_t *S_GetSfxByHandle( sound_t handle ); sfx_t *S_GetSfxByHandle( sound_t handle );
rawchan_t *S_FindRawChannel( int entnum, qboolean create ); 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_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_StopSound( int entnum, int channel, const char *soundname );
void S_UpdateFrame( struct ref_viewpass_s *rvp ); void S_UpdateFrame( struct ref_viewpass_s *rvp );
void S_StopAllSounds( qboolean ambient ); void S_StopAllSounds( qboolean ambient );
@@ -263,7 +265,6 @@ void SND_ForceCloseMouth( int entnum );
// //
// s_stream.c // s_stream.c
// //
void S_StreamSoundTrack( void );
void S_StreamBackgroundTrack( void ); void S_StreamBackgroundTrack( void );
void S_PrintBackgroundTrackState( void ); void S_PrintBackgroundTrackState( void );
void S_FadeMusicVolume( float fadePercent ); void S_FadeMusicVolume( float fadePercent );

View File

@@ -29,17 +29,20 @@ static void Sound_Reset( void )
static MALLOC_LIKE( FS_FreeSound, 1 ) wavdata_t *SoundPack( 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->size = sound.size;
pack->loopStart = sound.loopstart; pack->loopStart = sound.loopstart;
pack->samples = sound.samples; pack->samples = sound.samples;
pack->channels = sound.channels; pack->type = sound.type;
pack->flags = sound.flags; 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; return pack;
} }
@@ -132,7 +135,6 @@ free WAV buffer
void FS_FreeSound( wavdata_t *pack ) void FS_FreeSound( wavdata_t *pack )
{ {
if( !pack ) return; if( !pack ) return;
if( pack->buffer ) Mem_Free( pack->buffer );
Mem_Free( pack ); Mem_Free( pack );
} }
@@ -199,33 +201,6 @@ stream_t *FS_OpenStream( const char *filename )
return stream; 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 FS_ReadStream

View File

@@ -17,7 +17,7 @@ GNU General Public License for more details.
#include "base_cmd.h" #include "base_cmd.h"
#include "cdll_int.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; 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_t *basecmd; // base command: cvar, alias or command
base_command_hashmap_t *next; base_command_hashmap_t *next;
base_command_type_e type; // type for faster searching 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 base_command_hashmap_t *hashed_cmds[HASH_SIZE];
static poolhandle_t basecmd_pool;
#define BaseCmd_HashKey( x ) COM_HashKey( name, HASH_SIZE ) #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 ) 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; base_command_hashmap_t *i;
for( ; i && ( i->type != type || Q_stricmp( name, i->name ) ); // filter out
i = i->next );
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 *base = BaseCmd_GetBucket( name );
base_command_hashmap_t *i = base; base_command_hashmap_t *i = base;
ASSERT( cmd && alias && cvar );
*cmd = *alias = *cvar = NULL; *cmd = *alias = *cvar = NULL;
for( ; i; i = i->next ) 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;
case HM_CMD: break;
*cmd = i->basecmd; case HM_CMDALIAS:
break; *alias = i->basecmd;
case HM_CMDALIAS: break;
*alias = i->basecmd; case HM_CVAR:
break; *cvar = i->basecmd;
case HM_CVAR: break;
*cvar = i->basecmd; default:
break; 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 ); uint hash = BaseCmd_HashKey( name );
size_t len = Q_strlen( 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->basecmd = basecmd;
elem->type = type; elem->type = type;
Q_strncpy( elem->name, name, len + 1 ); Q_strncpy( elem->name, name, len + 1 );
// link the variable in alphanumerical order // link the variable in alphanumerical order
for( cur = NULL, find = hashed_cmds[hash]; 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 ); cur = find, find = find->next );
if( cur ) cur->next = elem; 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 ); uint hash = BaseCmd_HashKey( name );
base_command_hashmap_t *i, *prev; base_command_hashmap_t *i, *prev;
for( prev = NULL, i = hashed_cmds[hash]; i && for( prev = NULL, i = hashed_cmds[hash]; i != NULL; prev = i, i = i->next )
( Q_strcmp( i->name, name ) || i->type != type); // filter out {
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 ) if( !i )
{ {
@@ -183,9 +218,15 @@ initialize base command hashmap system
*/ */
void BaseCmd_Init( void ) void BaseCmd_Init( void )
{ {
basecmd_pool = Mem_AllocPool( "BaseCmd" );
memset( hashed_cmds, 0, sizeof( hashed_cmds ) ); memset( hashed_cmds, 0, sizeof( hashed_cmds ) );
} }
void BaseCmd_Shutdown( void )
{
Mem_FreePool( &basecmd_pool );
}
/* /*
============ ============
BaseCmd_Stats_f BaseCmd_Stats_f

View File

@@ -32,6 +32,7 @@ typedef enum base_command_type
typedef void base_command_t; typedef void base_command_t;
void BaseCmd_Init( void ); void BaseCmd_Init( void );
void BaseCmd_Shutdown( void );
base_command_t *BaseCmd_Find( base_command_type_e type, const char *name ); base_command_t *BaseCmd_Find( base_command_type_e type, const char *name );
void BaseCmd_FindAll( const char *name, void BaseCmd_FindAll( const char *name,
base_command_t **cmd, base_command_t **alias, base_command_t **cvar ); base_command_t **cmd, base_command_t **alias, base_command_t **cvar );

View File

@@ -46,6 +46,7 @@ static cmdalias_t *cmd_alias;
static uint cmd_condition; static uint cmd_condition;
static int cmd_condlevel; static int cmd_condlevel;
static qboolean cmd_currentCommandIsPrivileged; static qboolean cmd_currentCommandIsPrivileged;
static poolhandle_t cmd_pool;
static void Cmd_ExecuteStringWithPrivilegeCheck( const char *text, qboolean isPrivileged ); static void Cmd_ExecuteStringWithPrivilegeCheck( const char *text, qboolean isPrivileged );
@@ -432,7 +433,7 @@ static void Cmd_Alias_f( void )
{ {
if( !Q_strcmp( s, a->name )) if( !Q_strcmp( s, a->name ))
{ {
Z_Free( a->value ); Mem_Free( a->value );
break; break;
} }
} }
@@ -441,7 +442,7 @@ static void Cmd_Alias_f( void )
{ {
cmdalias_t *cur, *prev; 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 )); Q_strncpy( a->name, s, sizeof( a->name ));
@@ -469,7 +470,7 @@ static void Cmd_Alias_f( void )
} }
Q_strncat( cmd, "\n", sizeof( cmd )); Q_strncat( cmd, "\n", sizeof( cmd ));
a->value = copystring( cmd ); a->value = copystringpool( cmd_pool, cmd );
} }
/* /*
@@ -529,7 +530,7 @@ struct cmd_s
char *name; char *name;
xcommand_t function; xcommand_t function;
int flags; int flags;
char *desc; char desc[];
}; };
static int cmd_argc; static int cmd_argc;
@@ -636,7 +637,7 @@ void Cmd_TokenizeString( const char *text )
// clear the args from the last string // clear the args from the last string
for( i = 0; i < cmd_argc; i++ ) for( i = 0; i < cmd_argc; i++ )
Z_Free( cmd_argv[i] ); Mem_Free( cmd_argv[i] );
cmd_argc = 0; // clear previous args cmd_argc = 0; // clear previous args
cmd_args = NULL; cmd_args = NULL;
@@ -670,7 +671,7 @@ void Cmd_TokenizeString( const char *text )
if( cmd_argc < MAX_CMD_TOKENS ) if( cmd_argc < MAX_CMD_TOKENS )
{ {
cmd_argv[cmd_argc] = copystring( cmd_token ); cmd_argv[cmd_argc] = copystringpool( cmd_pool, cmd_token );
cmd_argc++; cmd_argc++;
} }
} }
@@ -683,7 +684,8 @@ Cmd_AddCommandEx
*/ */
int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd_desc, int iFlags, const char *funcname ) 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 )) if( !COM_CheckString( cmd_name ))
{ {
@@ -707,8 +709,8 @@ int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd
// unfortunately, we lose original command this way // unfortunately, we lose original command this way
if( FBitSet( cmd->flags, CMD_OVERRIDABLE )) if( FBitSet( cmd->flags, CMD_OVERRIDABLE ))
{ {
Mem_Free( cmd->desc ); desc_len = Q_strlen( cmd->desc ) + 1;
cmd->desc = copystring( cmd_desc ); Q_strncpy( cmd->desc, cmd_desc, desc_len );
cmd->function = function; cmd->function = function;
cmd->flags = iFlags; cmd->flags = iFlags;
@@ -723,9 +725,10 @@ int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd
} }
// use a small malloc to avoid zone fragmentation // use a small malloc to avoid zone fragmentation
cmd = Z_Malloc( sizeof( cmd_t ) ); desc_len = Q_strlen( cmd_desc ) + 1;
cmd->name = copystring( cmd_name ); cmd = Mem_Malloc( cmd_pool, sizeof( cmd_t ) + desc_len );
cmd->desc = copystring( cmd_desc ); cmd->name = copystringpool( cmd_pool, cmd_name );
Q_strncpy( cmd->desc, cmd_desc, desc_len );
cmd->function = function; cmd->function = function;
cmd->flags = iFlags; cmd->flags = iFlags;
@@ -772,9 +775,6 @@ void GAME_EXPORT Cmd_RemoveCommand( const char *cmd_name )
if( cmd->name ) if( cmd->name )
Mem_Free( cmd->name ); Mem_Free( cmd->name );
if( cmd->desc )
Mem_Free( cmd->desc );
Mem_Free( cmd ); Mem_Free( cmd );
return; return;
} }
@@ -1202,7 +1202,6 @@ void Cmd_Unlink( int group )
*prev = cmd->next; *prev = cmd->next;
if( cmd->name ) Mem_Free( cmd->name ); if( cmd->name ) Mem_Free( cmd->name );
if( cmd->desc ) Mem_Free( cmd->desc );
Mem_Free( cmd ); Mem_Free( cmd );
count++; count++;
@@ -1340,6 +1339,7 @@ Cmd_Init
*/ */
void Cmd_Init( void ) void Cmd_Init( void )
{ {
cmd_pool = Mem_AllocPool( "Console Commands" );
cmd_functions = NULL; cmd_functions = NULL;
cmd_condition = 0; cmd_condition = 0;
cmd_alias = NULL; cmd_alias = NULL;
@@ -1366,6 +1366,11 @@ void Cmd_Init( void )
#endif #endif
} }
void Cmd_Shutdown( void )
{
Mem_FreePool( &cmd_pool );
}
#if XASH_ENGINE_TESTS #if XASH_ENGINE_TESTS
#include "tests.h" #include "tests.h"

View File

@@ -108,14 +108,14 @@ typedef enum
#include "com_model.h" #include "com_model.h"
#include "com_strings.h" #include "com_strings.h"
#include "crtlib.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_OPEN
#define FSCALLBACK_OVERRIDE_LOADFILE #define FSCALLBACK_OVERRIDE_LOADFILE
#define FSCALLBACK_OVERRIDE_MALLOC_LIKE #define FSCALLBACK_OVERRIDE_MALLOC_LIKE
#include "fscallback.h" #include "fscallback.h"
#include "cvar.h"
#include "con_nprint.h"
#include "crclib.h"
#include "ref_api.h"
// PERFORMANCE INFO // PERFORMANCE INFO
#define MIN_FPS 20.0f // host minimum fps value for maxfps. #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 #define MAX_STATIC_ENTITIES 32 // static entities that moved on the client when level is spawn
#endif #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 GameState (&host.game)
#define FORCE_DRAW_VERSION_TIME 5.0 // draw version for 5 seconds #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 mempool; // static mempool for misc allocations
poolhandle_t imagepool; // imagelib mempool poolhandle_t imagepool; // imagelib mempool
poolhandle_t soundpool; // soundlib mempool poolhandle_t soundpool; // soundlib mempool
string finalmsg; // server shutdown final message
string downloadfile; // filename to be downloading string downloadfile; // filename to be downloading
int downloadcount; // how many files remain to downloading int downloadcount; // how many files remain to downloading
char deferred_cmd[128];// deferred commands char deferred_cmd[128];// deferred commands
@@ -433,6 +437,7 @@ int Cmd_Argc( void );
const char *Cmd_Args( void ) RETURNS_NONNULL; const char *Cmd_Args( void ) RETURNS_NONNULL;
const char *Cmd_Argv( int arg ) RETURNS_NONNULL; const char *Cmd_Argv( int arg ) RETURNS_NONNULL;
void Cmd_Init( void ); void Cmd_Init( void );
void Cmd_Shutdown( void );
void Cmd_Unlink( int group ); void Cmd_Unlink( int group );
int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd_desc, int flags, const char *funcname ); int Cmd_AddCommandEx( const char *cmd_name, xcommand_t function, const char *cmd_desc, int flags, const char *funcname );
@@ -514,27 +519,27 @@ typedef enum
typedef struct typedef struct
{ {
word rate; // num samples per second (e.g. 11025 - 11 khz) size_t size; // for bounds checking
byte width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2)
byte channels; // num channels (1 - mono, 2 - stereo)
uint loopStart; // offset at this point sound will be looping while playing more than only once uint loopStart; // offset at this point sound will be looping while playing more than only once
uint samples; // total samplecount in wav uint samples; // total samplecount in wav
uint type; // compression type uint type; // compression type
uint flags; // misc sound flags uint flags; // misc sound flags
byte *buffer; // sound buffer word rate; // num samples per second (e.g. 11025 - 11 khz)
size_t size; // for bounds checking 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; } wavdata_t;
// //
// soundlib // soundlib
// //
typedef struct stream_s stream_t;
void Sound_Init( void ); void Sound_Init( void );
void Sound_Shutdown( void ); void Sound_Shutdown( void );
void FS_FreeSound( wavdata_t *pack ); void FS_FreeSound( wavdata_t *pack );
void FS_FreeStream( stream_t *stream ); 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; 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; 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_ReadStream( stream_t *stream, int bytes, void *buffer );
int FS_SetStreamPos( stream_t *stream, int newpos ); int FS_SetStreamPos( stream_t *stream, int newpos );
int FS_GetStreamPos( stream_t *stream ); int FS_GetStreamPos( stream_t *stream );
@@ -560,6 +565,7 @@ void Host_Error( const char *error, ... ) FORMAT_CHECK( 1 );
void Host_ValidateEngineFeatures( uint32_t mask, uint32_t features ); void Host_ValidateEngineFeatures( uint32_t mask, uint32_t features );
void Host_Frame( double time ); void Host_Frame( double time );
void Host_Credits( void ); void Host_Credits( void );
void Host_ExitInMain( void );
// //
// host_state.c // host_state.c
@@ -578,11 +584,19 @@ CLIENT / SERVER SYSTEMS
============================================================== ==============================================================
*/ */
#if !XASH_DEDICATED
void CL_Init( void ); void CL_Init( void );
void CL_Shutdown( void ); void CL_Shutdown( void );
void Host_ClientBegin( void ); void Host_ClientBegin( void );
void Host_ClientFrame( void ); void Host_ClientFrame( void );
int CL_Active( 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_Init( void );
void SV_Shutdown( const char *finalmsg ); void SV_Shutdown( const char *finalmsg );
@@ -620,6 +634,7 @@ int pfnNumberOfEntities( void );
int pfnIsInGame( void ); int pfnIsInGame( void );
float pfnTime( void ); float pfnTime( void );
#define copystring( s ) _copystring( host.mempool, s, __FILE__, __LINE__ ) #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 SV_CopyString( s ) _copystring( svgame.stringspool, s, __FILE__, __LINE__ )
#define freestring( s ) if( s != NULL ) { Mem_Free( s ); s = NULL; } #define freestring( s ) if( s != NULL ) { Mem_Free( s ); s = NULL; }
char *_copystring( poolhandle_t mempool, const char *s, const char *filename, int fileline ); char *_copystring( poolhandle_t mempool, const char *s, const char *filename, int fileline );
@@ -670,6 +685,7 @@ int CSCR_WriteGameCVars( file_t *cfg, const char *scriptfilename );
// //
// hpak.c // hpak.c
// //
const char *COM_ResourceTypeFromIndex( int index );
void HPAK_Init( void ); void HPAK_Init( void );
qboolean HPAK_GetDataPointer( const char *filename, struct resource_s *pRes, byte **buffer, int *size ); 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 ); qboolean HPAK_ResourceForHash( const char *filename, byte *hash, struct resource_s *pRes );
@@ -703,13 +719,32 @@ typedef enum connprotocol_e
struct physent_s; struct physent_s;
struct sv_client_s; struct sv_client_s;
typedef struct sizebuf_s sizebuf_t; typedef struct sizebuf_s sizebuf_t;
int SV_GetMaxClients( void );
#if !XASH_DEDICATED
qboolean CL_Initialized( void );
qboolean CL_IsInGame( void ); qboolean CL_IsInGame( void );
qboolean CL_IsInConsole( void ); qboolean CL_IsInConsole( void );
qboolean CL_IsIntermission( 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 ); char *CL_Userinfo( void );
void CL_CharEvent( int key ); void CL_CharEvent( int key );
qboolean CL_DisableVisibility( void );
byte *COM_LoadFile( const char *filename, int usehunk, int *pLength ) MALLOC_LIKE( free, 1 ); byte *COM_LoadFile( const char *filename, int usehunk, int *pLength ) MALLOC_LIKE( free, 1 );
struct cmd_s *Cmd_GetFirstFunctionHandle( void ); struct cmd_s *Cmd_GetFirstFunctionHandle( void );
struct cmd_s *Cmd_GetNextFunctionHandle( struct cmd_s *cmd ); struct cmd_s *Cmd_GetNextFunctionHandle( struct cmd_s *cmd );
@@ -727,13 +762,7 @@ const char *CL_MsgInfo( int cmd );
void SV_DrawDebugTriangles( void ); void SV_DrawDebugTriangles( void );
void SV_DrawOrthoTriangles( void ); void SV_DrawOrthoTriangles( void );
double CL_GetDemoFramerate( void ); double CL_GetDemoFramerate( void );
qboolean UI_CreditsActive( void );
void CL_StopPlayback( 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 ); qboolean SV_Initialized( void );
void CL_ProcessFile( qboolean successfully_received, const char *filename ); void CL_ProcessFile( qboolean successfully_received, const char *filename );
int SV_GetSaveComment( const char *savename, char *comment ); int SV_GetSaveComment( const char *savename, char *comment );
@@ -755,8 +784,6 @@ void SCR_Init( void );
void SCR_UpdateScreen( void ); void SCR_UpdateScreen( void );
void SCR_BeginLoadingPlaque( qboolean is_background ); void SCR_BeginLoadingPlaque( qboolean is_background );
void SCR_CheckStartupVids( void ); void SCR_CheckStartupVids( void );
int SCR_GetAudioChunk( char *rawdata, int length );
wavdata_t *SCR_GetMovieInfo( void );
void SCR_Shutdown( void ); void SCR_Shutdown( void );
void Con_Print( const char *txt ); void Con_Print( const char *txt );
void Con_NPrintf( int idx, const char *fmt, ... ) FORMAT_CHECK( 2 ); void Con_NPrintf( int idx, const char *fmt, ... ) FORMAT_CHECK( 2 );
@@ -846,13 +873,6 @@ void V_CheckGamma( void );
void V_CheckGammaEnd( void ); void V_CheckGammaEnd( void );
intptr_t V_GetGammaPtr( int parm ); 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 // masterlist.c
// //

View File

@@ -1395,7 +1395,7 @@ void Host_WriteConfig( void )
{ {
Con_Reportf( "%s()\n", __func__ ); Con_Reportf( "%s()\n", __func__ );
FS_Printf( f, "//=======================================================================\n"); 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, "//\t\tconfig.cfg - archive of cvars\n" );
FS_Printf( f, "//=======================================================================\n" ); FS_Printf( f, "//=======================================================================\n" );
Key_WriteBindings( f ); Key_WriteBindings( f );
@@ -1443,7 +1443,7 @@ void GAME_EXPORT Host_WriteServerConfig( const char *name )
if(( f = FS_Open( newconfigfile, "w", false )) != NULL ) if(( f = FS_Open( newconfigfile, "w", false )) != NULL )
{ {
FS_Printf( f, "//=======================================================================\n" ); 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, "//\t\tgame.cfg - multiplayer server temporare config\n" );
FS_Printf( f, "//=======================================================================\n" ); FS_Printf( f, "//=======================================================================\n" );
@@ -1478,7 +1478,7 @@ void Host_WriteOpenGLConfig( void )
{ {
Con_Reportf( "%s()\n", __func__ ); Con_Reportf( "%s()\n", __func__ );
FS_Printf( f, "//=======================================================================\n" ); 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, "//\t\t%s - archive of renderer implementation cvars\n", name );
FS_Printf( f, "//=======================================================================\n" ); FS_Printf( f, "//=======================================================================\n" );
FS_Printf( f, "\n" ); FS_Printf( f, "\n" );
@@ -1508,7 +1508,7 @@ void Host_WriteVideoConfig( void )
{ {
Con_Reportf( "%s()\n", __func__ ); Con_Reportf( "%s()\n", __func__ );
FS_Printf( f, "//=======================================================================\n" ); 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, "//\t\tvideo.cfg - archive of renderer variables\n");
FS_Printf( f, "//=======================================================================\n" ); FS_Printf( f, "//=======================================================================\n" );
Cvar_WriteVariables( f, FCVAR_RENDERINFO ); Cvar_WriteVariables( f, FCVAR_RENDERINFO );
@@ -1534,7 +1534,7 @@ void Key_EnumCmds_f( void )
if( f ) if( f )
{ {
FS_Printf( f, "//=======================================================================\n"); 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, "//\t\thelp.txt - xash commands and console variables\n");
FS_Printf( f, "//=======================================================================\n"); FS_Printf( f, "//=======================================================================\n");

View File

@@ -19,6 +19,7 @@ GNU General Public License for more details.
#include "eiface.h" // ARRAYSIZE #include "eiface.h" // ARRAYSIZE
static convar_t *cvar_vars = NULL; // head of list 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" ); CVAR_DEFINE_AUTO( cmd_scripting, "0", FCVAR_ARCHIVE|FCVAR_PRIVILEGED, "enable simple condition checking and variable operations" );
typedef struct cvar_filter_quirks_s 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 // directly set value
freestring( var->string ); freestring( var->string );
var->string = copystring( value ); var->string = copystringpool( cvar_pool, value );
var->value = Q_atof( var->string ); var->value = Q_atof( var->string );
SetBits( var->flags, flags ); 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 ); Con_Reportf( "%s change description from %s to %s\n", var->name, var->desc, var_desc );
// update description if needs // update description if needs
freestring( var->desc ); freestring( var->desc );
var->desc = copystring( var_desc ); var->desc = copystringpool( cvar_pool, var_desc );
} }
return var; return var;
} }
// allocate a new cvar // allocate a new cvar
var = Z_Malloc( sizeof( *var )); var = Mem_Malloc( cvar_pool, sizeof( *var ));
var->name = copystring( name ); var->name = copystringpool( cvar_pool, name );
var->string = copystring( value ); var->string = copystringpool( cvar_pool, value );
var->def_string = copystring( value ); var->def_string = copystringpool( cvar_pool, value );
var->desc = copystring( var_desc ); var->desc = copystringpool( cvar_pool, var_desc );
var->value = Q_atof( var->string ); var->value = Q_atof( var->string );
var->flags = flags|FCVAR_ALLOCATED; var->flags = flags|FCVAR_ALLOCATED;
@@ -549,7 +550,7 @@ void Cvar_RegisterVariable( convar_t *var )
if( FBitSet( var->flags, FCVAR_EXTENDED )) if( FBitSet( var->flags, FCVAR_EXTENDED ))
var->def_string = var->string; // just swap pointers 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 ); var->value = Q_atof( var->string );
// find the supposed position in chain (alphanumerical order) // 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 // and finally changed the cvar itself
freestring( var->string ); freestring( var->string );
var->string = copystring( pszValue ); var->string = copystringpool( cvar_pool, pszValue );
var->value = Q_atof( var->string ); var->value = Q_atof( var->string );
// tell engine about changes // 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 // and finally changed the cvar itself
freestring( var->string ); freestring( var->string );
var->string = copystring( pszValue ); var->string = copystringpool( cvar_pool, pszValue );
var->value = Q_atof( var->string ); var->value = Q_atof( var->string );
// tell engine about changes // tell engine about changes
@@ -781,7 +782,7 @@ void Cvar_FullSet( const char *var_name, const char *value, int flags )
} }
freestring( var->string ); freestring( var->string );
var->string = copystring( value ); var->string = copystringpool( cvar_pool, value );
var->value = Q_atof( var->string ); var->value = Q_atof( var->string );
SetBits( var->flags, flags ); SetBits( var->flags, flags );
@@ -1189,6 +1190,7 @@ static void Cvar_List_f( void )
for( var = cvar_vars; var; var = var->next ) for( var = cvar_vars; var; var = var->next )
{ {
char value[MAX_VA_STRING]; char value[MAX_VA_STRING];
char *p;
if( var->name[0] == '@' ) if( var->name[0] == '@' )
continue; // never shows system cvars continue; // never shows system cvars
@@ -1196,7 +1198,9 @@ static void Cvar_List_f( void )
if( match && !Q_strnicmpext( match, var->name, matchlen )) if( match && !Q_strnicmpext( match, var->name, matchlen ))
continue; continue;
if( Q_colorstr( var->string )) p = Q_strchr( var->string, '^' );
if( IsColorString( p ))
Q_snprintf( value, sizeof( value ), "\"%s\"", var->string ); Q_snprintf( value, sizeof( value ), "\"%s\"", var->string );
else Q_snprintf( value, sizeof( value ), "\"^2%s^7\"", 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; continue;
namelen = Q_strlen( cv->name ) + 1; 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->next = NULL;
p->cv_cur = cv; p->cv_cur = cv;
p->cv_next = cv->next; p->cv_next = cv->next;
@@ -1333,6 +1337,7 @@ Reads in all archived cvars
*/ */
void Cvar_Init( void ) void Cvar_Init( void )
{ {
cvar_pool = Mem_AllocPool( "Console Variables" );
cvar_vars = NULL; cvar_vars = NULL;
cvar_active_filter_quirks = NULL; cvar_active_filter_quirks = NULL;
Cvar_RegisterVariable( &cmd_scripting ); 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" ); 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 Cvar_PostFSInit

View File

@@ -30,6 +30,8 @@ typedef struct pending_cvar_s
char cv_name[]; char cv_name[];
} pending_cvar_t; } pending_cvar_t;
typedef void (*setpair_t)( const char *key, const void *value, const void *buffer, void *numpairs );
cvar_t *Cvar_GetList( void ); cvar_t *Cvar_GetList( void );
#define Cvar_FindVar( name ) Cvar_FindVarExt( name, 0 ) #define Cvar_FindVar( name ) Cvar_FindVarExt( name, 0 )
convar_t *Cvar_FindVarExt( const char *var_name, int ignore_group ); 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 ); void Cvar_SetCheatState( void );
qboolean Cvar_CommandWithPrivilegeCheck( convar_t *v, qboolean isPrivileged ); qboolean Cvar_CommandWithPrivilegeCheck( convar_t *v, qboolean isPrivileged );
void Cvar_Init( void ); void Cvar_Init( void );
void Cvar_Shutdown( void );
void Cvar_PostFSInit( void ); void Cvar_PostFSInit( void );
void Cvar_Unlink( int group ); void Cvar_Unlink( int group );

View File

@@ -49,52 +49,6 @@ const char *CL_MsgInfo( int cmd )
return sz; 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 ) 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 ) 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 ) void IN_TouchInitConfig( void )
{ {
@@ -174,11 +113,6 @@ void CL_Disconnect( void )
} }
void CL_Shutdown( void )
{
}
void R_ClearStaticEntities( void ) void R_ClearStaticEntities( void )
{ {
@@ -189,11 +123,6 @@ void Host_Credits( void )
} }
qboolean UI_CreditsActive( void )
{
return false;
}
void S_StopBackgroundTrack( void ) 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 ) void S_StopAllSounds( qboolean ambient )
{ {

View File

@@ -183,14 +183,23 @@ static qboolean FS_DetermineRootDirectory( char *out, size_t size )
#elif XASH_PSVITA #elif XASH_PSVITA
if( PSVita_GetBasePath( out, size )) if( PSVita_GetBasePath( out, size ))
return true; return true;
Sys_Error( "couldn't find Xash3D data directory" ); Sys_Error( "couldn't find %s data directory", XASH_ENGINE_NAME );
return false; return false;
#elif ( XASH_SDL == 2 ) && !XASH_NSWITCH // GetBasePath not impl'd in switch-sdl2 #elif ( XASH_SDL == 2 ) && !XASH_NSWITCH // GetBasePath not impl'd in switch-sdl2
path = SDL_GetBasePath(); 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 ) if( path != NULL )
{ {
Q_strncpy( out, path, size ); Q_strncpy( out, path, size );
SDL_free(( void *)path ); SDL_free((void *)path );
return true; return true;
} }

View File

@@ -43,6 +43,27 @@ GNU General Public License for more details.
static pfnChangeGame pChangeGame = NULL; static pfnChangeGame pChangeGame = NULL;
host_parm_t host; // host parms 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 #ifdef XASH_ENGINE_TESTS
struct tests_stats_s tests_stats; struct tests_stats_s tests_stats;
#endif #endif
@@ -362,9 +383,8 @@ static void Host_NewInstance( const char *name, const char *finalmsg )
if( !pChangeGame ) return; if( !pChangeGame ) return;
host.change_game = true; 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 pChangeGame( name ); // call from hl.exe
} }
@@ -838,7 +858,6 @@ void GAME_EXPORT Host_Error( const char *error, ... )
recursive = true; recursive = true;
Q_strncpy( hosterror2, hosterror1, sizeof( hosterror2 )); Q_strncpy( hosterror2, hosterror1, sizeof( hosterror2 ));
host.errorframe = host.framecount; // to avoid multply calls per frame 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 // clearing cmd buffer to prevent execute any commands
COM_InitHostState(); COM_InitHostState();
@@ -1112,7 +1131,7 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
#if XASH_DEDICATED #if XASH_DEDICATED
Platform_SetupSigtermHandling(); Platform_SetupSigtermHandling();
#endif #endif
Platform_Init( Host_IsDedicated( ) || developer >= DEV_EXTENDED ); Platform_Init( Host_IsDedicated( ) || developer >= DEV_EXTENDED, basedir );
FS_Init( basedir ); FS_Init( basedir );
Sys_InitLog(); Sys_InitLog();
@@ -1214,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( "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( "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 ); 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(); Mod_Init();
@@ -1237,7 +1256,6 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
CL_Init(); CL_Init();
HTTP_Init(); HTTP_Init();
ID_Init();
SoundList_Init(); SoundList_Init();
if( Host_IsDedicated( )) if( Host_IsDedicated( ))
@@ -1321,6 +1339,11 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
// check after all configs were executed // check after all configs were executed
HPAK_CheckIntegrity( hpk_custom_file.string ); 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 // main window message loop
while( !host.crashed ) while( !host.crashed )
{ {
@@ -1359,9 +1382,6 @@ void Host_ShutdownWithReason( const char *reason )
if( host.status != HOST_ERR_FATAL ) if( host.status != HOST_ERR_FATAL )
host.status = HOST_SHUTDOWN; // prepare host to normal shutdown host.status = HOST_SHUTDOWN; // prepare host to normal shutdown
if( !host.change_game )
Q_strncpy( host.finalmsg, "Server shutdown", sizeof( host.finalmsg ));
#if !XASH_DEDICATED #if !XASH_DEDICATED
if( host.type == HOST_NORMAL && !error ) if( host.type == HOST_NORMAL && !error )
Host_WriteConfig(); Host_WriteConfig();
@@ -1379,10 +1399,14 @@ void Host_ShutdownWithReason( const char *reason )
Host_FreeCommon(); Host_FreeCommon();
Platform_Shutdown(); Platform_Shutdown();
BaseCmd_Shutdown();
Cmd_Shutdown();
Cvar_Shutdown();
// must be last, console uses this // must be last, console uses this
Mem_FreePool( &host.mempool ); Mem_FreePool( &host.mempool );
// restore filter // restore filter
Sys_RestoreCrashHandler(); Sys_RestoreCrashHandler();
Sys_CloseLog(); Sys_CloseLog( reason );
} }

View File

@@ -38,7 +38,7 @@ static void HPAK_MaxSize_f( void )
Con_Printf( S_ERROR "hpk_maxsize is deprecated, use hpk_max_size\n" ); 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 ) switch( type )
{ {
@@ -104,7 +104,7 @@ static void HPAK_CreatePak( const char *filename, resource_t *pResource, byte *p
string pakname; string pakname;
byte md5[16]; byte md5[16];
file_t *fout; file_t *fout;
MD5Context_t ctx; MD5Context_t ctx = { 0 };
if( !COM_CheckString( filename )) if( !COM_CheckString( filename ))
return; return;
@@ -125,7 +125,6 @@ static void HPAK_CreatePak( const char *filename, resource_t *pResource, byte *p
} }
// let's hash it. // let's hash it.
memset( &ctx, 0, sizeof( MD5Context_t ));
MD5Init( &ctx ); MD5Init( &ctx );
if( pData == NULL ) 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_src;
file_t *file_dst; file_t *file_dst;
byte md5[16]; byte md5[16];
MD5Context_t ctx; MD5Context_t ctx = { 0 };
if( pData == NULL && pFile == NULL ) if( pData == NULL && pFile == NULL )
return; return;
@@ -226,7 +225,6 @@ void HPAK_AddLump( qboolean bUseQueue, const char *name, resource_t *pResource,
} }
// hash it // hash it
memset( &ctx, 0, sizeof( MD5Context_t ));
MD5Init( &ctx ); MD5Init( &ctx );
if( !pData ) if( !pData )
@@ -463,7 +461,7 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet, qboolean de
if( !quiet ) 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 ); Q_pretifymem( pRes->nDownloadSize, 2 ), pRes->szFileName );
} }
@@ -944,7 +942,7 @@ static void HPAK_List_f( void )
{ {
entry = &directory.entries[nCurrent]; entry = &directory.entries[nCurrent];
COM_FileBase( entry->resource.szFileName, lumpname, sizeof( lumpname )); 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 ); 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 )); 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; continue;
COM_FileBase( entry->resource.szFileName, lumpname, sizeof( lumpname ) ); 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 ); size = Q_memprint( entry->resource.nDownloadSize );
Con_Printf( "Extracting %i: %10s %s %s\n", nCurrent + 1, type, size, lumpname ); Con_Printf( "Extracting %i: %10s %s %s\n", nCurrent + 1, type, size, lumpname );

View File

@@ -28,12 +28,20 @@ Image_LoadPAL
qboolean Image_LoadPAL( const char *name, const byte *buffer, fs_offset_t filesize ) qboolean Image_LoadPAL( const char *name, const byte *buffer, fs_offset_t filesize )
{ {
int rendermode = LUMP_NORMAL; 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; 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] == '#' ) if( name[0] == '#' )
{ {

View File

@@ -482,7 +482,7 @@ static int Mod_LoadTextureFromWadList( wadlist_t *list, const char *name, rgbdat
return -1; 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 ) if( !mt )
return 0; return 0;
@@ -2359,7 +2359,7 @@ static qboolean Mod_SearchForTextureReplacement( char *out, size_t size, const c
return false; 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 #if !XASH_DEDICATED
rgbdata_t r_temp, *r_sky; rgbdata_t r_temp, *r_sky;
@@ -2516,9 +2516,6 @@ done:
static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureIndex ) 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; uint32_t txFlags = 0;
char texpath[MAX_VA_STRING]; char texpath[MAX_VA_STRING];
char safemtname[16]; // only for external textures char safemtname[16]; // only for external textures
@@ -2526,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. // don't load texture data on dedicated server, as there is no renderer.
// but count the wadusage for automatic precache // but count the wadusage for automatic precache
// texture_t *texture = mod->textures[textureIndex];
// FIXME: for ENGINE_IMPROVED_LINETRACE we need to load textures on server too const mip_t *mipTex = Mod_GetMipTexForTexture( bmod, textureIndex );
// but there is no facility for this yet const qboolean usesCustomPalette = Mod_CalcMipTexUsesCustomPalette( mod, bmod, textureIndex );
texture = mod->textures[textureIndex]; const qboolean iswater = Mod_LooksLikeWaterTexture( mipTex->name );
mipTex = Mod_GetMipTexForTexture( bmod, textureIndex );
usesCustomPalette = Mod_CalcMipTexUsesCustomPalette( mod, bmod, textureIndex );
// check for multi-layered sky texture (quake1 specific) // check for multi-layered sky texture (quake1 specific)
if( bmod->isworld && Q_strncmp( mipTex->name, "sky", 3 ) == 0 && ( mipTex->width / mipTex->height ) == 2 ) if( bmod->isworld && Q_strncmp( mipTex->name, "sky", 3 ) == 0 && ( mipTex->width / mipTex->height ) == 2 )
@@ -2540,11 +2535,13 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
return; 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] == '{' ) if( FBitSet( host.features, ENGINE_IMPROVED_LINETRACE ) && mipTex->name[0] == '{' )
SetBits( txFlags, TF_KEEP_SOURCE ); // Paranoia2 texture alpha-tracing 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) // 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 ); SetBits( txFlags, TF_KEEP_SOURCE | TF_EXPAND_SOURCE );
// Texture loading order: // Texture loading order:
@@ -2609,8 +2606,13 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
texture->gl_texturenum = R_GetBuiltinTexture( REF_DEFAULT_TEXTURE ); texture->gl_texturenum = R_GetBuiltinTexture( REF_DEFAULT_TEXTURE );
} }
// Check for luma texture
texture->fb_texturenum = 0; 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( 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" )) if( Mod_SearchForTextureReplacement( texpath, sizeof( texpath ), mod->name, safemtname, "_luma" ))

View File

@@ -868,7 +868,7 @@ void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded )
mod->type = mod_studio; mod->type = mod_studio;
phdr = R_StudioLoadHeader( mod, buffer ); phdr = R_StudioLoadHeader( mod, buffer );
if( !phdr ) if( !phdr || phdr->length < sizeof( studiohdr_t )) // garbage value in length
return; // bad model return; // bad model
#if !XASH_DEDICATED #if !XASH_DEDICATED

View File

@@ -258,7 +258,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
{ {
char tempname[MAX_QPATH]; char tempname[MAX_QPATH];
fs_offset_t length = 0; fs_offset_t length = 0;
qboolean loaded; qboolean loaded, loaded2 = false;
byte *buf; byte *buf;
model_info_t *p; model_info_t *p;
@@ -279,7 +279,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
buf = FS_LoadFile( tempname, &length, false ); buf = FS_LoadFile( tempname, &length, false );
if( !buf ) if( !buf || length < sizeof( uint ))
{ {
memset( mod, 0, sizeof( model_t )); 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 // let the server.dll load custom data
svgame.physFuncs.Mod_ProcessUserData( mod, true, buf ); svgame.physFuncs.Mod_ProcessUserData( mod, true, buf );
} }
loaded2 = true;
} }
#if !XASH_DEDICATED #if !XASH_DEDICATED
else else
{ {
loaded = ref.dllFuncs.Mod_ProcessRenderData( mod, true, buf ); loaded2 = ref.dllFuncs.Mod_ProcessRenderData( mod, true, buf );
} }
#endif #endif
} }
@@ -345,7 +346,7 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
hdr->pposeverts = NULL; hdr->pposeverts = NULL;
} }
if( !loaded ) if( !loaded || !loaded2 )
{ {
Mod_FreeModel( mod ); Mod_FreeModel( mod );
Mem_Free( buf ); Mem_Free( buf );
@@ -610,3 +611,41 @@ void Mod_NeedCRC( const char *name, qboolean needCRC )
if( needCRC ) SetBits( p->flags, FCRC_SHOULD_CHECKSUM ); if( needCRC ) SetBits( p->flags, FCRC_SHOULD_CHECKSUM );
else ClearBits( 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

View File

@@ -18,11 +18,177 @@ GNU General Public License for more details.
#include "net_buffer.h" #include "net_buffer.h"
#include "xash3d_mathlib.h" #include "xash3d_mathlib.h"
// precalculated bit masks for WriteUBitLong. static const uint32_t BitWriteMasks[32][32] =
// Using these tables instead of doing the calculations { {
// gives a 33% speedup in WriteUBitLong. 0xfffffffe, 0xfffffffc, 0xfffffff8, 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80, 0xffffff00,
static uint32_t BitWriteMasks[32][33]; 0xfffffe00, 0xfffffc00, 0xfffff800, 0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000,
static uint32_t ExtraMasks[32]; 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] = const char *const svc_strings[svc_lastmsg+1] =
{ {
"svc_bad", "svc_bad",
@@ -132,65 +298,41 @@ const char *const svc_quake_strings[svc_lastmsg+1] =
[svc_fog] = "svc_quake_fog", [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 ) 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.. // bounds checking..
if(( sb->iCurBit + numbits ) > sb->nDataBits ) if( MSG_Overflow( sb, numbits ))
{ {
sb->bOverflow = true;
sb->iCurBit = sb->nDataBits; 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; iCurBitMasked = iCurBit & 31;
((uint32_t *)sb->pData)[iDWord] &= BitWriteMasks[iCurBitMasked][nBitsLeft]; ((uint32_t *)sb->pData)[iDWord+1] &= BitWriteMasks[iCurBitMasked][nBitsLeft-1];
((uint32_t *)sb->pData)[iDWord] |= curData << iCurBitMasked; ((uint32_t *)sb->pData)[iDWord+1] |= 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;
} }
sb->iCurBit += numbits;
} }
/* /*
@@ -238,7 +380,7 @@ qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits )
int nBitsLeft = nBits; int nBitsLeft = nBits;
// get output dword-aligned. // 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 ); MSG_WriteUBitLong( sb, *pOut, 8 );
@@ -275,16 +417,14 @@ qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits )
void MSG_WriteBitAngle( sizebuf_t *sb, float fAngle, int numbits ) 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; int d;
// clamp the angle before receiving // clamp the angle before receiving
fAngle = fmod( fAngle, 360.0f ); fAngle = fmod( fAngle, 360.0f );
if( fAngle < 0 ) fAngle += 360.0f; if( fAngle < 0 ) fAngle += 360.0f;
shift = ( 1 << numbits );
mask = shift - 1;
d = (int)(( fAngle * shift ) / 360.0f ); d = (int)(( fAngle * shift ) / 360.0f );
d &= mask; d &= mask;
@@ -438,9 +578,8 @@ uint MSG_ReadUBitLong( sizebuf_t *sb, int numbits )
return 0; // end of message return 0; // end of message
} }
if(( sb->iCurBit + numbits ) > sb->nDataBits ) if( MSG_Overflow( sb, numbits ))
{ {
sb->bOverflow = true;
sb->iCurBit = sb->nDataBits; sb->iCurBit = sb->nDataBits;
return 0; return 0;
} }
@@ -513,13 +652,9 @@ qboolean MSG_ReadBits( sizebuf_t *sb, void *pOutData, int nBits )
float MSG_ReadBitAngle( sizebuf_t *sb, int numbits ) float MSG_ReadBitAngle( sizebuf_t *sb, int numbits )
{ {
float fReturn, shift; float shift = (float)( 1 << numbits );
int i; int i = MSG_ReadUBitLong( sb, numbits );
float fReturn = (float)i * ( 360.0f / shift );
shift = (float)( 1 << numbits );
i = MSG_ReadUBitLong( sb, numbits );
fReturn = (float)i * ( 360.0f / shift );
// clamp the finale angle // clamp the finale angle
if( fReturn < -180.0f ) fReturn += 360.0f; if( fReturn < -180.0f ) fReturn += 360.0f;
@@ -531,11 +666,11 @@ float MSG_ReadBitAngle( sizebuf_t *sb, int numbits )
// Append numbits least significant bits from data to the current bit stream // Append numbits least significant bits from data to the current bit stream
int MSG_ReadSBitLong( sizebuf_t *sb, int numbits ) int MSG_ReadSBitLong( sizebuf_t *sb, int numbits )
{ {
int r, sign; int r;
if( sb->iAlternateSign ) if( sb->iAlternateSign )
{ {
sign = MSG_ReadOneBit( sb ); int sign = MSG_ReadOneBit( sb );
r = MSG_ReadUBitLong( sb, numbits - 1 ); r = MSG_ReadUBitLong( sb, numbits - 1 );
if( sign ) if( sign )
@@ -544,9 +679,7 @@ int MSG_ReadSBitLong( sizebuf_t *sb, int numbits )
else else
{ {
r = MSG_ReadUBitLong( sb, numbits - 1 ); r = MSG_ReadUBitLong( sb, numbits - 1 );
sign = MSG_ReadOneBit( sb ); if( MSG_ReadOneBit( sb ))
if( sign )
r = -( BIT( numbits - 1 ) - r ); r = -( BIT( numbits - 1 ) - r );
} }
@@ -667,12 +800,12 @@ qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes )
static char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine ) static char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
{ {
static char string[4096]; static char string[4096];
int l = 0, c; int l = 0;
do do
{ {
// use MSG_ReadByte so -1 is out of bounds // use MSG_ReadByte so -1 is out of bounds
c = MSG_ReadByte( sb ); int c = MSG_ReadByte( sb );
if( c == 0 ) break; if( c == 0 ) break;
else if( bLine && c == '\n' ) else if( bLine && c == '\n' )
@@ -865,8 +998,6 @@ static void Test_Buffer_ExciseBits( void )
void Test_RunBuffer( void ) void Test_RunBuffer( void )
{ {
MSG_InitMasks();
TRUN( Test_Buffer_BitByte( )); TRUN( Test_Buffer_BitByte( ));
TRUN( Test_Buffer_Write( )); TRUN( Test_Buffer_Write( ));
TRUN( Test_Buffer_Read( )); TRUN( Test_Buffer_Read( ));

View File

@@ -193,7 +193,6 @@ static inline void MSG_StartBitWriting( sizebuf_t *sb )
sb->iAlternateSign++; sb->iAlternateSign++;
} }
void MSG_InitMasks( void ); // called once at startup engine
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove ); void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
// Bit-write functions // Bit-write functions

View File

@@ -272,8 +272,6 @@ void Netchan_Init( void )
Cvar_FullSet( net_qport.name, buf, net_qport.flags ); Cvar_FullSet( net_qport.name, buf, net_qport.flags );
net_mempool = Mem_AllocPool( "Network Pool" ); net_mempool = Mem_AllocPool( "Network Pool" );
MSG_InitMasks(); // initialize bit-masks
} }
void Netchan_Shutdown( void ) 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->split = FBitSet( flags, NETCHAN_USE_LEGACY_SPLIT ) ? true : false;
chan->use_munge = FBitSet( flags, NETCHAN_USE_MUNGE ) ? true : false; chan->use_munge = FBitSet( flags, NETCHAN_USE_MUNGE ) ? true : false;
chan->use_bz2 = FBitSet( flags, NETCHAN_USE_BZIP2 ) ? 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; chan->gs_netchan = FBitSet( flags, NETCHAN_GOLDSRC ) ? true : false;
MSG_Init( &chan->message, "NetData", chan->message_buf, sizeof( chan->message_buf )); 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__ ); Host_Error( "%s: BZ2 compression is not supported for server", __func__ );
#endif #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 uCompressedSize = 0;
uint uSourceSize = MSG_GetNumBytesWritten( msg ); uint uSourceSize = MSG_GetNumBytesWritten( msg );
@@ -1175,7 +1174,7 @@ qboolean Netchan_CopyNormalFragments( netchan_t *chan, sizebuf_t *msg, size_t *l
p = n; 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 #if !XASH_DEDICATED
byte buf[0x10000]; 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__ ); Host_Error( "%s: BZ2 compression is not supported for server\n", __func__ );
#endif #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 ); uint uDecompressedLen = LZSS_GetActualSize( MSG_GetData( msg ), size );
byte buf[NET_MAX_MESSAGE]; 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__ ); Host_Error( "%s: BZ2 compression is not supported for server", __func__ );
#endif #endif
} }
else if( LZSS_IsCompressed( buffer, nsize + 1 )) else if( chan->use_lzss && LZSS_IsCompressed( buffer, nsize + 1 ))
{ {
byte *uncompressedBuffer; byte *uncompressedBuffer;

View File

@@ -2282,10 +2282,6 @@ void Test_RunDelta( void )
char buffer[4096] = { 0 }; char buffer[4096] = { 0 };
const double timebase = 123.123; 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_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_big", DT_TIMEWINDOW_BIG, 24, 1000.f, 1.0f );
Delta_AddField( dt, "dt_timewindow_8", DT_TIMEWINDOW_8, 8, 1.0f, 1.0f ); Delta_AddField( dt, "dt_timewindow_8", DT_TIMEWINDOW_8, 8, 1.0f, 1.0f );

View File

@@ -326,7 +326,7 @@ static int HTTP_FileConnect( httpfile_t *file )
if( !COM_CheckStringEmpty( http_useragent.string ) || !Q_strcmp( http_useragent.string, "xash3d" )) if( !COM_CheckStringEmpty( http_useragent.string ) || !Q_strcmp( http_useragent.string, "xash3d" ))
{ {
Q_snprintf( useragent, sizeof( useragent ), "%s/%s (%s-%s; build %d; %s)", 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 )); 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 ) 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; return 1;
} }

View File

@@ -214,6 +214,7 @@ typedef enum netchan_flags_e
NETCHAN_USE_MUNGE = BIT( 1 ), NETCHAN_USE_MUNGE = BIT( 1 ),
NETCHAN_USE_BZIP2 = BIT( 2 ), NETCHAN_USE_BZIP2 = BIT( 2 ),
NETCHAN_GOLDSRC = BIT( 3 ), NETCHAN_GOLDSRC = BIT( 3 ),
NETCHAN_USE_LZSS = BIT( 4 ), // mutually exclusive with bzip2
} netchan_flags_t; } netchan_flags_t;
// Network Connection Channel // Network Connection Channel
@@ -285,6 +286,7 @@ typedef struct netchan_s
qboolean split; qboolean split;
qboolean use_munge; qboolean use_munge;
qboolean use_bz2; qboolean use_bz2;
qboolean use_lzss;
qboolean gs_netchan; qboolean gs_netchan;
} netchan_t; } netchan_t;

View File

@@ -89,16 +89,6 @@ void Sound_Shutdown( void )
Mem_FreePool( &host.soundpool ); 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 ) uint GAME_EXPORT Sound_GetApproxWavePlayLen( const char *filepath )
{ {
string name; string name;
@@ -378,6 +368,7 @@ static qboolean Sound_ResampleInternal( wavdata_t *sc, int outrate, int outwidth
const int inwidth = sc->width; const int inwidth = sc->width;
const int inchannels = sc->channels; const int inchannels = sc->channels;
const int incount = sc->samples; const int incount = sc->samples;
const int insize = sc->size;
qboolean handled = false; qboolean handled = false;
double stepscale; double stepscale;
double t1, t2; double t1, t2;
@@ -431,22 +422,30 @@ static qboolean Sound_ResampleInternal( wavdata_t *sc, int outrate, int outwidth
else // upsample case, w/ interpolation else // upsample case, w/ interpolation
handled = Sound_ConvertUpsample( sc, inwidth, inchannels, incount, outwidth, outchannels, outcount, stepscale ); 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 // restore previously changed data
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 ); sc->rate = inrate;
else sc->width = inwidth;
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 ); sc->channels = inchannels;
} sc->samples = incount;
else 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 ); 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->rate = outrate;
sc->width = outwidth; 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 ) 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 ) if( result )
{ {
Mem_Free( snd->buffer ); // free original image buffer snd = Mem_Realloc( host.soundpool, snd, sizeof( *snd ) + snd->size );
snd->buffer = Sound_Copy( snd->size ); // unzone buffer memcpy( snd->buffer, sound.tempbuffer, snd->size );
Mem_Free( sound.tempbuffer );
sound.tempbuffer = NULL;
} }
} }

View File

@@ -109,44 +109,44 @@ void Sys_InitLog( void )
// fit to 80 columns for easier read on standard terminal // fit to 80 columns for easier read on standard terminal
fputs( "================================================================================\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, "%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 )); fprintf( s_ld.logfile, "Game started at %s\n", Q_timestamp( TIME_FULL ));
fputs( "================================================================================\n", s_ld.logfile ); fputs( "================================================================================\n", s_ld.logfile );
fflush( 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 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 ); switch( host.status )
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()); case HOST_CRASHED:
fprintf( s_ld.logfile, "Stopped with reason \"%s\" at %s\n", event_name, Q_timestamp( TIME_FULL )); finalmsg = "crashed";
fputs( "================================================================================\n", s_ld.logfile ); break;
fclose( s_ld.logfile ); case HOST_ERR_FATAL:
s_ld.logfile = NULL; 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 #if XASH_COLORIZE_CONSOLE

View File

@@ -420,6 +420,12 @@ void Sys_Error( const char *error, ... )
_exit->_Exit->asm._exit->_exit _exit->_Exit->asm._exit->_exit
As we do not need atexit(), just throw hidden exception 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> #include <emscripten.h>
#define exit my_exit #define exit my_exit
void my_exit(int ret) void my_exit(int ret)
@@ -438,7 +444,11 @@ Sys_Quit
void Sys_Quit( const char *reason ) void Sys_Quit( const char *reason )
{ {
Host_ShutdownWithReason( reason ); Host_ShutdownWithReason( reason );
#if XASH_ANDROID
Host_ExitInMain();
#else
exit( error_on_exit ); exit( error_on_exit );
#endif
} }
/* /*
@@ -529,7 +539,7 @@ but since engine will be unloaded during this call
it explicitly doesn't use internal allocation or string copy utils 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 #if XASH_NSWITCH
char newargs[4096]; char newargs[4096];
@@ -540,7 +550,7 @@ qboolean Sys_NewInstance( const char *gamedir )
// just restart the entire thing // just restart the entire thing
printf( "envSetNextLoad exe: `%s`\n", exe ); printf( "envSetNextLoad exe: `%s`\n", exe );
printf( "envSetNextLoad argv:\n`%s`\n", newargs ); printf( "envSetNextLoad argv:\n`%s`\n", newargs );
Host_ShutdownWithReason( "changing game" ); Host_ShutdownWithReason( finalmsg );
envSetNextLoad( exe, newargs ); envSetNextLoad( exe, newargs );
exit( 0 ); exit( 0 );
#else #else
@@ -578,7 +588,7 @@ qboolean Sys_NewInstance( const char *gamedir )
#if XASH_PSVITA #if XASH_PSVITA
// under normal circumstances it's always going to be the same path // under normal circumstances it's always going to be the same path
exe = strdup( "app0:/eboot.bin" ); exe = strdup( "app0:/eboot.bin" );
Host_ShutdownWithReason( "changing game" ); Host_ShutdownWithReason( finalmsg );
sceAppMgrLoadExec( exe, newargs, NULL ); sceAppMgrLoadExec( exe, newargs, NULL );
#else #else
exelen = wai_getExecutablePath( NULL, 0, NULL ); exelen = wai_getExecutablePath( NULL, 0, NULL );
@@ -586,7 +596,7 @@ qboolean Sys_NewInstance( const char *gamedir )
wai_getExecutablePath( exe, exelen, NULL ); wai_getExecutablePath( exe, exelen, NULL );
exe[exelen] = 0; exe[exelen] = 0;
Host_ShutdownWithReason( "changing game" ); Host_ShutdownWithReason( finalmsg );
execv( exe, newargs ); execv( exe, newargs );
#endif #endif

View File

@@ -41,6 +41,15 @@ NOTE: never change this structure because all dll descriptions in xash code
writes into struct by offsets not names writes into struct by offsets not names
======================================================================== ========================================================================
*/ */
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; extern int error_on_exit;
double Sys_DoubleTime( void ); double Sys_DoubleTime( void );
char *Sys_GetClipboardData( void ); char *Sys_GetClipboardData( void );
@@ -56,11 +65,8 @@ void Sys_DebugBreak( void );
qboolean _Sys_GetParmFromCmdLine( const char *parm, char *out, size_t size ); qboolean _Sys_GetParmFromCmdLine( const char *parm, char *out, size_t size );
qboolean Sys_GetIntFromCmdLine( const char *parm, int *out ); qboolean Sys_GetIntFromCmdLine( const char *parm, int *out );
void Sys_Print( const char *pMsg ); void Sys_Print( const char *pMsg );
void Sys_PrintLog( const char *pMsg );
void Sys_InitLog( void );
void Sys_CloseLog( void );
void Sys_Quit( const char *reason ) NORETURN; void Sys_Quit( const char *reason ) NORETURN;
qboolean Sys_NewInstance( const char *gamedir ); qboolean Sys_NewInstance( const char *gamedir, const char *finalmsg );
void *Sys_GetNativeObject( const char *obj ); void *Sys_GetNativeObject( const char *obj );
// //
@@ -68,7 +74,7 @@ void *Sys_GetNativeObject( const char *obj );
// //
char *Sys_Input( void ); char *Sys_Input( void );
void Sys_DestroyConsole( void ); void Sys_DestroyConsole( void );
void Sys_CloseLog( void ); void Sys_CloseLog( const char *finalmsg );
void Sys_InitLog( void ); void Sys_InitLog( void );
void Sys_PrintLog( const char *pMsg ); void Sys_PrintLog( const char *pMsg );
int Sys_LogFileNo( void ); int Sys_LogFileNo( void );

View File

@@ -68,7 +68,13 @@ extern "C" {
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma warning(pop) #pragma warning(pop)
#endif #endif
#if (_MSC_VER >= 1900)
#include <stdbool.h> #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) 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
#endif #endif
#if !defined(WAI_STRINGIZE)
#define WAI_STRINGIZE(s)
#define WAI_STRINGIZE_(s) #s
#endif
#if defined(__ANDROID__) || defined(ANDROID) #if defined(__ANDROID__) || defined(ANDROID)
#include <fcntl.h> #include <fcntl.h>
#include <sys/mman.h> #include <sys/mman.h>
@@ -265,20 +276,20 @@ int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length)
for (;;) for (;;)
{ {
char buffer[PATH_MAX < 1024 ? 1024 : PATH_MAX]; char buffer[128 + PATH_MAX];
uint64_t low, high; uintptr_t low, high;
char perms[5]; char perms[5];
uint64_t offset; uint64_t offset;
uint32_t major, minor; uint32_t major, minor, inode;
char path[PATH_MAX]; char path[PATH_MAX + 1];
uint32_t inode;
if (!fgets(buffer, sizeof(buffer), maps)) if (!fgets(buffer, sizeof(buffer), maps))
break; 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) if (low <= addr && addr <= high)
{ {
char* resolved; char* resolved;

View File

@@ -31,7 +31,8 @@ extern "C" {
* @param out destination buffer, optional * @param out destination buffer, optional
* @param capacity destination buffer capacity * @param capacity destination buffer capacity
* @param dirname_length optional recipient for the length of the dirname part * @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 * @return the length of the executable path on success (without a terminal NUL
* character), otherwise `-1` * character), otherwise `-1`
@@ -52,7 +53,8 @@ int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length);
* @param out destination buffer, optional * @param out destination buffer, optional
* @param capacity destination buffer capacity * @param capacity destination buffer capacity
* @param dirname_length optional recipient for the length of the dirname part * @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 * @return the length of the module path on success (without a terminal NUL
* character), otherwise `-1` * character), otherwise `-1`

View File

@@ -18,7 +18,7 @@ GNU General Public License for more details.
#include "common.h" #include "common.h"
#define MEMHEADER_SENTINEL1 0xDEADF00DU #define MEMHEADER_SENTINEL1 0xA1BAU
#define MEMHEADER_SENTINEL2 0xDFU #define MEMHEADER_SENTINEL2 0xDFU
#ifdef XASH_CUSTOM_SWAP #ifdef XASH_CUSTOM_SWAP
@@ -51,31 +51,29 @@ static void *Q_realloc( void *mem, size_t size )
#define Q_realloc realloc #define Q_realloc realloc
#endif #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 typedef struct memheader_s
{ {
struct memheader_s *next; // next and previous memheaders in chain belonging to pool struct memheader_s *next, *prev; // 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
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)
size_t size; // size of the memory after the header (excluding header and sentinel2) poolhandle_t poolptr; // pool this memheader belongs to
poolhandle_t poolptr; // pool this memheader belongs to uint16_t fileline;
int fileline; uint16_t sentinel1; // must be equal to MEMHEADER_SENTINEL1
#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
// immediately followed by data, which is followed by a MEMHEADER_SENTINEL2 byte // immediately followed by data, which is followed by a MEMHEADER_SENTINEL2 byte
} memheader_t; } memheader_t;
typedef struct mempool_s typedef struct mempool_s
{ {
struct memheader_s *chain; // chain of individual memory allocations struct memheader_s *chain; // chain of individual memory allocations
size_t totalsize; // total memory allocated in this pool (inside memheaders) size_t totalsize; // total memory allocated in this pool (inside memheaders)
size_t realsize; // total memory allocated in this pool (actual malloc total) size_t realsize; // total memory allocated in this pool (actual malloc total)
size_t lastchecksize; // updated each time the pool is displayed by memlist size_t lastchecksize; // updated each time the pool is displayed by memlist
const char *filename; // file name and line where Mem_AllocPool was called const char *filename; // file name and line where Mem_AllocPool was called
int fileline; int fileline;
char name[64]; // name of the pool char name[64]; // name of the pool
} mempool_t; } mempool_t;
static mempool_t *poolchain = NULL; // critical stuff static mempool_t *poolchain = NULL; // critical stuff
@@ -521,4 +519,5 @@ Memory_Init
void Memory_Init( void ) void Memory_Init( void )
{ {
poolchain = NULL; // init mem chain poolchain = NULL; // init mem chain
poolcount = 0;
} }

View File

@@ -1,186 +1,164 @@
/*** /*
* Copyright (C) 1997-2001 Id Software, Inc.
* 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.
*
****/
#ifndef KEYDEFS_H This program is free software; you can redistribute it and/or
#define KEYDEFS_H 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 // 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 // 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_KP_HOME 160
#define K_UPARROW 128 #define K_KP_UPARROW 161
#define K_DOWNARROW 129 #define K_KP_PGUP 162
#define K_LEFTARROW 130 #define K_KP_LEFTARROW 163
#define K_RIGHTARROW 131 #define K_KP_5 164
#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_RIGHTARROW 165 #define K_KP_RIGHTARROW 165
#define K_KP_END 166 #define K_KP_END 166
#define K_KP_DOWNARROW 167 #define K_KP_DOWNARROW 167
#define K_KP_PGDN 168 #define K_KP_PGDN 168
#define K_KP_ENTER 169 #define K_KP_ENTER 169
#define K_KP_INS 170 #define K_KP_INS 170
#define K_KP_DEL 171 #define K_KP_DEL 171
#define K_KP_SLASH 172 #define K_KP_SLASH 172
#define K_KP_MINUS 173 #define K_KP_MINUS 173
#define K_KP_PLUS 174 #define K_KP_PLUS 174
#define K_CAPSLOCK 175 #define K_CAPSLOCK 175
#define K_KP_MUL 176 #define K_KP_MUL 176
#define K_WIN 177 #define K_WIN 177
#define K_KP_NUMLOCK 178 #define K_KP_NUMLOCK 178
// //
// joystick buttons // joystick buttons
// //
#define K_JOY1 203 // LTRIGGER (L2) #define K_JOY1 203
#define K_JOY2 204 // RTRIGGER (R2) #define K_JOY2 204
#define K_JOY3 205 #define K_JOY3 205
#define K_JOY4 206 #define K_JOY4 206
// //
// aux keys are for multi-buttoned joysticks to generate so they can use // aux keys are for multi-buttoned joysticks to generate so they can use
// the normal binding process // the normal binding process
// //
#define K_AUX1 207 #define K_AUX1 207
#define K_A_BUTTON K_AUX1 #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 // button names for game pads
//
#define K_AUX3 209 #define K_A_BUTTON K_AUX1
#define K_X_BUTTON K_AUX3 #define K_B_BUTTON K_AUX2
#define K_X_BUTTON K_AUX3
#define K_AUX4 210 #define K_Y_BUTTON K_AUX4
#define K_Y_BUTTON K_AUX4 #define K_L1_BUTTON K_AUX5
#define K_R1_BUTTON K_AUX6
#define K_AUX5 211 #define K_BACK_BUTTON K_AUX7
#define K_L1_BUTTON K_AUX5 #define K_MODE_BUTTON K_AUX8
#define K_START_BUTTON K_AUX9
#define K_AUX6 212 #define K_LSTICK K_AUX10
#define K_R1_BUTTON K_AUX6 #define K_RSTICK K_AUX11
#define K_L2_BUTTON K_AUX12
#define K_AUX7 213 #define K_R2_BUTTON K_AUX13
#define K_BACK_BUTTON K_AUX7 #define K_C_BUTTON K_AUX14
#define K_Z_BUTTON K_AUX15
#define K_AUX8 214 #define K_DPAD_UP K_AUX16
#define K_MODE_BUTTON K_AUX8 #define K_DPAD_DOWN K_AUX17
#define K_DPAD_LEFT K_AUX18
#define K_AUX9 215 #define K_DPAD_RIGHT K_AUX19
#define K_START_BUTTON K_AUX9 #define K_MISC_BUTTON K_AUX20
#define K_PADDLE1_BUTTON K_AUX21
#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
#define K_PADDLE2_BUTTON K_AUX22 #define K_PADDLE2_BUTTON K_AUX22
#define K_AUX23 229
#define K_PADDLE3_BUTTON K_AUX23 #define K_PADDLE3_BUTTON K_AUX23
#define K_AUX24 230
#define K_PADDLE4_BUTTON K_AUX24 #define K_PADDLE4_BUTTON K_AUX24
#define K_TOUCHPAD K_AUX25
#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
// //
// mouse buttons generate virtual keys // mouse buttons generate virtual keys
// //
#define K_MOUSE1 241 #define K_MWHEELDOWN 239
#define K_MOUSE2 242 #define K_MWHEELUP 240
#define K_MOUSE3 243 #define K_MOUSE1 241
#define K_MOUSE4 244 #define K_MOUSE2 242
#define K_MOUSE5 245 #define K_MOUSE3 243
#define K_MOUSE4 244
#define K_MOUSE5 245
#endif//KEYDEFS_H #define K_PAUSE 255

View File

@@ -184,7 +184,7 @@ qboolean SNDDMA_Init( void )
return false; 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.samplepos = 0;
dma.samples = samples; dma.samples = samples;
dma.format.width = 2; dma.format.width = 2;

View File

@@ -55,7 +55,7 @@ char *Posix_Input( void );
#endif #endif
#if XASH_SDL #if XASH_SDL
void SDLash_Init( void ); void SDLash_Init( const char *basedir );
void SDLash_Shutdown( void ); void SDLash_Shutdown( void );
#endif #endif
@@ -104,7 +104,7 @@ void Linux_SetTimer( float time );
int Linux_GetProcessID( void ); int Linux_GetProcessID( void );
#endif #endif
static inline void Platform_Init( qboolean con_showalways ) static inline void Platform_Init( qboolean con_showalways, const char *basedir )
{ {
#if XASH_POSIX #if XASH_POSIX
// daemonize as early as possible, because we need to close our file descriptors // daemonize as early as possible, because we need to close our file descriptors
@@ -112,7 +112,7 @@ static inline void Platform_Init( qboolean con_showalways )
#endif #endif
#if XASH_SDL #if XASH_SDL
SDLash_Init( ); SDLash_Init( basedir );
#endif #endif
#if XASH_ANDROID #if XASH_ANDROID

View File

@@ -113,7 +113,7 @@ static void Sys_Crash( int signal, siginfo_t *si, void *context)
// safe actions first, stack and memory may be corrupted // 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", 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() ); Q_buildnum(), g_buildcommit, Q_buildos(), Q_buildarch() );
#if !XASH_FREEBSD && !XASH_NETBSD && !XASH_OPENBSD #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 ); 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 );

View File

@@ -265,7 +265,7 @@ static void SDLash_KeyEvent( SDL_KeyboardEvent key )
break; break;
} }
case SDL_SCANCODE_PAUSE: keynum = K_PAUSE; 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 ) #if SDL_VERSION_ATLEAST( 2, 0, 0 )
case SDL_SCANCODE_APPLICATION: keynum = K_WIN; break; // (compose key) ??? case SDL_SCANCODE_APPLICATION: keynum = K_WIN; break; // (compose key) ???
// don't console spam on known functional buttons, not used in engine // don't console spam on known functional buttons, not used in engine

View File

@@ -175,7 +175,7 @@ qboolean SNDDMA_Init( void )
if( !samplecount ) if( !samplecount )
samplecount = 0x8000; samplecount = 0x8000;
dma.samples = samplecount * obtained.channels; dma.samples = samplecount * obtained.channels;
dma.buffer = Z_Calloc( dma.samples * 2 ); dma.buffer = Mem_Malloc( sndpool, dma.samples * 2 );
dma.samplepos = 0; dma.samplepos = 0;
sdl_format = obtained.format; sdl_format = obtained.format;

View File

@@ -20,9 +20,9 @@ GNU General Public License for more details.
#if XASH_TIMER == TIMER_SDL #if XASH_TIMER == TIMER_SDL
double Platform_DoubleTime( void ) double Platform_DoubleTime( void )
{ {
static longtime_t g_PerformanceFrequency; static Uint64 g_PerformanceFrequency;
static longtime_t g_ClockStart; static Uint64 g_ClockStart;
longtime_t CurrentTime; Uint64 CurrentTime;
if( !g_PerformanceFrequency ) if( !g_PerformanceFrequency )
{ {
@@ -78,8 +78,19 @@ static void SDLCALL SDLash_LogOutputFunction( void *userdata, int category, SDL_
} }
} }
void SDLash_Init( void ) void SDLash_Init( const char *basedir )
{ {
#if XASH_APPLE
char *path = SDL_GetBasePath();
if( path != NULL )
{
char buf[MAX_VA_STRING];
Q_snprintf( buf, sizeof( buf ), "%s%s/extras.pk3", path, basedir );
setenv( "XASH3D_EXTRAS_PAK1", buf, true );
}
#endif
SDL_LogSetOutputFunction( SDLash_LogOutputFunction, NULL ); SDL_LogSetOutputFunction( SDLash_LogOutputFunction, NULL );
if( host_developer.value >= 2 ) if( host_developer.value >= 2 )

View File

@@ -145,7 +145,7 @@ void Wcon_ShowConsole( qboolean show )
void Wcon_DisableInput( void ) void Wcon_DisableInput( void )
{ {
if( host.type != HOST_DEDICATED ) if( host.type != HOST_DEDICATED || !s_wcd.hWnd )
return; return;
s_wcd.inputEnabled = false; s_wcd.inputEnabled = false;
@@ -469,6 +469,9 @@ print into window console
*/ */
void Wcon_WinPrint( const char *pMsg ) void Wcon_WinPrint( const char *pMsg )
{ {
if( !s_wcd.hWnd )
return;
int nLen; int nLen;
if( s_wcd.consoleTextLen ) if( s_wcd.consoleTextLen )
{ {
@@ -515,13 +518,18 @@ void Wcon_CreateConsole( qboolean con_showalways )
} }
s_wcd.attached = ( AttachConsole( ATTACH_PARENT_PROCESS ) != 0 ); s_wcd.attached = ( AttachConsole( ATTACH_PARENT_PROCESS ) != 0 );
if( s_wcd.attached ) { if( s_wcd.attached )
{
GetConsoleTitle( &s_wcd.previousTitle, sizeof( s_wcd.previousTitle )); GetConsoleTitle( &s_wcd.previousTitle, sizeof( s_wcd.previousTitle ));
s_wcd.previousCodePage = GetConsoleCP(); s_wcd.previousCodePage = GetConsoleCP();
s_wcd.previousOutputCodePage = GetConsoleOutputCP(); s_wcd.previousOutputCodePage = GetConsoleOutputCP();
} }
else { else
AllocConsole(); {
if( host.type != HOST_DEDICATED && host_developer.value == DEV_NONE )
return; // don't initialize console in case of regular game startup, it's useless anyway
else
AllocConsole();
} }
SetConsoleTitle( s_wcd.title ); SetConsoleTitle( s_wcd.title );
@@ -570,7 +578,7 @@ register console commands (dedicated only)
*/ */
void Wcon_InitConsoleCommands( void ) void Wcon_InitConsoleCommands( void )
{ {
if( host.type != HOST_DEDICATED ) if( host.type != HOST_DEDICATED || !s_wcd.hWnd )
return; return;
Cmd_AddCommand( "clear", Wcon_Clear_f, "clear console history" ); Cmd_AddCommand( "clear", Wcon_Clear_f, "clear console history" );
@@ -588,7 +596,7 @@ void Wcon_DestroyConsole( void )
// last text message into console or log // last text message into console or log
Con_Reportf( "%s: Unloading xash.dll\n", __func__ ); Con_Reportf( "%s: Unloading xash.dll\n", __func__ );
Sys_CloseLog(); Sys_CloseLog( NULL );
if( !s_wcd.attached ) if( !s_wcd.attached )
{ {
@@ -623,7 +631,7 @@ char *Wcon_Input( void )
DWORD eventsCount; DWORD eventsCount;
static INPUT_RECORD events[1024]; static INPUT_RECORD events[1024];
if( !s_wcd.inputEnabled ) if( !s_wcd.inputEnabled || !s_wcd.hWnd )
return NULL; return NULL;
while( true ) while( true )
@@ -666,7 +674,7 @@ set server status string in console
*/ */
void Platform_SetStatus( const char *pStatus ) void Platform_SetStatus( const char *pStatus )
{ {
if( s_wcd.attached ) if( s_wcd.attached || !s_wcd.hWnd )
return; return;
Q_strncpy( s_wcd.statusLine, pStatus, sizeof( s_wcd.statusLine ) - 1 ); Q_strncpy( s_wcd.statusLine, pStatus, sizeof( s_wcd.statusLine ) - 1 );

View File

@@ -138,7 +138,7 @@ static void Sys_StackTrace( PEXCEPTION_POINTERS pInfo )
#endif #endif
len = Q_snprintf( message, sizeof( message ), "Ver: " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n", 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() ); Q_buildnum(), g_buildcommit, Q_buildos(), Q_buildarch() );
len += Q_snprintf( message + len, 1024 - len, "Sys_Crash: address %p, code %p\n", len += Q_snprintf( message + len, 1024 - len, "Sys_Crash: address %p, code %p\n",
pInfo->ExceptionRecord->ExceptionAddress, (void*)pInfo->ExceptionRecord->ExceptionCode ); pInfo->ExceptionRecord->ExceptionAddress, (void*)pInfo->ExceptionRecord->ExceptionCode );
@@ -213,14 +213,14 @@ static void Sys_GetMinidumpFileName( const char *processName, char *mdmpFileName
struct tm *currentLocalTime = localtime( &currentUtcTime ); struct tm *currentLocalTime = localtime( &currentUtcTime );
Q_snprintf( mdmpFileName, bufferSize, "%s_%s_crash_%d%.2d%.2d_%.2d%.2d%.2d.mdmp", Q_snprintf( mdmpFileName, bufferSize, "%s_%s_crash_%d%.2d%.2d_%.2d%.2d%.2d.mdmp",
processName, processName,
Q_buildcommit(), g_buildcommit,
currentLocalTime->tm_year + 1900, currentLocalTime->tm_year + 1900,
currentLocalTime->tm_mon + 1, currentLocalTime->tm_mon + 1,
currentLocalTime->tm_mday, currentLocalTime->tm_mday,
currentLocalTime->tm_hour, currentLocalTime->tm_hour,
currentLocalTime->tm_min, currentLocalTime->tm_min,
currentLocalTime->tm_sec); currentLocalTime->tm_sec );
} }
static qboolean Sys_WriteMinidump(PEXCEPTION_POINTERS exceptionInfo, MINIDUMP_TYPE minidumpType) static qboolean Sys_WriteMinidump(PEXCEPTION_POINTERS exceptionInfo, MINIDUMP_TYPE minidumpType)

View File

@@ -66,6 +66,7 @@ extern int SV_UPDATE_BACKUP;
#define MAX_PUSHED_ENTS 256 #define MAX_PUSHED_ENTS 256
#define MAX_VIEWENTS 128 #define MAX_VIEWENTS 128
#define MAX_LOCALINFO_STRING 32768 // localinfo used on server and not sended to the clients
#define MAX_ENT_LEAFS( ext ) (( ext ) ? MAX_ENT_LEAFS_32 : MAX_ENT_LEAFS_16 ) #define MAX_ENT_LEAFS( ext ) (( ext ) ? MAX_ENT_LEAFS_32 : MAX_ENT_LEAFS_16 )
@@ -498,10 +499,24 @@ qboolean SV_ProcessUserAgent( netadr_t from, const char *useragent );
qboolean SV_InitGame( void ); qboolean SV_InitGame( void );
void SV_ActivateServer( int runPhysics ); void SV_ActivateServer( int runPhysics );
qboolean SV_SpawnServer( const char *server, const char *startspot, qboolean background ); qboolean SV_SpawnServer( const char *server, const char *startspot, qboolean background );
model_t *SV_ModelHandle( int modelindex );
void SV_DeactivateServer( void ); void SV_DeactivateServer( void );
void SV_FreeTestPacket( void ); void SV_FreeTestPacket( void );
/*
================
SV_ModelHandle
get model by handle
================
*/
static inline model_t *GAME_EXPORT SV_ModelHandle( int modelindex )
{
if( modelindex < 0 || modelindex >= MAX_MODELS )
return NULL;
return sv.models[modelindex];
}
// //
// sv_phys.c // sv_phys.c
// //
@@ -673,7 +688,6 @@ void SV_ClearGameState( void );
// sv_pmove.c // sv_pmove.c
// //
void SV_InitClientMove( void ); void SV_InitClientMove( void );
qboolean SV_PlayerIsFrozen( edict_t *pClient );
void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed ); void SV_RunCmd( sv_client_t *cl, usercmd_t *ucmd, int random_seed );
// //

View File

@@ -305,6 +305,7 @@ static void SV_ConnectClient( netadr_t from )
int challenge; int challenge;
const char *s; const char *s;
int extensions; int extensions;
uint netchan_flags = 0;
if( Cmd_Argc() < 5 ) if( Cmd_Argc() < 5 )
{ {
@@ -431,7 +432,9 @@ static void SV_ConnectClient( netadr_t from )
newcl->listeners = -1; newcl->listeners = -1;
// initailize netchan // initailize netchan
Netchan_Setup( NS_SERVER, &newcl->netchan, from, qport, newcl, SV_GetFragmentSize, 0 ); if( !Host_IsLocalClient( ))
SetBits( netchan_flags, NETCHAN_USE_LZSS );
Netchan_Setup( NS_SERVER, &newcl->netchan, from, qport, newcl, SV_GetFragmentSize, netchan_flags );
MSG_Init( &newcl->datagram, "Datagram", newcl->datagram_buf, sizeof( newcl->datagram_buf )); // datagram buf MSG_Init( &newcl->datagram, "Datagram", newcl->datagram_buf, sizeof( newcl->datagram_buf )); // datagram buf
Q_strncpy( newcl->hashedcdkey, Info_ValueForKey( protinfo, "uuid" ), 32 ); Q_strncpy( newcl->hashedcdkey, Info_ValueForKey( protinfo, "uuid" ), 32 );
@@ -450,8 +453,6 @@ static void SV_ConnectClient( netadr_t from )
newcl->delta_sequence = -1; newcl->delta_sequence = -1;
newcl->flags = 0; newcl->flags = 0;
// reset any remaining events // reset any remaining events
memset( &newcl->events, 0, sizeof( newcl->events )); memset( &newcl->events, 0, sizeof( newcl->events ));
@@ -477,7 +478,7 @@ static void SV_ConnectClient( netadr_t from )
// reset stats // reset stats
newcl->next_checkpingtime = -1.0; newcl->next_checkpingtime = -1.0;
newcl->packet_loss = 0.0f; newcl->packet_loss = 0;
// if this was the first client on the server, or the last client // if this was the first client on the server, or the last client
// the server can hold, send a heartbeat to the master. // the server can hold, send a heartbeat to the master.
@@ -1170,7 +1171,7 @@ SV_EstablishTimeBase
Finangles latency and the like. Finangles latency and the like.
=================== ===================
*/ */
static void SV_EstablishTimeBase( sv_client_t *cl, usercmd_t *cmds, int dropped, int numbackup, int numcmds ) static void SV_EstablishTimeBase( sv_client_t *cl, const usercmd_t *cmds, int dropped, int numbackup, int numcmds )
{ {
double runcmd_time = 0.0; double runcmd_time = 0.0;
int i, cmdnum = dropped; int i, cmdnum = dropped;
@@ -2226,7 +2227,7 @@ SV_SendBuildInfo_f
static qboolean SV_SendBuildInfo_f( sv_client_t *cl ) static qboolean SV_SendBuildInfo_f( sv_client_t *cl )
{ {
SV_ClientPrintf( cl, "Server running " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n", SV_ClientPrintf( cl, "Server running " XASH_ENGINE_NAME " " XASH_VERSION " (build %i-%s, %s-%s)\n",
Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch() ); Q_buildnum(), g_buildcommit, Q_buildos(), Q_buildarch() );
return true; return true;
} }
@@ -2869,14 +2870,20 @@ static qboolean SV_EntCreate_f( sv_client_t *cl )
// XashXT does not implement SV_CreateEntity, use saverestore export // XashXT does not implement SV_CreateEntity, use saverestore export
if( !ent && svgame.physFuncs.pfnCreateEntitiesInRestoreList ) if( !ent && svgame.physFuncs.pfnCreateEntitiesInRestoreList )
{ {
SAVERESTOREDATA data = { 0 }; ENTITYTABLE table = {
ENTITYTABLE table = { 0 }; .classname = classname,
data.tableCount = 1; .id = -1,
data.pTable = &table; .size = 1,
table.classname = classname; .flags = 1337,
table.id = -1; };
table.size = 1;
svgame.physFuncs.pfnCreateEntitiesInRestoreList( &data, 0, false ); SAVERESTOREDATA data = {
.tableCount = 1,
.pTable = &table
};
svgame.physFuncs.pfnCreateEntitiesInRestoreList( &data, table.flags, false );
ent = table.pent; ent = table.pent;
} }
@@ -3212,6 +3219,20 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
} }
} }
static qboolean SV_PlayerIsFrozen( const edict_t *pClient )
{
if( sv_background_freeze.value && sv.background )
return true;
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
return false;
if( FBitSet( pClient->v.flags, FL_FROZEN ))
return true;
return false;
}
/* /*
================== ==================
SV_ParseClientMove SV_ParseClientMove
@@ -3226,29 +3247,20 @@ each of the backup packets.
*/ */
static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg ) static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
{ {
client_frame_t *frame; const usercmd_t nullcmd = { 0 }, *from = &nullcmd; // first cmd are starting from null-compressed usercmd_t
int key, size, checksum1, checksum2; client_frame_t *frame = &cl->frames[cl->netchan.incoming_acknowledged & SV_UPDATE_MASK];
int i, numbackup, totalcmds, numcmds; usercmd_t cmds[CMD_BACKUP] = { 0 }, *to;
usercmd_t nullcmd, *to, *from; edict_t *player = cl->edict;
usercmd_t cmds[CMD_BACKUP]; model_t *model;
float packet_loss;
edict_t *player;
model_t *model;
player = cl->edict; int key = MSG_GetRealBytesRead( msg );
int checksum1 = MSG_ReadByte( msg );
int packet_loss = MSG_ReadByte( msg );
int numbackup = MSG_ReadByte( msg );
int numcmds = MSG_ReadByte( msg );
int totalcmds = numcmds + numbackup;
int i;
frame = &cl->frames[cl->netchan.incoming_acknowledged & SV_UPDATE_MASK];
memset( &nullcmd, 0, sizeof( usercmd_t ));
memset( cmds, 0, sizeof( cmds ));
key = MSG_GetRealBytesRead( msg );
checksum1 = MSG_ReadByte( msg );
packet_loss = MSG_ReadByte( msg );
numbackup = MSG_ReadByte( msg );
numcmds = MSG_ReadByte( msg );
totalcmds = numcmds + numbackup;
net_drop -= (numcmds - 1); net_drop -= (numcmds - 1);
if( totalcmds < 0 || totalcmds >= CMD_MASK ) if( totalcmds < 0 || totalcmds >= CMD_MASK )
@@ -3258,8 +3270,6 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
return; return;
} }
from = &nullcmd; // first cmd are starting from null-compressed usercmd_t
for( i = totalcmds - 1; i >= 0; i-- ) for( i = totalcmds - 1; i >= 0; i-- )
{ {
to = &cmds[i]; to = &cmds[i];
@@ -3270,14 +3280,17 @@ static void SV_ParseClientMove( sv_client_t *cl, sizebuf_t *msg )
if( cl->state != cs_spawned ) if( cl->state != cs_spawned )
return; return;
// if the checksum fails, ignore the rest of the packet if( !Host_IsLocalClient( ))
size = MSG_GetRealBytesRead( msg ) - key - 1;
checksum2 = CRC32_BlockSequence( msg->pData + key + 1, size, cl->netchan.incoming_sequence );
if( checksum2 != checksum1 )
{ {
Con_Reportf( S_ERROR "%s: failed command checksum for %s (%d != %d)\n", __func__, cl->name, checksum2, checksum1 ); // if the checksum fails, ignore the rest of the packet
return; int size = MSG_GetRealBytesRead( msg ) - key - 1;
int checksum2 = CRC32_BlockSequence( msg->pData + key + 1, size, cl->netchan.incoming_sequence );
if( checksum2 != checksum1 )
{
Con_Reportf( S_ERROR "%s: failed command checksum for %s (%d != %d)\n", __func__, cl->name, checksum2, checksum1 );
return;
}
} }
cl->packet_loss = packet_loss; cl->packet_loss = packet_loss;

View File

@@ -492,14 +492,15 @@ SV_EmitPings
*/ */
static void SV_EmitPings( sizebuf_t *msg ) static void SV_EmitPings( sizebuf_t *msg )
{ {
sv_client_t *cl; sv_client_t *cl;
int packet_loss; int i;
int i, ping;
MSG_BeginServerCmd( msg, svc_pings ); MSG_BeginServerCmd( msg, svc_pings );
for( i = 0, cl = svs.clients; i < svs.maxclients; i++, cl++ ) for( i = 0, cl = svs.clients; i < svs.maxclients; i++, cl++ )
{ {
int packet_loss, ping;
if( cl->state != cs_spawned ) if( cl->state != cs_spawned )
continue; continue;

View File

@@ -273,20 +273,6 @@ int GAME_EXPORT SV_GenericIndex( const char *filename )
return i; return i;
} }
/*
================
SV_ModelHandle
get model by handle
================
*/
model_t *GAME_EXPORT SV_ModelHandle( int modelindex )
{
if( modelindex < 0 || modelindex >= MAX_MODELS )
return NULL;
return sv.models[modelindex];
}
static resourcetype_t SV_DetermineResourceType( const char *filename ) static resourcetype_t SV_DetermineResourceType( const char *filename )
{ {
if( !Q_strncmp( filename, DEFAULT_SOUNDPATH, sizeof( DEFAULT_SOUNDPATH ) - 1 ) && Sound_SupportedFileFormat( COM_FileExtension( filename ))) if( !Q_strncmp( filename, DEFAULT_SOUNDPATH, sizeof( DEFAULT_SOUNDPATH ) - 1 ) && Sound_SupportedFileFormat( COM_FileExtension( filename )))

View File

@@ -970,7 +970,7 @@ void SV_Init( void )
MSG_Init( &net_message, "NetMessage", net_message_buffer, sizeof( net_message_buffer )); MSG_Init( &net_message, "NetMessage", net_message_buffer, sizeof( net_message_buffer ));
Q_snprintf( versionString, sizeof( versionString ), XASH_ENGINE_NAME ": " XASH_VERSION "-%s(%s-%s),%i,%i", Q_snprintf( versionString, sizeof( versionString ), XASH_ENGINE_NAME ": " XASH_VERSION "-%s(%s-%s),%i,%i",
Q_buildcommit(), Q_buildos(), Q_buildarch(), PROTOCOL_VERSION, Q_buildnum() ); g_buildcommit, Q_buildos(), Q_buildarch(), PROTOCOL_VERSION, Q_buildnum() );
Cvar_FullSet( "sv_version", versionString, FCVAR_READ_ONLY ); Cvar_FullSet( "sv_version", versionString, FCVAR_READ_ONLY );

View File

@@ -23,19 +23,6 @@ GNU General Public License for more details.
static qboolean has_update = false; static qboolean has_update = false;
static void SV_GetTrueOrigin( sv_client_t *cl, int edictnum, vec3_t origin ); static void SV_GetTrueOrigin( sv_client_t *cl, int edictnum, vec3_t origin );
qboolean SV_PlayerIsFrozen( edict_t *pClient )
{
if( sv_background_freeze.value && sv.background )
return true;
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
return false;
if( FBitSet( pClient->v.flags, FL_FROZEN ))
return true;
return false;
}
void SV_ClipPMoveToEntity( physent_t *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, pmtrace_t *tr ) void SV_ClipPMoveToEntity( physent_t *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, pmtrace_t *tr )
{ {
Assert( tr != NULL ); Assert( tr != NULL );

View File

@@ -2279,7 +2279,7 @@ int GAME_EXPORT SV_GetSaveComment( const char *savename, char *comment )
if( tag == 0x0065 ) if( tag == 0x0065 )
{ {
Q_strncpy( comment, "<old version Xash3D unsupported>", MAX_STRING ); Q_strncpy( comment, "<old version "XASH_ENGINE_NAME" unsupported>", MAX_STRING );
FS_Close( f ); FS_Close( f );
return 0; return 0;
} }

View File

@@ -8,6 +8,23 @@ import os
top = '.' top = '.'
FFMPEG_CHECK_FRAGMENT='''
#include <libswresample/swresample.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libavutil/avutil.h>
int main(int argc, char **argv)
{
swresample_version();
avformat_version();
avcodec_version();
swscale_version();
avutil_version();
return 0;
}
'''
def options(opt): def options(opt):
grp = opt.add_option_group('Engine options') grp = opt.add_option_group('Engine options')
@@ -35,6 +52,9 @@ def options(opt):
grp.add_option('--enable-ffmpeg', action = 'store_true', dest = 'FFMPEG', default = False, grp.add_option('--enable-ffmpeg', action = 'store_true', dest = 'FFMPEG', default = False,
help = '') # hidden option, does nothing help = '') # hidden option, does nothing
grp.add_option('--enable-ffmpeg', action = 'store_true', dest = 'FFMPEG', default = False,
help = 'enable ffmpeg based movie playback')
opt.load('sdl2') opt.load('sdl2')
def configure(conf): def configure(conf):
@@ -125,6 +145,20 @@ def configure(conf):
conf.define('ENGINE_DLL', 1) conf.define('ENGINE_DLL', 1)
if conf.options.FFMPEG:
# add ffmpeg libraries into single uselib package
conf.check_cfg(package='libswresample', uselib_store='SWRESAMPLE', args='--cflags --libs')
conf.check_cfg(package='libavformat', uselib_store='AVFORMAT', args='--cflags --libs')
conf.check_cfg(package='libavcodec', uselib_store='AVCODEC', args='--cflags --libs')
conf.check_cfg(package='libswscale', uselib_store='SWSCALE', args='--cflags --libs')
conf.check_cfg(package='libavutil', uselib_store='AVUTIL', args='--cflags --libs')
# validate ffmpeg libs installation
conf.check_cc(fragment=FFMPEG_CHECK_FRAGMENT, use='SWRESAMPLE AVCODEC AVFORMAT AVUTIL SWSCALE', msg='Checking for ffmpeg sanity')
conf.env.FFMPEG = True
conf.define('HAVE_FFMPEG', True)
conf.define_cond('XASH_ENGINE_TESTS', conf.env.ENGINE_TESTS) conf.define_cond('XASH_ENGINE_TESTS', conf.env.ENGINE_TESTS)
conf.define_cond('XASH_STATIC_LIBS', conf.env.STATIC_LINKING) conf.define_cond('XASH_STATIC_LIBS', conf.env.STATIC_LINKING)
conf.define_cond('XASH_CUSTOM_SWAP', conf.options.CUSTOM_SWAP) conf.define_cond('XASH_CUSTOM_SWAP', conf.options.CUSTOM_SWAP)
@@ -185,6 +219,13 @@ def build(bld):
libs.append('SDL3' if bld.env.HAVE_SDL3 else 'SDL2') libs.append('SDL3' if bld.env.HAVE_SDL3 else 'SDL2')
source += bld.path.ant_glob(['platform/sdl/*.c']) source += bld.path.ant_glob(['platform/sdl/*.c'])
if bld.get_define('HAVE_FFMPEG'):
libs.append('SWRESAMPLE')
libs.append('AVCODEC')
libs.append('AVFORMAT')
libs.append('AVUTIL')
libs.append('SWSCALE')
if bld.env.MAGX: if bld.env.MAGX:
libs.append('MAGX') libs.append('MAGX')
is_cxx_link = True is_cxx_link = True

View File

@@ -242,7 +242,7 @@ static byte *FS_LoadAndroidAssetsFile( searchpath_t *search, const char *path, i
if( filesize ) *filesize = 0; if( filesize ) *filesize = 0;
asset = AAssetManager_open( search->assets->asset_manager, path, AASSET_MODE_RANDOM ); asset = AAssetManager_open( search->assets->asset_manager, path, AASSET_MODE_BUFFER );
if( !asset ) if( !asset )
return NULL; return NULL;

View File

@@ -57,6 +57,12 @@ static qboolean Platform_GetDirectoryCaseSensitivity( const char *dir )
{ {
#if XASH_WIN32 || XASH_PSVITA || XASH_NSWITCH #if XASH_WIN32 || XASH_PSVITA || XASH_NSWITCH
return false; return false;
#elif XASH_ANDROID
// on Android, doing code below causes crash in MediaProviderGoogle.apk!libfuse_jni.so
// which in turn makes vold (Android's Volume Daemon) to umount /storage/emulated/0
// and because you can't unmount a filesystem when there is file descriptors open
// it has no other choice but to terminate and then kill our program
return true;
#elif XASH_LINUX && defined( FS_IOC_GETFLAGS ) #elif XASH_LINUX && defined( FS_IOC_GETFLAGS )
int flags = 0; int flags = 0;
int fd; int fd;
@@ -66,7 +72,10 @@ static qboolean Platform_GetDirectoryCaseSensitivity( const char *dir )
return true; return true;
if( ioctl( fd, FS_IOC_GETFLAGS, &flags ) < 0 ) if( ioctl( fd, FS_IOC_GETFLAGS, &flags ) < 0 )
{
close( fd );
return true; return true;
}
close( fd ); close( fd );

View File

@@ -49,6 +49,7 @@ GNU General Public License for more details.
#include "common/protocol.h" #include "common/protocol.h"
#define FILE_COPY_SIZE (1024 * 1024) #define FILE_COPY_SIZE (1024 * 1024)
#define SAVE_AGED_COUNT 2 // the default count of quick and auto saves
fs_globals_t FI; fs_globals_t FI;
qboolean fs_ext_path = false; // attempt to read\write from ./ or ../ pathes qboolean fs_ext_path = false; // attempt to read\write from ./ or ../ pathes
@@ -447,6 +448,7 @@ FS_ClearSearchPath
void FS_ClearSearchPath( void ) void FS_ClearSearchPath( void )
{ {
searchpath_t *cur, **prev; searchpath_t *cur, **prev;
int i;
prev = &fs_searchpaths; prev = &fs_searchpaths;
@@ -468,6 +470,12 @@ void FS_ClearSearchPath( void )
cur->pfnClose( cur ); cur->pfnClose( cur );
Mem_Free( cur ); Mem_Free( cur );
} }
for( i = 0; i < FI.numgames; i++ )
{
if( FI.games[i] )
FI.games[i]->added = false;
}
} }
/* /*
@@ -529,7 +537,7 @@ static qboolean FS_WriteGameInfo( const char *filepath, gameinfo_t *GameInfo )
if( !f ) if( !f )
return false; return false;
FS_Printf( f, "// generated by " XASH_ENGINE_NAME " " XASH_VERSION "-%s (%s-%s)\n\n\n", Q_buildcommit(), Q_buildos(), Q_buildarch() ); FS_Printf( f, "// generated by " XASH_ENGINE_NAME " " XASH_VERSION "-%s (%s-%s)\n\n\n", g_buildcommit, Q_buildos(), Q_buildarch() );
if( COM_CheckStringEmpty( GameInfo->basedir ) ) if( COM_CheckStringEmpty( GameInfo->basedir ) )
FS_Printf( f, "basedir\t\t\"%s\"\n", GameInfo->basedir ); FS_Printf( f, "basedir\t\t\"%s\"\n", GameInfo->basedir );
@@ -628,13 +636,11 @@ static qboolean FS_WriteGameInfo( const char *filepath, gameinfo_t *GameInfo )
if( GameInfo->noskills ) if( GameInfo->noskills )
FS_Printf( f, "noskills\t\t\"%i\"\n", GameInfo->noskills ); FS_Printf( f, "noskills\t\t\"%i\"\n", GameInfo->noskills );
#define SAVE_AGED_COUNT 2 // the default count of quick and auto saves
if( GameInfo->quicksave_aged_count != SAVE_AGED_COUNT ) if( GameInfo->quicksave_aged_count != SAVE_AGED_COUNT )
FS_Printf( f, "quicksave_aged_count\t\t%d\n", GameInfo->quicksave_aged_count ); FS_Printf( f, "quicksave_aged_count\t\t%d\n", GameInfo->quicksave_aged_count );
if( GameInfo->autosave_aged_count != SAVE_AGED_COUNT ) if( GameInfo->autosave_aged_count != SAVE_AGED_COUNT )
FS_Printf( f, "autosave_aged_count\t\t%d\n", GameInfo->autosave_aged_count ); FS_Printf( f, "autosave_aged_count\t\t%d\n", GameInfo->autosave_aged_count );
#undef SAVE_AGED_COUNT
// HL25 compatibility // HL25 compatibility
if( GameInfo->animated_title ) if( GameInfo->animated_title )
@@ -700,6 +706,9 @@ static void FS_InitGameInfo( gameinfo_t *GameInfo, const char *gamedir, qboolean
GameInfo->max_beams = 128; GameInfo->max_beams = 128;
GameInfo->max_particles = 4096; GameInfo->max_particles = 4096;
GameInfo->version = 1.0f; GameInfo->version = 1.0f;
GameInfo->quicksave_aged_count = SAVE_AGED_COUNT;
GameInfo->autosave_aged_count = SAVE_AGED_COUNT;
} }
static void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qboolean isGameInfo ) static void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qboolean isGameInfo )
@@ -1120,7 +1129,7 @@ static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo, qbo
if( rodir ) if( rodir )
Q_snprintf( gamedir_path, sizeof( gamedir_path ), "%s/%s", fs_rodir, gamedir ); Q_snprintf( gamedir_path, sizeof( gamedir_path ), "%s/%s", fs_rodir, gamedir );
else else
Q_snprintf( gamedir_path, sizeof( gamedir_path ), "%s/%s", fs_rootdir, gamedir ); Q_snprintf( gamedir_path, sizeof( gamedir_path ), "%s", gamedir );
if( !FS_CheckForXashGameDir( gamedir_path )) if( !FS_CheckForXashGameDir( gamedir_path ))
{ {
@@ -1190,11 +1199,11 @@ void FS_AddGameHierarchy( const char *dir, uint flags )
qboolean isGameDir = flags & FS_GAMEDIR_PATH; qboolean isGameDir = flags & FS_GAMEDIR_PATH;
char buf[MAX_VA_STRING]; char buf[MAX_VA_STRING];
GI->added = true;
if( !COM_CheckString( dir )) if( !COM_CheckString( dir ))
return; return;
Con_Printf( "%s( %s )\n", __func__, dir );
// add the common game directory // add the common game directory
// recursive gamedirs // recursive gamedirs
@@ -1205,12 +1214,21 @@ void FS_AddGameHierarchy( const char *dir, uint flags )
{ {
dir = FI.games[i]->gamefolder; // fixup directory case dir = FI.games[i]->gamefolder; // fixup directory case
if( FI.games[i]->added ) // already added, refusing
break;
// don't add our game directory as base dir to prevent cyclic dependency
if( Q_stricmp( FI.games[i]->basedir, GI->gamefolder ))
break;
// don't add directory which basedir is equal to this gamefolder to prevent
// endless loop
if( Q_stricmp( FI.games[i]->basedir, FI.games[i]->gamefolder ))
break;
Con_Reportf( "%s: adding recursive basedir %s\n", __func__, FI.games[i]->basedir ); Con_Reportf( "%s: adding recursive basedir %s\n", __func__, FI.games[i]->basedir );
if( !FI.games[i]->added && Q_stricmp( FI.games[i]->gamefolder, FI.games[i]->basedir )) FI.games[i]->added = true;
{ FS_AddGameHierarchy( FI.games[i]->basedir, flags & (~FS_GAMEDIR_PATH));
FI.games[i]->added = true;
FS_AddGameHierarchy( FI.games[i]->basedir, flags & (~FS_GAMEDIR_PATH) );
}
break; break;
} }
} }
@@ -1267,6 +1285,8 @@ void FS_Rescan( void )
FS_AddGameHierarchy( GI->basedir, 0 ); FS_AddGameHierarchy( GI->basedir, 0 );
if( Q_stricmp( GI->basedir, GI->falldir ) && Q_stricmp( GI->gamefolder, GI->falldir )) if( Q_stricmp( GI->basedir, GI->falldir ) && Q_stricmp( GI->gamefolder, GI->falldir ))
FS_AddGameHierarchy( GI->falldir, 0 ); FS_AddGameHierarchy( GI->falldir, 0 );
GI->added = true;
FS_AddGameHierarchy( GI->gamefolder, FS_GAMEDIR_PATH ); FS_AddGameHierarchy( GI->gamefolder, FS_GAMEDIR_PATH );
} }
@@ -2222,6 +2242,12 @@ int FS_Close( file_t *file )
return EOF; return EOF;
} }
if( file->ztk )
{
inflateEnd( &file->ztk->zstream );
Mem_Free( file->ztk );
}
Mem_Free( file ); Mem_Free( file );
return 0; return 0;
} }
@@ -2327,7 +2353,93 @@ fs_offset_t FS_Read( file_t *file, void *buffer, size_t buffersize )
// NOTE: at this point, the read buffer is always empty // NOTE: at this point, the read buffer is always empty
FS_EnsureOpenFile( file ); FS_EnsureOpenFile( file ); // FIXME: broken XASH_REDUCE_FD in case of compressed files!
if( FBitSet( file->flags, FILE_DEFLATED ))
{
// If the file is compressed, it's more complicated...
// We cycle through a few operations until we have read enough data
while( buffersize > 0 )
{
ztoolkit_t *ztk = file->ztk;
int error;
// NOTE: at this point, the read buffer is always empty
// If "input" is also empty, we need to refill it
if( ztk->in_ind == ztk->in_len )
{
// If we are at the end of the file
if( file->position == file->real_length )
return done;
count = (fs_offset_t)( ztk->comp_length - ztk->in_position );
if( count > (fs_offset_t)sizeof( ztk->input ))
count = (fs_offset_t)sizeof( ztk->input );
lseek( file->handle, file->offset + (fs_offset_t)ztk->in_position, SEEK_SET );
if( read( file->handle, ztk->input, count ) != count )
{
Con_Printf( "%s: unexpected end of file\n", __func__ );
break;
}
ztk->in_ind = 0;
ztk->in_len = count;
ztk->in_position += count;
}
ztk->zstream.next_in = &ztk->input[ztk->in_ind];
ztk->zstream.avail_in = (unsigned int)( ztk->in_len - ztk->in_ind );
// Now that we are sure we have compressed data available, we need to determine
// if it's better to inflate it in "file->buff" or directly in "buffer"
// Inflate the data in "file->buff"
if( buffersize < sizeof( file->buff ) / 2 )
{
ztk->zstream.next_out = file->buff;
ztk->zstream.avail_out = sizeof( file->buff );
}
else
{
ztk->zstream.next_out = &((unsigned char*)buffer)[done];
ztk->zstream.avail_out = (unsigned int)buffersize;
}
error = inflate( &ztk->zstream, Z_SYNC_FLUSH );
if( error != Z_OK && error != Z_STREAM_END )
{
Con_Printf( "%s: Can't inflate file (%d)\n", __func__, error );
break;
}
ztk->in_ind = ztk->in_len - ztk->zstream.avail_in;
if( buffersize < sizeof( file->buff ) / 2 )
{
file->buff_len = (fs_offset_t)sizeof( file->buff ) - ztk->zstream.avail_out;
file->position += file->buff_len;
// Copy the requested data in "buffer" (as much as we can)
count = (fs_offset_t)buffersize > file->buff_len ? file->buff_len : (fs_offset_t)buffersize;
memcpy( &((unsigned char*)buffer)[done], file->buff, count );
file->buff_ind = count;
}
else
{
count = (fs_offset_t)( buffersize - ztk->zstream.avail_out );
file->position += count;
// Purge cached data
FS_Purge( file );
}
done += count;
buffersize -= count;
}
return done;
}
// we must take care to not read after the end of the file // we must take care to not read after the end of the file
count = file->real_length - file->position; count = file->real_length - file->position;
@@ -2543,11 +2655,59 @@ int FS_Seek( file_t *file, fs_offset_t offset, int whence )
// Purge cached data // Purge cached data
FS_Purge( file ); FS_Purge( file );
if( FBitSet( file->flags, FILE_DEFLATED ))
{
// Seeking in compressed files is more a hack than anything else,
// but we need to support it, so here we go.
ztoolkit_t *ztk = file->ztk;
unsigned char *buffer;
fs_offset_t buffersize;
// If we have to go back in the file, we need to restart from the beginning
if( offset <= file->position )
{
ztk->in_ind = 0;
ztk->in_len = 0;
ztk->in_position = 0;
file->position = 0;
if( lseek( file->handle, file->offset, SEEK_SET ) == -1 )
Con_Printf("IMPOSSIBLE: couldn't seek in already opened pk3 file.\n");
// Reset the Zlib stream
ztk->zstream.next_in = ztk->input;
ztk->zstream.avail_in = 0;
inflateReset( &ztk->zstream );
}
// We need a big buffer to force inflating into it directly
buffersize = 2 * sizeof( file->buff );
buffer = (unsigned char *)Mem_Malloc( fs_mempool, buffersize );
// Skip all data until we reach the requested offset
while( offset > ( file->position - file->buff_len + file->buff_ind ))
{
fs_offset_t diff = offset - ( file->position - file->buff_len + file->buff_ind );
fs_offset_t count;
count = ( diff > buffersize ) ? buffersize : diff;
if( FS_Read( file, buffer, count ) != count )
{
Mem_Free( buffer );
return -1;
}
}
Mem_Free( buffer );
return 0;
}
if( lseek( file->handle, file->offset + offset, SEEK_SET ) == -1 ) if( lseek( file->handle, file->offset + offset, SEEK_SET ) == -1 )
return -1; return -1;
file->position = offset; file->position = offset;
return 0; return 0;
} }
/* /*
@@ -2705,25 +2865,20 @@ qboolean CRC32_File( dword *crcvalue, const char *filename )
qboolean MD5_HashFile( byte digest[16], const char *pszFileName, uint seed[4] ) qboolean MD5_HashFile( byte digest[16], const char *pszFileName, uint seed[4] )
{ {
file_t *file; file_t *file;
byte buffer[1024]; MD5Context_t MD5_Hash = { 0 };
MD5Context_t MD5_Hash;
int bytes;
if(( file = FS_Open( pszFileName, "rb", false )) == NULL ) if(( file = FS_Open( pszFileName, "rb", false )) == NULL )
return false; return false;
memset( &MD5_Hash, 0, sizeof( MD5Context_t ));
MD5Init( &MD5_Hash ); MD5Init( &MD5_Hash );
if( seed ) if( seed )
{
MD5Update( &MD5_Hash, (const byte *)seed, 16 ); MD5Update( &MD5_Hash, (const byte *)seed, 16 );
}
while( 1 ) while( 1 )
{ {
bytes = FS_Read( file, buffer, sizeof( buffer )); byte buffer[1024];
int bytes = FS_Read( file, buffer, sizeof( buffer ));
if( bytes > 0 ) if( bytes > 0 )
MD5Update( &MD5_Hash, buffer, bytes ); MD5Update( &MD5_Hash, buffer, bytes );

View File

@@ -143,6 +143,8 @@ typedef struct fs_globals_t
int numgames; int numgames;
} fs_globals_t; } fs_globals_t;
typedef struct file_s file_t;
typedef struct fs_api_t typedef struct fs_api_t
{ {
qboolean (*InitStdio)( qboolean unused_set_to_true, const char *rootdir, const char *basedir, const char *gamedir, const char *rodir ); qboolean (*InitStdio)( qboolean unused_set_to_true, const char *rootdir, const char *basedir, const char *gamedir, const char *rodir );

View File

@@ -22,6 +22,7 @@ GNU General Public License for more details.
#include <stdlib.h> #include <stdlib.h>
#include "xash3d_types.h" #include "xash3d_types.h"
#include "filesystem.h" #include "filesystem.h"
#include "miniz.h"
#if XASH_ANDROID #if XASH_ANDROID
#include <android/asset_manager.h> #include <android/asset_manager.h>
@@ -40,6 +41,16 @@ typedef struct wfile_s wfile_t;
typedef struct android_assets_s android_assets_t; typedef struct android_assets_s android_assets_t;
#define FILE_BUFF_SIZE (2048) #define FILE_BUFF_SIZE (2048)
#define FILE_DEFLATED BIT( 0 )
typedef struct ztoolkit_s
{
z_stream zstream;
size_t comp_length;
size_t in_ind, in_len;
size_t in_position;
byte input[FILE_BUFF_SIZE];
} ztoolkit_t;
struct file_s struct file_s
{ {
@@ -50,7 +61,9 @@ struct file_s
fs_offset_t real_length; // uncompressed file size (for files opened in "read" mode) fs_offset_t real_length; // uncompressed file size (for files opened in "read" mode)
fs_offset_t position; // current position in the file fs_offset_t position; // current position in the file
fs_offset_t offset; // offset into the package (0 if external file) fs_offset_t offset; // offset into the package (0 if external file)
uint32_t flags;
ztoolkit_t *ztk; // if not NULL, all read functions must go through decompression
// contents buffer // contents buffer
fs_offset_t buff_ind; // buffer current index fs_offset_t buff_ind; // buffer current index
fs_offset_t buff_len; // buffer current length fs_offset_t buff_len; // buffer current length

View File

@@ -92,20 +92,19 @@ struct wfile_s
typedef struct wadtype_s typedef struct wadtype_s
{ {
const char *ext; char ext[4];
signed char type; signed char type;
} wadtype_t; } wadtype_t;
// associate extension with wad type // associate extension with wad type
static const wadtype_t wad_types[7] = static const wadtype_t wad_types[] =
{ {
{ "pal", TYP_PALETTE }, // palette { "pal", TYP_PALETTE }, // palette
{ "dds", TYP_DDSTEX }, // DDS image { "dds", TYP_DDSTEX }, // DDS image
{ "lmp", TYP_GFXPIC }, // quake1, hl pic { "lmp", TYP_GFXPIC }, // quake1, hl pic
{ "fnt", TYP_QFONT }, // hl qfonts { "fnt", TYP_QFONT }, // hl qfonts
{ "mip", TYP_MIPTEX }, // hl/q1 mip { "mip", TYP_MIPTEX }, // hl/q1 mip
{ "txt", TYP_SCRIPT }, // scripts { "txt", TYP_SCRIPT }, // scripts
{ NULL, TYP_NONE }
}; };
/* /*
@@ -117,18 +116,19 @@ Extracts file type from extension
*/ */
static signed char W_TypeFromExt( const char *lumpname ) static signed char W_TypeFromExt( const char *lumpname )
{ {
const char *ext = COM_FileExtension( lumpname ); const char *ext = COM_FileExtension( lumpname );
const wadtype_t *type; int i;
// we not known about filetype, so match only by filename // we not known about filetype, so match only by filename
if( !Q_strcmp( ext, "*" ) || !COM_CheckStringEmpty( ext )) if( !Q_strcmp( ext, "*" ) || !COM_CheckStringEmpty( ext ))
return TYP_ANY; return TYP_ANY;
for( type = wad_types; type->ext; type++ ) for( i = 0; i < sizeof( wad_types ) / sizeof( wad_types[0] ); i++ )
{ {
if( !Q_stricmp( ext, type->ext )) if( !Q_stricmp( ext, wad_types[i].ext ))
return type->type; return wad_types[i].type;
} }
return TYP_NONE; return TYP_NONE;
} }
@@ -141,17 +141,18 @@ Convert type to extension
*/ */
static const char *W_ExtFromType( signed char lumptype ) static const char *W_ExtFromType( signed char lumptype )
{ {
const wadtype_t *type; int i;
// we not known aboyt filetype, so match only by filename // we not known aboyt filetype, so match only by filename
if( lumptype == TYP_NONE || lumptype == TYP_ANY ) if( lumptype == TYP_NONE || lumptype == TYP_ANY )
return ""; return "";
for( type = wad_types; type->ext; type++ ) for( i = 0; i < sizeof( wad_types ) / sizeof( wad_types[0] ); i++ )
{ {
if( lumptype == type->type ) if( lumptype == wad_types[i].type )
return type->ext; return wad_types[i].ext;
} }
return ""; return "";
} }

View File

@@ -27,7 +27,6 @@ GNU General Public License for more details.
#include "filesystem_internal.h" #include "filesystem_internal.h"
#include "crtlib.h" #include "crtlib.h"
#include "common/com_strings.h" #include "common/com_strings.h"
#include "miniz.h"
#define ZIP_HEADER_LF (('K'<<8)+('P')+(0x03<<16)+(0x04<<24)) #define ZIP_HEADER_LF (('K'<<8)+('P')+(0x03<<16)+(0x04<<24))
#define ZIP_HEADER_SPANNED ((0x08<<24)+(0x07<<16)+('K'<<8)+'P') #define ZIP_HEADER_SPANNED ((0x08<<24)+(0x07<<16)+('K'<<8)+'P')
@@ -389,15 +388,43 @@ Open a packed file using its package file descriptor
static file_t *FS_OpenFile_ZIP( searchpath_t *search, const char *filename, const char *mode, int pack_ind ) static file_t *FS_OpenFile_ZIP( searchpath_t *search, const char *filename, const char *mode, int pack_ind )
{ {
zipfile_t *pfile = &search->zip->files[pack_ind]; zipfile_t *pfile = &search->zip->files[pack_ind];
file_t *f = FS_OpenHandle( search, search->zip->handle->handle, pfile->offset, pfile->size );
// compressed files handled in Zip_LoadFile if( !f )
if( pfile->flags != ZIP_COMPRESSION_NO_COMPRESSION ) return NULL;
if( pfile->flags == ZIP_COMPRESSION_DEFLATED )
{ {
Con_Printf( S_ERROR "%s: can't open compressed file %s\n", __func__, pfile->name ); ztoolkit_t *ztk;
SetBits( f->flags, FILE_DEFLATED );
ztk = Mem_Calloc( fs_mempool, sizeof( *ztk ));
ztk->comp_length = pfile->compressed_size;
ztk->zstream.next_in = ztk->input;
ztk->zstream.avail_in = 0;
if( inflateInit2( &ztk->zstream, -MAX_WBITS ) != Z_OK )
{
Con_Printf( "%s: inflate init error (file: %s)\n", __func__, filename );
FS_Close( f );
Mem_Free( ztk );
return NULL;
}
ztk->zstream.next_out = f->buff;
ztk->zstream.avail_out = sizeof( f->buff );
f->ztk = ztk;
}
else if( pfile->flags != ZIP_COMPRESSION_NO_COMPRESSION )
{
Con_Reportf( S_ERROR "%s: %s: file compressed with unknown algorithm.\n", __func__, filename );
FS_Close( f );
return NULL; return NULL;
} }
return FS_OpenHandle( search, search->zip->handle->handle, pfile->offset, pfile->size ); return f;
} }
/* /*

View File

@@ -239,29 +239,3 @@ const char *Q_buildarch( void )
); );
} }
/*
=============
Q_buildcommit
Returns a short hash of current commit in VCS as string
XASH_BUILD_COMMIT must be passed in quotes
=============
*/
const char *Q_buildcommit( void )
{
return XASH_BUILD_COMMIT;
}
/*
=============
Q_buildbranch
Returns current branch name in VCS as string
XASH_BUILD_BRANCH must be passed in quotes
=============
*/
const char *Q_buildbranch( void )
{
return XASH_BUILD_BRANCH;
}

18
public/build_vcs.c Normal file
View File

@@ -0,0 +1,18 @@
/*
build_vcs.c - info from VCS
Copyright (C) 2025 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.
*/
const char *g_buildcommit = XASH_BUILD_COMMIT;
const char *g_buildbranch = XASH_BUILD_BRANCH;

View File

@@ -33,26 +33,6 @@ void Q_strnlwr( const char *in, char *out, size_t size_out )
out[i] = Q_tolower( out[i] ); out[i] = Q_tolower( out[i] );
} }
size_t Q_colorstr( const char *string )
{
const char *p = string;
size_t len = 0;
if( !string )
return len;
while(( p = Q_strchr( p, '^' )))
{
if( IsColorString( p ))
{
len += 2;
p += 2;
}
}
return len;
}
int Q_atoi_hex( int sign, const char *str ) int Q_atoi_hex( int sign, const char *str )
{ {
int c, val = 0; int c, val = 0;

View File

@@ -62,15 +62,14 @@ const char *Q_PlatformStringByID( const int platform );
const char *Q_buildos( void ); const char *Q_buildos( void );
const char *Q_ArchitectureStringByID( const int arch, const uint abi, const int endianness, const qboolean is64 ); const char *Q_ArchitectureStringByID( const int arch, const uint abi, const int endianness, const qboolean is64 );
const char *Q_buildarch( void ); const char *Q_buildarch( void );
const char *Q_buildcommit( void ); extern const char *g_buildcommit;
const char *Q_buildbranch( void ); extern const char *g_buildbranch;
// //
// crtlib.c // crtlib.c
// //
void Q_strnlwr( const char *in, char *out, size_t size_out ); void Q_strnlwr( const char *in, char *out, size_t size_out );
#define Q_strlen( str ) (( str ) ? strlen(( str )) : 0 ) #define Q_strlen( str ) (( str ) ? strlen(( str )) : 0 )
size_t Q_colorstr( const char *string );
int Q_atoi_hex( int sign, const char *str ); int Q_atoi_hex( int sign, const char *str );
int Q_atoi( const char *str ); int Q_atoi( const char *str );
float Q_atof( const char *str ); float Q_atof( const char *str );
@@ -108,6 +107,12 @@ int matchpattern_with_separator( const char *in, const char *pattern, qboolean c
// //
// dllhelpers.c // dllhelpers.c
// //
typedef struct dllfunc_s
{
const char *name;
void **func;
} dllfunc_t;
void ClearExports( const dllfunc_t *funcs, size_t num_funcs ); void ClearExports( const dllfunc_t *funcs, size_t num_funcs );
qboolean ValidateExports( const dllfunc_t *funcs, size_t num_funcs ); qboolean ValidateExports( const dllfunc_t *funcs, size_t num_funcs );

View File

@@ -46,17 +46,6 @@ static int Test_Strnlwr( void )
return 0; return 0;
} }
static int Test_Colorstr( void )
{
if( Q_colorstr( "^1color^2string" ) != 4 )
return 1;
if( Q_colorstr( "colorlessstring" ) != 0 )
return 2;
return 0;
}
static int Test_FixSlashes( void ) static int Test_FixSlashes( void )
{ {
string s = "path\\with\\back\\slashes"; string s = "path\\with\\back\\slashes";
@@ -93,11 +82,6 @@ int main( void )
if( ret > 0 ) if( ret > 0 )
return ret + 16; return ret + 16;
ret = Test_Colorstr();
if( ret > 0 )
return ret + 32;
ret = Test_FixSlashes(); ret = Test_FixSlashes();
if( ret > 0 ) if( ret > 0 )

View File

@@ -67,8 +67,6 @@ def options(opt):
def configure(conf): def configure(conf):
# private to libpublic # private to libpublic
conf.load('gitversion') conf.load('gitversion')
conf.define('XASH_BUILD_COMMIT', conf.env.GIT_VERSION if conf.env.GIT_VERSION else 'unknown-commit')
conf.define('XASH_BUILD_BRANCH', conf.env.GIT_BRANCH if conf.env.GIT_BRANCH else 'unknown-branch')
conf.env.VALIDATE_TARGET = conf.options.VALIDATE_TARGET conf.env.VALIDATE_TARGET = conf.options.VALIDATE_TARGET
# need to expose it for everyone using libpublic headers # need to expose it for everyone using libpublic headers
@@ -120,9 +118,14 @@ def build(bld):
export_includes = '. ../common ../pm_shared ../engine', export_includes = '. ../common ../pm_shared ../engine',
export_defines = bld.env.EXPORT_DEFINES_LIST) export_defines = bld.env.EXPORT_DEFINES_LIST)
bld.stlib(source = bld.path.ant_glob('*.c'), # build it separately to slightly improve rebuild times
target = 'public', bld.stlib(source = 'build_vcs.c',
use = 'sdk_includes werror') target = 'build_vcs',
defines = ['XASH_BUILD_COMMIT=\"%s\"' % bld.env.GIT_VERSION, 'XASH_BUILD_BRANCH=\"%s\"' % bld.env.GIT_BRANCH])
bld.stlib(source = bld.path.ant_glob('*.c', excl='build_vcs.c'),
target = 'public',
use = 'sdk_includes werror build_vcs')
if bld.env.TESTS: if bld.env.TESTS:
if bld.env.VALIDATE_TARGET: if bld.env.VALIDATE_TARGET:

View File

@@ -185,7 +185,7 @@ int BoxOnPlaneSide( const vec3_t emins, const vec3_t emaxs, const mplane_t *p );
// //
static inline void Matrix3x4_LoadIdentity( matrix3x4 m ) static inline void Matrix3x4_LoadIdentity( matrix3x4 m )
{ {
memset( m, 0, sizeof( *m )); memset( m, 0, sizeof( matrix3x4 ));
m[0][0] = m[1][1] = m[2][2] = 1.0f; m[0][0] = m[1][1] = m[2][2] = 1.0f;
} }
#define Matrix3x4_Copy( out, in ) memcpy( out, in, sizeof( matrix3x4 )) #define Matrix3x4_Copy( out, in ) memcpy( out, in, sizeof( matrix3x4 ))
@@ -201,7 +201,7 @@ void Matrix3x4_AnglesFromMatrix( const matrix3x4 in, vec3_t out );
static inline void Matrix4x4_LoadIdentity( matrix4x4 m ) static inline void Matrix4x4_LoadIdentity( matrix4x4 m )
{ {
memset( m, 0, sizeof( *m )); memset( m, 0, sizeof( matrix4x4 ));
m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f; m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f;
} }
#define Matrix4x4_Copy( out, in ) memcpy( out, in, sizeof( matrix4x4 )) #define Matrix4x4_Copy( out, in ) memcpy( out, in, sizeof( matrix4x4 ))

View File

@@ -88,11 +88,13 @@ static void Mod_BrushUnloadTextures( model_t *mod )
for( i = 0; i < mod->numtextures; i++ ) for( i = 0; i < mod->numtextures; i++ )
{ {
texture_t *tx = mod->textures[i]; texture_t *tx = mod->textures[i];
if( !tx || tx->gl_texturenum == tr.defaultTexture ) if( !tx )
continue; // free slot continue; // free slot
GL_FreeTexture( tx->gl_texturenum ); // main texture if( tx->gl_texturenum != tr.defaultTexture )
GL_FreeTexture( tx->fb_texturenum ); // luma texture GL_FreeTexture( tx->gl_texturenum ); // main texture
GL_FreeTexture( tx->fb_texturenum ); // luma texture
GL_FreeTexture( tx->dt_texturenum ); // detail texture
} }
} }
@@ -122,33 +124,35 @@ static void Mod_UnloadTextures( model_t *mod )
static qboolean Mod_ProcessRenderData( model_t *mod, qboolean create, const byte *buf ) static qboolean Mod_ProcessRenderData( model_t *mod, qboolean create, const byte *buf )
{ {
qboolean loaded = true; qboolean loaded = false;
if( create )
{
switch( mod->type )
{
case mod_studio:
// Mod_LoadStudioModel( mod, buf, loaded );
break;
case mod_sprite:
Mod_LoadSpriteModel( mod, buf, &loaded, mod->numtexinfo );
break;
case mod_alias:
Mod_LoadAliasModel( mod, buf, &loaded );
break;
case mod_brush:
// Mod_LoadBrushModel( mod, buf, loaded );
break;
default: gEngfuncs.Host_Error( "%s: unsupported type %d\n", __func__, mod->type );
}
}
if( loaded && gEngfuncs.drawFuncs->Mod_ProcessUserData )
gEngfuncs.drawFuncs->Mod_ProcessUserData( mod, create, buf );
if( !create ) if( !create )
{
if( gEngfuncs.drawFuncs->Mod_ProcessUserData )
gEngfuncs.drawFuncs->Mod_ProcessUserData( mod, false, buf );
Mod_UnloadTextures( mod ); Mod_UnloadTextures( mod );
return true;
}
switch( mod->type )
{
case mod_studio:
case mod_brush:
loaded = true;
break;
case mod_sprite:
Mod_LoadSpriteModel( mod, buf, &loaded, mod->numtexinfo );
break;
case mod_alias:
Mod_LoadAliasModel( mod, buf, &loaded );
break;
default:
gEngfuncs.Host_Error( "%s: unsupported type %d\n", __func__, mod->type );
return false;
}
if( gEngfuncs.drawFuncs->Mod_ProcessUserData )
gEngfuncs.drawFuncs->Mod_ProcessUserData( mod, true, buf );
return loaded; return loaded;
} }

View File

@@ -16,7 +16,7 @@ GNU General Public License for more details.
#include "gl_local.h" #include "gl_local.h"
#include "xash3d_mathlib.h" #include "xash3d_mathlib.h"
void GL_FrustumSetPlane( gl_frustum_t *out, int side, const vec3_t vecNormal, float flDist ) static void GL_FrustumSetPlane( gl_frustum_t *out, int side, const vec3_t vecNormal, float flDist )
{ {
Assert( side >= 0 && side < FRUSTUM_PLANES ); Assert( side >= 0 && side < FRUSTUM_PLANES );

View File

@@ -33,7 +33,6 @@ typedef struct gl_frustum_s
void GL_FrustumInitProj( gl_frustum_t *out, float flZNear, float flZFar, float flFovX, float flFovY ); void GL_FrustumInitProj( gl_frustum_t *out, float flZNear, float flZFar, float flFovX, float flFovY );
void GL_FrustumInitOrtho( gl_frustum_t *out, float xLeft, float xRight, float yTop, float yBottom, float flZNear, float flZFar ); void GL_FrustumInitOrtho( gl_frustum_t *out, float xLeft, float xRight, float yTop, float yBottom, float flZNear, float flZFar );
void GL_FrustumSetPlane( gl_frustum_t *out, int side, const vec3_t vecNormal, float flDist );
// cull methods // cull methods
qboolean GL_FrustumCullBox( gl_frustum_t *out, const vec3_t mins, const vec3_t maxs, int userClipFlags ); qboolean GL_FrustumCullBox( gl_frustum_t *out, const vec3_t mins, const vec3_t maxs, int userClipFlags );

Some files were not shown because too many files have changed in this diff Show More