mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-06 04:05:11 +08:00
Compare commits
43 Commits
continuous
...
android-le
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38a3154de0 | ||
|
|
0442af7920 | ||
|
|
42958bc746 | ||
|
|
bd5309b018 | ||
|
|
26cbb1d6bf | ||
|
|
d6cfc65ac0 | ||
|
|
be9dda2a56 | ||
|
|
dbc54fb522 | ||
|
|
ec92d05930 | ||
|
|
892c735c86 | ||
|
|
93e5faa26b | ||
|
|
4953656ee0 | ||
|
|
96c367973a | ||
|
|
ffe1ff326a | ||
|
|
9c097976df | ||
|
|
6fec0398b6 | ||
|
|
abeb267420 | ||
|
|
9484effd4c | ||
|
|
a5f3fce665 | ||
|
|
91d9ca7810 | ||
|
|
0901fd94e2 | ||
|
|
0d18753adb | ||
|
|
7841382fef | ||
|
|
e21d8df1fe | ||
|
|
16aa2e919f | ||
|
|
88f76c6e1e | ||
|
|
1b9af8c515 | ||
|
|
55943ad1ce | ||
|
|
313f2a86b0 | ||
|
|
16eeaef35c | ||
|
|
46c82e89e1 | ||
|
|
bb55de5963 | ||
|
|
d423c437ed | ||
|
|
44b1a8e863 | ||
|
|
06c6371e69 | ||
|
|
7b4fd3bcad | ||
|
|
ea35863c26 | ||
|
|
c2e14eb3a3 | ||
|
|
34aab39f9b | ||
|
|
30c69d3ac8 | ||
|
|
bb9775048b | ||
|
|
eed13cf9f2 | ||
|
|
fbb91e547d |
27
.cirrus.yml
27
.cirrus.yml
@@ -1,7 +1,32 @@
|
|||||||
|
task:
|
||||||
|
# Seems packages for it were removed from the mirrors
|
||||||
|
# name: freebsd-12-amd64
|
||||||
|
# freebsd_instance:
|
||||||
|
# image_family: freebsd-12-4
|
||||||
|
# setup_script:
|
||||||
|
# - pkg update
|
||||||
|
# - pkg install -y pkgconf git sdl2 python fontconfig opus
|
||||||
|
# - git submodule update --init --recursive
|
||||||
|
# test_script:
|
||||||
|
# - ./scripts/cirrus/build_freebsd.sh dedicated
|
||||||
|
# - ./scripts/cirrus/build_freebsd.sh full
|
||||||
|
|
||||||
|
task:
|
||||||
|
name: freebsd-13-amd64
|
||||||
|
freebsd_instance:
|
||||||
|
image_family: freebsd-13-2
|
||||||
|
setup_script:
|
||||||
|
- pkg update
|
||||||
|
- pkg install -y pkgconf git sdl2 python fontconfig opus
|
||||||
|
- git submodule update --init --recursive
|
||||||
|
test_script:
|
||||||
|
- ./scripts/cirrus/build_freebsd.sh dedicated
|
||||||
|
- ./scripts/cirrus/build_freebsd.sh full
|
||||||
|
|
||||||
task:
|
task:
|
||||||
name: freebsd-14-amd64
|
name: freebsd-14-amd64
|
||||||
freebsd_instance:
|
freebsd_instance:
|
||||||
image_family: freebsd-14-0
|
image_family: freebsd-14-0-snap
|
||||||
setup_script:
|
setup_script:
|
||||||
- pkg update
|
- pkg update
|
||||||
- pkg install -y pkgconf git sdl2 python fontconfig opus
|
- pkg install -y pkgconf git sdl2 python fontconfig opus
|
||||||
|
|||||||
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
@@ -1 +0,0 @@
|
|||||||
custom: https://github.com/FWGS/xash3d-fwgs/blob/master/Documentation/donate.md
|
|
||||||
2
.github/workflows/c-cpp.yml
vendored
2
.github/workflows/c-cpp.yml
vendored
@@ -44,7 +44,7 @@ jobs:
|
|||||||
targetos: win32
|
targetos: win32
|
||||||
targetarch: i386
|
targetarch: i386
|
||||||
env:
|
env:
|
||||||
SDL_VERSION: 2.30.3
|
SDL_VERSION: 2.28.5
|
||||||
GH_CPU_ARCH: ${{ matrix.targetarch }}
|
GH_CPU_ARCH: ${{ matrix.targetarch }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|||||||
2
3rdparty/mainui
vendored
2
3rdparty/mainui
vendored
Submodule 3rdparty/mainui updated: 757ace3d4e...d75b7f4a57
2
3rdparty/vgui_support
vendored
2
3rdparty/vgui_support
vendored
Submodule 3rdparty/vgui_support updated: 7276993f3f...a2a7b9073f
@@ -1,16 +1,17 @@
|
|||||||
# Bug-compatibility in Xash3D FWGS
|
# Bug-compatibility in Xash3D FWGS
|
||||||
|
|
||||||
Xash3D FWGS has special mode for games that rely on original engine bugs. In this mode, we emulate the behaviour of selected functions that may help running mods relying on engine bugs, but enabling them by default may break majority of other games.
|
Xash3D FWGS has special mode for games that rely on original engine bugs.
|
||||||
|
|
||||||
|
In this mode, we emulate the behaviour of selected functions that may help running mods relying on engine bugs, but enabling them by default may break majority of other games.
|
||||||
|
|
||||||
At this time, we only have implemented GoldSrc bug-compatibility. It can be enabled with `-bugcomp` command line switch.
|
At this time, we only have implemented GoldSrc bug-compatibility. It can be enabled with `-bugcomp` command line switch.
|
||||||
|
|
||||||
When `-bugcomp` is specified without argument, it enables everything. This behavior might be changed or removed in future versions.
|
|
||||||
|
|
||||||
When `-bugcomp` is specified with argument, it interpreted as flags separated with `+`. This way it's possible to combine multiple levels of bug-compatibility.
|
|
||||||
|
|
||||||
## GoldSrc bug-compatibility
|
## GoldSrc bug-compatibility
|
||||||
|
|
||||||
| Flag | Description | Games that require this flag |
|
### Emulated bugs
|
||||||
| ------- | ----------- | ---------------------------- |
|
|
||||||
| `peoei` | Reverts `pfnPEntityOfEntIndex` behavior to GoldSrc, where it returns NULL for last player due to incorrect player index comparison | * Counter-Strike: Condition Zero - Deleted Scenes |
|
* `pfnPEntityOfEntIndex` in GoldSrc returns NULL for last player due to incorrect player index comparison
|
||||||
| `gsmrf` | Rewrites message at the moment when Game DLL attempts to write an internal engine message, usually specific to GoldSrc protocol. Right now only supports `svc_spawnstaticsound`, more messages added by request. | * MetaMod/AMXModX based mods |
|
|
||||||
|
### Games and mods that require this
|
||||||
|
|
||||||
|
* Counter-Strike: Condition Zero - Deleted Scenes
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
## Environment variables
|
|
||||||
|
|
||||||
#### Xash3D FWGS
|
|
||||||
|
|
||||||
The engine respects these environment variables:
|
|
||||||
|
|
||||||
| Variable | Type | Description |
|
|
||||||
| --------------------- | ---------- | ----------- |
|
|
||||||
| `XASH3D_GAME` | _string_ | Overrides default game directory. Ignored if `-game` command line argument is set |
|
|
||||||
| `XASH3D_BASEDIR` | _string_ | Sets path to base (root) directory, instead of current working directory |
|
|
||||||
| `XASH3D_RODIR` | _string_ | Sets path to read-only base (root) directory. Ignored if `-rodir` command line argument is set |
|
|
||||||
| `XASH3D_EXTRAS_PAK1` | _string_ | Archive file from specified path will be added to virtual filesystem search path in the lowest possible priority |
|
|
||||||
| `XASH3D_EXTRAS_PAK2` | _string_ | Similar to `XASH3D_EXTRAS_PAK1` but next to it in priority list |
|
|
||||||
|
|
||||||
Environment variables NOT listed in the table above are used internally, and aren't considered as stable interface.
|
|
||||||
|
|
||||||
#### mdldec
|
|
||||||
|
|
||||||
| Variable | Type | Description |
|
|
||||||
| --------------------- | ---------- | ----------- |
|
|
||||||
| `MDLDEC_ACT_PATH` | _string_ | If set, will read activities list from this path |
|
|
||||||
@@ -18,17 +18,20 @@ GNU General Public License for more details.
|
|||||||
// video backends (XASH_VIDEO)
|
// video backends (XASH_VIDEO)
|
||||||
#define VIDEO_NULL 0
|
#define VIDEO_NULL 0
|
||||||
#define VIDEO_SDL 1
|
#define VIDEO_SDL 1
|
||||||
|
#define VIDEO_ANDROID 2
|
||||||
#define VIDEO_FBDEV 3
|
#define VIDEO_FBDEV 3
|
||||||
#define VIDEO_DOS 4
|
#define VIDEO_DOS 4
|
||||||
|
|
||||||
// audio backends (XASH_SOUND)
|
// audio backends (XASH_SOUND)
|
||||||
#define SOUND_NULL 0
|
#define SOUND_NULL 0
|
||||||
#define SOUND_SDL 1
|
#define SOUND_SDL 1
|
||||||
|
#define SOUND_OPENSLES 2
|
||||||
#define SOUND_ALSA 3
|
#define SOUND_ALSA 3
|
||||||
|
|
||||||
// input (XASH_INPUT)
|
// input (XASH_INPUT)
|
||||||
#define INPUT_NULL 0
|
#define INPUT_NULL 0
|
||||||
#define INPUT_SDL 1
|
#define INPUT_SDL 1
|
||||||
|
#define INPUT_ANDROID 2
|
||||||
#define INPUT_EVDEV 3
|
#define INPUT_EVDEV 3
|
||||||
|
|
||||||
// timer (XASH_TIMER)
|
// timer (XASH_TIMER)
|
||||||
@@ -41,6 +44,7 @@ GNU General Public License for more details.
|
|||||||
// messageboxes (XASH_MESSAGEBOX)
|
// messageboxes (XASH_MESSAGEBOX)
|
||||||
#define MSGBOX_STDERR 0
|
#define MSGBOX_STDERR 0
|
||||||
#define MSGBOX_SDL 1
|
#define MSGBOX_SDL 1
|
||||||
|
#define MSGBOX_ANDROID 2
|
||||||
#define MSGBOX_WIN32 3
|
#define MSGBOX_WIN32 3
|
||||||
#define MSGBOX_NSWITCH 4
|
#define MSGBOX_NSWITCH 4
|
||||||
|
|
||||||
|
|||||||
25
common/boneinfo.h
Normal file
25
common/boneinfo.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
boneinfo.h - structure that send delta-compressed bones across network
|
||||||
|
Copyright (C) 2018 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BONEINFO_H
|
||||||
|
#define BONEINFO_H
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
vec3_t angles;
|
||||||
|
vec3_t origin;
|
||||||
|
} boneinfo_t;
|
||||||
|
|
||||||
|
#endif//BONEINFO_H
|
||||||
@@ -52,6 +52,25 @@ SETUP BACKENDS DEFINITIONS
|
|||||||
#endif
|
#endif
|
||||||
#endif // XASH_MESSAGEBOX
|
#endif // XASH_MESSAGEBOX
|
||||||
#endif
|
#endif
|
||||||
|
#elif XASH_ANDROID
|
||||||
|
// we are building for Android platform, use Android APIs
|
||||||
|
#ifndef XASH_VIDEO
|
||||||
|
#define XASH_VIDEO VIDEO_ANDROID
|
||||||
|
#endif // XASH_VIDEO
|
||||||
|
|
||||||
|
#ifndef XASH_INPUT
|
||||||
|
#define XASH_INPUT INPUT_ANDROID
|
||||||
|
#endif // XASH_INPUT
|
||||||
|
|
||||||
|
#ifndef XASH_SOUND
|
||||||
|
#define XASH_SOUND SOUND_OPENSLES
|
||||||
|
#endif // XASH_SOUND
|
||||||
|
|
||||||
|
#ifndef XASH_MESSAGEBOX
|
||||||
|
#define XASH_MESSAGEBOX MSGBOX_ANDROID
|
||||||
|
#endif // XASH_MESSAGEBOX
|
||||||
|
|
||||||
|
#define XASH_USE_EVDEV 1
|
||||||
#elif XASH_LINUX
|
#elif XASH_LINUX
|
||||||
// we are building for Linux without SDL2, can draw only to framebuffer yet
|
// we are building for Linux without SDL2, can draw only to framebuffer yet
|
||||||
#ifndef XASH_VIDEO
|
#ifndef XASH_VIDEO
|
||||||
@@ -151,8 +170,6 @@ Default build-depended cvar and constant values
|
|||||||
#define DEFAULT_MODE_WIDTH 960
|
#define DEFAULT_MODE_WIDTH 960
|
||||||
#define DEFAULT_MODE_HEIGHT 544
|
#define DEFAULT_MODE_HEIGHT 544
|
||||||
#define DEFAULT_ALLOWCONSOLE 1
|
#define DEFAULT_ALLOWCONSOLE 1
|
||||||
#elif XASH_ANDROID
|
|
||||||
#define DEFAULT_TOUCH_ENABLE "1"
|
|
||||||
#elif XASH_MOBILE_PLATFORM
|
#elif XASH_MOBILE_PLATFORM
|
||||||
#define DEFAULT_TOUCH_ENABLE "1"
|
#define DEFAULT_TOUCH_ENABLE "1"
|
||||||
#define DEFAULT_M_IGNORE "1"
|
#define DEFAULT_M_IGNORE "1"
|
||||||
@@ -164,6 +181,10 @@ Default build-depended cvar and constant values
|
|||||||
#define XASH_INTERNAL_GAMELIBS
|
#define XASH_INTERNAL_GAMELIBS
|
||||||
#endif // XASH_ANDROID || XASH_IOS || XASH_EMSCRIPTEN
|
#endif // XASH_ANDROID || XASH_IOS || XASH_EMSCRIPTEN
|
||||||
|
|
||||||
|
#if XASH_ANDROID && XASH_SDL
|
||||||
|
#define XASH_ANDROID_ASSETS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
// Defaults
|
// Defaults
|
||||||
#ifndef DEFAULT_TOUCH_ENABLE
|
#ifndef DEFAULT_TOUCH_ENABLE
|
||||||
#define DEFAULT_TOUCH_ENABLE "0"
|
#define DEFAULT_TOUCH_ENABLE "0"
|
||||||
|
|||||||
@@ -28,7 +28,11 @@ typedef byte rgb_t[3]; // unsigned byte colorpack
|
|||||||
typedef vec_t matrix3x4[3][4];
|
typedef vec_t matrix3x4[3][4];
|
||||||
typedef vec_t matrix4x4[4][4];
|
typedef vec_t matrix4x4[4][4];
|
||||||
|
|
||||||
|
#if XASH_64BIT
|
||||||
typedef uint32_t poolhandle_t;
|
typedef uint32_t poolhandle_t;
|
||||||
|
#else
|
||||||
|
typedef void* poolhandle_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
#undef true
|
#undef true
|
||||||
#undef false
|
#undef false
|
||||||
@@ -70,50 +74,48 @@ typedef uint64_t longtime_t;
|
|||||||
#define IsColorString( p ) ( p && *( p ) == '^' && *(( p ) + 1) && *(( p ) + 1) >= '0' && *(( p ) + 1 ) <= '9' )
|
#define IsColorString( p ) ( p && *( p ) == '^' && *(( p ) + 1) && *(( p ) + 1) >= '0' && *(( p ) + 1 ) <= '9' )
|
||||||
#define ColorIndex( c ) ((( c ) - '0' ) & 7 )
|
#define ColorIndex( c ) ((( c ) - '0' ) & 7 )
|
||||||
|
|
||||||
#if defined( __GNUC__ )
|
#if defined(__GNUC__)
|
||||||
#if defined( __i386__ )
|
#ifdef __i386__
|
||||||
#define EXPORT __attribute__(( visibility( "default" ), force_align_arg_pointer ))
|
#define EXPORT __attribute__ ((visibility ("default"),force_align_arg_pointer))
|
||||||
#define GAME_EXPORT __attribute(( force_align_arg_pointer ))
|
#define GAME_EXPORT __attribute((force_align_arg_pointer))
|
||||||
#else
|
#else
|
||||||
#define EXPORT __attribute__(( visibility ( "default" )))
|
#define EXPORT __attribute__ ((visibility ("default")))
|
||||||
#define GAME_EXPORT
|
#define GAME_EXPORT
|
||||||
#endif
|
#endif
|
||||||
|
#define _format(x) __attribute__((format(printf, x, x+1)))
|
||||||
#define NORETURN __attribute__(( noreturn ))
|
#define NORETURN __attribute__((noreturn))
|
||||||
#define NONNULL __attribute__(( nonnull ))
|
#define NONNULL __attribute__((nonnull))
|
||||||
#define _format( x ) __attribute__(( format( printf, x, x + 1 )))
|
#define ALLOC_CHECK(x) __attribute__((alloc_size(x)))
|
||||||
#define ALLOC_CHECK( x ) __attribute__(( alloc_size( x )))
|
#elif defined(_MSC_VER)
|
||||||
#define NO_ASAN __attribute__(( no_sanitize( "address" )))
|
#define EXPORT __declspec( dllexport )
|
||||||
#define RENAME_SYMBOL( x ) asm( x )
|
|
||||||
#else
|
|
||||||
#if defined( _MSC_VER )
|
|
||||||
#define EXPORT __declspec( dllexport )
|
|
||||||
#define NO_ASAN __declspec( no_sanitize_address )
|
|
||||||
#else
|
|
||||||
#define EXPORT
|
|
||||||
#define NO_ASAN
|
|
||||||
#endif
|
|
||||||
#define GAME_EXPORT
|
#define GAME_EXPORT
|
||||||
|
#define _format(x)
|
||||||
#define NORETURN
|
#define NORETURN
|
||||||
#define NONNULL
|
#define NONNULL
|
||||||
#define _format( x )
|
#define ALLOC_CHECK(x)
|
||||||
#define ALLOC_CHECK( x )
|
#else
|
||||||
#define RENAME_SYMBOL( x )
|
#define EXPORT
|
||||||
|
#define GAME_EXPORT
|
||||||
|
#define _format(x)
|
||||||
|
#define NORETURN
|
||||||
|
#define NONNULL
|
||||||
|
#define ALLOC_CHECK(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __GNUC__ >= 3
|
#if ( __GNUC__ >= 3 )
|
||||||
#define unlikely( x ) __builtin_expect( x, 0 )
|
#define unlikely(x) __builtin_expect(x, 0)
|
||||||
#define likely( x ) __builtin_expect( x, 1 )
|
#define likely(x) __builtin_expect(x, 1)
|
||||||
#elif defined( __has_builtin )
|
#elif defined( __has_builtin )
|
||||||
#if __has_builtin( __builtin_expect ) // this must be after defined() check
|
#if __has_builtin( __builtin_expect )
|
||||||
#define unlikely( x ) __builtin_expect( x, 0 )
|
#define unlikely(x) __builtin_expect(x, 0)
|
||||||
#define likely( x ) __builtin_expect( x, 1 )
|
#define likely(x) __builtin_expect(x, 1)
|
||||||
|
#else
|
||||||
|
#define unlikely(x) (x)
|
||||||
|
#define likely(x) (x)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#else
|
||||||
|
#define unlikely(x) (x)
|
||||||
#if !defined( unlikely ) || !defined( likely )
|
#define likely(x) (x)
|
||||||
#define unlikely( x ) ( x )
|
|
||||||
#define likely( x ) ( x )
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __STDC_VERSION__ >= 202311L || __cplusplus >= 201103L // C23 or C++ static_assert is a keyword
|
#if __STDC_VERSION__ >= 202311L || __cplusplus >= 201103L // C23 or C++ static_assert is a keyword
|
||||||
@@ -130,14 +132,6 @@ typedef uint64_t longtime_t;
|
|||||||
#define STATIC_ASSERT( x, y ) STATIC_ASSERT_2( __LINE__, x, y )
|
#define STATIC_ASSERT( x, y ) STATIC_ASSERT_2( __LINE__, x, y )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined( __cplusplus ) && __STDC_VERSION__ >= 199101L // not C++ and C99 or newer
|
|
||||||
#define XASH_RESTRICT restrict
|
|
||||||
#elif _MSC_VER || __GNUC__ || __clang__ // compiler-specific extensions
|
|
||||||
#define XASH_RESTRICT __restrict
|
|
||||||
#else
|
|
||||||
#define XASH_RESTRICT // nothing
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef XASH_BIG_ENDIAN
|
#ifdef XASH_BIG_ENDIAN
|
||||||
#define LittleLong(x) (((int)(((x)&255)<<24)) + ((int)((((x)>>8)&255)<<16)) + ((int)(((x)>>16)&255)<<8) + (((x) >> 24)&255))
|
#define LittleLong(x) (((int)(((x)&255)<<24)) + ((int)((((x)>>8)&255)<<16)) + ((int)(((x)>>16)&255)<<8) + (((x) >> 24)&255))
|
||||||
#define LittleLongSW(x) (x = LittleLong(x) )
|
#define LittleLongSW(x) (x = LittleLong(x) )
|
||||||
|
|||||||
@@ -70,17 +70,16 @@ qboolean CL_CheckFile( sizebuf_t *msg, resource_t *pResource )
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
host.downloadcount++;
|
if( cl.downloadUrl[0] )
|
||||||
|
|
||||||
if( cl.http_download )
|
|
||||||
{
|
{
|
||||||
HTTP_AddDownload( filepath, pResource->nDownloadSize, true );
|
HTTP_AddDownload( filepath, pResource->nDownloadSize, true );
|
||||||
|
host.downloadcount++;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
MSG_BeginClientCmd( msg, clc_stringcmd );
|
||||||
MSG_BeginClientCmd( msg, clc_stringcmd );
|
MSG_WriteStringf( msg, "dlfile %s", filepath );
|
||||||
MSG_WriteStringf( msg, "dlfile %s", filepath );
|
host.downloadcount++;
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,15 +50,7 @@ const char *CL_MsgInfo( int cmd )
|
|||||||
if( cmd >= 0 && cmd <= svc_lastmsg )
|
if( cmd >= 0 && cmd <= svc_lastmsg )
|
||||||
{
|
{
|
||||||
// get engine message name
|
// get engine message name
|
||||||
const char *svc_string = NULL;
|
Q_strncpy( sz, svc_strings[cmd], sizeof( sz ));
|
||||||
|
|
||||||
if( cls.legacymode )
|
|
||||||
svc_string = svc_legacy_strings[cmd];
|
|
||||||
|
|
||||||
if( !svc_string )
|
|
||||||
svc_string = svc_strings[cmd];
|
|
||||||
|
|
||||||
Q_strncpy( sz, svc_string, sizeof( sz ));
|
|
||||||
}
|
}
|
||||||
else if( cmd > svc_lastmsg && cmd <= ( svc_lastmsg + MAX_USER_MESSAGES ))
|
else if( cmd > svc_lastmsg && cmd <= ( svc_lastmsg + MAX_USER_MESSAGES ))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -192,7 +192,7 @@ void CL_RegisterEvent( int lastnum, const char *szEvName, pfnEventHook func )
|
|||||||
ev = clgame.events[lastnum];
|
ev = clgame.events[lastnum];
|
||||||
|
|
||||||
// NOTE: ev->index will be set later
|
// NOTE: ev->index will be set later
|
||||||
Q_strncpy( ev->name, szEvName, sizeof( ev->name ));
|
Q_strncpy( ev->name, szEvName, MAX_QPATH );
|
||||||
ev->func = func;
|
ev->func = func;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1448,7 +1448,7 @@ pfnSPR_Draw
|
|||||||
*/
|
*/
|
||||||
static void GAME_EXPORT pfnSPR_Draw( int frame, int x, int y, const wrect_t *prc )
|
static void GAME_EXPORT pfnSPR_Draw( int frame, int x, int y, const wrect_t *prc )
|
||||||
{
|
{
|
||||||
ref.dllFuncs.GL_SetRenderMode( kRenderTransAlpha );
|
ref.dllFuncs.GL_SetRenderMode( kRenderNormal );
|
||||||
SPR_DrawGeneric( frame, x, y, -1, -1, prc );
|
SPR_DrawGeneric( frame, x, y, -1, -1, prc );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1713,8 +1713,7 @@ pfnCvar_RegisterVariable
|
|||||||
static cvar_t *GAME_EXPORT pfnCvar_RegisterClientVariable( const char *szName, const char *szValue, int flags )
|
static cvar_t *GAME_EXPORT pfnCvar_RegisterClientVariable( const char *szName, const char *szValue, int flags )
|
||||||
{
|
{
|
||||||
// a1ba: try to mitigate outdated client.dll vulnerabilities
|
// a1ba: try to mitigate outdated client.dll vulnerabilities
|
||||||
if( !Q_stricmp( szName, "motdfile" )
|
if( !Q_stricmp( szName, "motdfile" ))
|
||||||
|| !Q_stricmp( szName, "sensitivity" ))
|
|
||||||
flags |= FCVAR_PRIVILEGED;
|
flags |= FCVAR_PRIVILEGED;
|
||||||
|
|
||||||
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_CLIENTDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_CLIENTDLL ));
|
return (cvar_t *)Cvar_Get( szName, szValue, flags|FCVAR_CLIENTDLL, Cvar_BuildAutoDescription( szName, flags|FCVAR_CLIENTDLL ));
|
||||||
|
|||||||
@@ -1097,20 +1097,6 @@ static void GAME_EXPORT pfnCon_DefaultColor( int r, int g, int b )
|
|||||||
Con_DefaultColor( r, g, b, true );
|
Con_DefaultColor( r, g, b, true );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void GAME_EXPORT pfnSetCursor( void *hCursor )
|
|
||||||
{
|
|
||||||
uintptr_t cursor;
|
|
||||||
|
|
||||||
if( !gameui.use_extended_api )
|
|
||||||
return; // ignore original Xash menus
|
|
||||||
|
|
||||||
cursor = (uintptr_t)hCursor;
|
|
||||||
if( cursor < dc_user || cursor > dc_last )
|
|
||||||
return;
|
|
||||||
|
|
||||||
Platform_SetCursorType( cursor );
|
|
||||||
}
|
|
||||||
|
|
||||||
// engine callbacks
|
// engine callbacks
|
||||||
static ui_enginefuncs_t gEngfuncs =
|
static ui_enginefuncs_t gEngfuncs =
|
||||||
{
|
{
|
||||||
@@ -1190,7 +1176,7 @@ static ui_enginefuncs_t gEngfuncs =
|
|||||||
pfnHostEndGame,
|
pfnHostEndGame,
|
||||||
COM_RandomFloat,
|
COM_RandomFloat,
|
||||||
COM_RandomLong,
|
COM_RandomLong,
|
||||||
pfnSetCursor,
|
IN_SetCursor,
|
||||||
pfnIsMapValid,
|
pfnIsMapValid,
|
||||||
GL_ProcessTexture,
|
GL_ProcessTexture,
|
||||||
COM_CompareFileTime,
|
COM_CompareFileTime,
|
||||||
@@ -1300,7 +1286,7 @@ qboolean UI_LoadProgs( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
gameui.use_extended_api = false;
|
gameui.use_text_api = false;
|
||||||
|
|
||||||
// make local copy of engfuncs to prevent overwrite it with user dll
|
// make local copy of engfuncs to prevent overwrite it with user dll
|
||||||
memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs ));
|
memcpy( &gpEngfuncs, &gEngfuncs, sizeof( gpEngfuncs ));
|
||||||
@@ -1327,7 +1313,7 @@ qboolean UI_LoadProgs( void )
|
|||||||
if( GetExtAPI( MENU_EXTENDED_API_VERSION, &gameui.dllFuncs2, &gpExtendedfuncs ) )
|
if( GetExtAPI( MENU_EXTENDED_API_VERSION, &gameui.dllFuncs2, &gpExtendedfuncs ) )
|
||||||
{
|
{
|
||||||
Con_Reportf( "UI_LoadProgs: extended Menu API initialized\n" );
|
Con_Reportf( "UI_LoadProgs: extended Menu API initialized\n" );
|
||||||
gameui.use_extended_api = true;
|
gameui.use_text_api = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // otherwise, fallback to old and deprecated extensions
|
else // otherwise, fallback to old and deprecated extensions
|
||||||
@@ -1339,7 +1325,7 @@ qboolean UI_LoadProgs( void )
|
|||||||
if( GiveTextApi( &gpExtendedfuncs ) ) // they are binary compatible, so we can just pass extended funcs API to menu
|
if( GiveTextApi( &gpExtendedfuncs ) ) // they are binary compatible, so we can just pass extended funcs API to menu
|
||||||
{
|
{
|
||||||
Con_Reportf( "UI_LoadProgs: extended text API initialized\n" );
|
Con_Reportf( "UI_LoadProgs: extended text API initialized\n" );
|
||||||
gameui.use_extended_api = true;
|
gameui.use_text_api = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -587,38 +587,21 @@ CL_CreateCmd
|
|||||||
*/
|
*/
|
||||||
static void CL_CreateCmd( void )
|
static void CL_CreateCmd( void )
|
||||||
{
|
{
|
||||||
usercmd_t nullcmd, *cmd;
|
usercmd_t nullcmd, *cmd;
|
||||||
runcmd_t *pcmd;
|
runcmd_t *pcmd;
|
||||||
qboolean active;
|
vec3_t angles;
|
||||||
double accurate_ms;
|
qboolean active;
|
||||||
vec3_t angles;
|
int input_override;
|
||||||
int input_override;
|
int i, ms;
|
||||||
int i, ms;
|
|
||||||
|
|
||||||
if( cls.state < ca_connected || cls.state == ca_cinematic )
|
if( cls.state < ca_connected || cls.state == ca_cinematic )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// store viewangles in case it's will be freeze
|
// store viewangles in case it's will be freeze
|
||||||
VectorCopy( cl.viewangles, angles );
|
VectorCopy( cl.viewangles, angles );
|
||||||
|
ms = bound( 1, host.frametime * 1000, 255 );
|
||||||
input_override = 0;
|
input_override = 0;
|
||||||
|
|
||||||
// fix rounding error and framerate depending player move
|
|
||||||
accurate_ms = host.frametime * 1000;
|
|
||||||
ms = (int)accurate_ms;
|
|
||||||
cl.frametime_remainder += accurate_ms - ms; // accumulate rounding error each frame
|
|
||||||
|
|
||||||
// add a ms if error accumulates enough
|
|
||||||
if( cl.frametime_remainder >= 1.0 )
|
|
||||||
{
|
|
||||||
int ms2 = (int)cl.frametime_remainder;
|
|
||||||
|
|
||||||
ms += ms2;
|
|
||||||
cl.frametime_remainder -= ms2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ms can't be negative, rely on error accumulation only if FPS > 1000
|
|
||||||
ms = Q_min( ms, 255 );
|
|
||||||
|
|
||||||
CL_SetSolidEntities();
|
CL_SetSolidEntities();
|
||||||
CL_PushPMStates();
|
CL_PushPMStates();
|
||||||
CL_SetSolidPlayers( cl.playernum );
|
CL_SetSolidPlayers( cl.playernum );
|
||||||
@@ -1635,16 +1618,8 @@ static size_t NONNULL CL_BuildMasterServerScanRequest( char *buf, size_t size, u
|
|||||||
#ifndef XASH_ALL_SERVERS
|
#ifndef XASH_ALL_SERVERS
|
||||||
Info_SetValueForKey( info, "gamedir", GI->gamefolder, remaining );
|
Info_SetValueForKey( info, "gamedir", GI->gamefolder, remaining );
|
||||||
#endif
|
#endif
|
||||||
// let master know about client version
|
Info_SetValueForKey( info, "clver", XASH_VERSION, remaining ); // let master know about client version
|
||||||
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, "branch", Q_buildbranch(), remaining );
|
|
||||||
Info_SetValueForKey( info, "os", Q_buildos(), remaining );
|
|
||||||
Info_SetValueForKey( info, "arch", Q_buildarch(), remaining );
|
|
||||||
|
|
||||||
Q_snprintf( temp, sizeof( temp ), "%d", Q_buildnum() );
|
|
||||||
Info_SetValueForKey( info, "buildnum", temp, remaining );
|
|
||||||
|
|
||||||
Q_snprintf( temp, sizeof( temp ), "%x", *key );
|
Q_snprintf( temp, sizeof( temp ), "%x", *key );
|
||||||
Info_SetValueForKey( info, "key", temp, remaining );
|
Info_SetValueForKey( info, "key", temp, remaining );
|
||||||
@@ -2535,6 +2510,11 @@ void CL_ProcessFile( qboolean successfully_received, const char *filename )
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pfilename = filename;
|
||||||
|
|
||||||
|
if( !Q_strnicmp( filename, DEFAULT_SOUNDPATH, sound_len ))
|
||||||
|
pfilename += sound_len;
|
||||||
|
|
||||||
for( p = cl.resourcesneeded.pNext; p != &cl.resourcesneeded; p = p->pNext )
|
for( p = cl.resourcesneeded.pNext; p != &cl.resourcesneeded; p = p->pNext )
|
||||||
{
|
{
|
||||||
if( !Q_strnicmp( filename, "!MD5", 4 ))
|
if( !Q_strnicmp( filename, "!MD5", 4 ))
|
||||||
@@ -2544,20 +2524,18 @@ void CL_ProcessFile( qboolean successfully_received, const char *filename )
|
|||||||
if( !memcmp( p->rgucMD5_hash, rgucMD5_hash, 16 ))
|
if( !memcmp( p->rgucMD5_hash, rgucMD5_hash, 16 ))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if( p->type == t_sound )
|
|
||||||
{
|
|
||||||
const char *pfilename = filename;
|
|
||||||
|
|
||||||
if( !Q_strnicmp( filename, DEFAULT_SOUNDPATH, sound_len ))
|
|
||||||
pfilename += sound_len;
|
|
||||||
|
|
||||||
if( !Q_stricmp( p->szFileName, pfilename ))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( !Q_stricmp( p->szFileName, filename ))
|
if( p->type == t_generic )
|
||||||
|
{
|
||||||
|
if( !Q_stricmp( p->szFileName, filename ))
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( !Q_stricmp( p->szFileName, pfilename ))
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2622,7 +2600,7 @@ void CL_ProcessFile( qboolean successfully_received, const char *filename )
|
|||||||
|
|
||||||
if( cls.netchan.tempbuffer )
|
if( cls.netchan.tempbuffer )
|
||||||
{
|
{
|
||||||
Con_Printf( "Received a decal %s, but didn't find it in resources needed list!\n", filename );
|
Con_Printf( "Received a decal %s, but didn't find it in resources needed list!\n", pfilename );
|
||||||
Mem_Free( cls.netchan.tempbuffer );
|
Mem_Free( cls.netchan.tempbuffer );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2715,32 +2693,10 @@ static void CL_Physinfo_f( void )
|
|||||||
Con_Printf( "Total %i symbols\n", Q_strlen( cls.physinfo ));
|
Con_Printf( "Total %i symbols\n", Q_strlen( cls.physinfo ));
|
||||||
}
|
}
|
||||||
|
|
||||||
static qboolean CL_ShouldRescanFilesystem( void )
|
|
||||||
{
|
|
||||||
resource_t *res;
|
|
||||||
|
|
||||||
for( res = cl.resourcesonhand.pNext; res && res != &cl.resourcesonhand; res = res->pNext )
|
|
||||||
{
|
|
||||||
if( res->type == t_generic )
|
|
||||||
{
|
|
||||||
const char *ext = COM_FileExtension( res->szFileName );
|
|
||||||
// TODO: query supported archives format from fs_stdio
|
|
||||||
// TODO: query if was already opened
|
|
||||||
if( !Q_stricmp( ext, "wad" ) || !Q_stricmp( ext, "pk3" ) || !Q_stricmp( ext, "pak" ))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
qboolean CL_PrecacheResources( void )
|
qboolean CL_PrecacheResources( void )
|
||||||
{
|
{
|
||||||
resource_t *pRes;
|
resource_t *pRes;
|
||||||
|
|
||||||
// if we downloaded new WAD files or any other archives they must be added to searchpath
|
|
||||||
if( CL_ShouldRescanFilesystem( ))
|
|
||||||
g_fsapi.Rescan();
|
|
||||||
|
|
||||||
// NOTE: world need to be loaded as first model
|
// NOTE: world need to be loaded as first model
|
||||||
for( pRes = cl.resourcesonhand.pNext; pRes && pRes != &cl.resourcesonhand; pRes = pRes->pNext )
|
for( pRes = cl.resourcesonhand.pNext; pRes && pRes != &cl.resourcesonhand; pRes = pRes->pNext )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -458,7 +458,6 @@ void CL_BatchResourceRequest( qboolean initialize )
|
|||||||
byte data[MAX_INIT_MSG];
|
byte data[MAX_INIT_MSG];
|
||||||
resource_t *p, *n;
|
resource_t *p, *n;
|
||||||
sizebuf_t msg;
|
sizebuf_t msg;
|
||||||
qboolean done_downloading = true;
|
|
||||||
|
|
||||||
MSG_Init( &msg, "Resource Batch", data, sizeof( data ));
|
MSG_Init( &msg, "Resource Batch", data, sizeof( data ));
|
||||||
|
|
||||||
@@ -488,10 +487,7 @@ void CL_BatchResourceRequest( qboolean initialize )
|
|||||||
case t_model:
|
case t_model:
|
||||||
case t_eventscript:
|
case t_eventscript:
|
||||||
if( !CL_CheckFile( &msg, p ))
|
if( !CL_CheckFile( &msg, p ))
|
||||||
{
|
|
||||||
done_downloading = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
CL_MoveToOnHandList( p );
|
CL_MoveToOnHandList( p );
|
||||||
break;
|
break;
|
||||||
case t_skin:
|
case t_skin:
|
||||||
@@ -505,7 +501,6 @@ void CL_BatchResourceRequest( qboolean initialize )
|
|||||||
MSG_BeginClientCmd( &msg, clc_stringcmd );
|
MSG_BeginClientCmd( &msg, clc_stringcmd );
|
||||||
MSG_WriteStringf( &msg, "dlfile !MD5%s", MD5_Print( p->rgucMD5_hash ));;
|
MSG_WriteStringf( &msg, "dlfile !MD5%s", MD5_Print( p->rgucMD5_hash ));;
|
||||||
SetBits( p->ucFlags, RES_REQUESTED );
|
SetBits( p->ucFlags, RES_REQUESTED );
|
||||||
done_downloading = false;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -530,7 +525,11 @@ void CL_BatchResourceRequest( qboolean initialize )
|
|||||||
|
|
||||||
if( cls.state != ca_disconnected )
|
if( cls.state != ca_disconnected )
|
||||||
{
|
{
|
||||||
if( done_downloading && CL_PrecacheResources( ))
|
if( !cl.downloadUrl[0] && !MSG_GetNumBytesWritten( &msg ) && CL_PrecacheResources( ))
|
||||||
|
{
|
||||||
|
CL_RegisterResources( &msg );
|
||||||
|
}
|
||||||
|
if( cl.downloadUrl[0] && host.downloadcount == 0 && CL_PrecacheResources( ) )
|
||||||
{
|
{
|
||||||
CL_RegisterResources( &msg );
|
CL_RegisterResources( &msg );
|
||||||
}
|
}
|
||||||
@@ -1841,10 +1840,13 @@ void CL_ParseResLocation( sizebuf_t *msg )
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(( data = COM_ParseFile( data, token, sizeof( token ))))
|
while( ( data = COM_ParseFile( data, token, sizeof( token ) ) ) )
|
||||||
{
|
{
|
||||||
Con_Reportf( "Adding %s as download location\n", token );
|
Con_Reportf( "Adding %s as download location\n", token );
|
||||||
cl.http_download = true;
|
|
||||||
|
if( !cl.downloadUrl[0] )
|
||||||
|
Q_strncpy( cl.downloadUrl, token, sizeof( token ) );
|
||||||
|
|
||||||
HTTP_AddCustomServer( token );
|
HTTP_AddCustomServer( token );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1875,12 +1877,8 @@ void CL_ParseHLTV( sizebuf_t *msg )
|
|||||||
break;
|
break;
|
||||||
case HLTV_LISTEN:
|
case HLTV_LISTEN:
|
||||||
cls.signon = SIGNONS;
|
cls.signon = SIGNONS;
|
||||||
#if 1
|
|
||||||
MSG_ReadString( msg );
|
|
||||||
#else
|
|
||||||
NET_StringToAdr( MSG_ReadString( msg ), &cls.hltv_listen_address );
|
NET_StringToAdr( MSG_ReadString( msg ), &cls.hltv_listen_address );
|
||||||
NET_JoinGroup( cls.netchan.sock, cls.hltv_listen_address );
|
// NET_JoinGroup( cls.netchan.sock, cls.hltv_listen_address );
|
||||||
#endif
|
|
||||||
SCR_EndLoadingPlaque();
|
SCR_EndLoadingPlaque();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ static void CL_LegacyPrecacheModel( sizebuf_t *msg )
|
|||||||
if( modelIndex < 0 || modelIndex >= MAX_MODELS )
|
if( modelIndex < 0 || modelIndex >= MAX_MODELS )
|
||||||
Host_Error( "CL_PrecacheModel: bad modelindex %i\n", modelIndex );
|
Host_Error( "CL_PrecacheModel: bad modelindex %i\n", modelIndex );
|
||||||
|
|
||||||
Q_strncpy( model, MSG_ReadString( msg ), sizeof( model ));
|
Q_strncpy( model, MSG_ReadString( msg ), MAX_STRING );
|
||||||
//Q_strncpy( cl.model_precache[modelIndex], BF_ReadString( msg ), sizeof( cl.model_precache[0] ));
|
//Q_strncpy( cl.model_precache[modelIndex], BF_ReadString( msg ), sizeof( cl.model_precache[0] ));
|
||||||
|
|
||||||
// when we loading map all resources is precached sequentially
|
// when we loading map all resources is precached sequentially
|
||||||
@@ -261,7 +261,7 @@ static void CL_LegacyParseResourceList( sizebuf_t *msg )
|
|||||||
for( i = 0; i < reslist.rescount; i++ )
|
for( i = 0; i < reslist.rescount; i++ )
|
||||||
{
|
{
|
||||||
reslist.restype[i] = MSG_ReadWord( msg );
|
reslist.restype[i] = MSG_ReadWord( msg );
|
||||||
Q_strncpy( reslist.resnames[i], MSG_ReadString( msg ), sizeof( reslist.resnames[i] ));
|
Q_strncpy( reslist.resnames[i], MSG_ReadString( msg ), MAX_QPATH );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( CL_IsPlaybackDemo() )
|
if( CL_IsPlaybackDemo() )
|
||||||
|
|||||||
@@ -853,7 +853,7 @@ static void CL_SetupPMove( playermove_t *pmove, const local_state_t *from, const
|
|||||||
VectorCopy( cd->vuser4, pmove->vuser4 );
|
VectorCopy( cd->vuser4, pmove->vuser4 );
|
||||||
pmove->cmd = *ucmd; // copy current cmds
|
pmove->cmd = *ucmd; // copy current cmds
|
||||||
|
|
||||||
Q_strncpy( pmove->physinfo, cls.physinfo, sizeof( pmove->physinfo ));
|
Q_strncpy( pmove->physinfo, cls.physinfo, MAX_INFO_STRING );
|
||||||
}
|
}
|
||||||
|
|
||||||
static const void CL_FinishPMove( const playermove_t *pmove, local_state_t *to )
|
static const void CL_FinishPMove( const playermove_t *pmove, local_state_t *to )
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ static void CL_ParseQuakeServerInfo( sizebuf_t *msg )
|
|||||||
clgame.maxEntities = GI->max_edicts;
|
clgame.maxEntities = GI->max_edicts;
|
||||||
clgame.maxEntities = bound( 600, clgame.maxEntities, MAX_EDICTS );
|
clgame.maxEntities = bound( 600, clgame.maxEntities, MAX_EDICTS );
|
||||||
clgame.maxModels = MAX_MODELS;
|
clgame.maxModels = MAX_MODELS;
|
||||||
Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), sizeof( clgame.maptitle ));
|
Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), MAX_STRING );
|
||||||
|
|
||||||
// Re-init hud video, especially if we changed game directories
|
// Re-init hud video, especially if we changed game directories
|
||||||
clgame.dllFuncs.pfnVidInit();
|
clgame.dllFuncs.pfnVidInit();
|
||||||
@@ -844,7 +844,7 @@ static void CL_QuakeExecStuff( void )
|
|||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
// skip whitespace up to a /n
|
// skip whitespace up to a /n
|
||||||
while( *text && ((byte)*text ) <= ' ' && *text != '\r' && *text != '\n' )
|
while( *text && ((byte)*text) <= ' ' && *text != '\r' && *text != '\n' )
|
||||||
text++;
|
text++;
|
||||||
|
|
||||||
if( *text == '\n' || *text == '\r' )
|
if( *text == '\n' || *text == '\r' )
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ GNU General Public License for more details.
|
|||||||
|
|
||||||
int R_FatPVS( const vec3_t org, float radius, byte *visbuffer, qboolean merge, qboolean fullvis )
|
int R_FatPVS( const vec3_t org, float radius, byte *visbuffer, qboolean merge, qboolean fullvis )
|
||||||
{
|
{
|
||||||
return Mod_FatPVS( org, radius, visbuffer, world.visbytes, merge, fullvis, false );
|
return Mod_FatPVS( org, radius, visbuffer, world.visbytes, merge, fullvis );
|
||||||
}
|
}
|
||||||
|
|
||||||
lightstyle_t *CL_GetLightStyle( int number )
|
lightstyle_t *CL_GetLightStyle( int number )
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ typedef struct
|
|||||||
char serverinfo[MAX_SERVERINFO_STRING];
|
char serverinfo[MAX_SERVERINFO_STRING];
|
||||||
player_info_t players[MAX_CLIENTS]; // collected info about all other players include himself
|
player_info_t players[MAX_CLIENTS]; // collected info about all other players include himself
|
||||||
double lastresourcecheck;
|
double lastresourcecheck;
|
||||||
qboolean http_download;
|
string downloadUrl;
|
||||||
event_state_t events;
|
event_state_t events;
|
||||||
|
|
||||||
// predicting stuff but not only...
|
// predicting stuff but not only...
|
||||||
@@ -276,8 +276,6 @@ typedef struct
|
|||||||
model_t *worldmodel; // pointer to world
|
model_t *worldmodel; // pointer to world
|
||||||
|
|
||||||
int lostpackets; // count lost packets and show dialog in menu
|
int lostpackets; // count lost packets and show dialog in menu
|
||||||
|
|
||||||
double frametime_remainder;
|
|
||||||
} client_t;
|
} client_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -520,7 +518,7 @@ typedef struct
|
|||||||
int logo_yres;
|
int logo_yres;
|
||||||
float logo_length;
|
float logo_length;
|
||||||
|
|
||||||
qboolean use_extended_api;
|
qboolean use_text_api;
|
||||||
} gameui_static_t;
|
} gameui_static_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -541,8 +539,12 @@ typedef struct
|
|||||||
|
|
||||||
poolhandle_t mempool; // client premamnent pool: edicts etc
|
poolhandle_t mempool; // client premamnent pool: edicts etc
|
||||||
|
|
||||||
int signon; // 0 to SIGNONS, for the signon sequence.
|
netadr_t hltv_listen_address;
|
||||||
|
|
||||||
|
int signon; // 0 to SIGNONS, for the signon sequence.
|
||||||
|
int quakePort; // a 16 bit value that allows quake servers
|
||||||
|
// to work around address translating routers
|
||||||
|
// g-cont. this port allow many copies of engine in multiplayer game
|
||||||
// connection information
|
// connection information
|
||||||
char servername[MAX_QPATH]; // name of server from original connect
|
char servername[MAX_QPATH]; // name of server from original connect
|
||||||
double connect_time; // for connection retransmits
|
double connect_time; // for connection retransmits
|
||||||
@@ -632,9 +634,6 @@ typedef struct
|
|||||||
int extensions;
|
int extensions;
|
||||||
|
|
||||||
netadr_t serveradr;
|
netadr_t serveradr;
|
||||||
|
|
||||||
// do we accept utf8 as input
|
|
||||||
qboolean accept_utf8;
|
|
||||||
} client_static_t;
|
} client_static_t;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ GNU General Public License for more details.
|
|||||||
#include "qfont.h"
|
#include "qfont.h"
|
||||||
#include "wadfile.h"
|
#include "wadfile.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "utflib.h"
|
|
||||||
|
|
||||||
static CVAR_DEFINE_AUTO( scr_conspeed, "600", FCVAR_ARCHIVE, "console moving speed" );
|
static CVAR_DEFINE_AUTO( scr_conspeed, "600", FCVAR_ARCHIVE, "console moving speed" );
|
||||||
static CVAR_DEFINE_AUTO( con_notifytime, "3", FCVAR_ARCHIVE, "notify time to live" );
|
static CVAR_DEFINE_AUTO( con_notifytime, "3", FCVAR_ARCHIVE, "notify time to live" );
|
||||||
@@ -35,6 +34,7 @@ static CVAR_DEFINE_AUTO( scr_drawversion, "1", FCVAR_ARCHIVE, "draw version in m
|
|||||||
static CVAR_DEFINE_AUTO( con_oldfont, "0", 0, "use legacy font from gfx.wad, might be missing or broken" );
|
static CVAR_DEFINE_AUTO( con_oldfont, "0", 0, "use legacy font from gfx.wad, might be missing or broken" );
|
||||||
|
|
||||||
static int g_codepage = 0;
|
static int g_codepage = 0;
|
||||||
|
static qboolean g_utf8 = false;
|
||||||
|
|
||||||
static qboolean g_messagemode_privileged = true;
|
static qboolean g_messagemode_privileged = true;
|
||||||
|
|
||||||
@@ -610,6 +610,19 @@ static void Con_LoadConchars( void )
|
|||||||
con.curFont = &con.chars[fontSize];
|
con.curFont = &con.chars[fontSize];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CP1251 table
|
||||||
|
|
||||||
|
int table_cp1251[64] = {
|
||||||
|
0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
|
||||||
|
0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
|
||||||
|
0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
|
||||||
|
0x007F, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
|
||||||
|
0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
|
||||||
|
0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
|
||||||
|
0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
|
||||||
|
0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
============================
|
============================
|
||||||
Con_UtfProcessChar
|
Con_UtfProcessChar
|
||||||
@@ -619,28 +632,84 @@ Convert utf char to current font's single-byte encoding
|
|||||||
*/
|
*/
|
||||||
int Con_UtfProcessCharForce( int in )
|
int Con_UtfProcessCharForce( int in )
|
||||||
{
|
{
|
||||||
// TODO: get rid of global state where possible
|
static int m = -1, k = 0; //multibyte state
|
||||||
static utfstate_t state = { 0 };
|
static int uc = 0; //unicode char
|
||||||
|
|
||||||
int ch = Q_DecodeUTF8( &state, in );
|
if( !in )
|
||||||
|
{
|
||||||
|
m = -1;
|
||||||
|
k = 0;
|
||||||
|
uc = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if( g_codepage == 1251 )
|
// Get character length
|
||||||
return Q_UnicodeToCP1251( ch );
|
if(m == -1)
|
||||||
if( g_codepage == 1252 )
|
{
|
||||||
return Q_UnicodeToCP1252( ch );
|
uc = 0;
|
||||||
|
if( in >= 0xF8 )
|
||||||
|
return 0;
|
||||||
|
else if( in >= 0xF0 )
|
||||||
|
uc = in & 0x07, m = 3;
|
||||||
|
else if( in >= 0xE0 )
|
||||||
|
uc = in & 0x0F, m = 2;
|
||||||
|
else if( in >= 0xC0 )
|
||||||
|
uc = in & 0x1F, m = 1;
|
||||||
|
else if( in <= 0x7F)
|
||||||
|
return in; //ascii
|
||||||
|
// return 0 if we need more chars to decode one
|
||||||
|
k=0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// get more chars
|
||||||
|
else if( k <= m )
|
||||||
|
{
|
||||||
|
uc <<= 6;
|
||||||
|
uc += in & 0x3F;
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
if( in > 0xBF || m < 0 )
|
||||||
|
{
|
||||||
|
m = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if( k == m )
|
||||||
|
{
|
||||||
|
k = m = -1;
|
||||||
|
if( g_codepage == 1251 )
|
||||||
|
{
|
||||||
|
// cp1251 now
|
||||||
|
if( uc >= 0x0410 && uc <= 0x042F )
|
||||||
|
return uc - 0x410 + 0xC0;
|
||||||
|
if( uc >= 0x0430 && uc <= 0x044F )
|
||||||
|
return uc - 0x430 + 0xE0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for( i = 0; i < 64; i++ )
|
||||||
|
if( table_cp1251[i] == uc )
|
||||||
|
return i + 0x80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( g_codepage == 1252 )
|
||||||
|
{
|
||||||
|
if( uc < 255 )
|
||||||
|
return uc;
|
||||||
|
}
|
||||||
|
|
||||||
return '?'; // not implemented yet
|
// not implemented yet
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GAME_EXPORT Con_UtfProcessChar( int in )
|
int GAME_EXPORT Con_UtfProcessChar( int in )
|
||||||
{
|
{
|
||||||
if( !cls.accept_utf8 ) // incoming character is not a UTF-8 sequence
|
if( !g_utf8 )
|
||||||
return in;
|
return in;
|
||||||
|
else
|
||||||
// otherwise, decode it and convert to selected codepage
|
return Con_UtfProcessCharForce( in );
|
||||||
return Con_UtfProcessCharForce( in );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
Con_UtfMoveLeft
|
Con_UtfMoveLeft
|
||||||
@@ -650,22 +719,16 @@ get position of previous printful char
|
|||||||
*/
|
*/
|
||||||
int Con_UtfMoveLeft( char *str, int pos )
|
int Con_UtfMoveLeft( char *str, int pos )
|
||||||
{
|
{
|
||||||
utfstate_t state = { 0 };
|
int i, k = 0;
|
||||||
int k = 0;
|
// int j;
|
||||||
int i;
|
if( !g_utf8 )
|
||||||
|
|
||||||
if( !cls.accept_utf8 ) // incoming character is not a UTF-8 sequence
|
|
||||||
return pos - 1;
|
return pos - 1;
|
||||||
|
Con_UtfProcessChar( 0 );
|
||||||
if( pos == 1 )
|
if(pos == 1) return 0;
|
||||||
return 0;
|
for( i = 0; i < pos-1; i++ )
|
||||||
|
if( Con_UtfProcessChar( (unsigned char)str[i] ) )
|
||||||
for( i = 0; i < pos - 1; i++ )
|
k = i+1;
|
||||||
{
|
Con_UtfProcessChar( 0 );
|
||||||
if( Q_DecodeUTF8( &state, (byte)str[i] ))
|
|
||||||
k = i + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -678,19 +741,17 @@ get next of previous printful char
|
|||||||
*/
|
*/
|
||||||
int Con_UtfMoveRight( char *str, int pos, int length )
|
int Con_UtfMoveRight( char *str, int pos, int length )
|
||||||
{
|
{
|
||||||
utfstate_t state = { 0 };
|
|
||||||
int i;
|
int i;
|
||||||
|
if( !g_utf8 )
|
||||||
if( !cls.accept_utf8 ) // incoming character is not a UTF-8 sequence
|
|
||||||
return pos + 1;
|
return pos + 1;
|
||||||
|
Con_UtfProcessChar( 0 );
|
||||||
for( i = pos; i <= length; i++ )
|
for( i = pos; i <= length; i++ )
|
||||||
{
|
{
|
||||||
if( Q_DecodeUTF8( &state, (byte)str[i] ))
|
if( Con_UtfProcessChar( (unsigned char)str[i] ) )
|
||||||
return i + 1;
|
return i+1;
|
||||||
}
|
}
|
||||||
|
Con_UtfProcessChar( 0 );
|
||||||
return pos + 1;
|
return pos+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Con_DrawCharToConback( int num, const byte *conchars, byte *dest )
|
static void Con_DrawCharToConback( int num, const byte *conchars, byte *dest )
|
||||||
@@ -1064,7 +1125,7 @@ Con_ClearField
|
|||||||
*/
|
*/
|
||||||
static void Con_ClearField( field_t *edit )
|
static void Con_ClearField( field_t *edit )
|
||||||
{
|
{
|
||||||
memset( edit->buffer, 0, sizeof( edit->buffer ));
|
memset( edit->buffer, 0, MAX_STRING );
|
||||||
edit->cursor = 0;
|
edit->cursor = 0;
|
||||||
edit->scroll = 0;
|
edit->scroll = 0;
|
||||||
}
|
}
|
||||||
@@ -1077,7 +1138,7 @@ Field_Set
|
|||||||
static void Field_Set( field_t *f, const char *string )
|
static void Field_Set( field_t *f, const char *string )
|
||||||
{
|
{
|
||||||
f->scroll = 0;
|
f->scroll = 0;
|
||||||
f->cursor = Q_strncpy( f->buffer, string, sizeof( f->buffer ));
|
f->cursor = Q_strncpy( f->buffer, string, MAX_STRING );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1383,49 +1444,36 @@ static void Con_HistoryAppend( con_history_t *self, field_t *from )
|
|||||||
|
|
||||||
static void Con_LoadHistory( con_history_t *self )
|
static void Con_LoadHistory( con_history_t *self )
|
||||||
{
|
{
|
||||||
|
const byte *aFile = FS_LoadFile( "console_history.txt", NULL, true );
|
||||||
|
const char *pLine, *pFile;
|
||||||
|
int i, len;
|
||||||
field_t *f;
|
field_t *f;
|
||||||
file_t *fd;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
fd = FS_Open( "console_history.txt", "rb", true );
|
if( !aFile )
|
||||||
|
|
||||||
if( !fd )
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
while( !FS_Eof( fd ))
|
for( pFile = pLine = (char *)aFile; *pFile; pFile++ )
|
||||||
{
|
{
|
||||||
f = &self->lines[self->next % CON_HISTORY];
|
if( *pFile != '\n' )
|
||||||
|
|
||||||
Con_ClearField( f );
|
|
||||||
f->widthInChars = con.linewidth;
|
|
||||||
|
|
||||||
FS_Gets( fd, f->buffer, sizeof( f->buffer ));
|
|
||||||
f->cursor = Q_strlen( f->buffer );
|
|
||||||
|
|
||||||
// skip empty lines
|
|
||||||
if( f->cursor == 0 )
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// skip repeating lines
|
Con_ClearField( &self->lines[self->next] );
|
||||||
if( self->next > 0 )
|
|
||||||
{
|
len = Q_min( pFile - pLine + 1, sizeof( f->buffer ));
|
||||||
field_t *prev;
|
f = &self->lines[self->next % CON_HISTORY];
|
||||||
prev = &self->lines[(self->next - 1) % CON_HISTORY];
|
f->widthInChars = con.linewidth;
|
||||||
if( !Q_stricmp( prev->buffer, f->buffer ))
|
f->cursor = len - 1;
|
||||||
continue;
|
Q_strncpy( f->buffer, pLine, len);
|
||||||
}
|
|
||||||
|
|
||||||
self->next++;
|
self->next++;
|
||||||
}
|
|
||||||
|
|
||||||
FS_Close( fd );
|
pLine = pFile + 1;
|
||||||
|
}
|
||||||
|
|
||||||
for( i = self->next; i < CON_HISTORY; i++ )
|
for( i = self->next; i < CON_HISTORY; i++ )
|
||||||
{
|
{
|
||||||
f = &self->lines[i];
|
Con_ClearField( &self->lines[i] );
|
||||||
|
self->lines[i].widthInChars = con.linewidth;
|
||||||
Con_ClearField( f );
|
|
||||||
f->widthInChars = con.linewidth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self->line = self->next;
|
self->line = self->next;
|
||||||
@@ -1443,7 +1491,7 @@ static void Con_SaveHistory( con_history_t *self )
|
|||||||
if( historyStart < 0 )
|
if( historyStart < 0 )
|
||||||
historyStart = 0;
|
historyStart = 0;
|
||||||
|
|
||||||
f = FS_Open( "console_history.txt", "wb", true );
|
f = FS_Open( "console_history.txt", "w", true );
|
||||||
|
|
||||||
for( i = historyStart; i < self->next; i++ )
|
for( i = historyStart; i < self->next; i++ )
|
||||||
FS_Printf( f, "%s\n", self->lines[i % CON_HISTORY].buffer );
|
FS_Printf( f, "%s\n", self->lines[i % CON_HISTORY].buffer );
|
||||||
@@ -1488,9 +1536,6 @@ void Key_Console( int key )
|
|||||||
Con_Printf( ">%s\n", con.input.buffer );
|
Con_Printf( ">%s\n", con.input.buffer );
|
||||||
|
|
||||||
// copy line to history buffer
|
// copy line to history buffer
|
||||||
// just in case, remove all CR and LF characters pushing it to the history
|
|
||||||
// not sure how they get even added in the first place
|
|
||||||
COM_RemoveLineFeed( con.input.buffer, sizeof( con.input.buffer ));
|
|
||||||
Con_HistoryAppend( &con.history, &con.input );
|
Con_HistoryAppend( &con.history, &con.input );
|
||||||
|
|
||||||
Con_ClearField( &con.input );
|
Con_ClearField( &con.input );
|
||||||
@@ -2099,7 +2144,7 @@ void Con_RunConsole( void )
|
|||||||
g_codepage = 1252;
|
g_codepage = 1252;
|
||||||
}
|
}
|
||||||
|
|
||||||
cls.accept_utf8 = !Q_stricmp( cl_charset.string, "utf-8" );
|
g_utf8 = !Q_stricmp( cl_charset.string, "utf-8" );
|
||||||
Con_InvalidateFonts();
|
Con_InvalidateFonts();
|
||||||
Con_LoadConchars();
|
Con_LoadConchars();
|
||||||
ClearBits( con_charset.flags, FCVAR_CHANGED );
|
ClearBits( con_charset.flags, FCVAR_CHANGED );
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ GNU General Public License for more details.
|
|||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "vgui_draw.h"
|
#include "vgui_draw.h"
|
||||||
#include "cursor_type.h"
|
|
||||||
|
|
||||||
#if XASH_SDL
|
#if XASH_SDL
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
@@ -124,6 +123,11 @@ static void IN_StartupMouse( void )
|
|||||||
in_mouseinitialized = true;
|
in_mouseinitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GAME_EXPORT IN_SetCursor( void *hCursor )
|
||||||
|
{
|
||||||
|
// stub
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===========
|
===========
|
||||||
IN_MouseSavePos
|
IN_MouseSavePos
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ void IN_DeactivateMouse( void );
|
|||||||
void IN_MouseSavePos( void );
|
void IN_MouseSavePos( void );
|
||||||
void IN_MouseRestorePos( void );
|
void IN_MouseRestorePos( void );
|
||||||
void IN_ToggleClientMouse( int newstate, int oldstate );
|
void IN_ToggleClientMouse( int newstate, int oldstate );
|
||||||
|
void IN_SetCursor( void *hCursor );
|
||||||
|
|
||||||
uint IN_CollectInputDevices( void );
|
uint IN_CollectInputDevices( void );
|
||||||
void IN_LockInputDevices( qboolean lock );
|
void IN_LockInputDevices( qboolean lock );
|
||||||
|
|||||||
@@ -553,7 +553,7 @@ static void Key_AddKeyCommands( int key, const char *kb, qboolean down )
|
|||||||
}
|
}
|
||||||
|
|
||||||
buttonPtr = button;
|
buttonPtr = button;
|
||||||
while((((byte)kb[i]) <= ' ' || kb[i] == ';' ) && kb[i] != 0 )
|
while(( kb[i] <= ' ' || kb[i] == ';' ) && kb[i] != 0 )
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -749,10 +749,10 @@ void GAME_EXPORT Key_Event( int key, int down )
|
|||||||
if( cls.key_dest == key_menu )
|
if( cls.key_dest == key_menu )
|
||||||
{
|
{
|
||||||
// only non printable keys passed
|
// only non printable keys passed
|
||||||
if( !gameui.use_extended_api )
|
if( !gameui.use_text_api )
|
||||||
Key_EnableTextInput( true, false );
|
Key_EnableTextInput( true, false );
|
||||||
//pass printable chars for old menus
|
//pass printable chars for old menus
|
||||||
if( !gameui.use_extended_api && !host.textmode && down && ( key >= 32 ) && ( key <= 'z' ) )
|
if( !gameui.use_text_api && !host.textmode && down && ( key >= 32 ) && ( key <= 'z' ) )
|
||||||
{
|
{
|
||||||
if( Key_IsDown( K_SHIFT ) )
|
if( Key_IsDown( K_SHIFT ) )
|
||||||
{
|
{
|
||||||
@@ -1055,16 +1055,18 @@ static qboolean OSK_KeyEvent( int key, int down )
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ch = (byte)osk.curbutton.val;
|
if( !Q_stricmp( cl_charset.string, "utf-8" ) )
|
||||||
|
ch = (unsigned char)osk.curbutton.val;
|
||||||
// do not pass UTF-8 sequence into the engine, convert it here
|
else
|
||||||
if( !cls.accept_utf8 )
|
ch = Con_UtfProcessCharForce( (unsigned char)osk.curbutton.val );
|
||||||
ch = Con_UtfProcessCharForce( ch );
|
|
||||||
|
|
||||||
if( !ch )
|
if( !ch )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
CL_CharEvent( ch );
|
Con_CharEvent( ch );
|
||||||
|
if( cls.key_dest == key_menu )
|
||||||
|
UI_CharEvent ( ch );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1119,6 +1121,7 @@ static void OSK_EnableTextInput( qboolean enable, qboolean force )
|
|||||||
{
|
{
|
||||||
osk.curlayout = 0;
|
osk.curlayout = 0;
|
||||||
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -685,9 +685,6 @@ void Mod_CreatePolygonsForHull( int hullnum )
|
|||||||
if( hullnum < 1 || hullnum > 3 )
|
if( hullnum < 1 || hullnum > 3 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( !world.num_hull_models )
|
|
||||||
Mod_InitDebugHulls( mod ); // FIXME: build hulls for separate bmodels (shells, medkits etc)
|
|
||||||
|
|
||||||
Con_Printf( "generating polygons for hull %u...\n", hullnum );
|
Con_Printf( "generating polygons for hull %u...\n", hullnum );
|
||||||
start = Sys_DoubleTime();
|
start = Sys_DoubleTime();
|
||||||
|
|
||||||
|
|||||||
@@ -565,7 +565,7 @@ static void R_CollectRendererNames( void )
|
|||||||
"GL4ES",
|
"GL4ES",
|
||||||
#endif
|
#endif
|
||||||
#if XASH_REF_GLES3COMPAT_ENABLED
|
#if XASH_REF_GLES3COMPAT_ENABLED
|
||||||
"GLES3 (gl2_shim)",
|
"GLES3 (gl2_shim)"
|
||||||
#endif
|
#endif
|
||||||
#if XASH_REF_SOFT_ENABLED
|
#if XASH_REF_SOFT_ENABLED
|
||||||
"Software",
|
"Software",
|
||||||
|
|||||||
@@ -18,18 +18,19 @@ GNU General Public License for more details.
|
|||||||
|
|
||||||
#include "ref_api.h"
|
#include "ref_api.h"
|
||||||
|
|
||||||
#define RP_LOCALCLIENT( e ) ((e) != NULL && (e)->index == ( cl.playernum + 1 ) && e->player )
|
#define RP_LOCALCLIENT( e ) ((e) != NULL && (e)->index == ( cl.playernum + 1 ) && e->player )
|
||||||
|
|
||||||
struct ref_state_s
|
struct ref_state_s
|
||||||
{
|
{
|
||||||
HINSTANCE hInstance;
|
qboolean initialized;
|
||||||
qboolean initialized;
|
|
||||||
int numRenderers;
|
HINSTANCE hInstance;
|
||||||
ref_interface_t dllFuncs;
|
ref_interface_t dllFuncs;
|
||||||
|
|
||||||
// depends on build configuration
|
// depends on build configuration
|
||||||
const char **shortNames;
|
int numRenderers;
|
||||||
const char **readableNames;
|
const char **shortNames;
|
||||||
|
const char **readableNames;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct ref_state_s ref;
|
extern struct ref_state_s ref;
|
||||||
@@ -45,8 +46,8 @@ void R_GetTextureParms( int *w, int *h, int texnum );
|
|||||||
void GL_RenderFrame( const struct ref_viewpass_s *rvp );
|
void GL_RenderFrame( const struct ref_viewpass_s *rvp );
|
||||||
|
|
||||||
// common engine and renderer cvars
|
// common engine and renderer cvars
|
||||||
extern convar_t r_decals;
|
extern convar_t r_decals;
|
||||||
extern convar_t r_adjust_fov;
|
extern convar_t r_adjust_fov;
|
||||||
extern convar_t gl_clear;
|
extern convar_t gl_clear;
|
||||||
|
|
||||||
qboolean R_Init( void );
|
qboolean R_Init( void );
|
||||||
|
|||||||
@@ -154,8 +154,7 @@ static const sx_preset_t rgsxpre_hlalpha052[] =
|
|||||||
static const sx_preset_t *ptable = rgsxpre;
|
static const sx_preset_t *ptable = rgsxpre;
|
||||||
|
|
||||||
// cvars
|
// cvars
|
||||||
static CVAR_DEFINE_AUTO( dsp_off, "0", FCVAR_ARCHIVE, "disable DSP processing (deprecated)" );
|
static CVAR_DEFINE_AUTO( dsp_off, "0", FCVAR_ARCHIVE, "disable DSP processing" );
|
||||||
static CVAR_DEFINE_AUTO( room_off, "0", FCVAR_ARCHIVE, "disable DSP processing (GoldSrc compatible cvar)" );
|
|
||||||
static CVAR_DEFINE_AUTO( dsp_coeff_table, "0", FCVAR_ARCHIVE, "select DSP coefficient table: 0 for release or 1 for alpha 0.52" );
|
static CVAR_DEFINE_AUTO( dsp_coeff_table, "0", FCVAR_ARCHIVE, "select DSP coefficient table: 0 for release or 1 for alpha 0.52" );
|
||||||
static CVAR_DEFINE_AUTO( room_type, "0", 0, "current room type preset" );
|
static CVAR_DEFINE_AUTO( room_type, "0", 0, "current room type preset" );
|
||||||
|
|
||||||
@@ -233,7 +232,6 @@ void SX_Init( void )
|
|||||||
sxmod2cur = sxmod2 = 450 * ( idsp_dma_speed / SOUND_11k );
|
sxmod2cur = sxmod2 = 450 * ( idsp_dma_speed / SOUND_11k );
|
||||||
|
|
||||||
Cvar_RegisterVariable( &dsp_off );
|
Cvar_RegisterVariable( &dsp_off );
|
||||||
Cvar_RegisterVariable( &room_off );
|
|
||||||
Cvar_RegisterVariable( &dsp_coeff_table );
|
Cvar_RegisterVariable( &dsp_coeff_table );
|
||||||
|
|
||||||
Cvar_RegisterVariable( &roomwater_type );
|
Cvar_RegisterVariable( &roomwater_type );
|
||||||
@@ -811,7 +809,7 @@ DSP_Process
|
|||||||
*/
|
*/
|
||||||
void DSP_Process( portable_samplepair_t *pbfront, int sampleCount )
|
void DSP_Process( portable_samplepair_t *pbfront, int sampleCount )
|
||||||
{
|
{
|
||||||
if( dsp_off.value || room_off.value || !sampleCount )
|
if( dsp_off.value || !sampleCount )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// preset is already installed by CheckNewDspPresets
|
// preset is already installed by CheckNewDspPresets
|
||||||
@@ -845,7 +843,7 @@ CheckNewDspPresets
|
|||||||
*/
|
*/
|
||||||
void CheckNewDspPresets( void )
|
void CheckNewDspPresets( void )
|
||||||
{
|
{
|
||||||
if( dsp_off.value || room_off.value )
|
if( dsp_off.value != 0.0f )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( FBitSet( dsp_coeff_table.flags, FCVAR_CHANGED ))
|
if( FBitSet( dsp_coeff_table.flags, FCVAR_CHANGED ))
|
||||||
|
|||||||
@@ -52,11 +52,8 @@ void S_SoundList_f( void )
|
|||||||
{
|
{
|
||||||
totalSize += sc->size;
|
totalSize += sc->size;
|
||||||
|
|
||||||
if( FBitSet( sc->flags, SOUND_LOOPED ))
|
if( sc->loopStart >= 0 ) Con_Printf( "L" );
|
||||||
Con_Printf( "L" );
|
else Con_Printf( " " );
|
||||||
else
|
|
||||||
Con_Printf( " " );
|
|
||||||
|
|
||||||
if( sfx->name[0] == '*' || !Q_strncmp( sfx->name, DEFAULT_SOUNDPATH, sizeof( DEFAULT_SOUNDPATH ) - 1 ))
|
if( sfx->name[0] == '*' || !Q_strncmp( sfx->name, DEFAULT_SOUNDPATH, sizeof( DEFAULT_SOUNDPATH ) - 1 ))
|
||||||
Con_Printf( " (%2db) %s : %s\n", sc->width * 8, Q_memprint( sc->size ), sfx->name );
|
Con_Printf( " (%2db) %s : %s\n", sc->width * 8, Q_memprint( sc->size ), sfx->name );
|
||||||
else Con_Printf( " (%2db) %s : " DEFAULT_SOUNDPATH "%s\n", sc->width * 8, Q_memprint( sc->size ), sfx->name );
|
else Con_Printf( " (%2db) %s : " DEFAULT_SOUNDPATH "%s\n", sc->width * 8, Q_memprint( sc->size ), sfx->name );
|
||||||
@@ -113,7 +110,7 @@ static wavdata_t *S_CreateDefaultSound( void )
|
|||||||
|
|
||||||
sc->width = 2;
|
sc->width = 2;
|
||||||
sc->channels = 1;
|
sc->channels = 1;
|
||||||
sc->loopStart = 0;
|
sc->loopStart = -1;
|
||||||
sc->rate = SOUND_DMA_SPEED;
|
sc->rate = SOUND_DMA_SPEED;
|
||||||
sc->samples = SOUND_DMA_SPEED;
|
sc->samples = SOUND_DMA_SPEED;
|
||||||
sc->size = sc->samples * sc->width * sc->channels;
|
sc->size = sc->samples * sc->width * sc->channels;
|
||||||
@@ -158,7 +155,7 @@ wavdata_t *S_LoadSound( sfx_t *sfx )
|
|||||||
Sound_Process( &sc, SOUND_11k, sc->width, SOUND_RESAMPLE );
|
Sound_Process( &sc, SOUND_11k, sc->width, SOUND_RESAMPLE );
|
||||||
else if( sc->rate > SOUND_11k && sc->rate < SOUND_22k ) // some bad sounds
|
else if( sc->rate > SOUND_11k && sc->rate < SOUND_22k ) // some bad sounds
|
||||||
Sound_Process( &sc, SOUND_22k, sc->width, SOUND_RESAMPLE );
|
Sound_Process( &sc, SOUND_22k, sc->width, SOUND_RESAMPLE );
|
||||||
else if( sc->rate > SOUND_22k && sc->rate < SOUND_44k ) // some bad sounds
|
else if( sc->rate > SOUND_22k && sc->rate <= SOUND_32k ) // some bad sounds
|
||||||
Sound_Process( &sc, SOUND_44k, sc->width, SOUND_RESAMPLE );
|
Sound_Process( &sc, SOUND_44k, sc->width, SOUND_RESAMPLE );
|
||||||
|
|
||||||
sfx->cache = sc;
|
sfx->cache = sc;
|
||||||
@@ -221,7 +218,7 @@ sfx_t *S_FindName( const char *pname, int *pfInCache )
|
|||||||
sfx = &s_knownSfx[i];
|
sfx = &s_knownSfx[i];
|
||||||
memset( sfx, 0, sizeof( *sfx ));
|
memset( sfx, 0, sizeof( *sfx ));
|
||||||
if( pfInCache ) *pfInCache = false;
|
if( pfInCache ) *pfInCache = false;
|
||||||
Q_strncpy( sfx->name, name, sizeof( sfx->name ));
|
Q_strncpy( sfx->name, name, MAX_STRING );
|
||||||
sfx->servercount = cl.servercount;
|
sfx->servercount = cl.servercount;
|
||||||
sfx->hashValue = COM_HashKey( sfx->name, MAX_SFX_HASH );
|
sfx->hashValue = COM_HashKey( sfx->name, MAX_SFX_HASH );
|
||||||
|
|
||||||
@@ -380,7 +377,7 @@ S_InitSounds
|
|||||||
void S_InitSounds( void )
|
void S_InitSounds( void )
|
||||||
{
|
{
|
||||||
// create unused 0-entry
|
// create unused 0-entry
|
||||||
Q_strncpy( s_knownSfx->name, "*default", sizeof( s_knownSfx->name ));
|
Q_strncpy( s_knownSfx->name, "*default", MAX_QPATH );
|
||||||
s_knownSfx->hashValue = COM_HashKey( s_knownSfx->name, MAX_SFX_HASH );
|
s_knownSfx->hashValue = COM_HashKey( s_knownSfx->name, MAX_SFX_HASH );
|
||||||
s_knownSfx->hashNext = s_sfxHashList[s_knownSfx->hashValue];
|
s_knownSfx->hashNext = s_sfxHashList[s_knownSfx->hashValue];
|
||||||
s_sfxHashList[s_knownSfx->hashValue] = s_knownSfx;
|
s_sfxHashList[s_knownSfx->hashValue] = s_knownSfx;
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ CVAR_DEFINE_AUTO( s_lerping, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "apply interpo
|
|||||||
static CVAR_DEFINE( s_ambient_level, "ambient_level", "0.3", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "volume of environment noises (water and wind)" );
|
static CVAR_DEFINE( s_ambient_level, "ambient_level", "0.3", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "volume of environment noises (water and wind)" );
|
||||||
static CVAR_DEFINE( s_ambient_fade, "ambient_fade", "1000", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "rate of volume fading when client is moving" );
|
static CVAR_DEFINE( s_ambient_fade, "ambient_fade", "1000", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "rate of volume fading when client is moving" );
|
||||||
static CVAR_DEFINE_AUTO( s_combine_sounds, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "combine channels with same sounds" );
|
static CVAR_DEFINE_AUTO( s_combine_sounds, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "combine channels with same sounds" );
|
||||||
static CVAR_DEFINE_AUTO( snd_mute_losefocus, "1", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "silence the audio when game window loses focus" );
|
CVAR_DEFINE_AUTO( snd_mute_losefocus, "1", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "silence the audio when game window loses focus" );
|
||||||
CVAR_DEFINE_AUTO( s_test, "0", 0, "engine developer cvar for quick testing new features" );
|
CVAR_DEFINE_AUTO( s_test, "0", 0, "engine developer cvar for quick testing new features" );
|
||||||
CVAR_DEFINE_AUTO( s_samplecount, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "sample count (0 for default value)" );
|
CVAR_DEFINE_AUTO( s_samplecount, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "sample count (0 for default value)" );
|
||||||
CVAR_DEFINE_AUTO( s_warn_late_precache, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "warn about late precached sounds on client-side" );
|
CVAR_DEFINE_AUTO( s_warn_late_precache, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "warn about late precached sounds on client-side" );
|
||||||
@@ -64,18 +64,6 @@ float S_GetMasterVolume( void )
|
|||||||
{
|
{
|
||||||
float scale = 1.0f;
|
float scale = 1.0f;
|
||||||
|
|
||||||
if( host.status == HOST_NOFOCUS && snd_mute_losefocus.value != 0.0f )
|
|
||||||
{
|
|
||||||
// we return zero volume to keep sounds running
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( s_listener.inmenu && !ui_renderworld.value && !Host_IsLocalGame( ))
|
|
||||||
{
|
|
||||||
// mute sounds in menu when it's not transparent and we're in multiplayer
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !s_listener.inmenu && soundfade.percent != 0 )
|
if( !s_listener.inmenu && soundfade.percent != 0 )
|
||||||
{
|
{
|
||||||
scale = bound( 0.0f, soundfade.percent / 100.0f, 1.0f );
|
scale = bound( 0.0f, soundfade.percent / 100.0f, 1.0f );
|
||||||
@@ -334,7 +322,7 @@ channel_t *SND_PickDynamicChannel( int entnum, int channel, sfx_t *sfx, qboolean
|
|||||||
// don't restart looping sounds for the same entity
|
// don't restart looping sounds for the same entity
|
||||||
wavdata_t *sc = channels[first_to_die].sfx->cache;
|
wavdata_t *sc = channels[first_to_die].sfx->cache;
|
||||||
|
|
||||||
if( sc && FBitSet( sc->flags, SOUND_LOOPED ))
|
if( sc && sc->loopStart != -1 )
|
||||||
{
|
{
|
||||||
channel_t *ch = &channels[first_to_die];
|
channel_t *ch = &channels[first_to_die];
|
||||||
|
|
||||||
@@ -509,7 +497,7 @@ static void SND_Spatialize( channel_t *ch )
|
|||||||
|
|
||||||
pSource = ch->sfx->cache;
|
pSource = ch->sfx->cache;
|
||||||
|
|
||||||
if( ch->use_loop && pSource && FBitSet( pSource->flags, SOUND_LOOPED ))
|
if( ch->use_loop && pSource && pSource->loopStart != -1 )
|
||||||
looping = true;
|
looping = true;
|
||||||
|
|
||||||
if( !ch->staticsound )
|
if( !ch->staticsound )
|
||||||
@@ -647,7 +635,7 @@ void S_StartSound( const vec3_t pos, int ent, int chan, sound_t handle, float fv
|
|||||||
if( !target_chan->leftvol && !target_chan->rightvol )
|
if( !target_chan->leftvol && !target_chan->rightvol )
|
||||||
{
|
{
|
||||||
// looping sounds don't use this optimization because they should stick around until they're killed.
|
// looping sounds don't use this optimization because they should stick around until they're killed.
|
||||||
if( !sfx->cache || !FBitSet( sfx->cache->flags, SOUND_LOOPED ))
|
if( !sfx->cache || sfx->cache->loopStart == -1 )
|
||||||
{
|
{
|
||||||
// if this is a streaming sound, play the whole thing.
|
// if this is a streaming sound, play the whole thing.
|
||||||
if( chan != CHAN_STREAM )
|
if( chan != CHAN_STREAM )
|
||||||
@@ -899,7 +887,7 @@ int S_GetCurrentStaticSounds( soundlist_t *pout, int size )
|
|||||||
VectorCopy( channels[i].origin, pout->origin );
|
VectorCopy( channels[i].origin, pout->origin );
|
||||||
pout->volume = (float)channels[i].master_vol / 255.0f;
|
pout->volume = (float)channels[i].master_vol / 255.0f;
|
||||||
pout->attenuation = channels[i].dist_mult * SND_CLIP_DISTANCE;
|
pout->attenuation = channels[i].dist_mult * SND_CLIP_DISTANCE;
|
||||||
pout->looping = ( channels[i].use_loop && FBitSet( channels[i].sfx->cache->flags, SOUND_LOOPED ));
|
pout->looping = ( channels[i].use_loop && channels[i].sfx->cache->loopStart != -1 );
|
||||||
pout->pitch = channels[i].basePitch;
|
pout->pitch = channels[i].basePitch;
|
||||||
pout->channel = channels[i].entchannel;
|
pout->channel = channels[i].entchannel;
|
||||||
pout->wordIndex = channels[i].wordIndex;
|
pout->wordIndex = channels[i].wordIndex;
|
||||||
@@ -934,7 +922,7 @@ int S_GetCurrentDynamicSounds( soundlist_t *pout, int size )
|
|||||||
if( !channels[i].sfx || !channels[i].sfx->name[0] || !Q_stricmp( channels[i].sfx->name, "*default" ))
|
if( !channels[i].sfx || !channels[i].sfx->name[0] || !Q_stricmp( channels[i].sfx->name, "*default" ))
|
||||||
continue; // don't serialize default sounds
|
continue; // don't serialize default sounds
|
||||||
|
|
||||||
looped = ( channels[i].use_loop && FBitSet( channels[i].sfx->cache->flags, SOUND_LOOPED ));
|
looped = ( channels[i].use_loop && channels[i].sfx->cache->loopStart != -1 );
|
||||||
|
|
||||||
if( channels[i].entchannel == CHAN_STATIC && looped && !Host_IsQuakeCompatible())
|
if( channels[i].entchannel == CHAN_STATIC && looped && !Host_IsQuakeCompatible())
|
||||||
continue; // never serialize static looped sounds. It will be restoring in game code
|
continue; // never serialize static looped sounds. It will be restoring in game code
|
||||||
@@ -1605,6 +1593,7 @@ void SND_UpdateSound( void )
|
|||||||
// release raw-channels that no longer used more than 10 secs
|
// release raw-channels that no longer used more than 10 secs
|
||||||
S_FreeIdleRawChannels();
|
S_FreeIdleRawChannels();
|
||||||
|
|
||||||
|
VectorCopy( cl.simvel, s_listener.velocity );
|
||||||
s_listener.frametime = (cl.time - cl.oldtime);
|
s_listener.frametime = (cl.time - cl.oldtime);
|
||||||
s_listener.waterlevel = cl.local.waterlevel;
|
s_listener.waterlevel = cl.local.waterlevel;
|
||||||
s_listener.active = CL_IsInGame();
|
s_listener.active = CL_IsInGame();
|
||||||
|
|||||||
@@ -17,56 +17,30 @@ GNU General Public License for more details.
|
|||||||
#include "sound.h"
|
#include "sound.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
|
|
||||||
enum
|
#define IPAINTBUFFER 0
|
||||||
{
|
#define IROOMBUFFER 1
|
||||||
IPAINTBUFFER = 0,
|
#define ISTREAMBUFFER 2
|
||||||
IROOMBUFFER,
|
|
||||||
ISTREAMBUFFER,
|
|
||||||
CPAINTBUFFERS,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum
|
#define FILTERTYPE_NONE 0
|
||||||
{
|
#define FILTERTYPE_LINEAR 1
|
||||||
FILTERTYPE_NONE = 0,
|
#define FILTERTYPE_CUBIC 2
|
||||||
FILTERTYPE_LINEAR,
|
|
||||||
FILTERTYPE_CUBIC,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define CCHANVOLUMES 2
|
#define CCHANVOLUMES 2
|
||||||
|
|
||||||
#define SND_SCALE_BITS 7
|
#define SND_SCALE_BITS 7
|
||||||
#define SND_SCALE_SHIFT ( 8 - SND_SCALE_BITS )
|
#define SND_SCALE_SHIFT (8 - SND_SCALE_BITS)
|
||||||
#define SND_SCALE_LEVELS ( 1 << SND_SCALE_BITS )
|
#define SND_SCALE_LEVELS (1 << SND_SCALE_BITS)
|
||||||
|
|
||||||
// sound mixing buffer
|
portable_samplepair_t *g_curpaintbuffer;
|
||||||
#define CPAINTFILTERMEM 3
|
portable_samplepair_t streambuffer[(PAINTBUFFER_SIZE+1)];
|
||||||
#define CPAINTFILTERS 4 // maximum number of consecutive upsample passes per paintbuffer
|
portable_samplepair_t paintbuffer[(PAINTBUFFER_SIZE+1)];
|
||||||
|
portable_samplepair_t roombuffer[(PAINTBUFFER_SIZE+1)];
|
||||||
|
portable_samplepair_t facingbuffer[(PAINTBUFFER_SIZE+1)];
|
||||||
|
portable_samplepair_t temppaintbuffer[(PAINTBUFFER_SIZE+1)];
|
||||||
|
paintbuffer_t paintbuffers[CPAINTBUFFERS];
|
||||||
|
|
||||||
// fixed point stuff for real-time resampling
|
int snd_scaletable[SND_SCALE_LEVELS][256];
|
||||||
#define FIX_BITS 28
|
|
||||||
#define FIX_SCALE ( 1 << FIX_BITS )
|
|
||||||
#define FIX_MASK (( 1 << FIX_BITS ) - 1 )
|
|
||||||
#define FIX_FLOAT( a ) ((int)(( a ) * FIX_SCALE ))
|
|
||||||
#define FIX( a ) (((int)( a )) << FIX_BITS )
|
|
||||||
#define FIX_INTPART( a ) (((int)( a )) >> FIX_BITS )
|
|
||||||
#define FIX_FRACPART( a ) (( a ) & FIX_MASK )
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
qboolean factive; // if true, mix to this paintbuffer using flags
|
|
||||||
portable_samplepair_t *pbuf; // front stereo mix buffer, for 2 or 4 channel mixing
|
|
||||||
int ifilter; // current filter memory buffer to use for upsampling pass
|
|
||||||
portable_samplepair_t fltmem[CPAINTFILTERS][CPAINTFILTERMEM];
|
|
||||||
} paintbuffer_t;
|
|
||||||
|
|
||||||
static portable_samplepair_t *g_curpaintbuffer;
|
|
||||||
static portable_samplepair_t streambuffer[(PAINTBUFFER_SIZE+1)];
|
|
||||||
static portable_samplepair_t paintbuffer[(PAINTBUFFER_SIZE+1)];
|
|
||||||
static portable_samplepair_t roombuffer[(PAINTBUFFER_SIZE+1)];
|
|
||||||
static portable_samplepair_t temppaintbuffer[(PAINTBUFFER_SIZE+1)];
|
|
||||||
static paintbuffer_t paintbuffers[CPAINTBUFFERS];
|
|
||||||
|
|
||||||
static int snd_scaletable[SND_SCALE_LEVELS][256];
|
|
||||||
void S_InitScaletable( void )
|
void S_InitScaletable( void )
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
@@ -93,7 +67,7 @@ static void S_TransferPaintBuffer( int endtime )
|
|||||||
dword *pbuf;
|
dword *pbuf;
|
||||||
|
|
||||||
pbuf = (dword *)dma.buffer;
|
pbuf = (dword *)dma.buffer;
|
||||||
snd_p = (int *)g_curpaintbuffer;
|
snd_p = (int *)PAINTBUFFER;
|
||||||
lpaintedtime = paintedtime;
|
lpaintedtime = paintedtime;
|
||||||
sampleMask = ((dma.samples >> 1) - 1);
|
sampleMask = ((dma.samples >> 1) - 1);
|
||||||
|
|
||||||
@@ -137,20 +111,20 @@ static void S_TransferPaintBuffer( int endtime )
|
|||||||
//===============================================================================
|
//===============================================================================
|
||||||
// Activate a paintbuffer. All active paintbuffers are mixed in parallel within
|
// Activate a paintbuffer. All active paintbuffers are mixed in parallel within
|
||||||
// MIX_MixChannelsToPaintbuffer, according to flags
|
// MIX_MixChannelsToPaintbuffer, according to flags
|
||||||
static void MIX_ActivatePaintbuffer( int ipaintbuffer )
|
_inline void MIX_ActivatePaintbuffer( int ipaintbuffer )
|
||||||
{
|
{
|
||||||
Assert( ipaintbuffer < CPAINTBUFFERS );
|
Assert( ipaintbuffer < CPAINTBUFFERS );
|
||||||
paintbuffers[ipaintbuffer].factive = true;
|
paintbuffers[ipaintbuffer].factive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MIX_SetCurrentPaintbuffer( int ipaintbuffer )
|
_inline void MIX_SetCurrentPaintbuffer( int ipaintbuffer )
|
||||||
{
|
{
|
||||||
Assert( ipaintbuffer < CPAINTBUFFERS );
|
Assert( ipaintbuffer < CPAINTBUFFERS );
|
||||||
g_curpaintbuffer = paintbuffers[ipaintbuffer].pbuf;
|
g_curpaintbuffer = paintbuffers[ipaintbuffer].pbuf;
|
||||||
Assert( g_curpaintbuffer != NULL );
|
Assert( g_curpaintbuffer != NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
static int MIX_GetCurrentPaintbufferIndex( void )
|
_inline int MIX_GetCurrentPaintbufferIndex( void )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -162,7 +136,7 @@ static int MIX_GetCurrentPaintbufferIndex( void )
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static paintbuffer_t *MIX_GetCurrentPaintbufferPtr( void )
|
_inline paintbuffer_t *MIX_GetCurrentPaintbufferPtr( void )
|
||||||
{
|
{
|
||||||
int ipaint = MIX_GetCurrentPaintbufferIndex();
|
int ipaint = MIX_GetCurrentPaintbufferIndex();
|
||||||
|
|
||||||
@@ -171,7 +145,7 @@ static paintbuffer_t *MIX_GetCurrentPaintbufferPtr( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Don't mix into any paintbuffers
|
// Don't mix into any paintbuffers
|
||||||
static void MIX_DeactivateAllPaintbuffers( void )
|
_inline void MIX_DeactivateAllPaintbuffers( void )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -180,7 +154,7 @@ static void MIX_DeactivateAllPaintbuffers( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set upsampling filter indexes back to 0
|
// set upsampling filter indexes back to 0
|
||||||
static void MIX_ResetPaintbufferFilterCounters( void )
|
_inline void MIX_ResetPaintbufferFilterCounters( void )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -189,13 +163,13 @@ static void MIX_ResetPaintbufferFilterCounters( void )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return pointer to front paintbuffer pbuf, given index
|
// return pointer to front paintbuffer pbuf, given index
|
||||||
static portable_samplepair_t *MIX_GetPFrontFromIPaint( int ipaintbuffer )
|
_inline portable_samplepair_t *MIX_GetPFrontFromIPaint( int ipaintbuffer )
|
||||||
{
|
{
|
||||||
Assert( ipaintbuffer < CPAINTBUFFERS );
|
Assert( ipaintbuffer < CPAINTBUFFERS );
|
||||||
return paintbuffers[ipaintbuffer].pbuf;
|
return paintbuffers[ipaintbuffer].pbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static paintbuffer_t *MIX_GetPPaintFromIPaint( int ipaint )
|
_inline paintbuffer_t *MIX_GetPPaintFromIPaint( int ipaint )
|
||||||
{
|
{
|
||||||
Assert( ipaint < CPAINTBUFFERS );
|
Assert( ipaint < CPAINTBUFFERS );
|
||||||
return &paintbuffers[ipaint];
|
return &paintbuffers[ipaint];
|
||||||
@@ -549,7 +523,6 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
|
|||||||
wavdata_t *pSource;
|
wavdata_t *pSource;
|
||||||
int i, sampleCount;
|
int i, sampleCount;
|
||||||
qboolean bZeroVolume;
|
qboolean bZeroVolume;
|
||||||
qboolean local = Host_IsLocalGame();
|
|
||||||
|
|
||||||
// mix each channel into paintbuffer
|
// mix each channel into paintbuffer
|
||||||
ch = channels;
|
ch = channels;
|
||||||
@@ -576,7 +549,7 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
|
|||||||
{
|
{
|
||||||
// play, playvol
|
// play, playvol
|
||||||
}
|
}
|
||||||
else if(( s_listener.inmenu || s_listener.paused ) && !ch->localsound && local )
|
else if(( s_listener.inmenu || s_listener.paused ) && !ch->localsound )
|
||||||
{
|
{
|
||||||
// play only local sounds, keep pause for other
|
// play only local sounds, keep pause for other
|
||||||
continue;
|
continue;
|
||||||
@@ -594,7 +567,6 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
|
|||||||
|
|
||||||
// Don't mix sound data for sounds with zero volume. If it's a non-looping sound,
|
// Don't mix sound data for sounds with zero volume. If it's a non-looping sound,
|
||||||
// just remove the sound when its volume goes to zero.
|
// just remove the sound when its volume goes to zero.
|
||||||
|
|
||||||
bZeroVolume = !ch->leftvol && !ch->rightvol;
|
bZeroVolume = !ch->leftvol && !ch->rightvol;
|
||||||
|
|
||||||
if( !bZeroVolume )
|
if( !bZeroVolume )
|
||||||
@@ -604,7 +576,7 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
|
|||||||
bZeroVolume = true;
|
bZeroVolume = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !pSource || ( bZeroVolume && !FBitSet( pSource->flags, SOUND_LOOPED )))
|
if( !pSource || ( bZeroVolume && pSource->loopStart == -1 ))
|
||||||
{
|
{
|
||||||
if( !pSource )
|
if( !pSource )
|
||||||
{
|
{
|
||||||
@@ -657,7 +629,7 @@ static void MIX_MixChannelsToPaintbuffer( int endtime, int rate, int outputRate
|
|||||||
}
|
}
|
||||||
|
|
||||||
// pass in index -1...count+2, return pointer to source sample in either paintbuffer or delay buffer
|
// pass in index -1...count+2, return pointer to source sample in either paintbuffer or delay buffer
|
||||||
static portable_samplepair_t *S_GetNextpFilter( int i, portable_samplepair_t *pbuffer, portable_samplepair_t *pfiltermem )
|
_inline portable_samplepair_t *S_GetNextpFilter( int i, portable_samplepair_t *pbuffer, portable_samplepair_t *pfiltermem )
|
||||||
{
|
{
|
||||||
// The delay buffer is assumed to precede the paintbuffer by 6 duplicated samples
|
// The delay buffer is assumed to precede the paintbuffer by 6 duplicated samples
|
||||||
if( i == -1 ) return (&(pfiltermem[0]));
|
if( i == -1 ) return (&(pfiltermem[0]));
|
||||||
@@ -866,14 +838,6 @@ static void MIX_MixPaintbuffers( int ibuf1, int ibuf2, int ibuf3, int count, flo
|
|||||||
pbuf2 = paintbuffers[ibuf2].pbuf;
|
pbuf2 = paintbuffers[ibuf2].pbuf;
|
||||||
pbuf3 = paintbuffers[ibuf3].pbuf;
|
pbuf3 = paintbuffers[ibuf3].pbuf;
|
||||||
|
|
||||||
if( !gain )
|
|
||||||
{
|
|
||||||
// do not mix buf2 into buf3, just copy
|
|
||||||
if( pbuf1 != pbuf3 )
|
|
||||||
memcpy( pbuf3, pbuf1, sizeof( *pbuf1 ) * count );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// destination buffer stereo - average n chans down to stereo
|
// destination buffer stereo - average n chans down to stereo
|
||||||
|
|
||||||
// destination 2ch:
|
// destination 2ch:
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ S_StreamGetCurrentState
|
|||||||
save\restore code
|
save\restore code
|
||||||
=================
|
=================
|
||||||
*/
|
*/
|
||||||
qboolean S_StreamGetCurrentState( char *currentTrack, size_t currentTrackSize, char *loopTrack, size_t loopTrackSize, int *position )
|
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position )
|
||||||
{
|
{
|
||||||
if( !s_bgTrack.stream )
|
if( !s_bgTrack.stream )
|
||||||
return false; // not active
|
return false; // not active
|
||||||
@@ -150,15 +150,15 @@ qboolean S_StreamGetCurrentState( char *currentTrack, size_t currentTrackSize, c
|
|||||||
if( currentTrack )
|
if( currentTrack )
|
||||||
{
|
{
|
||||||
if( s_bgTrack.current[0] )
|
if( s_bgTrack.current[0] )
|
||||||
Q_strncpy( currentTrack, s_bgTrack.current, currentTrackSize );
|
Q_strncpy( currentTrack, s_bgTrack.current, MAX_STRING );
|
||||||
else Q_strncpy( currentTrack, "*", currentTrackSize ); // no track
|
else Q_strncpy( currentTrack, "*", MAX_STRING ); // no track
|
||||||
}
|
}
|
||||||
|
|
||||||
if( loopTrack )
|
if( loopTrack )
|
||||||
{
|
{
|
||||||
if( s_bgTrack.loopName[0] )
|
if( s_bgTrack.loopName[0] )
|
||||||
Q_strncpy( loopTrack, s_bgTrack.loopName, loopTrackSize );
|
Q_strncpy( loopTrack, s_bgTrack.loopName, MAX_STRING );
|
||||||
else Q_strncpy( loopTrack, "*", loopTrackSize ); // no track
|
else Q_strncpy( loopTrack, "*", MAX_STRING ); // no track
|
||||||
}
|
}
|
||||||
|
|
||||||
if( position )
|
if( position )
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ int S_ConvertLoopedPosition( wavdata_t *pSource, int samplePosition, qboolean us
|
|||||||
// convert to a position within the loop
|
// convert to a position within the loop
|
||||||
// At the end of the loop, we return a short buffer, and subsequent call
|
// At the end of the loop, we return a short buffer, and subsequent call
|
||||||
// will loop back and get the rest of the buffer
|
// will loop back and get the rest of the buffer
|
||||||
if( FBitSet( pSource->flags, SOUND_LOOPED ) && samplePosition >= pSource->samples && use_loop )
|
if( pSource->loopStart >= 0 && samplePosition >= pSource->samples && use_loop )
|
||||||
{
|
{
|
||||||
// size of loop
|
// size of loop
|
||||||
int loopSize = pSource->samples - pSource->loopStart;
|
int loopSize = pSource->samples - pSource->loopStart;
|
||||||
|
|||||||
@@ -20,179 +20,208 @@ extern poolhandle_t sndpool;
|
|||||||
|
|
||||||
#include "xash3d_mathlib.h"
|
#include "xash3d_mathlib.h"
|
||||||
|
|
||||||
#define XASH_AUDIO_CD_QUALITY 1 // some platforms might need this
|
|
||||||
|
|
||||||
// sound engine rate defines
|
// sound engine rate defines
|
||||||
#if XASH_AUDIO_CD_QUALITY
|
#define SOUND_DMA_SPEED 44100 // hardware playback rate
|
||||||
#define SOUND_11k 11025 // 11khz sample rate
|
#define SOUND_11k 11025 // 11khz sample rate
|
||||||
#define SOUND_22k 22050 // 22khz sample rate
|
#define SOUND_16k 16000 // 16khz sample rate
|
||||||
#define SOUND_44k 44100 // 44khz sample rate
|
#define SOUND_22k 22050 // 22khz sample rate
|
||||||
#else // XASH_AUDIO_CD_QUALITY
|
#define SOUND_32k 32000 // 32khz sample rate
|
||||||
#define SOUND_11k 12000 // 11khz sample rate
|
#define SOUND_44k 44100 // 44khz sample rate
|
||||||
#define SOUND_22k 24000 // 22khz sample rate
|
#define DMA_MSEC_PER_SAMPLE ((float)(1000.0 / SOUND_DMA_SPEED))
|
||||||
#define SOUND_44k 48000 // 44khz sample rate
|
|
||||||
#endif // XASH_AUDIO_CD_QUALITY
|
|
||||||
|
|
||||||
#define SOUND_DMA_SPEED SOUND_44k // hardware playback rate
|
// fixed point stuff for real-time resampling
|
||||||
|
#define FIX_BITS 28
|
||||||
|
#define FIX_SCALE (1 << FIX_BITS)
|
||||||
|
#define FIX_MASK ((1 << FIX_BITS)-1)
|
||||||
|
#define FIX_FLOAT(a) ((int)((a) * FIX_SCALE))
|
||||||
|
#define FIX(a) (((int)(a)) << FIX_BITS)
|
||||||
|
#define FIX_INTPART(a) (((int)(a)) >> FIX_BITS)
|
||||||
|
#define FIX_FRACTION(a,b) (FIX(a)/(b))
|
||||||
|
#define FIX_FRACPART(a) ((a) & FIX_MASK)
|
||||||
|
|
||||||
// NOTE: clipped sound at 32760 to avoid overload
|
// NOTE: clipped sound at 32760 to avoid overload
|
||||||
#define CLIP( x ) (( x ) > 32760 ? 32760 : (( x ) < -32760 ? -32760 : ( x )))
|
#define CLIP( x ) (( x ) > 32760 ? 32760 : (( x ) < -32760 ? -32760 : ( x )))
|
||||||
|
|
||||||
#define PAINTBUFFER_SIZE 1024 // 44k: was 512
|
#define PAINTBUFFER_SIZE 1024 // 44k: was 512
|
||||||
|
#define PAINTBUFFER (g_curpaintbuffer)
|
||||||
|
#define CPAINTBUFFERS 3
|
||||||
|
|
||||||
#define S_RAW_SOUND_IDLE_SEC 10 // time interval for idling raw sound before it's freed
|
// sound mixing buffer
|
||||||
#define S_RAW_SOUND_BACKGROUNDTRACK -2
|
#define CPAINTFILTERMEM 3
|
||||||
#define S_RAW_SOUND_SOUNDTRACK -1
|
#define CPAINTFILTERS 4 // maximum number of consecutive upsample passes per paintbuffer
|
||||||
#define S_RAW_SAMPLES_PRECISION_BITS 14
|
|
||||||
|
#define S_RAW_SOUND_IDLE_SEC 10 // time interval for idling raw sound before it's freed
|
||||||
|
#define S_RAW_SOUND_BACKGROUNDTRACK -2
|
||||||
|
#define S_RAW_SOUND_SOUNDTRACK -1
|
||||||
|
#define S_RAW_SAMPLES_PRECISION_BITS 14
|
||||||
|
|
||||||
|
#define CIN_FRAMETIME (1.0f / 30.0f)
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int left;
|
int left;
|
||||||
int right;
|
int right;
|
||||||
} portable_samplepair_t;
|
} portable_samplepair_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
qboolean factive; // if true, mix to this paintbuffer using flags
|
||||||
|
portable_samplepair_t *pbuf; // front stereo mix buffer, for 2 or 4 channel mixing
|
||||||
|
int ifilter; // current filter memory buffer to use for upsampling pass
|
||||||
|
portable_samplepair_t fltmem[CPAINTFILTERS][CPAINTFILTERMEM];
|
||||||
|
} paintbuffer_t;
|
||||||
|
|
||||||
typedef struct sfx_s
|
typedef struct sfx_s
|
||||||
{
|
{
|
||||||
char name[MAX_QPATH];
|
char name[MAX_QPATH];
|
||||||
wavdata_t *cache;
|
wavdata_t *cache;
|
||||||
|
|
||||||
int servercount;
|
int servercount;
|
||||||
uint hashValue;
|
uint hashValue;
|
||||||
struct sfx_s *hashNext;
|
struct sfx_s *hashNext;
|
||||||
} sfx_t;
|
} sfx_t;
|
||||||
|
|
||||||
|
extern portable_samplepair_t paintbuffer[];
|
||||||
|
extern portable_samplepair_t roombuffer[];
|
||||||
|
extern portable_samplepair_t temppaintbuffer[];
|
||||||
|
extern portable_samplepair_t *g_curpaintbuffer;
|
||||||
|
extern paintbuffer_t paintbuffers[];
|
||||||
|
|
||||||
// structure used for fading in and out client sound volume.
|
// structure used for fading in and out client sound volume.
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
float initial_percent;
|
float initial_percent;
|
||||||
float percent; // how far to adjust client's volume down by.
|
float percent; // how far to adjust client's volume down by.
|
||||||
float starttime; // GetHostTime() when we started adjusting volume
|
float starttime; // GetHostTime() when we started adjusting volume
|
||||||
float fadeouttime; // # of seconds to get to faded out state
|
float fadeouttime; // # of seconds to get to faded out state
|
||||||
float holdtime; // # of seconds to hold
|
float holdtime; // # of seconds to hold
|
||||||
float fadeintime; // # of seconds to restore
|
float fadeintime; // # of seconds to restore
|
||||||
} soundfade_t;
|
} soundfade_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
float percent;
|
float percent;
|
||||||
} musicfade_t;
|
} musicfade_t;
|
||||||
|
|
||||||
typedef struct snd_format_s
|
typedef struct snd_format_s
|
||||||
{
|
{
|
||||||
uint speed;
|
unsigned int speed;
|
||||||
byte width;
|
unsigned int width;
|
||||||
byte channels;
|
unsigned int channels;
|
||||||
} snd_format_t;
|
} snd_format_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
snd_format_t format;
|
snd_format_t format;
|
||||||
int samples; // mono samples in buffer
|
int samples; // mono samples in buffer
|
||||||
int samplepos; // in mono samples
|
int samplepos; // in mono samples
|
||||||
qboolean initialized; // sound engine is active
|
byte *buffer;
|
||||||
byte *buffer;
|
qboolean initialized; // sound engine is active
|
||||||
const char *backendName;
|
const char *backendName;
|
||||||
} dma_t;
|
} dma_t;
|
||||||
|
|
||||||
#include "vox.h"
|
#include "vox.h"
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
double sample;
|
double sample;
|
||||||
wavdata_t *pData;
|
|
||||||
double forcedEndSample;
|
wavdata_t *pData;
|
||||||
qboolean finished;
|
double forcedEndSample;
|
||||||
|
qboolean finished;
|
||||||
} mixer_t;
|
} mixer_t;
|
||||||
|
|
||||||
typedef struct rawchan_s
|
typedef struct rawchan_s
|
||||||
{
|
{
|
||||||
int entnum;
|
int entnum;
|
||||||
int master_vol;
|
int master_vol;
|
||||||
int leftvol; // 0-255 left volume
|
int leftvol; // 0-255 left volume
|
||||||
int rightvol; // 0-255 right volume
|
int rightvol; // 0-255 right volume
|
||||||
float dist_mult; // distance multiplier (attenuation/clipK)
|
float dist_mult; // distance multiplier (attenuation/clipK)
|
||||||
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
|
wavdata_t sound_info; // advance play position
|
||||||
wavdata_t sound_info; // advance play position
|
float oldtime; // catch time jumps
|
||||||
size_t max_samples; // buffer length
|
size_t max_samples; // buffer length
|
||||||
portable_samplepair_t rawsamples[1]; // variable sized
|
portable_samplepair_t rawsamples[1]; // variable sized
|
||||||
} rawchan_t;
|
} rawchan_t;
|
||||||
|
|
||||||
typedef struct channel_s
|
typedef struct channel_s
|
||||||
{
|
{
|
||||||
char name[16]; // keep sentence name
|
char name[16]; // keept sentence name
|
||||||
sfx_t *sfx; // sfx number
|
sfx_t *sfx; // sfx number
|
||||||
|
|
||||||
int leftvol; // 0-255 left volume
|
int leftvol; // 0-255 left volume
|
||||||
int rightvol; // 0-255 right volume
|
int rightvol; // 0-255 right volume
|
||||||
|
|
||||||
int entnum; // entity soundsource
|
int entnum; // entity soundsource
|
||||||
int entchannel; // sound channel (CHAN_STREAM, CHAN_VOICE, etc.)
|
int entchannel; // sound channel (CHAN_STREAM, CHAN_VOICE, etc.)
|
||||||
vec3_t origin; // only use if fixed_origin is set
|
vec3_t origin; // only use if fixed_origin is set
|
||||||
float dist_mult; // distance multiplier (attenuation/clipK)
|
float dist_mult; // distance multiplier (attenuation/clipK)
|
||||||
int master_vol; // 0-255 master volume
|
int master_vol; // 0-255 master volume
|
||||||
int basePitch; // base pitch percent (100% is normal pitch playback)
|
qboolean isSentence; // bit who indicated sentence
|
||||||
float pitch; // real-time pitch after any modulation or shift by dynamic data
|
int basePitch; // base pitch percent (100% is normal pitch playback)
|
||||||
qboolean use_loop; // don't loop default and local sounds
|
float pitch; // real-time pitch after any modulation or shift by dynamic data
|
||||||
qboolean staticsound; // use origin instead of fetching entnum's origin
|
qboolean use_loop; // don't loop default and local sounds
|
||||||
qboolean localsound; // it's a local menu sound (not looped, not paused)
|
qboolean staticsound; // use origin instead of fetching entnum's origin
|
||||||
mixer_t pMixer;
|
qboolean localsound; // it's a local menu sound (not looped, not paused)
|
||||||
|
mixer_t pMixer;
|
||||||
|
|
||||||
// sentence mixer
|
// sentence mixer
|
||||||
qboolean isSentence; // bit indicating sentence
|
int wordIndex;
|
||||||
int wordIndex;
|
mixer_t *currentWord; // NULL if sentence is finished
|
||||||
mixer_t *currentWord; // NULL if sentence is finished
|
voxword_t words[CVOXWORDMAX];
|
||||||
voxword_t words[CVOXWORDMAX];
|
|
||||||
} channel_t;
|
} channel_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
vec3_t origin; // simorg + view_ofs
|
vec3_t origin; // simorg + view_ofs
|
||||||
vec3_t forward;
|
vec3_t velocity;
|
||||||
vec3_t right;
|
vec3_t forward;
|
||||||
vec3_t up;
|
vec3_t right;
|
||||||
|
vec3_t up;
|
||||||
|
|
||||||
int entnum;
|
int entnum;
|
||||||
int waterlevel;
|
int waterlevel;
|
||||||
float frametime; // used for sound fade
|
float frametime; // used for sound fade
|
||||||
qboolean active;
|
qboolean active;
|
||||||
qboolean inmenu; // listener in-menu ?
|
qboolean inmenu; // listener in-menu ?
|
||||||
qboolean paused;
|
qboolean paused;
|
||||||
qboolean streaming; // playing AVI-file
|
qboolean streaming; // playing AVI-file
|
||||||
qboolean stream_paused; // pause only background track
|
qboolean stream_paused; // pause only background track
|
||||||
} listener_t;
|
} listener_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
string current; // a currently playing track
|
string current; // a currently playing track
|
||||||
string loopName; // may be empty
|
string loopName; // may be empty
|
||||||
stream_t *stream;
|
stream_t *stream;
|
||||||
int source; // may be game, menu, etc
|
int source; // may be game, menu, etc
|
||||||
} bg_track_t;
|
} bg_track_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 8192
|
||||||
|
|
||||||
extern sound_t ambient_sfx[NUM_AMBIENTS];
|
extern sound_t ambient_sfx[NUM_AMBIENTS];
|
||||||
extern qboolean snd_ambient;
|
extern qboolean snd_ambient;
|
||||||
extern channel_t channels[MAX_CHANNELS];
|
extern channel_t channels[MAX_CHANNELS];
|
||||||
extern rawchan_t *raw_channels[MAX_RAW_CHANNELS];
|
extern rawchan_t *raw_channels[MAX_RAW_CHANNELS];
|
||||||
extern int total_channels;
|
extern int total_channels;
|
||||||
extern int paintedtime;
|
extern int paintedtime;
|
||||||
extern int soundtime;
|
extern int soundtime;
|
||||||
extern listener_t s_listener;
|
extern listener_t s_listener;
|
||||||
extern int idsp_room;
|
extern int idsp_room;
|
||||||
extern dma_t dma;
|
extern dma_t dma;
|
||||||
|
|
||||||
extern convar_t s_musicvolume;
|
extern convar_t s_musicvolume;
|
||||||
extern convar_t s_lerping;
|
extern convar_t s_lerping;
|
||||||
extern convar_t s_test; // cvar to test new effects
|
extern convar_t s_test; // cvar to testify new effects
|
||||||
extern convar_t s_samplecount;
|
extern convar_t s_samplecount;
|
||||||
|
extern convar_t snd_mute_losefocus;
|
||||||
extern convar_t s_warn_late_precache;
|
extern convar_t s_warn_late_precache;
|
||||||
|
|
||||||
void S_InitScaletable( void );
|
void S_InitScaletable( void );
|
||||||
@@ -264,6 +293,7 @@ void SND_ForceCloseMouth( int entnum );
|
|||||||
//
|
//
|
||||||
void S_StreamSoundTrack( void );
|
void S_StreamSoundTrack( void );
|
||||||
void S_StreamBackgroundTrack( void );
|
void S_StreamBackgroundTrack( void );
|
||||||
|
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position );
|
||||||
void S_PrintBackgroundTrackState( void );
|
void S_PrintBackgroundTrackState( void );
|
||||||
void S_FadeMusicVolume( float fadePercent );
|
void S_FadeMusicVolume( float fadePercent );
|
||||||
|
|
||||||
|
|||||||
@@ -25,12 +25,11 @@ voice_state_t voice = { 0 };
|
|||||||
CVAR_DEFINE_AUTO( voice_enable, "1", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "enable voice chat" );
|
CVAR_DEFINE_AUTO( voice_enable, "1", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "enable voice chat" );
|
||||||
CVAR_DEFINE_AUTO( voice_loopback, "0", FCVAR_PRIVILEGED, "loopback voice back to the speaker" );
|
CVAR_DEFINE_AUTO( voice_loopback, "0", FCVAR_PRIVILEGED, "loopback voice back to the speaker" );
|
||||||
CVAR_DEFINE_AUTO( voice_scale, "1.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "incoming voice volume scale" );
|
CVAR_DEFINE_AUTO( voice_scale, "1.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "incoming voice volume scale" );
|
||||||
CVAR_DEFINE_AUTO( voice_transmit_scale, "1.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "outcoming voice volume scale" );
|
|
||||||
CVAR_DEFINE_AUTO( voice_avggain, "0.5", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "automatic voice gain control (average)" );
|
CVAR_DEFINE_AUTO( voice_avggain, "0.5", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "automatic voice gain control (average)" );
|
||||||
CVAR_DEFINE_AUTO( voice_maxgain, "5.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "automatic voice gain control (maximum)" );
|
CVAR_DEFINE_AUTO( voice_maxgain, "5.0", FCVAR_PRIVILEGED|FCVAR_ARCHIVE, "automatic voice gain control (maximum)" );
|
||||||
CVAR_DEFINE_AUTO( voice_inputfromfile, "0", FCVAR_PRIVILEGED, "input voice from voice_input.wav" );
|
CVAR_DEFINE_AUTO( voice_inputfromfile, "0", FCVAR_PRIVILEGED, "input voice from voice_input.wav" );
|
||||||
|
|
||||||
static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale );
|
static void Voice_ApplyGainAdjust( int16_t *samples, int count );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============================================================================
|
===============================================================================
|
||||||
@@ -40,25 +39,6 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale );
|
|||||||
===============================================================================
|
===============================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static qboolean Voice_InitCustomMode( void )
|
|
||||||
{
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
voice.width = sizeof( opus_int16 );
|
|
||||||
voice.samplerate = VOICE_OPUS_CUSTOM_SAMPLERATE;
|
|
||||||
voice.frame_size = VOICE_OPUS_CUSTOM_FRAME_SIZE;
|
|
||||||
|
|
||||||
voice.custom_mode = opus_custom_mode_create( SOUND_44k, voice.frame_size, &err );
|
|
||||||
|
|
||||||
if( !voice.custom_mode )
|
|
||||||
{
|
|
||||||
Con_Printf( S_ERROR "Can't create Opus Custom mode: %s\n", opus_strerror( err ));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=========================
|
=========================
|
||||||
Voice_InitOpusDecoder
|
Voice_InitOpusDecoder
|
||||||
@@ -67,17 +47,24 @@ Voice_InitOpusDecoder
|
|||||||
*/
|
*/
|
||||||
static qboolean Voice_InitOpusDecoder( void )
|
static qboolean Voice_InitOpusDecoder( void )
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err;
|
||||||
|
|
||||||
for( int i = 0; i < cl.maxclients; i++ )
|
voice.width = sizeof( opus_int16 );
|
||||||
|
voice.samplerate = VOICE_OPUS_CUSTOM_SAMPLERATE;
|
||||||
|
voice.frame_size = VOICE_OPUS_CUSTOM_FRAME_SIZE;
|
||||||
|
|
||||||
|
voice.custom_mode = opus_custom_mode_create( SOUND_44k, voice.frame_size, &err );
|
||||||
|
if( !voice.custom_mode )
|
||||||
{
|
{
|
||||||
voice.decoders[i] = opus_custom_decoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
Con_Printf( S_ERROR "Can't create Opus Custom mode: %s\n", opus_strerror( err ));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if( !voice.decoders[i] )
|
voice.decoder = opus_custom_decoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
||||||
{
|
if( !voice.decoder )
|
||||||
Con_Printf( S_ERROR "Can't create Opus decoder for %i: %s\n", i, opus_strerror( err ));
|
{
|
||||||
return false;
|
Con_Printf( S_ERROR "Can't create Opus encoder: %s\n", opus_strerror( err ));
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -91,7 +78,7 @@ Voice_InitOpusEncoder
|
|||||||
*/
|
*/
|
||||||
static qboolean Voice_InitOpusEncoder( int quality )
|
static qboolean Voice_InitOpusEncoder( int quality )
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err;
|
||||||
|
|
||||||
voice.encoder = opus_custom_encoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
voice.encoder = opus_custom_encoder_create( voice.custom_mode, VOICE_PCM_CHANNELS, &err );
|
||||||
if( !voice.encoder )
|
if( !voice.encoder )
|
||||||
@@ -130,13 +117,10 @@ Voice_ShutdownOpusDecoder
|
|||||||
*/
|
*/
|
||||||
static void Voice_ShutdownOpusDecoder( void )
|
static void Voice_ShutdownOpusDecoder( void )
|
||||||
{
|
{
|
||||||
for( int i = 0; i < MAX_CLIENTS; i++ )
|
if( voice.decoder )
|
||||||
{
|
{
|
||||||
if( !voice.decoders[i] )
|
opus_custom_decoder_destroy( voice.decoder );
|
||||||
continue;
|
voice.decoder = NULL;
|
||||||
|
|
||||||
opus_custom_decoder_destroy( voice.decoders[i] );
|
|
||||||
voice.decoders[i] = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,10 +137,7 @@ static void Voice_ShutdownOpusEncoder( void )
|
|||||||
opus_custom_encoder_destroy( voice.encoder );
|
opus_custom_encoder_destroy( voice.encoder );
|
||||||
voice.encoder = NULL;
|
voice.encoder = NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static void Voice_ShutdownCustomMode( void )
|
|
||||||
{
|
|
||||||
if( voice.custom_mode )
|
if( voice.custom_mode )
|
||||||
{
|
{
|
||||||
opus_custom_mode_destroy( voice.custom_mode );
|
opus_custom_mode_destroy( voice.custom_mode );
|
||||||
@@ -203,7 +184,7 @@ static uint Voice_GetOpusCompressedData( byte *out, uint maxsize, uint *frames )
|
|||||||
if( !voice.input_file )
|
if( !voice.input_file )
|
||||||
{
|
{
|
||||||
// adjust gain before encoding, but only for input from voice
|
// adjust gain before encoding, but only for input from voice
|
||||||
Voice_ApplyGainAdjust((opus_int16*)(voice.input_buffer + ofs), voice.frame_size, voice_transmit_scale.value);
|
Voice_ApplyGainAdjust((opus_int16*)(voice.input_buffer + ofs), voice.frame_size);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -257,10 +238,10 @@ Voice_ApplyGainAdjust
|
|||||||
|
|
||||||
=========================
|
=========================
|
||||||
*/
|
*/
|
||||||
static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale )
|
static void Voice_ApplyGainAdjust( int16_t *samples, int count )
|
||||||
{
|
{
|
||||||
float gain, modifiedMax;
|
float gain, modifiedMax;
|
||||||
int average, blockOffset = 0;
|
int average, adjustedSample, blockOffset = 0;
|
||||||
|
|
||||||
for( ;; )
|
for( ;; )
|
||||||
{
|
{
|
||||||
@@ -279,8 +260,10 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale )
|
|||||||
localMax = absSample;
|
localMax = absSample;
|
||||||
|
|
||||||
localSum += absSample;
|
localSum += absSample;
|
||||||
|
|
||||||
gain = voice.autogain.current_gain + i * voice.autogain.gain_multiplier;
|
gain = voice.autogain.current_gain + i * voice.autogain.gain_multiplier;
|
||||||
samples[blockOffset + i] = bound( SHRT_MIN, (int)( sample * gain ), SHRT_MAX );
|
adjustedSample = Q_min( SHRT_MAX, Q_max(( int )( sample * gain ), SHRT_MIN ));
|
||||||
|
samples[blockOffset + i] = adjustedSample;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( blockOffset % voice.autogain.block_size == 0 )
|
if( blockOffset % voice.autogain.block_size == 0 )
|
||||||
@@ -288,9 +271,9 @@ static void Voice_ApplyGainAdjust( int16_t *samples, int count, float scale )
|
|||||||
average = localSum / blockSize;
|
average = localSum / blockSize;
|
||||||
modifiedMax = average + ( localMax - average ) * voice_avggain.value;
|
modifiedMax = average + ( localMax - average ) * voice_avggain.value;
|
||||||
|
|
||||||
voice.autogain.current_gain = voice.autogain.next_gain * scale;
|
voice.autogain.current_gain = voice.autogain.next_gain * voice_scale.value;
|
||||||
voice.autogain.next_gain = Q_min( (float)SHRT_MAX / modifiedMax, voice_maxgain.value ) * scale;
|
voice.autogain.next_gain = Q_min( (float)SHRT_MAX / modifiedMax, voice_maxgain.value ) * voice_scale.value;
|
||||||
voice.autogain.gain_multiplier = ( voice.autogain.next_gain - voice.autogain.current_gain ) / ( blockSize - 1 );
|
voice.autogain.gain_multiplier = ( voice.autogain.next_gain - voice.autogain.current_gain ) / ( voice.autogain.block_size - 1 );
|
||||||
}
|
}
|
||||||
blockOffset += blockSize;
|
blockOffset += blockSize;
|
||||||
}
|
}
|
||||||
@@ -460,7 +443,7 @@ Feed the decoded data to engine sound subsystem
|
|||||||
static void Voice_StartChannel( uint samples, byte *data, int entnum )
|
static void Voice_StartChannel( uint samples, byte *data, int entnum )
|
||||||
{
|
{
|
||||||
SND_ForceInitMouth( entnum );
|
SND_ForceInitMouth( entnum );
|
||||||
S_RawEntSamples( entnum, samples, voice.samplerate, voice.width, VOICE_PCM_CHANNELS, data, bound( 0, 255 * voice_scale.value, 255 ));
|
S_RawEntSamples( entnum, samples, voice.samplerate, voice.width, VOICE_PCM_CHANNELS, data, 255 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -472,11 +455,10 @@ Received encoded voice data, decode it
|
|||||||
*/
|
*/
|
||||||
void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames )
|
void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames )
|
||||||
{
|
{
|
||||||
const int playernum = ent - 1;
|
|
||||||
int samples = 0;
|
int samples = 0;
|
||||||
int ofs = 0;
|
int ofs = 0;
|
||||||
|
|
||||||
if( playernum < 0 || playernum >= cl.maxclients || !voice.decoders[playernum] )
|
if( !voice.decoder )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// decode frame by frame
|
// decode frame by frame
|
||||||
@@ -496,7 +478,7 @@ void Voice_AddIncomingData( int ent, const byte *data, uint size, uint frames )
|
|||||||
if( ofs + compressed_size > size )
|
if( ofs + compressed_size > size )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
frame_samples = opus_custom_decode( voice.decoders[playernum], data + ofs, compressed_size,
|
frame_samples = opus_custom_decode( voice.decoder, data + ofs, compressed_size,
|
||||||
(opus_int16*)voice.decompress_buffer + samples, voice.frame_size );
|
(opus_int16*)voice.decompress_buffer + samples, voice.frame_size );
|
||||||
|
|
||||||
ofs += compressed_size;
|
ofs += compressed_size;
|
||||||
@@ -521,7 +503,7 @@ void CL_AddVoiceToDatagram( void )
|
|||||||
if( cls.state != ca_active || !Voice_IsRecording() || !voice.encoder )
|
if( cls.state != ca_active || !Voice_IsRecording() || !voice.encoder )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
size = Voice_GetOpusCompressedData( voice.compress_buffer, sizeof( voice.compress_buffer ), &frames );
|
size = Voice_GetOpusCompressedData( voice.output_buffer, sizeof( voice.output_buffer ), &frames );
|
||||||
|
|
||||||
if( size > 0 && MSG_GetNumBytesLeft( &cls.datagram ) >= size + 32 )
|
if( size > 0 && MSG_GetNumBytesLeft( &cls.datagram ) >= size + 32 )
|
||||||
{
|
{
|
||||||
@@ -529,7 +511,7 @@ void CL_AddVoiceToDatagram( void )
|
|||||||
MSG_WriteByte( &cls.datagram, voice_loopback.value != 0 );
|
MSG_WriteByte( &cls.datagram, voice_loopback.value != 0 );
|
||||||
MSG_WriteByte( &cls.datagram, frames );
|
MSG_WriteByte( &cls.datagram, frames );
|
||||||
MSG_WriteShort( &cls.datagram, size );
|
MSG_WriteShort( &cls.datagram, size );
|
||||||
MSG_WriteBytes( &cls.datagram, voice.compress_buffer, size );
|
MSG_WriteBytes( &cls.datagram, voice.output_buffer, size );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -545,7 +527,6 @@ void Voice_RegisterCvars( void )
|
|||||||
Cvar_RegisterVariable( &voice_enable );
|
Cvar_RegisterVariable( &voice_enable );
|
||||||
Cvar_RegisterVariable( &voice_loopback );
|
Cvar_RegisterVariable( &voice_loopback );
|
||||||
Cvar_RegisterVariable( &voice_scale );
|
Cvar_RegisterVariable( &voice_scale );
|
||||||
Cvar_RegisterVariable( &voice_transmit_scale );
|
|
||||||
Cvar_RegisterVariable( &voice_avggain );
|
Cvar_RegisterVariable( &voice_avggain );
|
||||||
Cvar_RegisterVariable( &voice_maxgain );
|
Cvar_RegisterVariable( &voice_maxgain );
|
||||||
Cvar_RegisterVariable( &voice_inputfromfile );
|
Cvar_RegisterVariable( &voice_inputfromfile );
|
||||||
@@ -563,9 +544,8 @@ static void Voice_Shutdown( void )
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
Voice_RecordStop();
|
Voice_RecordStop();
|
||||||
Voice_ShutdownOpusDecoder();
|
|
||||||
Voice_ShutdownOpusEncoder();
|
Voice_ShutdownOpusEncoder();
|
||||||
Voice_ShutdownCustomMode();
|
Voice_ShutdownOpusDecoder();
|
||||||
VoiceCapture_Shutdown();
|
VoiceCapture_Shutdown();
|
||||||
|
|
||||||
if( voice.local.talking_ack )
|
if( voice.local.talking_ack )
|
||||||
@@ -629,10 +609,11 @@ qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit )
|
|||||||
|
|
||||||
voice.autogain.block_size = 128;
|
voice.autogain.block_size = 128;
|
||||||
|
|
||||||
if( !Voice_InitCustomMode( ))
|
if( !Voice_InitOpusDecoder( ))
|
||||||
{
|
{
|
||||||
// no reason to init encoder and open audio device
|
// no reason to init encoder and open audio device
|
||||||
// if we can't hear other players
|
// if we can't hear other players
|
||||||
|
Con_Printf( S_ERROR "Voice chat disabled.\n" );
|
||||||
Voice_Shutdown();
|
Voice_Shutdown();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -652,16 +633,6 @@ qboolean Voice_Init( const char *pszCodecName, int quality, qboolean preinit )
|
|||||||
|
|
||||||
if( !preinit )
|
if( !preinit )
|
||||||
{
|
{
|
||||||
Voice_ShutdownOpusDecoder();
|
|
||||||
if( !Voice_InitOpusDecoder())
|
|
||||||
{
|
|
||||||
// no reason to init encoder and open audio device
|
|
||||||
// if we can't hear other players
|
|
||||||
Con_Printf( S_ERROR "Can't create decoders, voice chat is disabled.\n" );
|
|
||||||
Voice_Shutdown();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
voice.device_opened = VoiceCapture_Init();
|
voice.device_opened = VoiceCapture_Init();
|
||||||
|
|
||||||
if( !voice.device_opened )
|
if( !voice.device_opened )
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ typedef struct OpusCustomMode OpusCustomMode;
|
|||||||
#define VOICE_PCM_CHANNELS 1 // always mono
|
#define VOICE_PCM_CHANNELS 1 // always mono
|
||||||
|
|
||||||
// never change these parameters when using opuscustom
|
// never change these parameters when using opuscustom
|
||||||
#define VOICE_OPUS_CUSTOM_SAMPLERATE 44100
|
#define VOICE_OPUS_CUSTOM_SAMPLERATE SOUND_44k
|
||||||
// must follow opus custom requirements
|
// must follow opus custom requirements
|
||||||
// also be divisible with MAX_RAW_SAMPLES
|
// also be divisible with MAX_RAW_SAMPLES
|
||||||
#define VOICE_OPUS_CUSTOM_FRAME_SIZE 1024
|
#define VOICE_OPUS_CUSTOM_FRAME_SIZE 1024
|
||||||
@@ -62,7 +62,7 @@ typedef struct voice_state_s
|
|||||||
// opus stuff
|
// opus stuff
|
||||||
OpusCustomMode *custom_mode;
|
OpusCustomMode *custom_mode;
|
||||||
OpusCustomEncoder *encoder;
|
OpusCustomEncoder *encoder;
|
||||||
OpusCustomDecoder *decoders[MAX_CLIENTS];
|
OpusCustomDecoder *decoder;
|
||||||
|
|
||||||
// audio info
|
// audio info
|
||||||
uint width;
|
uint width;
|
||||||
@@ -71,7 +71,7 @@ typedef struct voice_state_s
|
|||||||
|
|
||||||
// buffers
|
// buffers
|
||||||
byte input_buffer[MAX_RAW_SAMPLES];
|
byte input_buffer[MAX_RAW_SAMPLES];
|
||||||
byte compress_buffer[MAX_RAW_SAMPLES];
|
byte output_buffer[MAX_RAW_SAMPLES];
|
||||||
byte decompress_buffer[MAX_RAW_SAMPLES];
|
byte decompress_buffer[MAX_RAW_SAMPLES];
|
||||||
fs_offset_t input_buffer_pos; // in bytes
|
fs_offset_t input_buffer_pos; // in bytes
|
||||||
|
|
||||||
|
|||||||
@@ -16,20 +16,21 @@ GNU General Public License for more details.
|
|||||||
#ifndef VOX_H
|
#ifndef VOX_H
|
||||||
#define VOX_H
|
#define VOX_H
|
||||||
|
|
||||||
#define CVOXWORDMAX 64
|
#define CVOXWORDMAX 64
|
||||||
#define SENTENCE_INDEX -99999 // unique sentence index
|
|
||||||
|
#define SENTENCE_INDEX -99999 // unique sentence index
|
||||||
|
|
||||||
typedef struct voxword_s
|
typedef struct voxword_s
|
||||||
{
|
{
|
||||||
int volume; // increase percent, ie: 125 = 125% increase
|
int volume; // increase percent, ie: 125 = 125% increase
|
||||||
int pitch; // pitch shift up percent
|
int pitch; // pitch shift up percent
|
||||||
int start; // offset start of wave percent
|
int start; // offset start of wave percent
|
||||||
int end; // offset end of wave percent
|
int end; // offset end of wave percent
|
||||||
int cbtrim; // end of wave after being trimmed to 'end'
|
int cbtrim; // end of wave after being trimmed to 'end'
|
||||||
int fKeepCached; // 1 if this word was already in cache before sentence referenced it
|
int fKeepCached; // 1 if this word was already in cache before sentence referenced it
|
||||||
int samplefrac; // if pitch shifting, this is position into wav * 256
|
int samplefrac; // if pitch shifting, this is position into wav * 256
|
||||||
int timecompress; // % of wave to skip during playback (causes no pitch shift)
|
int timecompress; // % of wave to skip during playback (causes no pitch shift)
|
||||||
sfx_t *sfx; // name and cache pointer
|
sfx_t *sfx; // name and cache pointer
|
||||||
} voxword_t;
|
} voxword_t;
|
||||||
|
|
||||||
struct channel_s;
|
struct channel_s;
|
||||||
|
|||||||
@@ -19,15 +19,13 @@ GNU General Public License for more details.
|
|||||||
|
|
||||||
#define HASH_SIZE 128 // 128 * 4 * 4 == 2048 bytes
|
#define HASH_SIZE 128 // 128 * 4 * 4 == 2048 bytes
|
||||||
|
|
||||||
typedef struct base_command_hashmap_s base_command_hashmap_t;
|
typedef struct base_command_hashmap_s
|
||||||
|
|
||||||
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;
|
const char *name; // key for searching
|
||||||
base_command_type_e type; // type for faster searching
|
base_command_type_e type; // type for faster searching
|
||||||
char name[1]; // key for searching
|
struct base_command_hashmap_s *next;
|
||||||
};
|
} base_command_hashmap_t;
|
||||||
|
|
||||||
static base_command_hashmap_t *hashed_cmds[HASH_SIZE];
|
static base_command_hashmap_t *hashed_cmds[HASH_SIZE];
|
||||||
|
|
||||||
@@ -126,12 +124,11 @@ void BaseCmd_Insert( base_command_type_e type, base_command_t *basecmd, const ch
|
|||||||
{
|
{
|
||||||
base_command_hashmap_t *elem, *cur, *find;
|
base_command_hashmap_t *elem, *cur, *find;
|
||||||
uint hash = BaseCmd_HashKey( name );
|
uint hash = BaseCmd_HashKey( name );
|
||||||
size_t len = Q_strlen( name );
|
|
||||||
|
|
||||||
elem = Z_Malloc( sizeof( base_command_hashmap_t ) + len );
|
elem = Z_Malloc( sizeof( base_command_hashmap_t ) );
|
||||||
elem->basecmd = basecmd;
|
elem->basecmd = basecmd;
|
||||||
elem->type = type;
|
elem->type = type;
|
||||||
Q_strncpy( elem->name, name, len + 1 );
|
elem->name = name;
|
||||||
|
|
||||||
// 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];
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ typedef enum base_command_type
|
|||||||
|
|
||||||
typedef void base_command_t;
|
typedef void base_command_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void BaseCmd_Init( void );
|
void BaseCmd_Init( 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,
|
||||||
|
|||||||
@@ -640,7 +640,7 @@ void Cmd_TokenizeString( const char *text )
|
|||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
// skip whitespace up to a /n
|
// skip whitespace up to a /n
|
||||||
while( *text && ((byte)*text ) <= ' ' && *text != '\r' && *text != '\n' )
|
while( *text && *text <= ' ' && *text != '\r' && *text != '\n' )
|
||||||
text++;
|
text++;
|
||||||
|
|
||||||
if( *text == '\n' || *text == '\r' )
|
if( *text == '\n' || *text == '\r' )
|
||||||
@@ -949,7 +949,7 @@ static void Cmd_Else_f( void )
|
|||||||
|
|
||||||
static qboolean Cmd_ShouldAllowCommand( cmd_t *cmd, qboolean isPrivileged )
|
static qboolean Cmd_ShouldAllowCommand( cmd_t *cmd, qboolean isPrivileged )
|
||||||
{
|
{
|
||||||
const char *prefixes[] = { "cl_", "gl_", "r_", "m_", "hud_", "joy_", "con_", "scr_" };
|
const char *prefixes[] = { "cl_", "gl_", "r_", "m_", "hud_" };
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
// always allow local commands
|
// always allow local commands
|
||||||
@@ -1015,7 +1015,7 @@ static void Cmd_ExecuteStringWithPrivilegeCheck( const char *text, qboolean isPr
|
|||||||
*ptoken++ = *text++;
|
*ptoken++ = *text++;
|
||||||
*ptoken = 0;
|
*ptoken = 0;
|
||||||
|
|
||||||
len += Q_strncpy( pcmd, Cvar_VariableString( token ), sizeof( token ) - len );
|
len += Q_strncpy( pcmd, Cvar_VariableString( token ), MAX_CMD_LINE - len );
|
||||||
pcmd = command + len;
|
pcmd = command + len;
|
||||||
|
|
||||||
if( !*text ) break;
|
if( !*text ) break;
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ GNU General Public License for more details.
|
|||||||
#define DEFAULT_UPDATE_PAGE "https://github.com/FWGS/xash3d-fwgs/releases/latest"
|
#define DEFAULT_UPDATE_PAGE "https://github.com/FWGS/xash3d-fwgs/releases/latest"
|
||||||
|
|
||||||
#define XASH_ENGINE_NAME "Xash3D FWGS"
|
#define XASH_ENGINE_NAME "Xash3D FWGS"
|
||||||
#define XASH_DEDICATED_SERVER_NAME "XashDS"
|
|
||||||
#define XASH_VERSION "0.20" // engine current version
|
#define XASH_VERSION "0.20" // engine current version
|
||||||
#define XASH_COMPAT_VERSION "0.99" // version we are based on
|
#define XASH_COMPAT_VERSION "0.99" // version we are based on
|
||||||
|
|
||||||
|
|||||||
@@ -25,19 +25,16 @@ GNU General Public License for more details.
|
|||||||
|
|
||||||
static const char *file_exts[] =
|
static const char *file_exts[] =
|
||||||
{
|
{
|
||||||
// ban text files that don't make sense as resource
|
"cfg",
|
||||||
"cfg", "lst", "ini", "log",
|
"lst",
|
||||||
|
"exe",
|
||||||
// ban Windows code
|
"vbs",
|
||||||
"exe", "vbs", "com", "bat",
|
"com",
|
||||||
"dll", "sys", "ps1",
|
"bat",
|
||||||
|
"dll",
|
||||||
// ban common unix code
|
"ini",
|
||||||
// NOTE: in unix anything can be executed as long it has access flag
|
"log",
|
||||||
"so", "sh", "dylib",
|
"sys",
|
||||||
|
|
||||||
// ban mobile archives
|
|
||||||
"apk", "ipa",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
@@ -393,9 +390,6 @@ byte *LZSS_Compress( byte *pInput, int inputLength, uint *pOutputSize )
|
|||||||
byte *pFinal = NULL;
|
byte *pFinal = NULL;
|
||||||
lzss_state_t state;
|
lzss_state_t state;
|
||||||
|
|
||||||
if( !pStart )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
memset( &state, 0, sizeof( state ));
|
memset( &state, 0, sizeof( state ));
|
||||||
state.window_size = LZSS_WINDOW_SIZE;
|
state.window_size = LZSS_WINDOW_SIZE;
|
||||||
|
|
||||||
@@ -903,10 +897,7 @@ qboolean COM_IsSafeFileToDownload( const char *filename )
|
|||||||
if( !COM_CheckString( filename ))
|
if( !COM_CheckString( filename ))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ext = COM_FileExtension( lwrfilename );
|
if( !Q_strncmp( filename, "!MD5", 4 ))
|
||||||
|
|
||||||
// only allow extensionless files that start with !MD5
|
|
||||||
if( !Q_strncmp( filename, "!MD5", 4 ) && ext[0] == 0 )
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Q_strnlwr( filename, lwrfilename, sizeof( lwrfilename ));
|
Q_strnlwr( filename, lwrfilename, sizeof( lwrfilename ));
|
||||||
@@ -929,6 +920,8 @@ qboolean COM_IsSafeFileToDownload( const char *filename )
|
|||||||
if( Q_strlen( first ) != 4 )
|
if( Q_strlen( first ) != 4 )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
ext = COM_FileExtension( lwrfilename );
|
||||||
|
|
||||||
for( i = 0; i < ARRAYSIZE( file_exts ); i++ )
|
for( i = 0; i < ARRAYSIZE( file_exts ); i++ )
|
||||||
{
|
{
|
||||||
if( !Q_stricmp( ext, file_exts[i] ))
|
if( !Q_stricmp( ext, file_exts[i] ))
|
||||||
|
|||||||
@@ -273,12 +273,12 @@ typedef struct
|
|||||||
|
|
||||||
typedef enum bugcomp_e
|
typedef enum bugcomp_e
|
||||||
{
|
{
|
||||||
// reverts fix for pfnPEntityOfEntIndex for bug compatibility with GoldSrc
|
// default mode, we assume that user dlls are not relying on engine bugs
|
||||||
BUGCOMP_PENTITYOFENTINDEX_FLAG = BIT( 0 ),
|
BUGCOMP_OFF,
|
||||||
|
|
||||||
// rewrites mod's attempts to write GoldSrc-specific messages into Xash protocol
|
// GoldSrc mode, user dlls are relying on GoldSrc specific bugs
|
||||||
// (new wrappers are added by request)
|
// but fixing them may break regular Xash games
|
||||||
BUGCOMP_MESSAGE_REWRITE_FACILITY_FLAG = BIT( 1 ),
|
BUGCOMP_GOLDSRC,
|
||||||
} bugcomp_t;
|
} bugcomp_t;
|
||||||
|
|
||||||
typedef struct host_parm_s
|
typedef struct host_parm_s
|
||||||
@@ -356,7 +356,7 @@ typedef struct host_parm_s
|
|||||||
int numdecals;
|
int numdecals;
|
||||||
|
|
||||||
// bug compatibility level, for very "special" games
|
// bug compatibility level, for very "special" games
|
||||||
uint32_t bugcomp;
|
bugcomp_t bugcomp;
|
||||||
|
|
||||||
// measure time to first frame
|
// measure time to first frame
|
||||||
double starttime;
|
double starttime;
|
||||||
@@ -479,6 +479,14 @@ typedef enum
|
|||||||
WF_TOTALCOUNT, // must be last
|
WF_TOTALCOUNT, // must be last
|
||||||
} sndformat_t;
|
} sndformat_t;
|
||||||
|
|
||||||
|
// soundlib global settings
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SL_USE_LERPING = BIT(0), // lerping sounds during resample
|
||||||
|
SL_KEEP_8BIT = BIT(1), // don't expand 8bit sounds automatically up to 16 bit
|
||||||
|
SL_ALLOW_OVERWRITE = BIT(2), // allow to overwrite stored sounds
|
||||||
|
} slFlags_t;
|
||||||
|
|
||||||
// wavdata output flags
|
// wavdata output flags
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@@ -487,20 +495,21 @@ typedef enum
|
|||||||
SOUND_STREAM = BIT( 1 ), // this is a streaminfo, not a real sound
|
SOUND_STREAM = BIT( 1 ), // this is a streaminfo, not a real sound
|
||||||
|
|
||||||
// Sound_Process manipulation flags
|
// Sound_Process manipulation flags
|
||||||
SOUND_RESAMPLE = BIT( 12 ), // resample sound to specified rate
|
SOUND_RESAMPLE = BIT(12), // resample sound to specified rate
|
||||||
|
SOUND_CONVERT16BIT = BIT(13), // change sound resolution from 8 bit to 16
|
||||||
} sndFlags_t;
|
} sndFlags_t;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
word rate; // num samples per second (e.g. 11025 - 11 khz)
|
word rate; // num samples per second (e.g. 11025 - 11 khz)
|
||||||
byte width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2)
|
byte width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2)
|
||||||
byte channels; // num channels (1 - mono, 2 - stereo)
|
byte channels; // num channels (1 - mono, 2 - stereo)
|
||||||
uint loopStart; // offset at this point sound will be looping while playing more than only once
|
int loopStart; // offset at this point sound will be looping while playing more than only once
|
||||||
uint samples; // total samplecount in wav
|
int 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
|
byte *buffer; // sound buffer
|
||||||
size_t size; // for bounds checking
|
size_t size; // for bounds checking
|
||||||
} wavdata_t;
|
} wavdata_t;
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -695,7 +704,7 @@ void Log_Printf( const char *fmt, ... ) _format( 1 );
|
|||||||
void SV_BroadcastCommand( const char *fmt, ... ) _format( 1 );
|
void SV_BroadcastCommand( const char *fmt, ... ) _format( 1 );
|
||||||
void SV_BroadcastPrintf( struct sv_client_s *ignore, const char *fmt, ... ) _format( 2 );
|
void SV_BroadcastPrintf( struct sv_client_s *ignore, const char *fmt, ... ) _format( 2 );
|
||||||
void CL_ClearStaticEntities( void );
|
void CL_ClearStaticEntities( void );
|
||||||
qboolean S_StreamGetCurrentState( char *currentTrack, size_t currentTrackSize, char *loopTrack, size_t loopTrackSize, int *position );
|
qboolean S_StreamGetCurrentState( char *currentTrack, char *loopTrack, int *position );
|
||||||
void CL_ServerCommand( qboolean reliable, const char *fmt, ... ) _format( 2 );
|
void CL_ServerCommand( qboolean reliable, const char *fmt, ... ) _format( 2 );
|
||||||
void CL_HudMessage( const char *pMessage );
|
void CL_HudMessage( const char *pMessage );
|
||||||
const char *CL_MsgInfo( int cmd );
|
const char *CL_MsgInfo( int cmd );
|
||||||
|
|||||||
@@ -465,7 +465,7 @@ static qboolean Cmd_GetSoundList( const char *s, char *completedname, int length
|
|||||||
t = FS_Search( va( "%s%s*.*", DEFAULT_SOUNDPATH, s ), true, false );
|
t = FS_Search( va( "%s%s*.*", DEFAULT_SOUNDPATH, s ), true, false );
|
||||||
if( !t ) return false;
|
if( !t ) return false;
|
||||||
|
|
||||||
Q_strncpy( matchbuf, t->filenames[0] + sizeof( DEFAULT_SOUNDPATH ) - 1, sizeof( matchbuf ));
|
Q_strncpy( matchbuf, t->filenames[0] + sizeof( DEFAULT_SOUNDPATH ) - 1, MAX_STRING );
|
||||||
COM_StripExtension( matchbuf );
|
COM_StripExtension( matchbuf );
|
||||||
if( completedname && length )
|
if( completedname && length )
|
||||||
Q_strncpy( completedname, matchbuf, length );
|
Q_strncpy( completedname, matchbuf, length );
|
||||||
@@ -478,7 +478,7 @@ static qboolean Cmd_GetSoundList( const char *s, char *completedname, int length
|
|||||||
if( Q_stricmp( ext, "wav" ) && Q_stricmp( ext, "mp3" ))
|
if( Q_stricmp( ext, "wav" ) && Q_stricmp( ext, "mp3" ))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Q_strncpy( matchbuf, t->filenames[i] + sizeof( DEFAULT_SOUNDPATH ) - 1, sizeof( matchbuf ));
|
Q_strncpy( matchbuf, t->filenames[i] + sizeof( DEFAULT_SOUNDPATH ) - 1, MAX_STRING );
|
||||||
COM_StripExtension( matchbuf );
|
COM_StripExtension( matchbuf );
|
||||||
Con_Printf( "%16s\n", matchbuf );
|
Con_Printf( "%16s\n", matchbuf );
|
||||||
numsounds++;
|
numsounds++;
|
||||||
@@ -764,14 +764,14 @@ static qboolean Cmd_GetGamesList( const char *s, char *completedname, int length
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( !numgamedirs ) return false;
|
if( !numgamedirs ) return false;
|
||||||
Q_strncpy( matchbuf, gamedirs[0], sizeof( matchbuf ));
|
Q_strncpy( matchbuf, gamedirs[0], MAX_STRING );
|
||||||
if( completedname && length )
|
if( completedname && length )
|
||||||
Q_strncpy( completedname, matchbuf, length );
|
Q_strncpy( completedname, matchbuf, length );
|
||||||
if( numgamedirs == 1 ) return true;
|
if( numgamedirs == 1 ) return true;
|
||||||
|
|
||||||
for( i = 0; i < numgamedirs; i++ )
|
for( i = 0; i < numgamedirs; i++ )
|
||||||
{
|
{
|
||||||
Q_strncpy( matchbuf, gamedirs[i], sizeof( matchbuf ));
|
Q_strncpy( matchbuf, gamedirs[i], MAX_STRING );
|
||||||
Con_Printf( "%16s\n", matchbuf );
|
Con_Printf( "%16s\n", matchbuf );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -825,14 +825,14 @@ static qboolean Cmd_GetCDList( const char *s, char *completedname, int length )
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( !numcdcommands ) return false;
|
if( !numcdcommands ) return false;
|
||||||
Q_strncpy( matchbuf, cdcommands[0], sizeof( matchbuf ));
|
Q_strncpy( matchbuf, cdcommands[0], MAX_STRING );
|
||||||
if( completedname && length )
|
if( completedname && length )
|
||||||
Q_strncpy( completedname, matchbuf, length );
|
Q_strncpy( completedname, matchbuf, length );
|
||||||
if( numcdcommands == 1 ) return true;
|
if( numcdcommands == 1 ) return true;
|
||||||
|
|
||||||
for( i = 0; i < numcdcommands; i++ )
|
for( i = 0; i < numcdcommands; i++ )
|
||||||
{
|
{
|
||||||
Q_strncpy( matchbuf, cdcommands[i], sizeof( matchbuf ));
|
Q_strncpy( matchbuf, cdcommands[i], MAX_STRING );
|
||||||
Con_Printf( "%16s\n", matchbuf );
|
Con_Printf( "%16s\n", matchbuf );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -866,7 +866,7 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
|||||||
return true; // exist
|
return true; // exist
|
||||||
|
|
||||||
// setup mpfilter
|
// setup mpfilter
|
||||||
Q_snprintf( mpfilter, sizeof( mpfilter ), "maps/%s", GI->mp_filter );
|
size = Q_snprintf( mpfilter, sizeof( mpfilter ), "maps/%s", GI->mp_filter );
|
||||||
t = FS_Search( "maps/*.bsp", false, onlyingamedir );
|
t = FS_Search( "maps/*.bsp", false, onlyingamedir );
|
||||||
|
|
||||||
if( !t )
|
if( !t )
|
||||||
@@ -900,11 +900,13 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
|||||||
|
|
||||||
if( f )
|
if( f )
|
||||||
{
|
{
|
||||||
qboolean have_spawnpoints = false;
|
int num_spawnpoints = 0;
|
||||||
dlump_t entities;
|
dheader_t *header;
|
||||||
|
dlump_t entities;
|
||||||
|
|
||||||
memset( buf, 0, MAX_SYSPATH );
|
memset( buf, 0, MAX_SYSPATH );
|
||||||
FS_Read( f, buf, MAX_SYSPATH );
|
FS_Read( f, buf, MAX_SYSPATH );
|
||||||
|
header = (dheader_t *)buf;
|
||||||
|
|
||||||
// check all the lumps and some other errors
|
// check all the lumps and some other errors
|
||||||
if( !Mod_TestBmodelLumps( f, t->filenames[i], buf, true, &entities ))
|
if( !Mod_TestBmodelLumps( f, t->filenames[i], buf, true, &entities ))
|
||||||
@@ -935,24 +937,13 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
|||||||
char token[MAX_TOKEN];
|
char token[MAX_TOKEN];
|
||||||
qboolean worldspawn = true;
|
qboolean worldspawn = true;
|
||||||
|
|
||||||
Q_strncpy( message, "No Title", sizeof( message ));
|
Q_strncpy( message, "No Title", MAX_STRING );
|
||||||
pfile = ents;
|
pfile = ents;
|
||||||
|
|
||||||
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
|
while(( pfile = COM_ParseFile( pfile, token, sizeof( token ))) != NULL )
|
||||||
{
|
{
|
||||||
if( token[0] == '}' && worldspawn )
|
if( token[0] == '}' && worldspawn )
|
||||||
{
|
|
||||||
worldspawn = false;
|
worldspawn = false;
|
||||||
|
|
||||||
// if mod has mp_filter set up, then it's a mod that
|
|
||||||
// might not have valid mp_entity set in GI
|
|
||||||
// if mod is multiplayer only, assume all maps are valid
|
|
||||||
if( use_filter || GI->gamemode == GAME_MULTIPLAYER_ONLY )
|
|
||||||
{
|
|
||||||
have_spawnpoints = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( !Q_strcmp( token, "message" ) && worldspawn )
|
else if( !Q_strcmp( token, "message" ) && worldspawn )
|
||||||
{
|
{
|
||||||
// get the message contents
|
// get the message contents
|
||||||
@@ -961,23 +952,17 @@ static qboolean Cmd_CheckMapsList_R( qboolean fRefresh, qboolean onlyingamedir )
|
|||||||
else if( !Q_strcmp( token, "classname" ))
|
else if( !Q_strcmp( token, "classname" ))
|
||||||
{
|
{
|
||||||
pfile = COM_ParseFile( pfile, token, sizeof( token ));
|
pfile = COM_ParseFile( pfile, token, sizeof( token ));
|
||||||
|
if( !Q_strcmp( token, GI->mp_entity ) || use_filter )
|
||||||
if( !Q_strcmp( token, GI->mp_entity ))
|
num_spawnpoints++;
|
||||||
{
|
|
||||||
have_spawnpoints = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if( num_spawnpoints ) break; // valid map
|
||||||
if( have_spawnpoints )
|
|
||||||
break; // valid map
|
|
||||||
}
|
}
|
||||||
Mem_Free( ents );
|
Mem_Free( ents );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( f ) FS_Close( f );
|
if( f ) FS_Close( f );
|
||||||
|
|
||||||
if( have_spawnpoints )
|
if( num_spawnpoints )
|
||||||
{
|
{
|
||||||
// format: mapname "maptitle"\n
|
// format: mapname "maptitle"\n
|
||||||
Q_snprintf( result, sizeof( result ), "%s \"%s\"\n", mapname, message );
|
Q_snprintf( result, sizeof( result ), "%s \"%s\"\n", mapname, message );
|
||||||
|
|||||||
@@ -129,22 +129,6 @@ static void Sys_StackTrace( PEXCEPTION_POINTERS pInfo )
|
|||||||
stackframe.AddrBStore.Mode = AddrModeFlat;
|
stackframe.AddrBStore.Mode = AddrModeFlat;
|
||||||
stackframe.AddrStack.Offset = context.IntSp;
|
stackframe.AddrStack.Offset = context.IntSp;
|
||||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
stackframe.AddrStack.Mode = AddrModeFlat;
|
||||||
#elif _M_ARM
|
|
||||||
image = IMAGE_FILE_MACHINE_ARMNT;
|
|
||||||
stackframe.AddrPC.Offset = context.Pc;
|
|
||||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
|
||||||
stackframe.AddrFrame.Offset = context.R11;
|
|
||||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
|
||||||
stackframe.AddrStack.Offset = context.Sp;
|
|
||||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
|
||||||
#elif _M_ARM64
|
|
||||||
image = IMAGE_FILE_MACHINE_ARM64;
|
|
||||||
stackframe.AddrPC.Offset = context.Pc;
|
|
||||||
stackframe.AddrPC.Mode = AddrModeFlat;
|
|
||||||
stackframe.AddrFrame.Offset = context.Fp;
|
|
||||||
stackframe.AddrFrame.Mode = AddrModeFlat;
|
|
||||||
stackframe.AddrStack.Offset = context.Sp;
|
|
||||||
stackframe.AddrStack.Mode = AddrModeFlat;
|
|
||||||
#elif
|
#elif
|
||||||
#error
|
#error
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -152,10 +152,8 @@ static qboolean Cvar_UpdateInfo( convar_t *var, const char *value, qboolean noti
|
|||||||
if ( Host_IsDedicated() )
|
if ( Host_IsDedicated() )
|
||||||
{
|
{
|
||||||
// g-cont. this is a very strange behavior...
|
// g-cont. this is a very strange behavior...
|
||||||
char *info = SV_Serverinfo();
|
Info_SetValueForKey( SV_Serverinfo(), var->name, value, MAX_SERVERINFO_STRING ),
|
||||||
|
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", SV_Serverinfo( ));
|
||||||
Info_SetValueForKey( info, var->name, value, MAX_SERVERINFO_STRING ),
|
|
||||||
SV_BroadcastCommand( "fullserverinfo \"%s\"\n", info );
|
|
||||||
}
|
}
|
||||||
#if !XASH_DEDICATED
|
#if !XASH_DEDICATED
|
||||||
else
|
else
|
||||||
@@ -955,7 +953,7 @@ static void Cvar_SetGL( const char *name, const char *value )
|
|||||||
|
|
||||||
static qboolean Cvar_ShouldSetCvar( convar_t *v, qboolean isPrivileged )
|
static qboolean Cvar_ShouldSetCvar( convar_t *v, qboolean isPrivileged )
|
||||||
{
|
{
|
||||||
const char *prefixes[] = { "cl_", "gl_", "m_", "r_", "hud_", "joy_", "con_", "scr_" };
|
const char *prefixes[] = { "cl_", "gl_", "m_", "r_", "hud_" };
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if( isPrivileged )
|
if( isPrivileged )
|
||||||
|
|||||||
@@ -89,32 +89,32 @@ qboolean FS_LoadProgs( void )
|
|||||||
|
|
||||||
if( !fs_hInstance )
|
if( !fs_hInstance )
|
||||||
{
|
{
|
||||||
Host_Error( "%s: can't load filesystem library %s: %s\n", __func__, name, COM_GetLibraryError() );
|
Host_Error( "FS_LoadProgs: can't load filesystem library %s: %s\n", name, COM_GetLibraryError() );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !( GetFSAPI = (FSAPI)COM_GetProcAddress( fs_hInstance, GET_FS_API )))
|
if( !( GetFSAPI = (FSAPI)COM_GetProcAddress( fs_hInstance, GET_FS_API )))
|
||||||
{
|
{
|
||||||
FS_UnloadProgs();
|
FS_UnloadProgs();
|
||||||
Host_Error( "%s: can't find GetFSAPI entry point in %s\n", __func__, name );
|
Host_Error( "FS_LoadProgs: can't find GetFSAPI entry point in %s\n", name );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( GetFSAPI( FS_API_VERSION, &g_fsapi, &FI, &fs_memfuncs ) != FS_API_VERSION )
|
if( !GetFSAPI( FS_API_VERSION, &g_fsapi, &FI, &fs_memfuncs ))
|
||||||
{
|
{
|
||||||
FS_UnloadProgs();
|
FS_UnloadProgs();
|
||||||
Host_Error( "%s: can't initialize filesystem API: wrong version\n", __func__ );
|
Host_Error( "FS_LoadProgs: can't initialize filesystem API: wrong version\n" );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !( fs_pfnCreateInterface = (pfnCreateInterface_t)COM_GetProcAddress( fs_hInstance, "CreateInterface" )))
|
if( !( fs_pfnCreateInterface = (pfnCreateInterface_t)COM_GetProcAddress( fs_hInstance, "CreateInterface" )))
|
||||||
{
|
{
|
||||||
FS_UnloadProgs();
|
FS_UnloadProgs();
|
||||||
Host_Error( "%s: can't find CreateInterface entry point in %s\n", __func__, name );
|
Host_Error( "FS_LoadProgs: can't find CreateInterface entry point in %s\n", name );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Con_DPrintf( "%s: filesystem_stdio successfully loaded\n", __func__ );
|
Con_DPrintf( "FS_LoadProgs: filesystem_stdio successfully loaded\n" );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,33 +65,6 @@ static CVAR_DEFINE( host_sleeptime, "sleeptime", "1", FCVAR_ARCHIVE|FCVAR_FILTER
|
|||||||
static CVAR_DEFINE_AUTO( host_sleeptime_debug, "0", 0, "print sleeps between frames" );
|
static CVAR_DEFINE_AUTO( host_sleeptime_debug, "0", 0, "print sleeps between frames" );
|
||||||
CVAR_DEFINE( con_gamemaps, "con_mapfilter", "1", FCVAR_ARCHIVE, "when true show only maps in game folder" );
|
CVAR_DEFINE( con_gamemaps, "con_mapfilter", "1", FCVAR_ARCHIVE, "when true show only maps in game folder" );
|
||||||
|
|
||||||
typedef struct feature_message_s
|
|
||||||
{
|
|
||||||
uint32_t mask;
|
|
||||||
const char *msg;
|
|
||||||
const char *arg;
|
|
||||||
} feature_message_t;
|
|
||||||
|
|
||||||
static feature_message_t bugcomp_features[] =
|
|
||||||
{
|
|
||||||
{ BUGCOMP_PENTITYOFENTINDEX_FLAG, "pfnPEntityOfEntIndex bugfix revert", "peoei" },
|
|
||||||
{ BUGCOMP_MESSAGE_REWRITE_FACILITY_FLAG, "GoldSrc Message Rewrite Facility", "gsmrf" },
|
|
||||||
};
|
|
||||||
|
|
||||||
static feature_message_t engine_features[] =
|
|
||||||
{
|
|
||||||
{ ENGINE_WRITE_LARGE_COORD, "Big World Support" },
|
|
||||||
{ ENGINE_QUAKE_COMPATIBLE, "Quake Compatibility" },
|
|
||||||
{ ENGINE_LOAD_DELUXEDATA, "Deluxemap Support" },
|
|
||||||
{ ENGINE_PHYSICS_PUSHER_EXT, "Improved MOVETYPE_PUSH" },
|
|
||||||
{ ENGINE_LARGE_LIGHTMAPS, "Large Lightmaps" },
|
|
||||||
{ ENGINE_COMPENSATE_QUAKE_BUG, "Stupid Quake Bug Compensation" },
|
|
||||||
{ ENGINE_IMPROVED_LINETRACE, "Improved Trace Line" },
|
|
||||||
{ ENGINE_COMPUTE_STUDIO_LERP, "Studio MOVETYPE_STEP Lerping" },
|
|
||||||
{ ENGINE_LINEAR_GAMMA_SPACE, "Linear Gamma Space" },
|
|
||||||
{ ENGINE_STEP_POSHISTORY_LERP, "MOVETYPE_STEP Position History Based Lerping" },
|
|
||||||
};
|
|
||||||
|
|
||||||
static void Sys_PrintUsage( void )
|
static void Sys_PrintUsage( void )
|
||||||
{
|
{
|
||||||
string version_str;
|
string version_str;
|
||||||
@@ -119,9 +92,8 @@ static void Sys_PrintUsage( void )
|
|||||||
O("-minidumps ", "enable writing minidumps when game is crashed")
|
O("-minidumps ", "enable writing minidumps when game is crashed")
|
||||||
#endif
|
#endif
|
||||||
O("-rodir <path> ", "set read-only base directory")
|
O("-rodir <path> ", "set read-only base directory")
|
||||||
O("-bugcomp [opts] ", "enable precise bug compatibility")
|
O("-bugcomp ", "enable precise bug compatibility. Will break games that don't require it")
|
||||||
O(" ", "will break games that don't require it")
|
O(" ", "Refer to engine documentation for more info")
|
||||||
O(" ", "refer to engine documentation for more info")
|
|
||||||
O("-disablehelp ", "disable this message")
|
O("-disablehelp ", "disable this message")
|
||||||
#if !XASH_DEDICATED
|
#if !XASH_DEDICATED
|
||||||
O("-dedicated ", "run engine in dedicated mode")
|
O("-dedicated ", "run engine in dedicated mode")
|
||||||
@@ -134,8 +106,7 @@ static void Sys_PrintUsage( void )
|
|||||||
O("-noip6 ", "disable IPv6")
|
O("-noip6 ", "disable IPv6")
|
||||||
O("-ip6 <ip> ", "set IPv6 address")
|
O("-ip6 <ip> ", "set IPv6 address")
|
||||||
O("-port6 <port> ", "set IPv6 port")
|
O("-port6 <port> ", "set IPv6 port")
|
||||||
O("-clockwindow <cw>", "adjust clockwindow used to ignore client commands")
|
O("-clockwindow <cw>", "adjust clockwindow used to ignore client commands to prevent speed hacks")
|
||||||
O(" ", "to prevent speed hacks")
|
|
||||||
|
|
||||||
"\nGame options:\n"
|
"\nGame options:\n"
|
||||||
O("-game <directory>", "set game directory to start engine with")
|
O("-game <directory>", "set game directory to start engine with")
|
||||||
@@ -220,14 +191,31 @@ void Host_ShutdownServer( void )
|
|||||||
Host_PrintEngineFeatures
|
Host_PrintEngineFeatures
|
||||||
================
|
================
|
||||||
*/
|
*/
|
||||||
static void Host_PrintFeatures( uint32_t flags, const char *s, feature_message_t *features, size_t size )
|
static void Host_PrintEngineFeatures( int features )
|
||||||
{
|
{
|
||||||
size_t i;
|
struct
|
||||||
|
|
||||||
for( i = 0; i < size; i++ )
|
|
||||||
{
|
{
|
||||||
if( FBitSet( flags, features[i].mask ))
|
uint32_t mask;
|
||||||
Con_Printf( "^3%s:^7 %s is enabled\n", s, features[i].msg );
|
const char *msg;
|
||||||
|
} features_str[] =
|
||||||
|
{
|
||||||
|
{ ENGINE_WRITE_LARGE_COORD, "Big World Support" },
|
||||||
|
{ ENGINE_QUAKE_COMPATIBLE, "Quake Compatibility" },
|
||||||
|
{ ENGINE_LOAD_DELUXEDATA, "Deluxemap Support" },
|
||||||
|
{ ENGINE_PHYSICS_PUSHER_EXT, "Improved MOVETYPE_PUSH" },
|
||||||
|
{ ENGINE_LARGE_LIGHTMAPS, "Large Lightmaps" },
|
||||||
|
{ ENGINE_COMPENSATE_QUAKE_BUG, "Stupid Quake Bug Compensation" },
|
||||||
|
{ ENGINE_IMPROVED_LINETRACE, "Improved Trace Line" },
|
||||||
|
{ ENGINE_COMPUTE_STUDIO_LERP, "Studio MOVETYPE_STEP Lerping" },
|
||||||
|
{ ENGINE_LINEAR_GAMMA_SPACE, "Linear Gamma Space" },
|
||||||
|
{ ENGINE_STEP_POSHISTORY_LERP, "MOVETYPE_STEP Position History Based Lerping" },
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for( i = 0; i < ARRAYSIZE( features_str ); i++ )
|
||||||
|
{
|
||||||
|
if( FBitSet( features, features_str[i].mask ))
|
||||||
|
Con_Reportf( "^3EXT:^7 %s is enabled\n", features_str[i].msg );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +243,7 @@ void Host_ValidateEngineFeatures( uint32_t features )
|
|||||||
SetBits( features, ENGINE_STEP_POSHISTORY_LERP );
|
SetBits( features, ENGINE_STEP_POSHISTORY_LERP );
|
||||||
|
|
||||||
// print requested first
|
// print requested first
|
||||||
Host_PrintFeatures( features, "EXT", engine_features, ARRAYSIZE( engine_features ));
|
Host_PrintEngineFeatures( features );
|
||||||
|
|
||||||
// now warn about incompatible bits
|
// now warn about incompatible bits
|
||||||
if( FBitSet( features, ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ) == ( ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ))
|
if( FBitSet( features, ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ) == ( ENGINE_STEP_POSHISTORY_LERP|ENGINE_COMPUTE_STUDIO_LERP ))
|
||||||
@@ -865,7 +853,7 @@ void GAME_EXPORT Host_Error( const char *error, ... )
|
|||||||
}
|
}
|
||||||
|
|
||||||
recursive = true;
|
recursive = true;
|
||||||
Q_strncpy( hosterror2, hosterror1, sizeof( hosterror2 ));
|
Q_strncpy( hosterror2, hosterror1, MAX_SYSPATH );
|
||||||
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 );
|
Q_snprintf( host.finalmsg, sizeof( host.finalmsg ), "Server crashed: %s", hosterror1 );
|
||||||
|
|
||||||
@@ -951,59 +939,11 @@ static void Host_RunTests( int stage )
|
|||||||
TEST_LIST_1_CLIENT;
|
TEST_LIST_1_CLIENT;
|
||||||
#endif
|
#endif
|
||||||
Msg( "Done! %d passed, %d failed\n", tests_stats.passed, tests_stats.failed );
|
Msg( "Done! %d passed, %d failed\n", tests_stats.passed, tests_stats.failed );
|
||||||
error_on_exit = tests_stats.failed > 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
||||||
Sys_Quit();
|
Sys_Quit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static uint32_t Host_CheckBugcomp( void )
|
|
||||||
{
|
|
||||||
const char *prev, *next;
|
|
||||||
uint32_t flags = 0;
|
|
||||||
string args, arg;
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
if( !Sys_CheckParm( "-bugcomp" ))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if( Sys_GetParmFromCmdLine( "-bugcomp", args ) && isalpha( args[0] ))
|
|
||||||
{
|
|
||||||
for( prev = args, next = Q_strchrnul( prev, '+' ); ; prev = next + 1, next = Q_strchrnul( prev, '+' ))
|
|
||||||
{
|
|
||||||
Q_strncpy( arg, prev, next - prev + 1 );
|
|
||||||
for( i = 0; i < ARRAYSIZE( bugcomp_features ); i++ )
|
|
||||||
{
|
|
||||||
if( !Q_stricmp( bugcomp_features[i].arg, arg ))
|
|
||||||
{
|
|
||||||
SetBits( flags, bugcomp_features[i].mask );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( i == ARRAYSIZE( bugcomp_features ))
|
|
||||||
{
|
|
||||||
Con_Printf( S_ERROR "Unknown bugcomp flag %s\n", arg );
|
|
||||||
Con_Printf( "Valid flags are:\n" );
|
|
||||||
for( i = 0; i < ARRAYSIZE( bugcomp_features ); i++ )
|
|
||||||
Con_Printf( "\t%s: %s\n", bugcomp_features[i].arg, bugcomp_features[i].msg );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !*next )
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// no argument specified -bugcomp just enables everything
|
|
||||||
flags = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Host_PrintFeatures( flags, "BUGCOMP", bugcomp_features, ARRAYSIZE( bugcomp_features ));
|
|
||||||
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
Host_InitCommon
|
Host_InitCommon
|
||||||
@@ -1108,6 +1048,13 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
|
|||||||
// member console allowing
|
// member console allowing
|
||||||
host.allow_console_init = host.allow_console;
|
host.allow_console_init = host.allow_console;
|
||||||
|
|
||||||
|
if( Sys_CheckParm( "-bugcomp" ))
|
||||||
|
{
|
||||||
|
// add argument check here when we add other levels
|
||||||
|
// of bugcompatibility
|
||||||
|
host.bugcomp = BUGCOMP_GOLDSRC;
|
||||||
|
}
|
||||||
|
|
||||||
// timeBeginPeriod( 1 ); // a1ba: Do we need this?
|
// timeBeginPeriod( 1 ); // a1ba: Do we need this?
|
||||||
|
|
||||||
// NOTE: this message couldn't be passed into game console but it doesn't matter
|
// NOTE: this message couldn't be passed into game console but it doesn't matter
|
||||||
@@ -1234,11 +1181,11 @@ static void Host_InitCommon( int argc, char **argv, const char *progname, qboole
|
|||||||
|
|
||||||
Sys_InitLog();
|
Sys_InitLog();
|
||||||
|
|
||||||
// print current developer level to simplify processing users feedback
|
// print bugcompatibility level here, after log was initialized
|
||||||
if( developer > 0 )
|
if( host.bugcomp == BUGCOMP_GOLDSRC )
|
||||||
Con_Printf( "Developer level: ^3%i\n", developer );
|
{
|
||||||
|
Con_Printf( "^3BUGCOMP^7: GoldSrc bug-compatibility enabled\n" );
|
||||||
host.bugcomp = Host_CheckBugcomp();
|
}
|
||||||
|
|
||||||
Cmd_AddCommand( "exec", Host_Exec_f, "execute a script file" );
|
Cmd_AddCommand( "exec", Host_Exec_f, "execute a script file" );
|
||||||
Cmd_AddCommand( "memlist", Host_MemStats_f, "prints memory pool information" );
|
Cmd_AddCommand( "memlist", Host_MemStats_f, "prints memory pool information" );
|
||||||
@@ -1422,11 +1369,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
|||||||
host.status = HOST_FRAME;
|
host.status = HOST_FRAME;
|
||||||
|
|
||||||
if( GameState->nextstate == STATE_RUNFRAME )
|
if( GameState->nextstate == STATE_RUNFRAME )
|
||||||
#if XASH_WIN32 // FIXME: implement autocomplete on *nix
|
|
||||||
Con_Printf( "Type 'map <mapname>' to start game... (TAB-autocomplete is working too)\n" );
|
Con_Printf( "Type 'map <mapname>' to start game... (TAB-autocomplete is working too)\n" );
|
||||||
#else // !XASH_WIN32
|
|
||||||
Con_Printf( "Type 'map <mapname>' to start game...\n" );
|
|
||||||
#endif // !XASH_WIN32
|
|
||||||
|
|
||||||
// execute server.cfg after commandline
|
// execute server.cfg after commandline
|
||||||
// so we have a chance to set servercfgfile
|
// so we have a chance to set servercfgfile
|
||||||
|
|||||||
@@ -400,8 +400,7 @@ static qboolean HPAK_Validate( const char *filename, qboolean quiet, qboolean de
|
|||||||
f = FS_Open( pakname, "rb", true );
|
f = FS_Open( pakname, "rb", true );
|
||||||
if( !f )
|
if( !f )
|
||||||
{
|
{
|
||||||
if( !quiet )
|
Con_DPrintf( S_ERROR "Couldn't find %s.\n", pakname );
|
||||||
Con_DPrintf( S_ERROR "Couldn't find %s.\n", pakname );
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
|
|||||||
if( Q_strrchr( name, '{' ))
|
if( Q_strrchr( name, '{' ))
|
||||||
{
|
{
|
||||||
// NOTE: decals with 'blue base' can be interpret as colored decals
|
// NOTE: decals with 'blue base' can be interpret as colored decals
|
||||||
if( !Image_CheckFlag( IL_LOAD_DECAL ) || ( pal && pal[765] == 0 && pal[766] == 0 && pal[767] == 255 ))
|
if( !Image_CheckFlag( IL_LOAD_DECAL ) || ( pal[765] == 0 && pal[766] == 0 && pal[767] == 255 ))
|
||||||
{
|
{
|
||||||
SetBits( image.flags, IMAGE_ONEBIT_ALPHA );
|
SetBits( image.flags, IMAGE_ONEBIT_ALPHA );
|
||||||
rendermode = LUMP_MASKED;
|
rendermode = LUMP_MASKED;
|
||||||
@@ -488,40 +488,37 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check for half-life water texture
|
// check for half-life water texture
|
||||||
if( pal != NULL )
|
if( hl_texture && ( mip.name[0] == '!' || !Q_strnicmp( mip.name, "water", 5 )))
|
||||||
{
|
{
|
||||||
if( hl_texture && ( mip.name[0] == '!' || !Q_strnicmp( mip.name, "water", 5 )))
|
// grab the fog color
|
||||||
{
|
image.fogParams[0] = pal[3*3+0];
|
||||||
// grab the fog color
|
image.fogParams[1] = pal[3*3+1];
|
||||||
image.fogParams[0] = pal[3*3+0];
|
image.fogParams[2] = pal[3*3+2];
|
||||||
image.fogParams[1] = pal[3*3+1];
|
|
||||||
image.fogParams[2] = pal[3*3+2];
|
|
||||||
|
|
||||||
// grab the fog density
|
// grab the fog density
|
||||||
image.fogParams[3] = pal[4*3+0];
|
image.fogParams[3] = pal[4*3+0];
|
||||||
}
|
}
|
||||||
else if( hl_texture && ( rendermode == LUMP_GRADIENT ))
|
else if( hl_texture && ( rendermode == LUMP_GRADIENT ))
|
||||||
{
|
{
|
||||||
// grab the decal color
|
// grab the decal color
|
||||||
image.fogParams[0] = pal[255*3+0];
|
image.fogParams[0] = pal[255*3+0];
|
||||||
image.fogParams[1] = pal[255*3+1];
|
image.fogParams[1] = pal[255*3+1];
|
||||||
image.fogParams[2] = pal[255*3+2];
|
image.fogParams[2] = pal[255*3+2];
|
||||||
|
|
||||||
// calc the decal reflectivity
|
// calc the decal reflectivity
|
||||||
image.fogParams[3] = VectorAvg( image.fogParams );
|
image.fogParams[3] = VectorAvg( image.fogParams );
|
||||||
}
|
}
|
||||||
else
|
else if( pal != NULL )
|
||||||
|
{
|
||||||
|
// calc texture reflectivity
|
||||||
|
for( i = 0; i < 256; i++ )
|
||||||
{
|
{
|
||||||
// calc texture reflectivity
|
reflectivity[0] += pal[i*3+0];
|
||||||
for( i = 0; i < 256; i++ )
|
reflectivity[1] += pal[i*3+1];
|
||||||
{
|
reflectivity[2] += pal[i*3+2];
|
||||||
reflectivity[0] += pal[i*3+0];
|
|
||||||
reflectivity[1] += pal[i*3+1];
|
|
||||||
reflectivity[2] += pal[i*3+2];
|
|
||||||
}
|
|
||||||
|
|
||||||
VectorDivide( reflectivity, 256, image.fogParams );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VectorDivide( reflectivity, 256, image.fogParams );
|
||||||
}
|
}
|
||||||
|
|
||||||
image.type = PF_INDEXED_32; // 32-bit palete
|
image.type = PF_INDEXED_32; // 32-bit palete
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ typedef struct dll_user_s
|
|||||||
qboolean custom_loader; // a bit who indicated loader type
|
qboolean custom_loader; // a bit who indicated loader type
|
||||||
qboolean encrypted; // dll is crypted (some client.dll in HL, CS etc)
|
qboolean encrypted; // dll is crypted (some client.dll in HL, CS etc)
|
||||||
char dllName[32]; // for debug messages
|
char dllName[32]; // for debug messages
|
||||||
char fullPath[2048];
|
string fullPath, shortPath; // actual dll paths
|
||||||
string shortPath; // actual dll paths
|
|
||||||
|
|
||||||
// ordinals stuff, valid only on Win32
|
// ordinals stuff, valid only on Win32
|
||||||
word *ordinals;
|
word *ordinals;
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ static void NET_AnnounceToMaster( master_t *m )
|
|||||||
MSG_WriteBytes( &msg, "q\xFF", 2 );
|
MSG_WriteBytes( &msg, "q\xFF", 2 );
|
||||||
MSG_WriteDword( &msg, m->heartbeat_challenge );
|
MSG_WriteDword( &msg, m->heartbeat_challenge );
|
||||||
|
|
||||||
NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &msg ), MSG_GetData( &msg ), m->adr );
|
NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &msg ), MSG_GetBuf( &msg ), m->adr );
|
||||||
|
|
||||||
if( sv_verbose_heartbeats.value )
|
if( sv_verbose_heartbeats.value )
|
||||||
{
|
{
|
||||||
@@ -262,7 +262,7 @@ static void NET_AddMaster( const char *addr, qboolean save )
|
|||||||
}
|
}
|
||||||
|
|
||||||
master = Mem_Malloc( host.mempool, sizeof( master_t ) );
|
master = Mem_Malloc( host.mempool, sizeof( master_t ) );
|
||||||
Q_strncpy( master->address, addr, sizeof( master->address ));
|
Q_strncpy( master->address, addr, MAX_STRING );
|
||||||
master->sent = false;
|
master->sent = false;
|
||||||
master->save = save;
|
master->save = save;
|
||||||
master->next = NULL;
|
master->next = NULL;
|
||||||
|
|||||||
@@ -24,9 +24,6 @@ GNU General Public License for more details.
|
|||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "server.h" // LUMP_ error codes
|
#include "server.h" // LUMP_ error codes
|
||||||
#include "ref_common.h"
|
#include "ref_common.h"
|
||||||
#if defined( HAVE_OPENMP )
|
|
||||||
#include <omp.h>
|
|
||||||
#endif // HAVE_OPENMP
|
|
||||||
|
|
||||||
#define MIPTEX_CUSTOM_PALETTE_SIZE_BYTES ( sizeof( int16_t ) + 768 )
|
#define MIPTEX_CUSTOM_PALETTE_SIZE_BYTES ( sizeof( int16_t ) + 768 )
|
||||||
|
|
||||||
@@ -581,42 +578,6 @@ void Mod_PrintWorldStats_f( void )
|
|||||||
|
|
||||||
===============================================================================
|
===============================================================================
|
||||||
*/
|
*/
|
||||||
/*
|
|
||||||
===================
|
|
||||||
Mod_DecompressPVS
|
|
||||||
|
|
||||||
TODO: replace all Mod_DecompressPVS calls by this
|
|
||||||
===================
|
|
||||||
*/
|
|
||||||
static void Mod_DecompressPVSTo( byte *const out, const byte *in, size_t visbytes )
|
|
||||||
{
|
|
||||||
byte *dst = out;
|
|
||||||
|
|
||||||
if( !in ) // no visinfo, make all visible
|
|
||||||
{
|
|
||||||
memset( out, 0xFF, visbytes );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while( dst < out + visbytes )
|
|
||||||
{
|
|
||||||
if( *in ) // uncompressed
|
|
||||||
{
|
|
||||||
*dst++ = *in++;
|
|
||||||
}
|
|
||||||
else // zero repeated `c` times
|
|
||||||
{
|
|
||||||
size_t c = in[1];
|
|
||||||
if( c > out + visbytes - dst )
|
|
||||||
c = out + visbytes - dst;
|
|
||||||
|
|
||||||
memset( dst, 0, c );
|
|
||||||
in += 2;
|
|
||||||
dst += c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===================
|
===================
|
||||||
Mod_DecompressPVS
|
Mod_DecompressPVS
|
||||||
@@ -624,36 +585,41 @@ Mod_DecompressPVS
|
|||||||
*/
|
*/
|
||||||
static byte *Mod_DecompressPVS( const byte *in, int visbytes )
|
static byte *Mod_DecompressPVS( const byte *in, int visbytes )
|
||||||
{
|
{
|
||||||
Mod_DecompressPVSTo( g_visdata, in, visbytes );
|
byte *out;
|
||||||
return g_visdata;
|
int c;
|
||||||
}
|
|
||||||
|
|
||||||
static size_t Mod_CompressPVS( byte *const out, const byte *in, size_t inbytes )
|
out = g_visdata;
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
byte *dst = out;
|
|
||||||
|
|
||||||
for( i = 0; i < inbytes; i++ )
|
if( !in )
|
||||||
{
|
{
|
||||||
size_t j = i + 1, rep = 1;
|
// no vis info, so make all visible
|
||||||
|
while( visbytes )
|
||||||
*dst++ = in[i];
|
|
||||||
|
|
||||||
// only compress zeros
|
|
||||||
if( in[i] )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for( ; j < inbytes && rep != 255; j++, rep++ )
|
|
||||||
{
|
{
|
||||||
if( in[j] )
|
*out++ = 0xff;
|
||||||
break;
|
visbytes--;
|
||||||
}
|
}
|
||||||
|
return g_visdata;
|
||||||
*dst++ = rep;
|
|
||||||
i = j - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dst - out;
|
do
|
||||||
|
{
|
||||||
|
if( *in )
|
||||||
|
{
|
||||||
|
*out++ = *in++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
c = in[1];
|
||||||
|
in += 2;
|
||||||
|
|
||||||
|
while( c )
|
||||||
|
{
|
||||||
|
*out++ = 0;
|
||||||
|
c--;
|
||||||
|
}
|
||||||
|
} while( out - g_visdata < visbytes );
|
||||||
|
|
||||||
|
return g_visdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -687,11 +653,22 @@ NOTE: can return NULL
|
|||||||
*/
|
*/
|
||||||
byte *Mod_GetPVSForPoint( const vec3_t p )
|
byte *Mod_GetPVSForPoint( const vec3_t p )
|
||||||
{
|
{
|
||||||
mleaf_t *leaf;
|
mnode_t *node;
|
||||||
|
mleaf_t *leaf = NULL;
|
||||||
|
|
||||||
ASSERT( worldmodel != NULL );
|
ASSERT( worldmodel != NULL );
|
||||||
|
|
||||||
leaf = Mod_PointInLeaf( p, worldmodel->nodes );
|
node = worldmodel->nodes;
|
||||||
|
|
||||||
|
while( 1 )
|
||||||
|
{
|
||||||
|
if( node->contents < 0 )
|
||||||
|
{
|
||||||
|
leaf = (mleaf_t *)node;
|
||||||
|
break; // we found a leaf
|
||||||
|
}
|
||||||
|
node = node->children[PlaneDiff( p, node->plane ) <= 0];
|
||||||
|
}
|
||||||
|
|
||||||
if( leaf && leaf->cluster >= 0 )
|
if( leaf && leaf->cluster >= 0 )
|
||||||
return Mod_DecompressPVS( leaf->compressed_vis, world.visbytes );
|
return Mod_DecompressPVS( leaf->compressed_vis, world.visbytes );
|
||||||
@@ -704,7 +681,7 @@ Mod_FatPVS_RecursiveBSPNode
|
|||||||
|
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
static void Mod_FatPVS_RecursiveBSPNode( const vec3_t org, float radius, byte *visbuffer, int visbytes, mnode_t *node, qboolean phs )
|
static void Mod_FatPVS_RecursiveBSPNode( const vec3_t org, float radius, byte *visbuffer, int visbytes, mnode_t *node )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -719,7 +696,7 @@ static void Mod_FatPVS_RecursiveBSPNode( const vec3_t org, float radius, byte *v
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// go down both sides
|
// go down both sides
|
||||||
Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, visbytes, node->children[0], phs );
|
Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, visbytes, node->children[0] );
|
||||||
node = node->children[1];
|
node = node->children[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -727,19 +704,10 @@ static void Mod_FatPVS_RecursiveBSPNode( const vec3_t org, float radius, byte *v
|
|||||||
// if this leaf is in a cluster, accumulate the vis bits
|
// if this leaf is in a cluster, accumulate the vis bits
|
||||||
if(((mleaf_t *)node)->cluster >= 0 )
|
if(((mleaf_t *)node)->cluster >= 0 )
|
||||||
{
|
{
|
||||||
byte *vis;
|
byte *vis = Mod_DecompressPVS( ((mleaf_t *)node)->compressed_vis, world.visbytes );
|
||||||
|
|
||||||
if( phs )
|
for( i = 0; i < visbytes; i++ )
|
||||||
{
|
visbuffer[i] |= vis[i];
|
||||||
int i = ((mleaf_t *)node)->cluster + 1;
|
|
||||||
vis = Mod_DecompressPVS( &world.compressed_phs[world.phsofs[i]], world.visbytes );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vis = Mod_DecompressPVS( ((mleaf_t *)node)->compressed_vis, world.visbytes );
|
|
||||||
}
|
|
||||||
|
|
||||||
Q_memor( visbuffer, vis, visbytes );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -751,7 +719,7 @@ Calculates a PVS that is the inclusive or of all leafs
|
|||||||
within radius pixels of the given point.
|
within radius pixels of the given point.
|
||||||
==================
|
==================
|
||||||
*/
|
*/
|
||||||
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis, qboolean phs )
|
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis )
|
||||||
{
|
{
|
||||||
int bytes = world.visbytes;
|
int bytes = world.visbytes;
|
||||||
mleaf_t *leaf = NULL;
|
mleaf_t *leaf = NULL;
|
||||||
@@ -768,17 +736,9 @@ int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, q
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// requested PHS but we don't have PHS for some reason
|
|
||||||
// enable full visibility
|
|
||||||
if( phs && !( world.compressed_phs && world.phsofs ))
|
|
||||||
{
|
|
||||||
memset( visbuffer, 0xFF, bytes );
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !merge ) memset( visbuffer, 0x00, bytes );
|
if( !merge ) memset( visbuffer, 0x00, bytes );
|
||||||
|
|
||||||
Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, bytes, worldmodel->nodes, phs );
|
Mod_FatPVS_RecursiveBSPNode( org, radius, visbuffer, bytes, worldmodel->nodes );
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
@@ -1863,8 +1823,8 @@ static void Mod_LoadEntities( model_t *mod, dbspmodel_t *bmod )
|
|||||||
{
|
{
|
||||||
char *pszWadFile;
|
char *pszWadFile;
|
||||||
|
|
||||||
Q_strncpy( wadstring, token, sizeof( wadstring ) - 2 );
|
Q_strncpy( wadstring, token, MAX_TOKEN - 2 );
|
||||||
wadstring[sizeof( wadstring ) - 2] = 0;
|
wadstring[MAX_TOKEN - 2] = 0;
|
||||||
|
|
||||||
if( !Q_strchr( wadstring, ';' ))
|
if( !Q_strchr( wadstring, ';' ))
|
||||||
Q_strncat( wadstring, ";", sizeof( wadstring ));
|
Q_strncat( wadstring, ";", sizeof( wadstring ));
|
||||||
@@ -1875,7 +1835,7 @@ static void Mod_LoadEntities( model_t *mod, dbspmodel_t *bmod )
|
|||||||
COM_FixSlashes( pszWadFile );
|
COM_FixSlashes( pszWadFile );
|
||||||
COM_FileBase( pszWadFile, token, sizeof( token ));
|
COM_FileBase( pszWadFile, token, sizeof( token ));
|
||||||
|
|
||||||
// make sure that wad is really exist
|
// make sure what wad is really exist
|
||||||
if( FS_FileExists( va( "%s.wad", token ), false ))
|
if( FS_FileExists( va( "%s.wad", token ), false ))
|
||||||
{
|
{
|
||||||
int num = bmod->wadlist.count++;
|
int num = bmod->wadlist.count++;
|
||||||
@@ -2068,16 +2028,18 @@ static qboolean Mod_LooksLikeWaterTexture( const char *name )
|
|||||||
|
|
||||||
static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureIndex )
|
static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureIndex )
|
||||||
{
|
{
|
||||||
|
#if !XASH_DEDICATED
|
||||||
texture_t *texture = NULL;
|
texture_t *texture = NULL;
|
||||||
mip_t *mipTex = NULL;
|
mip_t *mipTex = NULL;
|
||||||
qboolean usesCustomPalette = false;
|
qboolean usesCustomPalette = false;
|
||||||
uint32_t txFlags = 0;
|
uint32_t txFlags = 0;
|
||||||
|
|
||||||
// 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
|
|
||||||
//
|
|
||||||
// FIXME: for ENGINE_IMPROVED_LINETRACE we need to load textures on server too
|
// FIXME: for ENGINE_IMPROVED_LINETRACE we need to load textures on server too
|
||||||
// but there is no facility for this yet
|
// but there is no facility for this yet
|
||||||
|
if( Host_IsDedicated( ))
|
||||||
|
return;
|
||||||
|
|
||||||
texture = mod->textures[textureIndex];
|
texture = mod->textures[textureIndex];
|
||||||
mipTex = Mod_GetMipTexForTexture( bmod, textureIndex );
|
mipTex = Mod_GetMipTexForTexture( bmod, textureIndex );
|
||||||
|
|
||||||
@@ -2093,15 +2055,10 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
|
|||||||
// 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 )
|
||||||
{
|
{
|
||||||
#if !XASH_DEDICATED
|
ref.dllFuncs.R_InitSkyClouds( mipTex, texture, usesCustomPalette ); // load quake sky
|
||||||
if( !Host_IsDedicated( ))
|
|
||||||
{
|
|
||||||
ref.dllFuncs.R_InitSkyClouds( mipTex, texture, usesCustomPalette ); // load quake sky
|
|
||||||
|
|
||||||
if( R_GetBuiltinTexture( REF_SOLIDSKY_TEXTURE ) && R_GetBuiltinTexture( REF_ALPHASKY_TEXTURE ))
|
if( R_GetBuiltinTexture( REF_SOLIDSKY_TEXTURE ) && R_GetBuiltinTexture( REF_ALPHASKY_TEXTURE ))
|
||||||
SetBits( world.flags, FWORLD_SKYSPHERE );
|
SetBits( world.flags, FWORLD_SKYSPHERE );
|
||||||
}
|
|
||||||
#endif // !XASH_DEDICATED
|
|
||||||
|
|
||||||
// No texture to load in this case, so just exit.
|
// No texture to load in this case, so just exit.
|
||||||
return;
|
return;
|
||||||
@@ -2119,18 +2076,11 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
|
|||||||
|
|
||||||
if( wadIndex >= 0 )
|
if( wadIndex >= 0 )
|
||||||
{
|
{
|
||||||
#if !XASH_DEDICATED
|
texture->gl_texturenum = ref.dllFuncs.GL_LoadTexture( texpath, NULL, 0, txFlags );
|
||||||
if( !Host_IsDedicated( ))
|
|
||||||
texture->gl_texturenum = ref.dllFuncs.GL_LoadTexture( texpath, NULL, 0, txFlags );
|
|
||||||
#endif // !XASH_DEDICATED
|
|
||||||
bmod->wadlist.wadusage[wadIndex]++;
|
bmod->wadlist.wadusage[wadIndex]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !XASH_DEDICATED
|
|
||||||
if( Host_IsDedicated( ))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// WAD failed, so use internal texture (if present)
|
// WAD failed, so use internal texture (if present)
|
||||||
if( mipTex->offsets[0] > 0 && texture->gl_texturenum == 0 )
|
if( mipTex->offsets[0] > 0 && texture->gl_texturenum == 0 )
|
||||||
{
|
{
|
||||||
@@ -2759,153 +2709,6 @@ static void Mod_LoadLeafs( model_t *mod, dbspmodel_t *bmod )
|
|||||||
SetBits( world.flags, FWORLD_WATERALPHA );
|
SetBits( world.flags, FWORLD_WATERALPHA );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
===========
|
|
||||||
Mod_CalcPHS
|
|
||||||
|
|
||||||
To be called while loading world for multiplayer game server
|
|
||||||
===========
|
|
||||||
*/
|
|
||||||
static void Mod_CalcPHS( model_t *mod )
|
|
||||||
{
|
|
||||||
const qboolean vis_stats = host_developer.value >= DEV_EXTENDED;
|
|
||||||
const size_t rowbytes = ALIGN( world.visbytes, 4 ); // force align rows by 32-bit boundary
|
|
||||||
const size_t count = mod->numleafs + 1; // same as mod->submodels[0].visleafs + 1
|
|
||||||
double t1;
|
|
||||||
double t2;
|
|
||||||
size_t total_compressed_size = 0;
|
|
||||||
size_t hcount = 0;
|
|
||||||
size_t vcount = 0;
|
|
||||||
int i;
|
|
||||||
byte *uncompressed_pvs;
|
|
||||||
byte *uncompressed_phs;
|
|
||||||
|
|
||||||
if( !mod->visdata )
|
|
||||||
return;
|
|
||||||
|
|
||||||
#if defined( HAVE_OPENMP )
|
|
||||||
Con_Reportf( "Building PHS in %d threads...\n", omp_get_max_threads( ));
|
|
||||||
#else
|
|
||||||
Con_Reportf( "Building PHS...\n" );
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uncompressed_pvs = Mem_Calloc( mod->mempool, rowbytes * count * 2 );
|
|
||||||
uncompressed_phs = &uncompressed_pvs[rowbytes * count];
|
|
||||||
|
|
||||||
world.phsofs = Mem_Calloc( mod->mempool, sizeof( size_t ) * count );
|
|
||||||
world.compressed_phs = NULL;
|
|
||||||
|
|
||||||
t1 = Platform_DoubleTime();
|
|
||||||
|
|
||||||
#pragma omp parallel
|
|
||||||
{
|
|
||||||
// uncompress pvs first
|
|
||||||
#pragma omp for schedule( static, 256 ) // there might be thousands of leafs, split by 256
|
|
||||||
for( i = 0; i < count; i++ )
|
|
||||||
Mod_DecompressPVSTo( &uncompressed_pvs[rowbytes * i], mod->leafs[i].compressed_vis, world.visbytes );
|
|
||||||
|
|
||||||
// now create phs
|
|
||||||
#pragma omp for schedule( static, 256 ) reduction( + : vcount, hcount )
|
|
||||||
for( i = 0; i < count; i++ )
|
|
||||||
{
|
|
||||||
const byte *scan = &uncompressed_pvs[rowbytes * i];
|
|
||||||
byte *dst = &uncompressed_phs[rowbytes * i]; // rowbytes, not rowwords!
|
|
||||||
size_t j;
|
|
||||||
|
|
||||||
memcpy( dst, scan, rowbytes );
|
|
||||||
|
|
||||||
for( j = 0; j < rowbytes; j++ )
|
|
||||||
{
|
|
||||||
size_t k;
|
|
||||||
uint bitbyte = scan[j];
|
|
||||||
|
|
||||||
if( bitbyte == 0 )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for( k = 0; k < 8; k++ )
|
|
||||||
{
|
|
||||||
size_t index;
|
|
||||||
|
|
||||||
if( !FBitSet( bitbyte, BIT( k )))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// OR this pvs row into the phs
|
|
||||||
// +1 because pvs is 1 based
|
|
||||||
index = (( j * 8 ) + k + 1 );
|
|
||||||
if( index >= count )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Q_memor( dst, &uncompressed_pvs[rowbytes * index], rowbytes );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( vis_stats && i != 0 )
|
|
||||||
{
|
|
||||||
size_t j;
|
|
||||||
|
|
||||||
for( j = 0; j < count; j++ )
|
|
||||||
{
|
|
||||||
if( CHECKVISBIT( scan, j ))
|
|
||||||
vcount++;
|
|
||||||
|
|
||||||
if( CHECKVISBIT( dst, j ))
|
|
||||||
hcount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// since I can't predict at which spot compressed array
|
|
||||||
// should be put, this loop is single threaded
|
|
||||||
for( i = 0; i < count; i++ )
|
|
||||||
{
|
|
||||||
const byte *src = &uncompressed_phs[rowbytes * i];
|
|
||||||
byte temp_compressed_row[(MAX_MAP_LEAFS+1)/4]; // compression for this row might be ineffective
|
|
||||||
size_t compressed_size;
|
|
||||||
|
|
||||||
compressed_size = Mod_CompressPVS( temp_compressed_row, src, rowbytes );
|
|
||||||
|
|
||||||
world.compressed_phs = Mem_Realloc( mod->mempool, world.compressed_phs, total_compressed_size + compressed_size );
|
|
||||||
memcpy( &world.compressed_phs[total_compressed_size], temp_compressed_row, compressed_size );
|
|
||||||
world.phsofs[i] = total_compressed_size;
|
|
||||||
|
|
||||||
total_compressed_size += compressed_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
t2 = Platform_DoubleTime();
|
|
||||||
|
|
||||||
if( vis_stats )
|
|
||||||
Con_Reportf( "Average leaves visible / audible / total: %i / %i / %i\n", vcount / count, hcount / count, count );
|
|
||||||
Con_Reportf( "Uncompressed PHS size: %s\n", Q_memprint( rowbytes * count ));
|
|
||||||
Con_Reportf( "Compressed PHS size: %s\n", Q_memprint( total_compressed_size + sizeof( *world.phsofs ) * count ));
|
|
||||||
Con_Reportf( "PHS building time: %.2f ms\n", ( t2 - t1 ) * 1000.0f );
|
|
||||||
|
|
||||||
// TODO: rewrite this into a unit test
|
|
||||||
// NOTE: how to get GoldSrc fat PHS and PVS data
|
|
||||||
// start a multiplayer server with some op4_bootcamp (for example)
|
|
||||||
// attach to process with GDB:
|
|
||||||
// (gdb) p gPAS[0]
|
|
||||||
// $0 = (byte *) ...
|
|
||||||
// (gdb) p gPAS[gPVSRowBytes * (cl.worldmodel->numleafs + 1)]
|
|
||||||
// $1 = (byte *) ...
|
|
||||||
// (gdb) dump binary memory op4_bootcamp_gs.phs $0 $1
|
|
||||||
// (gdb) p gPVS[0]
|
|
||||||
// $2 = (byte *) ...
|
|
||||||
// (gdb) p gPVS[gPVSRowBytes * (cl.worldmodel->numleafs + 1)]
|
|
||||||
// $3 = (byte *) ...
|
|
||||||
// (gdb) dump binary memory op4_bootcamp_gs.pvs $0 $1
|
|
||||||
//
|
|
||||||
// NOTE: as of writing, uncompressed PVS and PHS data do match! hooray!
|
|
||||||
//
|
|
||||||
// FS_WriteFile( "op4_bootcamp.pvs", uncompressed_pvs, rowbytes * count );
|
|
||||||
// FS_WriteFile( "op4_bootcamp.phs", uncompressed_phs, rowbytes * count );
|
|
||||||
|
|
||||||
// release uncompressed data
|
|
||||||
Mem_Free( uncompressed_pvs );
|
|
||||||
|
|
||||||
// TODO: cache the PHS somewhere, it might take a long time on giant maps
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
Mod_LoadClipnodes
|
Mod_LoadClipnodes
|
||||||
@@ -3103,7 +2906,6 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, const byte *mod_base, qboolea
|
|||||||
char wadvalue[2048];
|
char wadvalue[2048];
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
int i, ret, flags = 0;
|
int i, ret, flags = 0;
|
||||||
qboolean wadlist_warn = false;
|
|
||||||
|
|
||||||
// always reset the intermediate struct
|
// always reset the intermediate struct
|
||||||
memset( bmod, 0, sizeof( dbspmodel_t ));
|
memset( bmod, 0, sizeof( dbspmodel_t ));
|
||||||
@@ -3198,37 +3000,23 @@ static qboolean Mod_LoadBmodelLumps( model_t *mod, const byte *mod_base, qboolea
|
|||||||
{
|
{
|
||||||
world.version = bmod->version;
|
world.version = bmod->version;
|
||||||
#if !XASH_DEDICATED
|
#if !XASH_DEDICATED
|
||||||
|
Mod_InitDebugHulls( mod ); // FIXME: build hulls for separate bmodels (shells, medkits etc)
|
||||||
world.deluxedata = bmod->deluxedata_out; // deluxemap data pointer
|
world.deluxedata = bmod->deluxedata_out; // deluxemap data pointer
|
||||||
world.shadowdata = bmod->shadowdata_out; // occlusion data pointer
|
world.shadowdata = bmod->shadowdata_out; // occlusion data pointer
|
||||||
#endif // XASH_DEDICATED
|
#endif // XASH_DEDICATED
|
||||||
|
|
||||||
if( SV_Active() && svs.maxclients > 1 )
|
|
||||||
Mod_CalcPHS( mod );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for( i = 0; i < bmod->wadlist.count; i++ )
|
for( i = 0; i < bmod->wadlist.count; i++ )
|
||||||
{
|
{
|
||||||
string wadname;
|
|
||||||
|
|
||||||
if( !bmod->wadlist.wadusage[i] )
|
if( !bmod->wadlist.wadusage[i] )
|
||||||
continue;
|
continue;
|
||||||
|
ret = Q_snprintf( &wadvalue[len], sizeof( wadvalue ), "%s.wad; ", bmod->wadlist.wadnames[i] );
|
||||||
Q_snprintf( wadname, sizeof( wadname ), "%s.wad", bmod->wadlist.wadnames[i] );
|
if( ret == -1 )
|
||||||
|
|
||||||
// a1ba: automatically precache used wad files so client will download it
|
|
||||||
if( SV_Active( ))
|
|
||||||
SV_GenericIndex( wadname );
|
|
||||||
|
|
||||||
if( !wadlist_warn )
|
|
||||||
{
|
{
|
||||||
ret = Q_snprintf( &wadvalue[len], sizeof( wadvalue ), "%s; ", wadname );
|
Con_DPrintf( S_WARN "Too many wad files for output!\n" );
|
||||||
if( ret == -1 )
|
break;
|
||||||
{
|
|
||||||
Con_DPrintf( S_WARN "Too many wad files for output!\n" );
|
|
||||||
wadlist_warn = true;
|
|
||||||
}
|
|
||||||
len += ret;
|
|
||||||
}
|
}
|
||||||
|
len += ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( COM_CheckString( wadvalue ))
|
if( COM_CheckString( wadvalue ))
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ GNU General Public License for more details.
|
|||||||
|
|
||||||
#define REFPVS_RADIUS 2.0f // radius for rendering
|
#define REFPVS_RADIUS 2.0f // radius for rendering
|
||||||
#define FATPVS_RADIUS 8.0f // FatPVS use radius smaller than the FatPHS
|
#define FATPVS_RADIUS 8.0f // FatPVS use radius smaller than the FatPHS
|
||||||
#define FATPHS_RADIUS 8.0f // see SV_AddToFatPAS in GoldSrc
|
#define FATPHS_RADIUS 16.0f
|
||||||
|
|
||||||
#define WORLD_INDEX (1) // world index is always 1
|
#define WORLD_INDEX (1) // world index is always 1
|
||||||
|
|
||||||
@@ -115,10 +115,6 @@ typedef struct world_static_s
|
|||||||
int max_recursion;
|
int max_recursion;
|
||||||
|
|
||||||
uint32_t version; // BSP version
|
uint32_t version; // BSP version
|
||||||
|
|
||||||
// Potentially Hearable Set
|
|
||||||
byte *compressed_phs;
|
|
||||||
size_t *phsofs;
|
|
||||||
} world_static_t;
|
} world_static_t;
|
||||||
|
|
||||||
#ifndef REF_DLL
|
#ifndef REF_DLL
|
||||||
@@ -155,7 +151,7 @@ void Mod_FreeUnused( void );
|
|||||||
void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *loaded );
|
void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *loaded );
|
||||||
qboolean Mod_TestBmodelLumps( file_t *f, const char *name, const byte *mod_base, qboolean silent, dlump_t *entities );
|
qboolean Mod_TestBmodelLumps( file_t *f, const char *name, const byte *mod_base, qboolean silent, dlump_t *entities );
|
||||||
qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, int *lastleaf );
|
qboolean Mod_HeadnodeVisible( mnode_t *node, const byte *visbits, int *lastleaf );
|
||||||
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis, qboolean false );
|
int Mod_FatPVS( const vec3_t org, float radius, byte *visbuffer, int visbytes, qboolean merge, qboolean fullvis );
|
||||||
qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbits );
|
qboolean Mod_BoxVisible( const vec3_t mins, const vec3_t maxs, const byte *visbits );
|
||||||
int Mod_CheckLump( const char *filename, const int lump, int *lumpsize );
|
int Mod_CheckLump( const char *filename, const int lump, int *lumpsize );
|
||||||
int Mod_ReadLump( const char *filename, const int lump, void **lumpdata, int *lumpsize );
|
int Mod_ReadLump( const char *filename, const int lump, void **lumpdata, int *lumpsize );
|
||||||
|
|||||||
@@ -780,7 +780,7 @@ extract texture filename from modelname
|
|||||||
*/
|
*/
|
||||||
const char *Mod_StudioTexName( const char *modname )
|
const char *Mod_StudioTexName( const char *modname )
|
||||||
{
|
{
|
||||||
static char texname[MAX_QPATH+1];
|
static char texname[MAX_QPATH];
|
||||||
|
|
||||||
Q_strncpy( texname, modname, sizeof( texname ));
|
Q_strncpy( texname, modname, sizeof( texname ));
|
||||||
COM_StripExtension( texname );
|
COM_StripExtension( texname );
|
||||||
@@ -841,22 +841,6 @@ static studiohdr_t *R_StudioLoadHeader( model_t *mod, const void *buffer )
|
|||||||
return (studiohdr_t *)buffer;
|
return (studiohdr_t *)buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static studiohdr_t *Mod_MaybeTruncateStudioTextureData( model_t *mod )
|
|
||||||
{
|
|
||||||
#if XASH_LOW_MEMORY
|
|
||||||
studiohdr_t *phdr = (studiohdr_t *)mod->cache.data;
|
|
||||||
|
|
||||||
mod->cache.data = Mem_Realloc( mod->mempool, mod->cache.data, phdr->texturedataindex );
|
|
||||||
phdr = (studiohdr_t *)mod->cache.data; // get the new pointer on studiohdr
|
|
||||||
phdr->length = phdr->texturedataindex; // update model size
|
|
||||||
|
|
||||||
return phdr;
|
|
||||||
#else
|
|
||||||
// NOTE: some mods potentially might require full studio model data
|
|
||||||
return (studiohdr_t *)mod->cache.data;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
Mod_LoadStudioModel
|
Mod_LoadStudioModel
|
||||||
@@ -876,62 +860,73 @@ void Mod_LoadStudioModel( model_t *mod, const void *buffer, qboolean *loaded )
|
|||||||
phdr = R_StudioLoadHeader( mod, buffer );
|
phdr = R_StudioLoadHeader( mod, buffer );
|
||||||
if( !phdr ) return; // bad model
|
if( !phdr ) return; // bad model
|
||||||
|
|
||||||
if( !Host_IsDedicated( ) && phdr->numtextures == 0 )
|
if( !Host_IsDedicated() )
|
||||||
{
|
{
|
||||||
studiohdr_t *thdr;
|
if( phdr->numtextures == 0 )
|
||||||
void *buffer2;
|
|
||||||
|
|
||||||
buffer2 = FS_LoadFile( Mod_StudioTexName( mod->name ), NULL, false );
|
|
||||||
thdr = R_StudioLoadHeader( mod, buffer2 );
|
|
||||||
|
|
||||||
if( thdr != NULL )
|
|
||||||
{
|
{
|
||||||
byte *in, *out;
|
studiohdr_t *thdr;
|
||||||
size_t size1, size2;
|
byte *in, *out;
|
||||||
|
void *buffer2 = NULL;
|
||||||
|
size_t size1, size2;
|
||||||
|
|
||||||
|
buffer2 = FS_LoadFile( Mod_StudioTexName( mod->name ), NULL, false );
|
||||||
|
thdr = R_StudioLoadHeader( mod, buffer2 );
|
||||||
|
|
||||||
|
if( !thdr )
|
||||||
|
{
|
||||||
|
Con_Printf( S_WARN "Mod_LoadStudioModel: %s missing textures file\n", mod->name );
|
||||||
|
if( buffer2 ) Mem_Free( buffer2 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
#if !XASH_DEDICATED
|
#if !XASH_DEDICATED
|
||||||
// TODO: Mod_StudioLoadTextures will crash if passed a merged studio model!
|
ref.dllFuncs.Mod_StudioLoadTextures( mod, thdr );
|
||||||
ref.dllFuncs.Mod_StudioLoadTextures( mod, thdr );
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// give space for textures and skinrefs
|
// give space for textures and skinrefs
|
||||||
size1 = thdr->numtextures * sizeof( mstudiotexture_t );
|
size1 = thdr->numtextures * sizeof( mstudiotexture_t );
|
||||||
size2 = thdr->numskinfamilies * thdr->numskinref * sizeof( short );
|
size2 = thdr->numskinfamilies * thdr->numskinref * sizeof( short );
|
||||||
mod->cache.data = Mem_Calloc( mod->mempool, phdr->length + size1 + size2 );
|
mod->cache.data = Mem_Calloc( mod->mempool, phdr->length + size1 + size2 );
|
||||||
memcpy( mod->cache.data, buffer, phdr->length ); // copy main mdl buffer
|
memcpy( mod->cache.data, buffer, phdr->length ); // copy main mdl buffer
|
||||||
phdr = (studiohdr_t *)mod->cache.data; // get the new pointer on studiohdr
|
phdr = (studiohdr_t *)mod->cache.data; // get the new pointer on studiohdr
|
||||||
phdr->numskinfamilies = thdr->numskinfamilies;
|
phdr->numskinfamilies = thdr->numskinfamilies;
|
||||||
phdr->numtextures = thdr->numtextures;
|
phdr->numtextures = thdr->numtextures;
|
||||||
phdr->numskinref = thdr->numskinref;
|
phdr->numskinref = thdr->numskinref;
|
||||||
phdr->textureindex = phdr->length;
|
phdr->textureindex = phdr->length;
|
||||||
phdr->skinindex = phdr->textureindex + size1;
|
phdr->skinindex = phdr->textureindex + size1;
|
||||||
|
|
||||||
in = (byte *)thdr + thdr->textureindex;
|
in = (byte *)thdr + thdr->textureindex;
|
||||||
out = (byte *)phdr + phdr->textureindex;
|
out = (byte *)phdr + phdr->textureindex;
|
||||||
memcpy( out, in, size1 + size2 ); // copy textures + skinrefs
|
memcpy( out, in, size1 + size2 ); // copy textures + skinrefs
|
||||||
phdr->length += size1 + size2;
|
phdr->length += size1 + size2;
|
||||||
|
Mem_Free( buffer2 ); // release T.mdl
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else Con_Printf( S_WARN "%s: %s missing textures file\n", __func__, mod->name );
|
else
|
||||||
|
{
|
||||||
|
// NOTE: don't modify source buffer because it's used for CRC computing
|
||||||
|
mod->cache.data = Mem_Calloc( mod->mempool, phdr->length );
|
||||||
|
memcpy( mod->cache.data, buffer, phdr->length );
|
||||||
|
phdr = (studiohdr_t *)mod->cache.data; // get the new pointer on studiohdr
|
||||||
|
#if !XASH_DEDICATED
|
||||||
|
ref.dllFuncs.Mod_StudioLoadTextures( mod, phdr );
|
||||||
|
#endif
|
||||||
|
|
||||||
if( buffer2 )
|
// NOTE: we wan't keep raw textures in memory. just cutoff model pointer above texture base
|
||||||
Mem_Free( buffer2 ); // release T.mdl
|
mod->cache.data = Mem_Realloc( mod->mempool, mod->cache.data, phdr->texturedataindex );
|
||||||
|
phdr = (studiohdr_t *)mod->cache.data; // get the new pointer on studiohdr
|
||||||
|
phdr->length = phdr->texturedataindex; // update model size
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// NOTE: don't modify source buffer because it's used for CRC computing
|
// just copy model into memory
|
||||||
mod->cache.data = Mem_Calloc( mod->mempool, phdr->length );
|
mod->cache.data = Mem_Calloc( mod->mempool, phdr->length );
|
||||||
memcpy( mod->cache.data, buffer, phdr->length );
|
memcpy( mod->cache.data, buffer, phdr->length );
|
||||||
|
|
||||||
phdr = mod->cache.data;
|
phdr = mod->cache.data;
|
||||||
|
|
||||||
#if !XASH_DEDICATED
|
|
||||||
if( !Host_IsDedicated( ))
|
|
||||||
ref.dllFuncs.Mod_StudioLoadTextures( mod, phdr );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: we may not want to keep raw textures in memory. just cutoff model pointer above texture base
|
|
||||||
phdr = Mod_MaybeTruncateStudioTextureData( mod );
|
|
||||||
|
|
||||||
// setup bounding box
|
// setup bounding box
|
||||||
if( !VectorCompare( vec3_origin, phdr->bbmin ))
|
if( !VectorCompare( vec3_origin, phdr->bbmin ))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -114,11 +114,6 @@ void Mod_FreeModel( model_t *mod )
|
|||||||
world.version = 0;
|
world.version = 0;
|
||||||
world.shadowdata = NULL;
|
world.shadowdata = NULL;
|
||||||
world.deluxedata = NULL;
|
world.deluxedata = NULL;
|
||||||
|
|
||||||
// data already freed by Mem_FreePool above
|
|
||||||
world.hull_models = NULL;
|
|
||||||
world.compressed_phs = NULL;
|
|
||||||
world.phsofs = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memset( mod, 0, sizeof( *mod ));
|
memset( mod, 0, sizeof( *mod ));
|
||||||
|
|||||||
@@ -89,36 +89,6 @@ const char *svc_strings[svc_lastmsg+1] =
|
|||||||
"svc_exec",
|
"svc_exec",
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *svc_legacy_strings[svc_lastmsg+1] =
|
|
||||||
{
|
|
||||||
[svc_legacy_changing] = "svc_legacy_changing",
|
|
||||||
[svc_legacy_ambientsound] = "svc_legacy_ambientsound",
|
|
||||||
[svc_legacy_soundindex] = "svc_legacy_soundindex",
|
|
||||||
[svc_legacy_ambientsound] = "svc_legacy_ambientsound",
|
|
||||||
[svc_legacy_modelindex] = "svc_legacy_modelindex",
|
|
||||||
[svc_legacy_eventindex] = "svc_legacy_eventindex",
|
|
||||||
[svc_legacy_chokecount] = "svc_legacy_chokecount",
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *svc_goldsrc_strings[svc_lastmsg+1] =
|
|
||||||
{
|
|
||||||
[svc_goldsrc_version] = "svc_goldsrc_version",
|
|
||||||
[svc_goldsrc_serverinfo] = "svc_goldsrc_serverinfo",
|
|
||||||
[svc_goldsrc_deltadescription] = "svc_goldsrc_deltadescription",
|
|
||||||
[svc_goldsrc_stopsound] = "svc_goldsrc_stopsound",
|
|
||||||
[svc_goldsrc_damage] = "svc_goldsrc_damage",
|
|
||||||
[svc_goldsrc_killedmonster] = "svc_goldsrc_killedmonster",
|
|
||||||
[svc_goldsrc_foundsecret] = "svc_goldsrc_foundsecret",
|
|
||||||
[svc_goldsrc_spawnstaticsound] = "svc_goldsrc_spawnstaticsound",
|
|
||||||
[svc_goldsrc_decalname] = "svc_goldsrc_decalname",
|
|
||||||
[svc_goldsrc_newusermsg] = "svc_goldsrc_newusermsg",
|
|
||||||
[svc_goldsrc_newmovevars] = "svc_goldsrc_newmovevars",
|
|
||||||
[svc_goldsrc_sendextrainfo] = "svc_goldsrc_sendextrainfo",
|
|
||||||
[svc_goldsrc_timescale] = "svc_goldsrc_timescale",
|
|
||||||
[svc_goldsrc_sendcvarvalue] = "svc_goldsrc_sendcvarvalue",
|
|
||||||
[svc_goldsrc_sendcvarvalue2] = "svc_goldsrc_sendcvarvalue2",
|
|
||||||
};
|
|
||||||
|
|
||||||
void MSG_InitMasks( void )
|
void MSG_InitMasks( void )
|
||||||
{
|
{
|
||||||
uint startbit, endbit;
|
uint startbit, endbit;
|
||||||
@@ -139,6 +109,85 @@ void MSG_InitMasks( void )
|
|||||||
ExtraMasks[maskBit] = (uint)BIT( maskBit ) - 1;
|
ExtraMasks[maskBit] = (uint)BIT( maskBit ) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits )
|
||||||
|
{
|
||||||
|
MSG_StartWriting( sb, pData, nBytes, 0, nMaxBits );
|
||||||
|
|
||||||
|
sb->pDebugName = pDebugName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits )
|
||||||
|
{
|
||||||
|
// make sure it's dword aligned and padded.
|
||||||
|
Assert(((uint32_t)pData & 3 ) == 0 );
|
||||||
|
|
||||||
|
sb->pDebugName = "Unnamed";
|
||||||
|
sb->pData = (byte *)pData;
|
||||||
|
|
||||||
|
if( nBits == -1 )
|
||||||
|
{
|
||||||
|
sb->nDataBits = nBytes << 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert( nBits <= nBytes * 8 );
|
||||||
|
sb->nDataBits = nBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb->iCurBit = iStartBit;
|
||||||
|
sb->bOverflow = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=======================
|
||||||
|
MSG_Clear
|
||||||
|
|
||||||
|
for clearing overflowed buffer
|
||||||
|
=======================
|
||||||
|
*/
|
||||||
|
void MSG_Clear( sizebuf_t *sb )
|
||||||
|
{
|
||||||
|
sb->iCurBit = 0;
|
||||||
|
sb->bOverflow = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static qboolean MSG_Overflow( sizebuf_t *sb, int nBits )
|
||||||
|
{
|
||||||
|
if( sb->iCurBit + nBits > sb->nDataBits )
|
||||||
|
sb->bOverflow = true;
|
||||||
|
return sb->bOverflow;
|
||||||
|
}
|
||||||
|
|
||||||
|
qboolean MSG_CheckOverflow( sizebuf_t *sb )
|
||||||
|
{
|
||||||
|
return MSG_Overflow( sb, 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence )
|
||||||
|
{
|
||||||
|
// compute the file offset
|
||||||
|
switch( whence )
|
||||||
|
{
|
||||||
|
case SEEK_CUR:
|
||||||
|
bitPos += sb->iCurBit;
|
||||||
|
break;
|
||||||
|
case SEEK_SET:
|
||||||
|
break;
|
||||||
|
case SEEK_END:
|
||||||
|
bitPos += sb->nDataBits;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( bitPos < 0 || bitPos > sb->nDataBits )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
sb->iCurBit = bitPos;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void MSG_WriteOneBit( sizebuf_t *sb, int nValue )
|
void MSG_WriteOneBit( sizebuf_t *sb, int nValue )
|
||||||
{
|
{
|
||||||
if( !MSG_Overflow( sb, 1 ))
|
if( !MSG_Overflow( sb, 1 ))
|
||||||
@@ -620,7 +669,7 @@ qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes )
|
|||||||
return MSG_ReadBits( sb, pOut, nBytes << 3 );
|
return MSG_ReadBits( sb, pOut, nBytes << 3 );
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
|
char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
|
||||||
{
|
{
|
||||||
static char string[4096];
|
static char string[4096];
|
||||||
int l = 0, c;
|
int l = 0, c;
|
||||||
@@ -646,16 +695,6 @@ static char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine )
|
|||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *MSG_ReadString( sizebuf_t *sb )
|
|
||||||
{
|
|
||||||
return MSG_ReadStringExt( sb, false );
|
|
||||||
}
|
|
||||||
|
|
||||||
char *MSG_ReadStringLine( sizebuf_t *sb )
|
|
||||||
{
|
|
||||||
return MSG_ReadStringExt( sb, true );
|
|
||||||
}
|
|
||||||
|
|
||||||
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove )
|
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove )
|
||||||
{
|
{
|
||||||
int i, endbit = startbit + bitstoremove;
|
int i, endbit = startbit + bitstoremove;
|
||||||
|
|||||||
@@ -30,128 +30,39 @@ GNU General Public License for more details.
|
|||||||
// So PAD_NUMBER(0,4) is 0 and PAD_NUMBER(1,4) is 4
|
// So PAD_NUMBER(0,4) is 0 and PAD_NUMBER(1,4) is 4
|
||||||
#define PAD_NUMBER( num, boundary ) ((( num ) + (( boundary ) - 1 )) / ( boundary )) * ( boundary )
|
#define PAD_NUMBER( num, boundary ) ((( num ) + (( boundary ) - 1 )) / ( boundary )) * ( boundary )
|
||||||
|
|
||||||
static inline int BitByte( int bits )
|
_inline int BitByte( int bits )
|
||||||
{
|
{
|
||||||
return PAD_NUMBER( bits, 8 ) >> 3;
|
return PAD_NUMBER( bits, 8 ) >> 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sizebuf_s
|
struct sizebuf_s
|
||||||
{
|
{
|
||||||
byte *pData;
|
qboolean bOverflow; // overflow reading or writing
|
||||||
qboolean bOverflow; // overflow reading or writing
|
const char *pDebugName; // buffer name (pointer to const name)
|
||||||
int iCurBit;
|
|
||||||
int nDataBits;
|
byte *pData;
|
||||||
const char *pDebugName; // buffer name (pointer to const name)
|
int iCurBit;
|
||||||
|
int nDataBits;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MSG_StartReading MSG_StartWriting
|
#define MSG_StartReading MSG_StartWriting
|
||||||
#define MSG_GetNumBytesRead MSG_GetNumBytesWritten
|
#define MSG_GetNumBytesRead MSG_GetNumBytesWritten
|
||||||
#define MSG_GetRealBytesRead MSG_GetRealBytesWritten
|
#define MSG_GetRealBytesRead MSG_GetRealBytesWritten
|
||||||
#define MSG_GetNumBitsRead MSG_GetNumBitsWritten
|
#define MSG_GetNumBitsRead MSG_GetNumBitsWritten
|
||||||
#define MSG_ReadBitAngles MSG_ReadBitVec3Coord
|
#define MSG_ReadBitAngles MSG_ReadBitVec3Coord
|
||||||
#define MSG_ReadAngle( sb ) (float)( MSG_ReadChar( sb ) * ( 360.0f / 256.0f ))
|
#define MSG_ReadString( sb ) MSG_ReadStringExt( sb, false )
|
||||||
#define MSG_Init( sb, name, data, bytes ) MSG_InitExt( sb, name, data, bytes, -1 )
|
#define MSG_ReadStringLine( sb ) MSG_ReadStringExt( sb, true )
|
||||||
#define MSG_CheckOverflow( sb ) MSG_Overflow( sb, 0 )
|
#define MSG_ReadAngle( sb ) (float)(MSG_ReadChar( sb ) * ( 360.0f / 256.0f ))
|
||||||
|
#define MSG_Init( sb, name, data, bytes ) MSG_InitExt( sb, name, data, bytes, -1 )
|
||||||
|
|
||||||
// common functions
|
// common functions
|
||||||
static inline void MSG_Clear( sizebuf_t *sb )
|
void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nMaxBits );
|
||||||
{
|
void MSG_InitMasks( void ); // called once at startup engine
|
||||||
sb->bOverflow = false;
|
int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence );
|
||||||
sb->iCurBit = 0;
|
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
|
||||||
}
|
_inline int MSG_TellBit( sizebuf_t *sb ) { return sb->iCurBit; }
|
||||||
|
_inline const char *MSG_GetName( sizebuf_t *sb ) { return sb->pDebugName; }
|
||||||
static inline void MSG_InitExt( sizebuf_t *sb, const char *pDebugName, void *pData, int nBytes, int nBits )
|
qboolean MSG_CheckOverflow( sizebuf_t *sb );
|
||||||
{
|
|
||||||
sb->pData = pData;
|
|
||||||
MSG_Clear( sb );
|
|
||||||
|
|
||||||
if( nBits < 0 )
|
|
||||||
sb->nDataBits = nBytes << 3;
|
|
||||||
else
|
|
||||||
sb->nDataBits = nBits;
|
|
||||||
|
|
||||||
sb->pDebugName = pDebugName;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits )
|
|
||||||
{
|
|
||||||
MSG_InitExt( sb, "Unnamed", pData, nBytes, nBits );
|
|
||||||
sb->iCurBit = iStartBit;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int MSG_SeekToBit( sizebuf_t *sb, int bitPos, int whence )
|
|
||||||
{
|
|
||||||
// compute the file offset
|
|
||||||
switch( whence )
|
|
||||||
{
|
|
||||||
case SEEK_CUR:
|
|
||||||
bitPos += sb->iCurBit;
|
|
||||||
break;
|
|
||||||
case SEEK_SET:
|
|
||||||
break;
|
|
||||||
case SEEK_END:
|
|
||||||
bitPos += sb->nDataBits;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( unlikely( bitPos < 0 || bitPos > sb->nDataBits ))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
sb->iCurBit = bitPos;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int MSG_TellBit( sizebuf_t *sb )
|
|
||||||
{
|
|
||||||
return sb->iCurBit;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline const char *MSG_GetName( sizebuf_t *sb )
|
|
||||||
{
|
|
||||||
return sb->pDebugName;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int MSG_GetNumBytesWritten( sizebuf_t *sb )
|
|
||||||
{
|
|
||||||
return BitByte( sb->iCurBit );
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int MSG_GetRealBytesWritten( sizebuf_t *sb )
|
|
||||||
{
|
|
||||||
return sb->iCurBit >> 3; // unpadded
|
|
||||||
}
|
|
||||||
static inline int MSG_GetNumBitsWritten( sizebuf_t *sb )
|
|
||||||
{
|
|
||||||
return sb->iCurBit;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int MSG_GetMaxBits( sizebuf_t *sb )
|
|
||||||
{
|
|
||||||
return sb->nDataBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int MSG_GetMaxBytes( sizebuf_t *sb )
|
|
||||||
{
|
|
||||||
return sb->nDataBits >> 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int MSG_GetNumBitsLeft( sizebuf_t *sb )
|
|
||||||
{
|
|
||||||
return sb->nDataBits - sb->iCurBit;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int MSG_GetNumBytesLeft( sizebuf_t *sb )
|
|
||||||
{
|
|
||||||
return MSG_GetNumBitsLeft( sb ) >> 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline byte *MSG_GetData( sizebuf_t *sb )
|
|
||||||
{
|
|
||||||
return sb->pData;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if XASH_BIG_ENDIAN
|
#if XASH_BIG_ENDIAN
|
||||||
#define MSG_BigShort( x ) ( x )
|
#define MSG_BigShort( x ) ( x )
|
||||||
@@ -162,19 +73,13 @@ static inline uint16_t MSG_BigShort( const uint16_t x )
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline qboolean MSG_Overflow( sizebuf_t *sb, int nBits )
|
// init writing
|
||||||
{
|
void MSG_StartWriting( sizebuf_t *sb, void *pData, int nBytes, int iStartBit, int nBits );
|
||||||
if( sb->iCurBit + nBits > sb->nDataBits )
|
void MSG_Clear( sizebuf_t *sb );
|
||||||
sb->bOverflow = true;
|
|
||||||
return sb->bOverflow;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MSG_InitMasks( void ); // called once at startup engine
|
|
||||||
void MSG_ExciseBits( sizebuf_t *sb, int startbit, int bitstoremove );
|
|
||||||
|
|
||||||
// Bit-write functions
|
// Bit-write functions
|
||||||
void MSG_WriteOneBit( sizebuf_t *sb, int nValue );
|
void MSG_WriteOneBit( sizebuf_t *sb, int nValue );
|
||||||
NO_ASAN void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits );
|
void MSG_WriteUBitLong( sizebuf_t *sb, uint curData, int numbits );
|
||||||
void MSG_WriteSBitLong( sizebuf_t *sb, int data, int numbits );
|
void MSG_WriteSBitLong( sizebuf_t *sb, int data, int numbits );
|
||||||
void MSG_WriteBitLong( sizebuf_t *sb, uint data, int numbits, qboolean bSigned );
|
void MSG_WriteBitLong( sizebuf_t *sb, uint data, int numbits, qboolean bSigned );
|
||||||
qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits );
|
qboolean MSG_WriteBits( sizebuf_t *sb, const void *pData, int nBits );
|
||||||
@@ -194,11 +99,20 @@ void MSG_WriteCoord( sizebuf_t *sb, float val );
|
|||||||
void MSG_WriteFloat( sizebuf_t *sb, float val );
|
void MSG_WriteFloat( sizebuf_t *sb, float val );
|
||||||
void MSG_WriteVec3Coord( sizebuf_t *sb, const float *fa );
|
void MSG_WriteVec3Coord( sizebuf_t *sb, const float *fa );
|
||||||
void MSG_WriteVec3Angles( sizebuf_t *sb, const float *fa );
|
void MSG_WriteVec3Angles( sizebuf_t *sb, const float *fa );
|
||||||
|
qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes ); // same as MSG_WriteData
|
||||||
qboolean MSG_WriteString( sizebuf_t *sb, const char *pStr ); // returns false if it overflows the buffer.
|
qboolean MSG_WriteString( sizebuf_t *sb, const char *pStr ); // returns false if it overflows the buffer.
|
||||||
qboolean MSG_WriteStringf( sizebuf_t *sb, const char *format, ... ) _format( 2 );
|
qboolean MSG_WriteStringf( sizebuf_t *sb, const char *format, ... ) _format( 2 );
|
||||||
qboolean MSG_WriteBytes( sizebuf_t *sb, const void *pBuf, int nBytes );
|
|
||||||
|
|
||||||
// helper functions
|
// helper functions
|
||||||
|
_inline int MSG_GetNumBytesWritten( sizebuf_t *sb ) { return BitByte( sb->iCurBit ); }
|
||||||
|
_inline int MSG_GetRealBytesWritten( sizebuf_t *sb ) { return sb->iCurBit >> 3; } // unpadded
|
||||||
|
_inline int MSG_GetNumBitsWritten( sizebuf_t *sb ) { return sb->iCurBit; }
|
||||||
|
_inline int MSG_GetMaxBits( sizebuf_t *sb ) { return sb->nDataBits; }
|
||||||
|
_inline int MSG_GetMaxBytes( sizebuf_t *sb ) { return sb->nDataBits >> 3; }
|
||||||
|
_inline int MSG_GetNumBitsLeft( sizebuf_t *sb ) { return sb->nDataBits - sb->iCurBit; }
|
||||||
|
_inline int MSG_GetNumBytesLeft( sizebuf_t *sb ) { return MSG_GetNumBitsLeft( sb ) >> 3; }
|
||||||
|
_inline byte *MSG_GetData( sizebuf_t *sb ) { return sb->pData; }
|
||||||
|
_inline byte *MSG_GetBuf( sizebuf_t *sb ) { return sb->pData; } // just an alias
|
||||||
|
|
||||||
// Bit-read functions
|
// Bit-read functions
|
||||||
int MSG_ReadOneBit( sizebuf_t *sb );
|
int MSG_ReadOneBit( sizebuf_t *sb );
|
||||||
@@ -222,8 +136,7 @@ float MSG_ReadCoord( sizebuf_t *sb );
|
|||||||
float MSG_ReadFloat( sizebuf_t *sb );
|
float MSG_ReadFloat( sizebuf_t *sb );
|
||||||
void MSG_ReadVec3Coord( sizebuf_t *sb, vec3_t fa );
|
void MSG_ReadVec3Coord( sizebuf_t *sb, vec3_t fa );
|
||||||
void MSG_ReadVec3Angles( sizebuf_t *sb, vec3_t fa );
|
void MSG_ReadVec3Angles( sizebuf_t *sb, vec3_t fa );
|
||||||
char *MSG_ReadString( sizebuf_t *sb );
|
|
||||||
char *MSG_ReadStringLine( sizebuf_t *sb );
|
|
||||||
qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes );
|
qboolean MSG_ReadBytes( sizebuf_t *sb, void *pOut, int nBytes );
|
||||||
|
char *MSG_ReadStringExt( sizebuf_t *sb, qboolean bLine );
|
||||||
|
|
||||||
#endif//NET_BUFFER_H
|
#endif//NET_BUFFER_H
|
||||||
|
|||||||
@@ -919,20 +919,13 @@ int Netchan_CreateFileFragments( netchan_t *chan, const char *filename )
|
|||||||
int remaining;
|
int remaining;
|
||||||
int bufferid = 1;
|
int bufferid = 1;
|
||||||
fs_offset_t filesize = 0;
|
fs_offset_t filesize = 0;
|
||||||
|
char compressedfilename[MAX_OSPATH];
|
||||||
int compressedFileTime;
|
int compressedFileTime;
|
||||||
int fileTime;
|
int fileTime;
|
||||||
qboolean firstfragment = true;
|
qboolean firstfragment = true;
|
||||||
qboolean bCompressed = false;
|
qboolean bCompressed = false;
|
||||||
fragbufwaiting_t *wait, *p;
|
fragbufwaiting_t *wait, *p;
|
||||||
fragbuf_t *buf;
|
fragbuf_t *buf;
|
||||||
char compressedfilename[sizeof( buf->filename ) + 5];
|
|
||||||
|
|
||||||
// shouldn't be critical, but just in case
|
|
||||||
if( Q_strlen( filename ) > sizeof( buf->filename ) - 1 )
|
|
||||||
{
|
|
||||||
Con_Printf( S_WARN "Unable to transfer %s due to path length overflow\n", filename );
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(( filesize = FS_FileSize( filename, false )) <= 0 )
|
if(( filesize = FS_FileSize( filename, false )) <= 0 )
|
||||||
{
|
{
|
||||||
@@ -944,7 +937,8 @@ int Netchan_CreateFileFragments( netchan_t *chan, const char *filename )
|
|||||||
chunksize = chan->pfnBlockSize( chan->client, FRAGSIZE_FRAG );
|
chunksize = chan->pfnBlockSize( chan->client, FRAGSIZE_FRAG );
|
||||||
else chunksize = FRAGMENT_MAX_SIZE; // fallback
|
else chunksize = FRAGMENT_MAX_SIZE; // fallback
|
||||||
|
|
||||||
Q_snprintf( compressedfilename, sizeof( compressedfilename ), "%s.ztmp", filename );
|
Q_strncpy( compressedfilename, filename, sizeof( compressedfilename ));
|
||||||
|
COM_ReplaceExtension( compressedfilename, ".ztmp", sizeof( compressedfilename ));
|
||||||
compressedFileTime = FS_FileTime( compressedfilename, false );
|
compressedFileTime = FS_FileTime( compressedfilename, false );
|
||||||
fileTime = FS_FileTime( filename, false );
|
fileTime = FS_FileTime( filename, false );
|
||||||
|
|
||||||
@@ -1527,9 +1521,10 @@ void Netchan_TransmitBits( netchan_t *chan, int length, byte *data )
|
|||||||
|
|
||||||
if( pbuf->iscompressed )
|
if( pbuf->iscompressed )
|
||||||
{
|
{
|
||||||
char compressedfilename[sizeof( pbuf->filename ) + 5];
|
char compressedfilename[MAX_OSPATH];
|
||||||
|
|
||||||
Q_snprintf( compressedfilename, sizeof( compressedfilename ), "%s.ztmp", pbuf->filename );
|
Q_strncpy( compressedfilename, pbuf->filename, sizeof( compressedfilename ));
|
||||||
|
COM_ReplaceExtension( compressedfilename, ".ztmp", sizeof( compressedfilename ));
|
||||||
file = FS_Open( compressedfilename, "rb", false );
|
file = FS_Open( compressedfilename, "rb", false );
|
||||||
}
|
}
|
||||||
else file = FS_Open( pbuf->filename, "rb", false );
|
else file = FS_Open( pbuf->filename, "rb", false );
|
||||||
|
|||||||
@@ -315,43 +315,6 @@ static const delta_field_t ent_fields[] =
|
|||||||
{ NULL },
|
{ NULL },
|
||||||
};
|
};
|
||||||
|
|
||||||
#if XASH_ENGINE_TESTS
|
|
||||||
typedef struct delta_test_struct_t
|
|
||||||
{
|
|
||||||
char dt_string[128]; // always signed
|
|
||||||
float dt_timewindow_big; // always signed
|
|
||||||
float dt_timewindow_8; // always signed
|
|
||||||
float dt_angle; // always_signed
|
|
||||||
float dt_float_signed;
|
|
||||||
float dt_float_unsigned;
|
|
||||||
int32_t dt_integer_signed;
|
|
||||||
uint32_t dt_integer_unsigned;
|
|
||||||
int16_t dt_short_signed;
|
|
||||||
uint16_t dt_short_unsigned;
|
|
||||||
int8_t dt_byte_signed;
|
|
||||||
uint8_t dt_byte_unsigned;
|
|
||||||
} delta_test_struct_t;
|
|
||||||
|
|
||||||
#define TEST_DEF( x ) #x, offsetof( delta_test_struct_t, x ), sizeof( ((delta_test_struct_t *)0)->x )
|
|
||||||
|
|
||||||
static const delta_field_t test_fields[] =
|
|
||||||
{
|
|
||||||
{ TEST_DEF( dt_string ) },
|
|
||||||
{ TEST_DEF( dt_timewindow_big )},
|
|
||||||
{ TEST_DEF( dt_timewindow_8 )},
|
|
||||||
{ TEST_DEF( dt_angle ) },
|
|
||||||
{ TEST_DEF( dt_float_signed ) },
|
|
||||||
{ TEST_DEF( dt_float_unsigned ) },
|
|
||||||
{ TEST_DEF( dt_integer_signed ) },
|
|
||||||
{ TEST_DEF( dt_integer_unsigned ) },
|
|
||||||
{ TEST_DEF( dt_short_signed ) },
|
|
||||||
{ TEST_DEF( dt_short_unsigned ) },
|
|
||||||
{ TEST_DEF( dt_byte_signed ) },
|
|
||||||
{ TEST_DEF( dt_byte_unsigned ) },
|
|
||||||
{ NULL },
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
DT_EVENT_T = 0,
|
DT_EVENT_T = 0,
|
||||||
@@ -362,10 +325,6 @@ enum
|
|||||||
DT_ENTITY_STATE_T,
|
DT_ENTITY_STATE_T,
|
||||||
DT_ENTITY_STATE_PLAYER_T,
|
DT_ENTITY_STATE_PLAYER_T,
|
||||||
DT_CUSTOM_ENTITY_STATE_T,
|
DT_CUSTOM_ENTITY_STATE_T,
|
||||||
#if XASH_ENGINE_TESTS
|
|
||||||
DT_DELTA_TEST_STRUCT_T,
|
|
||||||
#endif
|
|
||||||
DT_STRUCT_COUNT
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static delta_info_t dt_info[] =
|
static delta_info_t dt_info[] =
|
||||||
@@ -378,10 +337,7 @@ static delta_info_t dt_info[] =
|
|||||||
[DT_ENTITY_STATE_T] = { "entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
[DT_ENTITY_STATE_T] = { "entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||||
[DT_ENTITY_STATE_PLAYER_T] = { "entity_state_player_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
[DT_ENTITY_STATE_PLAYER_T] = { "entity_state_player_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||||
[DT_CUSTOM_ENTITY_STATE_T] = { "custom_entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
[DT_CUSTOM_ENTITY_STATE_T] = { "custom_entity_state_t", ent_fields, NUM_FIELDS( ent_fields ) },
|
||||||
#if XASH_ENGINE_TESTS
|
{ NULL },
|
||||||
[DT_DELTA_TEST_STRUCT_T] = { "delta_test_struct_t", test_fields, NUM_FIELDS( test_fields ) },
|
|
||||||
#endif
|
|
||||||
[DT_STRUCT_COUNT] = { NULL },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static delta_info_t *Delta_FindStruct( const char *name )
|
static delta_info_t *Delta_FindStruct( const char *name )
|
||||||
@@ -455,7 +411,9 @@ static void Delta_CustomEncode( delta_info_t *dt, const void *from, const void *
|
|||||||
dt->pFields[i].bInactive = false;
|
dt->pFields[i].bInactive = false;
|
||||||
|
|
||||||
if( dt->userCallback )
|
if( dt->userCallback )
|
||||||
|
{
|
||||||
dt->userCallback( dt->pFields, from, to );
|
dt->userCallback( dt->pFields, from, to );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName )
|
static delta_field_t *Delta_FindFieldInfo( const delta_field_t *pInfo, const char *fieldName )
|
||||||
@@ -1016,14 +974,14 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
|
|||||||
toF = *(uint8_t *)((int8_t *)to + pField->offset );
|
toF = *(uint8_t *)((int8_t *)to + pField->offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !Q_equal(pField->multiplier, 1.0f ))
|
|
||||||
{
|
|
||||||
fromF *= pField->multiplier;
|
|
||||||
toF *= pField->multiplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
||||||
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
|
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
|
||||||
|
|
||||||
|
if( !Q_equal(pField->multiplier, 1.0f ))
|
||||||
|
fromF *= pField->multiplier;
|
||||||
|
|
||||||
|
if( !Q_equal( pField->multiplier, 1.0f ))
|
||||||
|
toF *= pField->multiplier;
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_SHORT )
|
else if( pField->flags & DT_SHORT )
|
||||||
{
|
{
|
||||||
@@ -1038,14 +996,14 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
|
|||||||
toF = *(uint16_t *)((int8_t *)to + pField->offset );
|
toF = *(uint16_t *)((int8_t *)to + pField->offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !Q_equal(pField->multiplier, 1.0f ))
|
|
||||||
{
|
|
||||||
fromF *= pField->multiplier;
|
|
||||||
toF *= pField->multiplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
||||||
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
|
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
|
||||||
|
|
||||||
|
if( !Q_equal(pField->multiplier, 1.0f ))
|
||||||
|
fromF *= pField->multiplier;
|
||||||
|
|
||||||
|
if( !Q_equal( pField->multiplier, 1.0f ))
|
||||||
|
toF *= pField->multiplier;
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_INTEGER )
|
else if( pField->flags & DT_INTEGER )
|
||||||
{
|
{
|
||||||
@@ -1059,15 +1017,14 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
|
|||||||
fromF = *(uint32_t *)((int8_t *)from + pField->offset );
|
fromF = *(uint32_t *)((int8_t *)from + pField->offset );
|
||||||
toF = *(uint32_t *)((int8_t *)to + pField->offset );
|
toF = *(uint32_t *)((int8_t *)to + pField->offset );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !Q_equal(pField->multiplier, 1.0f ))
|
|
||||||
{
|
|
||||||
fromF *= pField->multiplier;
|
|
||||||
toF *= pField->multiplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
fromF = Delta_ClampIntegerField( pField, fromF, signbit, pField->bits );
|
||||||
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
|
toF = Delta_ClampIntegerField( pField, toF, signbit, pField->bits );
|
||||||
|
|
||||||
|
if( !Q_equal(pField->multiplier, 1.0f ))
|
||||||
|
fromF *= pField->multiplier;
|
||||||
|
|
||||||
|
if( !Q_equal( pField->multiplier, 1.0f ))
|
||||||
|
toF *= pField->multiplier;
|
||||||
}
|
}
|
||||||
else if( pField->flags & ( DT_ANGLE|DT_FLOAT ))
|
else if( pField->flags & ( DT_ANGLE|DT_FLOAT ))
|
||||||
{
|
{
|
||||||
@@ -1077,17 +1034,33 @@ static qboolean Delta_CompareField( delta_t *pField, void *from, void *to, doubl
|
|||||||
}
|
}
|
||||||
else if( pField->flags & DT_TIMEWINDOW_8 )
|
else if( pField->flags & DT_TIMEWINDOW_8 )
|
||||||
{
|
{
|
||||||
val_a = *(float *)((byte *)from + pField->offset );
|
val_a = Q_rint((*(float *)((byte *)from + pField->offset )) * 100.0f );
|
||||||
val_b = *(float *)((byte *)to + pField->offset );
|
val_b = Q_rint((*(float *)((byte *)to + pField->offset )) * 100.0f );
|
||||||
fromF = Q_rint( val_a * 100.0 );
|
val_a -= Q_rint(timebase * 100.0);
|
||||||
toF = Q_rint( val_b * 100.0 );
|
val_b -= Q_rint(timebase * 100.0);
|
||||||
|
fromF = FloatAsInt( val_a );
|
||||||
|
toF = FloatAsInt( val_b );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
||||||
{
|
{
|
||||||
val_a = *(float *)((byte *)from + pField->offset );
|
val_a = (*(float *)((byte *)from + pField->offset ));
|
||||||
val_b = *(float *)((byte *)to + pField->offset );
|
val_b = (*(float *)((byte *)to + pField->offset ));
|
||||||
fromF = Q_rint( val_a * pField->multiplier );
|
|
||||||
toF = Q_rint( val_b * pField->multiplier );
|
if( !Q_equal( pField->multiplier, 1.0f ))
|
||||||
|
{
|
||||||
|
val_a *= pField->multiplier;
|
||||||
|
val_b *= pField->multiplier;
|
||||||
|
val_a = (timebase * pField->multiplier) - val_a;
|
||||||
|
val_b = (timebase * pField->multiplier) - val_b;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
val_a = timebase - val_a;
|
||||||
|
val_b = timebase - val_b;
|
||||||
|
}
|
||||||
|
|
||||||
|
fromF = FloatAsInt( val_a );
|
||||||
|
toF = FloatAsInt( val_b );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_STRING )
|
else if( pField->flags & DT_STRING )
|
||||||
{
|
{
|
||||||
@@ -1171,7 +1144,6 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
|
|||||||
int signbit = FBitSet( pField->flags, DT_SIGNED ) ? 1 : 0;
|
int signbit = FBitSet( pField->flags, DT_SIGNED ) ? 1 : 0;
|
||||||
float flValue, flAngle;
|
float flValue, flAngle;
|
||||||
uint iValue;
|
uint iValue;
|
||||||
int dt;
|
|
||||||
const char *pStr;
|
const char *pStr;
|
||||||
|
|
||||||
if( Delta_CompareField( pField, from, to, timebase ))
|
if( Delta_CompareField( pField, from, to, timebase ))
|
||||||
@@ -1188,11 +1160,11 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
|
|||||||
iValue = *(int8_t *)((int8_t *)to + pField->offset );
|
iValue = *(int8_t *)((int8_t *)to + pField->offset );
|
||||||
else
|
else
|
||||||
iValue = *(uint8_t *)((int8_t *)to + pField->offset );
|
iValue = *(uint8_t *)((int8_t *)to + pField->offset );
|
||||||
|
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
||||||
|
|
||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||||
iValue *= pField->multiplier;
|
iValue *= pField->multiplier;
|
||||||
|
|
||||||
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
|
||||||
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_SHORT )
|
else if( pField->flags & DT_SHORT )
|
||||||
@@ -1201,11 +1173,11 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
|
|||||||
iValue = *(int16_t *)((int8_t *)to + pField->offset );
|
iValue = *(int16_t *)((int8_t *)to + pField->offset );
|
||||||
else
|
else
|
||||||
iValue = *(uint16_t *)((int8_t *)to + pField->offset );
|
iValue = *(uint16_t *)((int8_t *)to + pField->offset );
|
||||||
|
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
||||||
|
|
||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||||
iValue *= pField->multiplier;
|
iValue *= pField->multiplier;
|
||||||
|
|
||||||
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
|
||||||
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_INTEGER )
|
else if( pField->flags & DT_INTEGER )
|
||||||
@@ -1214,11 +1186,11 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
|
|||||||
iValue = *(int32_t *)((int8_t *)to + pField->offset );
|
iValue = *(int32_t *)((int8_t *)to + pField->offset );
|
||||||
else
|
else
|
||||||
iValue = *(uint32_t *)((int8_t *)to + pField->offset );
|
iValue = *(uint32_t *)((int8_t *)to + pField->offset );
|
||||||
|
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
||||||
|
|
||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||||
iValue *= pField->multiplier;
|
iValue *= pField->multiplier;
|
||||||
|
|
||||||
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
|
||||||
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_FLOAT )
|
else if( pField->flags & DT_FLOAT )
|
||||||
@@ -1238,17 +1210,19 @@ static qboolean Delta_WriteField( sizebuf_t *msg, delta_t *pField, void *from, v
|
|||||||
}
|
}
|
||||||
else if( pField->flags & DT_TIMEWINDOW_8 )
|
else if( pField->flags & DT_TIMEWINDOW_8 )
|
||||||
{
|
{
|
||||||
|
signbit = 1; // timewindow is always signed
|
||||||
flValue = *(float *)((byte *)to + pField->offset );
|
flValue = *(float *)((byte *)to + pField->offset );
|
||||||
dt = Q_rint(( timebase - flValue ) * 100.0 );
|
iValue = (int)Q_rint( timebase * 100.0 ) - (int)Q_rint( flValue * 100.0 );
|
||||||
dt = Delta_ClampIntegerField( pField, dt, 1, pField->bits );
|
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
||||||
MSG_WriteSBitLong( msg, dt, pField->bits );
|
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
||||||
{
|
{
|
||||||
|
signbit = 1; // timewindow is always signed
|
||||||
flValue = *(float *)((byte *)to + pField->offset );
|
flValue = *(float *)((byte *)to + pField->offset );
|
||||||
dt = Q_rint(( timebase - flValue ) * pField->multiplier );
|
iValue = (int)Q_rint( timebase * pField->multiplier ) - (int)Q_rint( flValue * pField->multiplier );
|
||||||
dt = Delta_ClampIntegerField( pField, dt, 1, pField->bits );
|
iValue = Delta_ClampIntegerField( pField, iValue, signbit, pField->bits );
|
||||||
MSG_WriteSBitLong( msg, dt, pField->bits );
|
MSG_WriteBitLong( msg, iValue, pField->bits, signbit );
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_STRING )
|
else if( pField->flags & DT_STRING )
|
||||||
{
|
{
|
||||||
@@ -1332,12 +1306,9 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
|||||||
if( pField->flags & DT_BYTE )
|
if( pField->flags & DT_BYTE )
|
||||||
{
|
{
|
||||||
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||||
iValue /= pField->multiplier;
|
iValue /= pField->multiplier;
|
||||||
|
|
||||||
if( !Q_equal( pField->post_multiplier, 1.0 ))
|
|
||||||
iValue *= pField->post_multiplier;
|
|
||||||
|
|
||||||
if( bSigned )
|
if( bSigned )
|
||||||
*(int8_t *)((uint8_t *)to + pField->offset ) = iValue;
|
*(int8_t *)((uint8_t *)to + pField->offset ) = iValue;
|
||||||
else
|
else
|
||||||
@@ -1346,12 +1317,9 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
|||||||
else if( pField->flags & DT_SHORT )
|
else if( pField->flags & DT_SHORT )
|
||||||
{
|
{
|
||||||
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||||
iValue /= pField->multiplier;
|
iValue /= pField->multiplier;
|
||||||
|
|
||||||
if( !Q_equal( pField->post_multiplier, 1.0 ))
|
|
||||||
iValue *= pField->post_multiplier;
|
|
||||||
|
|
||||||
if( bSigned )
|
if( bSigned )
|
||||||
*(int16_t *)((uint8_t *)to + pField->offset ) = iValue;
|
*(int16_t *)((uint8_t *)to + pField->offset ) = iValue;
|
||||||
else
|
else
|
||||||
@@ -1360,12 +1328,9 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
|||||||
else if( pField->flags & DT_INTEGER )
|
else if( pField->flags & DT_INTEGER )
|
||||||
{
|
{
|
||||||
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||||
iValue /= pField->multiplier;
|
iValue /= pField->multiplier;
|
||||||
|
|
||||||
if( !Q_equal( pField->post_multiplier, 1.0 ))
|
|
||||||
iValue *= pField->post_multiplier;
|
|
||||||
|
|
||||||
if( bSigned )
|
if( bSigned )
|
||||||
*(int32_t *)((uint8_t *)to + pField->offset ) = iValue;
|
*(int32_t *)((uint8_t *)to + pField->offset ) = iValue;
|
||||||
else
|
else
|
||||||
@@ -1379,11 +1344,11 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
|||||||
else
|
else
|
||||||
flValue = iValue;
|
flValue = iValue;
|
||||||
|
|
||||||
if( !Q_equal( pField->multiplier, 1.0 ))
|
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||||
flValue /= pField->multiplier;
|
flValue = flValue / pField->multiplier;
|
||||||
|
|
||||||
if( !Q_equal( pField->post_multiplier, 1.0 ))
|
if( !Q_equal( pField->post_multiplier, 1.0 ) )
|
||||||
flValue *= pField->post_multiplier;
|
flValue = flValue * pField->post_multiplier;
|
||||||
|
|
||||||
*(float *)((byte *)to + pField->offset ) = flValue;
|
*(float *)((byte *)to + pField->offset ) = flValue;
|
||||||
}
|
}
|
||||||
@@ -1394,14 +1359,22 @@ static qboolean Delta_ReadField( sizebuf_t *msg, delta_t *pField, void *from, vo
|
|||||||
}
|
}
|
||||||
else if( pField->flags & DT_TIMEWINDOW_8 )
|
else if( pField->flags & DT_TIMEWINDOW_8 )
|
||||||
{
|
{
|
||||||
iValue = MSG_ReadSBitLong( msg, pField->bits );
|
bSigned = true; // timewindow is always signed
|
||||||
flTime = ( timebase * 100.0 - (int)iValue ) / 100.0;
|
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
||||||
|
flTime = (timebase * 100.0 - (int)iValue) / 100.0;
|
||||||
|
|
||||||
*(float *)((byte *)to + pField->offset ) = flTime;
|
*(float *)((byte *)to + pField->offset ) = flTime;
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
else if( pField->flags & DT_TIMEWINDOW_BIG )
|
||||||
{
|
{
|
||||||
iValue = MSG_ReadSBitLong( msg, pField->bits );
|
bSigned = true; // timewindow is always signed
|
||||||
flTime = ( timebase * pField->multiplier - (int)iValue ) / pField->multiplier;
|
iValue = MSG_ReadBitLong( msg, pField->bits, bSigned );
|
||||||
|
|
||||||
|
if( !Q_equal( pField->multiplier, 1.0 ) )
|
||||||
|
flTime = ( timebase * pField->multiplier - (int)iValue ) / pField->multiplier;
|
||||||
|
else
|
||||||
|
flTime = timebase - (int)iValue;
|
||||||
|
|
||||||
*(float *)((byte *)to + pField->offset ) = flTime;
|
*(float *)((byte *)to + pField->offset ) = flTime;
|
||||||
}
|
}
|
||||||
else if( pField->flags & DT_STRING )
|
else if( pField->flags & DT_STRING )
|
||||||
@@ -2096,103 +2069,3 @@ void GAME_EXPORT Delta_UnsetFieldByIndex( delta_t *pFields, int fieldNumber )
|
|||||||
|
|
||||||
dt->pFields[fieldNumber].bInactive = true;
|
dt->pFields[fieldNumber].bInactive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if XASH_ENGINE_TESTS
|
|
||||||
#include "tests.h"
|
|
||||||
|
|
||||||
void Test_RunDelta( void )
|
|
||||||
{
|
|
||||||
delta_info_t *dt = &dt_info[DT_DELTA_TEST_STRUCT_T];
|
|
||||||
delta_test_struct_t from, to = { 0 };
|
|
||||||
delta_test_struct_t null = { 0 };
|
|
||||||
sizebuf_t msg;
|
|
||||||
int i;
|
|
||||||
char buffer[4096] = { 0 };
|
|
||||||
const double timebase = 123.123;
|
|
||||||
|
|
||||||
// a1ba: netbuffer bitmasks are initialized in netchan for some reason
|
|
||||||
// initialize it ourselves just in case
|
|
||||||
MSG_InitMasks(); // initialize bit-masks
|
|
||||||
|
|
||||||
Delta_AddField( dt, "dt_string", DT_STRING, 1, 1.0f, 1.0f );
|
|
||||||
Delta_AddField( dt, "dt_timewindow_big", DT_TIMEWINDOW_BIG, 24, 1000.f, 1.0f );
|
|
||||||
Delta_AddField( dt, "dt_timewindow_8", DT_TIMEWINDOW_8, 8, 1.0f, 1.0f );
|
|
||||||
Delta_AddField( dt, "dt_angle", DT_ANGLE, 16, 1.0f, 1.0f );
|
|
||||||
Delta_AddField( dt, "dt_float_signed", DT_FLOAT | DT_SIGNED, 22, 100.0f, 1.0f );
|
|
||||||
Delta_AddField( dt, "dt_float_unsigned", DT_FLOAT, 24, 10000.0f, 0.1f );
|
|
||||||
Delta_AddField( dt, "dt_integer_signed", DT_INTEGER | DT_SIGNED, 24, 1.0f, 1.0f );
|
|
||||||
Delta_AddField( dt, "dt_integer_unsigned", DT_INTEGER, 24, 1.0f, 1.0f );
|
|
||||||
Delta_AddField( dt, "dt_short_signed", DT_SHORT | DT_SIGNED, 16, 1.0f, 1.0f );
|
|
||||||
Delta_AddField( dt, "dt_short_unsigned", DT_SHORT, 15, 0.125f, 1.0f );
|
|
||||||
Delta_AddField( dt, "dt_byte_signed", DT_BYTE | DT_SIGNED, 6, 1.0f, 1.0f );
|
|
||||||
Delta_AddField( dt, "dt_byte_unsigned", DT_BYTE, 8, 1.0f, 1.0f );
|
|
||||||
|
|
||||||
Q_strncpy( from.dt_string, "test data check it's the same", sizeof( from.dt_string ));
|
|
||||||
from.dt_timewindow_big = timebase + 2.3456;
|
|
||||||
from.dt_timewindow_8 = timebase + 0.0234;
|
|
||||||
from.dt_angle = 160.245f;
|
|
||||||
from.dt_float_signed = -15.123f;
|
|
||||||
from.dt_float_unsigned = 1235.321f;
|
|
||||||
from.dt_integer_signed = -412784;
|
|
||||||
from.dt_integer_unsigned = 123453;
|
|
||||||
from.dt_short_signed = -12343;
|
|
||||||
from.dt_short_unsigned = 32131;
|
|
||||||
from.dt_byte_signed = 16;
|
|
||||||
from.dt_byte_unsigned = 218;
|
|
||||||
|
|
||||||
MSG_Init( &msg, "test message", buffer, sizeof( buffer ));
|
|
||||||
|
|
||||||
for( i = 0; i < dt->numFields; i++ )
|
|
||||||
Delta_WriteField( &msg, &dt->pFields[i], &null, &from, timebase );
|
|
||||||
|
|
||||||
MSG_SeekToBit( &msg, 0, SEEK_SET );
|
|
||||||
|
|
||||||
for( i = 0; i < dt->numFields; i++ )
|
|
||||||
Delta_ReadField( &msg, &dt->pFields[i], &null, &to, timebase );
|
|
||||||
|
|
||||||
Con_Printf( "struct as encoded to delta:\n" );
|
|
||||||
TASSERT_STR( from.dt_string, to.dt_string );
|
|
||||||
|
|
||||||
// the epsilon value is derived from multiplier value
|
|
||||||
TASSERT( Q_equal_e( from.dt_timewindow_big, to.dt_timewindow_big, 0.001f ));
|
|
||||||
|
|
||||||
// dt_timewindow_8 type has multiplier locked at 100.0f
|
|
||||||
TASSERT( Q_equal_e( from.dt_timewindow_8, to.dt_timewindow_8, 0.01f ));
|
|
||||||
TASSERT( Q_equal_e( from.dt_angle, to.dt_angle, 0.1f ));
|
|
||||||
TASSERT( Q_equal_e( from.dt_float_signed, to.dt_float_signed, 0.01f ));
|
|
||||||
|
|
||||||
// dt_float_unsigned has post-multiplier that doesn't affect network data
|
|
||||||
// and therefore should be reverted back when comparing
|
|
||||||
TASSERT( Q_equal_e( from.dt_float_unsigned, to.dt_float_unsigned * 10.f , 0.01f ));
|
|
||||||
|
|
||||||
TASSERT_EQi( from.dt_integer_signed, to.dt_integer_signed );
|
|
||||||
TASSERT_EQi( from.dt_integer_unsigned, to.dt_integer_unsigned );
|
|
||||||
TASSERT_EQi( from.dt_short_signed, to.dt_short_signed );
|
|
||||||
TASSERT(( from.dt_short_unsigned & ( 0xffff << 3 )) == to.dt_short_unsigned );
|
|
||||||
TASSERT_EQi( from.dt_byte_signed, to.dt_byte_signed );
|
|
||||||
TASSERT_EQi( from.dt_byte_unsigned, to.dt_byte_unsigned );
|
|
||||||
|
|
||||||
Con_Printf( "from.dt_timewindow_big = %f\n", from.dt_timewindow_big );
|
|
||||||
Con_Printf( "to.dt_timewindow_big = %f\n", to.dt_timewindow_big );
|
|
||||||
Con_Printf( "from.dt_timewindow_8 = %f\n", from.dt_timewindow_8 );
|
|
||||||
Con_Printf( "to.dt_timewindow_8 = %f\n", to.dt_timewindow_8 );
|
|
||||||
Con_Printf( "from.dt_angle = %f\n", from.dt_angle );
|
|
||||||
Con_Printf( "to.dt_angle = %f\n", to.dt_angle );
|
|
||||||
Con_Printf( "from.dt_float_signed = %f\n", from.dt_float_signed );
|
|
||||||
Con_Printf( "to.dt_float_signed = %f\n", to.dt_float_signed );
|
|
||||||
Con_Printf( "from.dt_float_unsigned = %f\n", from.dt_float_unsigned );
|
|
||||||
Con_Printf( "to.dt_float_unsigned = %f\n", to.dt_float_unsigned );
|
|
||||||
Con_Printf( "from.dt_integer_signed = %i\n", from.dt_integer_signed );
|
|
||||||
Con_Printf( "to.dt_integer_signed = %i\n", to.dt_integer_signed );
|
|
||||||
Con_Printf( "from.dt_integer_unsigned = %i\n", from.dt_integer_unsigned );
|
|
||||||
Con_Printf( "to.dt_integer_unsigned = %i\n", to.dt_integer_unsigned );
|
|
||||||
Con_Printf( "from.dt_short_signed = %i\n", from.dt_short_signed );
|
|
||||||
Con_Printf( "to.dt_short_signed = %i\n", to.dt_short_signed );
|
|
||||||
Con_Printf( "from.dt_short_unsigned = %i\n", from.dt_short_unsigned );
|
|
||||||
Con_Printf( "to.dt_short_unsigned = %i\n", to.dt_short_unsigned );
|
|
||||||
Con_Printf( "from.dt_byte_signed = %i\n", from.dt_byte_signed );
|
|
||||||
Con_Printf( "to.dt_byte_signed = %i\n", to.dt_byte_signed );
|
|
||||||
Con_Printf( "from.dt_byte_unsigned = %i\n", from.dt_byte_unsigned );
|
|
||||||
Con_Printf( "to.dt_byte_unsigned = %i\n", to.dt_byte_unsigned );
|
|
||||||
}
|
|
||||||
#endif // XASH_ENGINE_TESTS
|
|
||||||
|
|||||||
@@ -2375,7 +2375,7 @@ static qboolean HTTP_ProcessStream( httpfile_t *curfile )
|
|||||||
|
|
||||||
if( curfile->header_size >= sizeof( buf ))
|
if( curfile->header_size >= sizeof( buf ))
|
||||||
{
|
{
|
||||||
Con_Reportf( S_ERROR "Header too big, the size is %d\n", curfile->header_size );
|
Con_Reportf( S_ERROR "Header too big, the size is %s\n", curfile->header_size );
|
||||||
HTTP_FreeFile( curfile, true );
|
HTTP_FreeFile( curfile, true );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2395,6 +2395,8 @@ static qboolean HTTP_ProcessStream( httpfile_t *curfile )
|
|||||||
int cutheadersize = begin - curfile->buf + 4; // after that begin of data
|
int cutheadersize = begin - curfile->buf + 4; // after that begin of data
|
||||||
char *content_length_line;
|
char *content_length_line;
|
||||||
|
|
||||||
|
Con_Reportf( "HTTP: Got response!\n" );
|
||||||
|
|
||||||
if( !Q_strstr( curfile->buf, "200 OK" ))
|
if( !Q_strstr( curfile->buf, "200 OK" ))
|
||||||
{
|
{
|
||||||
*begin = 0; // cut string to print out response
|
*begin = 0; // cut string to print out response
|
||||||
@@ -2418,10 +2420,10 @@ static qboolean HTTP_ProcessStream( httpfile_t *curfile )
|
|||||||
content_length_line += sizeof( "Content-Length: " ) - 1;
|
content_length_line += sizeof( "Content-Length: " ) - 1;
|
||||||
size = Q_atoi( content_length_line );
|
size = Q_atoi( content_length_line );
|
||||||
|
|
||||||
Con_Reportf( "HTTP: Got 200 OK! File size is %d\n", size );
|
Con_Reportf( "HTTP: File size is %d\n", size );
|
||||||
|
|
||||||
if( ( curfile->size != -1 ) && ( curfile->size != size )) // check size if specified, not used
|
if( ( curfile->size != -1 ) && ( curfile->size != size )) // check size if specified, not used
|
||||||
Con_Reportf( S_WARN "Server reports wrong file size for %s!\n", curfile->path );
|
Con_Reportf( S_WARN "Server reports wrong file size!\n" );
|
||||||
|
|
||||||
curfile->size = size;
|
curfile->size = size;
|
||||||
curfile->header_size = 0;
|
curfile->header_size = 0;
|
||||||
@@ -2533,7 +2535,7 @@ void HTTP_Run( void )
|
|||||||
|
|
||||||
if( !curfile->file )
|
if( !curfile->file )
|
||||||
{
|
{
|
||||||
Con_Printf( S_ERROR "HTTP: cannot open %s!\n", name );
|
Con_Printf( S_ERROR "cannot open %s!\n", name );
|
||||||
HTTP_FreeFile( curfile, true );
|
HTTP_FreeFile( curfile, true );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -278,8 +278,6 @@ GNU General Public License for more details.
|
|||||||
#define SU_WEAPON (1<<14)
|
#define SU_WEAPON (1<<14)
|
||||||
|
|
||||||
extern const char *svc_strings[svc_lastmsg+1];
|
extern const char *svc_strings[svc_lastmsg+1];
|
||||||
extern const char *svc_legacy_strings[svc_lastmsg+1];
|
|
||||||
extern const char *svc_goldsrc_strings[svc_lastmsg+1];
|
|
||||||
extern const char *clc_strings[clc_lastmsg+1];
|
extern const char *clc_strings[clc_lastmsg+1];
|
||||||
|
|
||||||
// FWGS extensions
|
// FWGS extensions
|
||||||
@@ -318,40 +316,4 @@ extern const char *clc_strings[clc_lastmsg+1];
|
|||||||
// Master Server protocol
|
// Master Server protocol
|
||||||
#define MS_SCAN_REQUEST "1\xFF" "0.0.0.0:0\0" // TODO: implement IP filter
|
#define MS_SCAN_REQUEST "1\xFF" "0.0.0.0:0\0" // TODO: implement IP filter
|
||||||
|
|
||||||
// GoldSrc protocol definitions
|
|
||||||
#define PROTOCOL_GOLDSRC_VERSION_REAL 48
|
|
||||||
#define PROTOCOL_GOLDSRC_VERSION (PROTOCOL_GOLDSRC_VERSION_REAL | (BIT( 7 ))) // should be 48, only to differentiate it from PROTOCOL_LEGACY_VERSION
|
|
||||||
|
|
||||||
#define svc_goldsrc_version svc_changing
|
|
||||||
#define svc_goldsrc_serverinfo svc_serverdata
|
|
||||||
#define svc_goldsrc_deltadescription svc_deltatable
|
|
||||||
#define svc_goldsrc_stopsound svc_resource
|
|
||||||
#define svc_goldsrc_damage svc_restoresound
|
|
||||||
#define svc_goldsrc_killedmonster 27
|
|
||||||
#define svc_goldsrc_foundsecret 28
|
|
||||||
#define svc_goldsrc_spawnstaticsound 29
|
|
||||||
#define svc_goldsrc_decalname svc_bspdecal
|
|
||||||
#define svc_goldsrc_newusermsg svc_usermessage
|
|
||||||
#define svc_goldsrc_newmovevars svc_deltamovevars
|
|
||||||
#define svc_goldsrc_sendextrainfo 54
|
|
||||||
#define svc_goldsrc_timescale 55
|
|
||||||
#define svc_goldsrc_sendcvarvalue svc_querycvarvalue
|
|
||||||
#define svc_goldsrc_sendcvarvalue2 svc_querycvarvalue2
|
|
||||||
|
|
||||||
#define clc_goldsrc_hltv clc_requestcvarvalue // 9
|
|
||||||
#define clc_goldsrc_requestcvarvalue clc_requestcvarvalue2 // 10
|
|
||||||
#define clc_goldsrc_requestcvarvalue2 11
|
|
||||||
#define clc_goldsrc_lastmsg 12
|
|
||||||
|
|
||||||
#define S2C_REJECT_BADPASSWORD '8'
|
|
||||||
#define S2C_REJECT '9'
|
|
||||||
#define S2C_CHALLENGE "A00000000"
|
|
||||||
#define S2C_CONNECTION "B"
|
|
||||||
|
|
||||||
#define MAX_GOLDSRC_RESOURCE_BITS 12
|
|
||||||
#define MAX_GOLDSRC_ENTITY_BITS 11
|
|
||||||
// #define MAX_GOLDSRC_EDICTS BIT( MAX_ENTITY_BITS )
|
|
||||||
#define MAX_GOLDSRC_EDICTS ( BIT( MAX_ENTITY_BITS ) + ( MAX_CLIENTS * 15 ))
|
|
||||||
#define LAST_GOLDSRC_EDICT ( BIT( MAX_ENTITY_BITS ) - 1 )
|
|
||||||
|
|
||||||
#endif//NET_PROTOCOL_H
|
#endif//NET_PROTOCOL_H
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ int open_mpeg_stream( void *mpg, void *file, pfread f_read, pfseek f_seek, wavin
|
|||||||
|
|
||||||
if( !mh || !sc ) return 0;
|
if( !mh || !sc ) return 0;
|
||||||
|
|
||||||
ret = mpg123_replace_reader_handle( mh, f_read, f_seek, NULL );
|
ret = mpg123_replace_reader_handle( mh, (void *)f_read, (void *)f_seek, NULL );
|
||||||
if( ret != MPG123_OK )
|
if( ret != MPG123_OK )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|||||||
@@ -34,15 +34,9 @@ typedef struct
|
|||||||
int playtime; // stream size in milliseconds
|
int playtime; // stream size in milliseconds
|
||||||
} wavinfo_t;
|
} wavinfo_t;
|
||||||
|
|
||||||
#ifdef _MSC_VER // a1ba: MSVC6 don't have ssize_t
|
|
||||||
typedef long mpg_ssize_t;
|
|
||||||
#else
|
|
||||||
typedef ssize_t mpg_ssize_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// custom stdio
|
// custom stdio
|
||||||
typedef mpg_ssize_t (*pfread)( void *handle, void *buf, size_t count );
|
typedef long (*pfread)( void *handle, void *buf, size_t count );
|
||||||
typedef fs_offset_t (*pfseek)( void *handle, fs_offset_t offset, int whence );
|
typedef long (*pfseek)( void *handle, long offset, int whence );
|
||||||
|
|
||||||
extern void *create_decoder( int *error );
|
extern void *create_decoder( int *error );
|
||||||
extern int feed_mpeg_header( void *mpg, const byte *data, long bufsize, long streamsize, wavinfo_t *sc );
|
extern int feed_mpeg_header( void *mpg, const byte *data, long bufsize, long streamsize, wavinfo_t *sc );
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ typedef struct mpg123_handle_s mpg123_handle_t;
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "fmt123.h"
|
#include "fmt123.h"
|
||||||
#include STDINT_H
|
#include STDINT_H
|
||||||
#include "xash3d_types.h"
|
|
||||||
|
|
||||||
#ifndef FALSE
|
#ifndef FALSE
|
||||||
#define FALSE 0
|
#define FALSE 0
|
||||||
@@ -51,7 +50,7 @@ typedef unsigned char byte;
|
|||||||
typedef unsigned short word;
|
typedef unsigned short word;
|
||||||
typedef unsigned long ulong;
|
typedef unsigned long ulong;
|
||||||
typedef unsigned int uint;
|
typedef unsigned int uint;
|
||||||
typedef fs_offset_t mpg_off_t;
|
typedef long mpg_off_t;
|
||||||
|
|
||||||
#ifdef _MSC_VER // a1ba: MSVC6 don't have ssize_t
|
#ifdef _MSC_VER // a1ba: MSVC6 don't have ssize_t
|
||||||
typedef long mpg_ssize_t;
|
typedef long mpg_ssize_t;
|
||||||
|
|||||||
@@ -853,21 +853,11 @@ int open_feed( mpg123_handle_t *fr )
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static mpg_ssize_t read_mpgtypes( int fd, void *buf, size_t count )
|
|
||||||
{
|
|
||||||
return read( fd, buf, count );
|
|
||||||
}
|
|
||||||
|
|
||||||
static mpg_off_t lseek_mpgtypes( int fd, mpg_off_t offset, int whence )
|
|
||||||
{
|
|
||||||
return lseek( fd, offset, whence );
|
|
||||||
}
|
|
||||||
|
|
||||||
static int default_init( mpg123_handle_t *fr )
|
static int default_init( mpg123_handle_t *fr )
|
||||||
{
|
{
|
||||||
fr->rdat.fdread = plain_read;
|
fr->rdat.fdread = plain_read;
|
||||||
fr->rdat.read = fr->rdat.r_read != NULL ? fr->rdat.r_read : read_mpgtypes;
|
fr->rdat.read = fr->rdat.r_read != NULL ? fr->rdat.r_read : read;
|
||||||
fr->rdat.lseek = fr->rdat.r_lseek != NULL ? fr->rdat.r_lseek : lseek_mpgtypes;
|
fr->rdat.lseek = fr->rdat.r_lseek != NULL ? fr->rdat.r_lseek : lseek;
|
||||||
fr->rdat.filelen = get_fileinfo( fr );
|
fr->rdat.filelen = get_fileinfo( fr );
|
||||||
fr->rdat.filepos = 0;
|
fr->rdat.filepos = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ wavdata_t *FS_StreamInfo( stream_t *stream )
|
|||||||
if( !stream ) return NULL;
|
if( !stream ) return NULL;
|
||||||
|
|
||||||
// fill structure
|
// fill structure
|
||||||
info.loopStart = 0;
|
info.loopStart = -1;
|
||||||
info.rate = stream->rate;
|
info.rate = stream->rate;
|
||||||
info.width = stream->width;
|
info.width = stream->width;
|
||||||
info.channels = stream->channels;
|
info.channels = stream->channels;
|
||||||
|
|||||||
@@ -74,10 +74,7 @@ static uint32_t Sound_ParseSynchInteger( uint32_t v )
|
|||||||
static void Sound_HandleCustomID3Comment( const char *key, const char *value )
|
static void Sound_HandleCustomID3Comment( const char *key, const char *value )
|
||||||
{
|
{
|
||||||
if( !Q_strcmp( key, "LOOP_START" ) || !Q_strcmp( key, "LOOPSTART" ))
|
if( !Q_strcmp( key, "LOOP_START" ) || !Q_strcmp( key, "LOOPSTART" ))
|
||||||
{
|
|
||||||
sound.loopstart = Q_atoi( value );
|
sound.loopstart = Q_atoi( value );
|
||||||
SetBits( sound.flags, SOUND_LOOPED );
|
|
||||||
}
|
|
||||||
// unknown comment is not an error
|
// unknown comment is not an error
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,6 +233,7 @@ qboolean Sound_LoadMPG( const char *name, const byte *buffer, fs_offset_t filesi
|
|||||||
sound.channels = sc.channels;
|
sound.channels = sc.channels;
|
||||||
sound.rate = sc.rate;
|
sound.rate = sc.rate;
|
||||||
sound.width = 2; // always 16-bit PCM
|
sound.width = 2; // always 16-bit PCM
|
||||||
|
sound.loopstart = -1;
|
||||||
sound.size = ( sound.channels * sound.rate * sound.width ) * ( sc.playtime / 1000 ); // in bytes
|
sound.size = ( sound.channels * sound.rate * sound.width ) * ( sc.playtime / 1000 ); // in bytes
|
||||||
padsize = sound.size % FRAME_SIZE;
|
padsize = sound.size % FRAME_SIZE;
|
||||||
pos += FRAME_SIZE; // evaluate pos
|
pos += FRAME_SIZE; // evaluate pos
|
||||||
@@ -243,6 +241,7 @@ qboolean Sound_LoadMPG( const char *name, const byte *buffer, fs_offset_t filesi
|
|||||||
if( !Sound_ParseID3Tag( buffer, filesize ))
|
if( !Sound_ParseID3Tag( buffer, filesize ))
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_WARN "Sound_LoadMPG: (%s) failed to extract LOOP_START tag\n", name );
|
Con_DPrintf( S_WARN "Sound_LoadMPG: (%s) failed to extract LOOP_START tag\n", name );
|
||||||
|
sound.loopstart = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !sound.size )
|
if( !sound.size )
|
||||||
@@ -291,14 +290,14 @@ qboolean Sound_LoadMPG( const char *name, const byte *buffer, fs_offset_t filesi
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fs_offset_t FS_SeekMpg( void *file, fs_offset_t offset, int whence )
|
/*
|
||||||
|
=================
|
||||||
|
FS_SeekEx
|
||||||
|
=================
|
||||||
|
*/
|
||||||
|
static fs_offset_t FS_SeekEx( file_t *file, fs_offset_t offset, int whence )
|
||||||
{
|
{
|
||||||
return g_fsapi.Seek((file_t *)file, offset, whence ) == -1 ? -1 : g_fsapi.Tell((file_t *)file );
|
return FS_Seek( file, offset, whence ) == -1 ? -1 : FS_Tell( file );
|
||||||
}
|
|
||||||
|
|
||||||
static mpg_ssize_t FS_ReadMpg( void *file, void *buf, size_t count )
|
|
||||||
{
|
|
||||||
return g_fsapi.Read((file_t *)file, buf, count );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -334,7 +333,7 @@ stream_t *Stream_OpenMPG( const char *filename )
|
|||||||
if( ret ) Con_DPrintf( S_ERROR "%s\n", get_error( mpeg ));
|
if( ret ) Con_DPrintf( S_ERROR "%s\n", get_error( mpeg ));
|
||||||
|
|
||||||
// trying to open stream and read header
|
// trying to open stream and read header
|
||||||
if( !open_mpeg_stream( mpeg, file, FS_ReadMpg, FS_SeekMpg, &sc ))
|
if( !open_mpeg_stream( mpeg, file, (void*)FS_Read, (void*)FS_SeekEx, &sc ))
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "Stream_OpenMPG: failed to load (%s): %s\n", filename, get_error( mpeg ));
|
Con_DPrintf( S_ERROR "Stream_OpenMPG: failed to load (%s): %s\n", filename, get_error( mpeg ));
|
||||||
close_decoder( mpeg );
|
close_decoder( mpeg );
|
||||||
|
|||||||
@@ -14,9 +14,6 @@ GNU General Public License for more details.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "soundlib.h"
|
#include "soundlib.h"
|
||||||
#if XASH_SDL
|
|
||||||
#include <SDL_audio.h>
|
|
||||||
#endif // XASH_SDL
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=============================================================================
|
=============================================================================
|
||||||
@@ -133,309 +130,7 @@ uint GAME_EXPORT Sound_GetApproxWavePlayLen( const char *filepath )
|
|||||||
return msecs;
|
return msecs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static qboolean Sound_ConvertNoResample( wavdata_t *sc, int inwidth, int outwidth, int outcount )
|
#define drint( v ) (int)( v + 0.5 )
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
if( inwidth == 1 && outwidth == 2 ) // S8 to S16
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount * sc->channels; i++ )
|
|
||||||
((int16_t*)sound.tempbuffer)[i] = ((int8_t *)sc->buffer)[i] * 256;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( inwidth == 2 && outwidth == 1 ) // S16 to S8
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount * sc->channels; i++ )
|
|
||||||
((int8_t*)sound.tempbuffer)[i] = ((int16_t *)sc->buffer)[i] / 256;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static qboolean Sound_ConvertDownsample( wavdata_t *sc, int inwidth, int outwidth, int outcount, double stepscale )
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
double j;
|
|
||||||
|
|
||||||
if( inwidth == 1 && outwidth == 1 )
|
|
||||||
{
|
|
||||||
int8_t *data = (int8_t *)sc->buffer;
|
|
||||||
|
|
||||||
if( outwidth == 1 )
|
|
||||||
{
|
|
||||||
int8_t *outdata = (int8_t *)sound.tempbuffer;
|
|
||||||
|
|
||||||
if( sc->channels == 2 )
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount; i++ )
|
|
||||||
{
|
|
||||||
j = stepscale * i;
|
|
||||||
outdata[i*2+0] = data[((int)j)*2+0];
|
|
||||||
outdata[i*2+1] = data[((int)j)*2+1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount; i++ )
|
|
||||||
{
|
|
||||||
j = stepscale * i;
|
|
||||||
outdata[i] = data[(int)j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( outwidth == 2 )
|
|
||||||
{
|
|
||||||
int16_t *outdata = (int16_t *)sound.tempbuffer;
|
|
||||||
|
|
||||||
if( sc->channels == 2 )
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount; i++ )
|
|
||||||
{
|
|
||||||
j = stepscale * i;
|
|
||||||
outdata[i*2+0] = data[((int)j)*2+0] * 256;
|
|
||||||
outdata[i*2+1] = data[((int)j)*2+1] * 256;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount; i++ )
|
|
||||||
{
|
|
||||||
j = stepscale * i;
|
|
||||||
outdata[i] = data[(int)j] * 256;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( inwidth == 2 )
|
|
||||||
{
|
|
||||||
int16_t *data = (int16_t *)sc->buffer;
|
|
||||||
|
|
||||||
if( outwidth == 1 )
|
|
||||||
{
|
|
||||||
int8_t *outdata = (int8_t *)sound.tempbuffer;
|
|
||||||
|
|
||||||
if( sc->channels == 2 )
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount; i++ )
|
|
||||||
{
|
|
||||||
j = stepscale * i;
|
|
||||||
outdata[i*2+0] = data[((int)j)*2+0] / 256;
|
|
||||||
outdata[i*2+1] = data[((int)j)*2+1] / 256;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount; i++ )
|
|
||||||
{
|
|
||||||
j = stepscale * i;
|
|
||||||
outdata[i] = data[(int)j] / 256;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( outwidth == 2 )
|
|
||||||
{
|
|
||||||
int16_t *outdata = (int16_t *)sound.tempbuffer;
|
|
||||||
|
|
||||||
if( sc->channels == 2 )
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount; i++ )
|
|
||||||
{
|
|
||||||
j = stepscale * i;
|
|
||||||
outdata[i*2+0] = data[((int)j)*2+0];
|
|
||||||
outdata[i*2+1] = data[((int)j)*2+1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount; i++ )
|
|
||||||
{
|
|
||||||
j = stepscale * i;
|
|
||||||
outdata[i] = data[(int)j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static qboolean Sound_ConvertUpsample( wavdata_t *sc, int inwidth, int outwidth, int outcount, int incount, double stepscale )
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
double j;
|
|
||||||
double frac;
|
|
||||||
|
|
||||||
incount--; // to not go past last sample while interpolating
|
|
||||||
|
|
||||||
if( inwidth == 1 )
|
|
||||||
{
|
|
||||||
int8_t *data = (int8_t *)sc->buffer;
|
|
||||||
|
|
||||||
if( outwidth == 1 )
|
|
||||||
{
|
|
||||||
int8_t *outdata = (int8_t *)sound.tempbuffer;
|
|
||||||
|
|
||||||
if( sc->channels == 2 )
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount; i++ )
|
|
||||||
{
|
|
||||||
j = stepscale * i;
|
|
||||||
outdata[i*2+0] = data[((int)j)*2+0];
|
|
||||||
outdata[i*2+1] = data[((int)j)*2+1];
|
|
||||||
if( j != (int)j && j < incount )
|
|
||||||
{
|
|
||||||
frac = j - (int)j;
|
|
||||||
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
|
|
||||||
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount; i++ )
|
|
||||||
{
|
|
||||||
j = stepscale * i;
|
|
||||||
outdata[i] = data[(int)j];
|
|
||||||
if( j != (int)j && j < incount )
|
|
||||||
{
|
|
||||||
frac = j - (int)j;
|
|
||||||
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( outwidth == 2 )
|
|
||||||
{
|
|
||||||
int16_t *outdata = (int16_t *)sound.tempbuffer;
|
|
||||||
|
|
||||||
if( sc->channels == 2 )
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount; i++ )
|
|
||||||
{
|
|
||||||
j = stepscale * i;
|
|
||||||
outdata[i*2+0] = data[((int)j)*2+0] * 256;
|
|
||||||
outdata[i*2+1] = data[((int)j)*2+1] * 256;
|
|
||||||
if( j != (int)j && j < incount )
|
|
||||||
{
|
|
||||||
frac = ( j - (int)j ) * 256;
|
|
||||||
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
|
|
||||||
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount; i++ )
|
|
||||||
{
|
|
||||||
j = stepscale * i;
|
|
||||||
outdata[i] = data[(int)j] * 256;
|
|
||||||
if( j != (int)j && j < incount )
|
|
||||||
{
|
|
||||||
frac = ( j - (int)j ) * 256;
|
|
||||||
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( inwidth == 2 )
|
|
||||||
{
|
|
||||||
int16_t *data = (int16_t *)sc->buffer;
|
|
||||||
|
|
||||||
if( outwidth == 1 )
|
|
||||||
{
|
|
||||||
int8_t *outdata = (int8_t *)sound.tempbuffer;
|
|
||||||
|
|
||||||
if( sc->channels == 2 )
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount; i++ )
|
|
||||||
{
|
|
||||||
j = stepscale * i;
|
|
||||||
outdata[i*2+0] = data[((int)j)*2+0] / 256;
|
|
||||||
outdata[i*2+1] = data[((int)j)*2+1] / 256;
|
|
||||||
if( j != (int)j && j < incount )
|
|
||||||
{
|
|
||||||
frac = ( j - (int)j ) / 256;
|
|
||||||
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
|
|
||||||
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount; i++ )
|
|
||||||
{
|
|
||||||
j = stepscale * i;
|
|
||||||
outdata[i] = data[(int)j] / 256;
|
|
||||||
if( j != (int)j && j < incount )
|
|
||||||
{
|
|
||||||
frac = ( j - (int)j ) / 256;
|
|
||||||
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( outwidth == 2 )
|
|
||||||
{
|
|
||||||
int16_t *outdata = (int16_t *)sound.tempbuffer;
|
|
||||||
|
|
||||||
if( sc->channels == 2 )
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount; i++ )
|
|
||||||
{
|
|
||||||
j = stepscale * i;
|
|
||||||
outdata[i*2+0] = data[((int)j)*2+0];
|
|
||||||
outdata[i*2+1] = data[((int)j)*2+1];
|
|
||||||
if( j != (int)j && j < incount )
|
|
||||||
{
|
|
||||||
frac = j - (int)j;
|
|
||||||
outdata[i*2+0] += (data[((int)j+1)*2+0] - data[((int)j)*2+0]) * frac;
|
|
||||||
outdata[i*2+1] += (data[((int)j+1)*2+1] - data[((int)j)*2+1]) * frac;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for( i = 0; i < outcount; i++ )
|
|
||||||
{
|
|
||||||
j = stepscale * i;
|
|
||||||
outdata[i] = data[(int)j];
|
|
||||||
if( j != (int)j && j < incount )
|
|
||||||
{
|
|
||||||
frac = j - (int)j;
|
|
||||||
outdata[i] += (data[(int)j+1] - data[(int)j]) * frac;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
@@ -446,70 +141,125 @@ We need convert sound to signed even if nothing to resample
|
|||||||
*/
|
*/
|
||||||
static qboolean Sound_ResampleInternal( wavdata_t *sc, int inrate, int inwidth, int outrate, int outwidth )
|
static qboolean Sound_ResampleInternal( wavdata_t *sc, int inrate, int inwidth, int outrate, int outwidth )
|
||||||
{
|
{
|
||||||
const size_t oldsize = sc->size;
|
double stepscale, j;
|
||||||
|
int outcount;
|
||||||
|
int i;
|
||||||
qboolean handled = false;
|
qboolean handled = false;
|
||||||
double stepscale;
|
|
||||||
double t1, t2;
|
|
||||||
int outcount, incount = sc->samples;
|
|
||||||
|
|
||||||
if( inrate == outrate && inwidth == outwidth )
|
if( inrate == outrate && inwidth == outwidth )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
t1 = Sys_DoubleTime();
|
|
||||||
|
|
||||||
stepscale = (double)inrate / outrate; // this is usually 0.5, 1, or 2
|
stepscale = (double)inrate / outrate; // this is usually 0.5, 1, or 2
|
||||||
outcount = sc->samples / stepscale;
|
outcount = sc->samples / stepscale;
|
||||||
sc->size = outcount * outwidth * sc->channels;
|
sc->size = outcount * outwidth * sc->channels;
|
||||||
|
|
||||||
|
sound.tempbuffer = (byte *)Mem_Realloc( host.soundpool, sound.tempbuffer, sc->size );
|
||||||
|
|
||||||
sc->samples = outcount;
|
sc->samples = outcount;
|
||||||
if( FBitSet( sc->flags, SOUND_LOOPED ))
|
if( sc->loopStart != -1 )
|
||||||
sc->loopStart = sc->loopStart / stepscale;
|
sc->loopStart = sc->loopStart / stepscale;
|
||||||
|
|
||||||
#if 0 && XASH_SDL // slow but somewhat accurate
|
if( inrate == outrate )
|
||||||
{
|
{
|
||||||
const SDL_AudioFormat infmt = inwidth == 1 ? AUDIO_S8 : AUDIO_S16;
|
if( inwidth == 1 && outwidth == 2 ) // S8 to S16
|
||||||
const SDL_AudioFormat outfmt = outwidth == 1 ? AUDIO_S8 : AUDIO_S16;
|
|
||||||
SDL_AudioCVT cvt;
|
|
||||||
|
|
||||||
// SDL_AudioCVT does conversion in place, original buffer is used for it
|
|
||||||
if( SDL_BuildAudioCVT( &cvt, infmt, sc->channels, inrate, outfmt, sc->channels, outrate ) > 0 && cvt.needed )
|
|
||||||
{
|
{
|
||||||
sc->buffer = (byte *)Mem_Realloc( host.soundpool, sc->buffer, oldsize * cvt.len_mult );
|
for( i = 0; i < outcount * sc->channels; i++ )
|
||||||
cvt.len = oldsize;
|
((int16_t*)sound.tempbuffer)[i] = ((int8_t *)sc->buffer)[i] * 256;
|
||||||
cvt.buf = sc->buffer;
|
handled = true;
|
||||||
|
}
|
||||||
|
else if( inwidth == 2 && outwidth == 1 ) // S16 to S8
|
||||||
|
{
|
||||||
|
for( i = 0; i < outcount * sc->channels; i++ )
|
||||||
|
((int8_t*)sound.tempbuffer)[i] = ((int16_t *)sc->buffer)[i] / 256;
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // resample case
|
||||||
|
{
|
||||||
|
if( inwidth == 1 )
|
||||||
|
{
|
||||||
|
int8_t *data = (int8_t *)sc->buffer;
|
||||||
|
|
||||||
if( !SDL_ConvertAudio( &cvt ))
|
if( outwidth == 1 )
|
||||||
{
|
{
|
||||||
t2 = Sys_DoubleTime();
|
if( sc->channels == 2 )
|
||||||
Con_Reportf( "Sound_Resample: from [%d bit %d Hz] to [%d bit %d Hz] (took %.3fs through SDL)\n", inwidth * 8, inrate, outwidth * 8, outrate, t2 - t1 );
|
{
|
||||||
sc->rate = outrate;
|
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
|
||||||
sc->width = outwidth;
|
{
|
||||||
return false; // HACKHACK: return false so Sound_Process won't reallocate buffer
|
((int8_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0];
|
||||||
|
((int8_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
|
||||||
|
((int8_t*)sound.tempbuffer)[i] = data[(int)j];
|
||||||
|
}
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
else if( outwidth == 2 )
|
||||||
|
{
|
||||||
|
if( sc->channels == 2 )
|
||||||
|
{
|
||||||
|
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
|
||||||
|
{
|
||||||
|
((int16_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0] * 256;
|
||||||
|
((int16_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1] * 256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
|
||||||
|
((int16_t*)sound.tempbuffer)[i] = data[(int)j] * 256;
|
||||||
|
}
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( inwidth == 2 )
|
||||||
|
{
|
||||||
|
int16_t *data = (int16_t *)sc->buffer;
|
||||||
|
|
||||||
|
if( outwidth == 1 )
|
||||||
|
{
|
||||||
|
if( sc->channels == 2 )
|
||||||
|
{
|
||||||
|
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
|
||||||
|
{
|
||||||
|
((int8_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0] / 256;
|
||||||
|
((int8_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1] / 256;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
|
||||||
|
((int8_t*)sound.tempbuffer)[i] = data[(int)j] / 256;
|
||||||
|
}
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
else if( outwidth == 2 )
|
||||||
|
{
|
||||||
|
if( sc->channels == 2 )
|
||||||
|
{
|
||||||
|
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
|
||||||
|
{
|
||||||
|
((int16_t*)sound.tempbuffer)[i*2+0] = data[((int)j)*2+0];
|
||||||
|
((int16_t*)sound.tempbuffer)[i*2+1] = data[((int)j)*2+1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for( i = 0, j = 0; i < outcount; i++, j += stepscale )
|
||||||
|
((int16_t*)sound.tempbuffer)[i] = data[(int)j];
|
||||||
|
}
|
||||||
|
handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
sound.tempbuffer = (byte *)Mem_Realloc( host.soundpool, sound.tempbuffer, sc->size );
|
|
||||||
|
|
||||||
if( inrate == outrate ) // no resampling, just copy data
|
|
||||||
handled = Sound_ConvertNoResample( sc, inwidth, outwidth, outcount );
|
|
||||||
else if( inrate > outrate ) // fast case, usually downsample but is also ok for upsampling
|
|
||||||
handled = Sound_ConvertDownsample( sc, inwidth, outwidth, outcount, stepscale );
|
|
||||||
else // upsample case, w/ interpolation
|
|
||||||
handled = Sound_ConvertUpsample( sc, inwidth, outwidth, outcount, incount, stepscale );
|
|
||||||
|
|
||||||
t2 = Sys_DoubleTime();
|
|
||||||
|
|
||||||
if( handled )
|
if( handled )
|
||||||
{
|
Con_Reportf( "Sound_Resample: from [%d bit %d Hz] to [%d bit %d Hz]\n", inwidth * 8, inrate, outwidth * 8, outrate );
|
||||||
if( t2 - t1 > 0.01f ) // critical, report to mod developer
|
|
||||||
Con_Printf( S_WARN "Sound_Resample: from [%d bit %d Hz] to [%d bit %d Hz] (took %.3fs)\n", inwidth * 8, inrate, outwidth * 8, outrate, t2 - t1 );
|
|
||||||
else
|
|
||||||
Con_Reportf( "Sound_Resample: from [%d bit %d Hz] to [%d bit %d Hz] (took %.3fs)\n", inwidth * 8, inrate, outwidth * 8, outrate, t2 - t1 );
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
Con_Printf( S_ERROR "Sound_Resample: unsupported from [%d bit %d Hz] to [%d bit %d Hz]\n", inwidth * 8, inrate, outwidth * 8, outrate );
|
Con_Reportf( S_ERROR "Sound_Resample: unsupported from [%d bit %d Hz] to [%d bit %d Hz]\n", inwidth * 8, inrate, outwidth * 8, outrate );
|
||||||
|
|
||||||
sc->rate = outrate;
|
sc->rate = outrate;
|
||||||
sc->width = outwidth;
|
sc->width = outwidth;
|
||||||
@@ -526,20 +276,23 @@ qboolean Sound_Process( wavdata_t **wav, int rate, int width, uint flags )
|
|||||||
if( !snd || !snd->buffer )
|
if( !snd || !snd->buffer )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( FBitSet( flags, SOUND_RESAMPLE ) && ( width > 0 || rate > 0 ))
|
if(( flags & SOUND_RESAMPLE ) && ( width > 0 || rate > 0 ))
|
||||||
{
|
{
|
||||||
result = Sound_ResampleInternal( snd, snd->rate, snd->width, rate, width );
|
if( Sound_ResampleInternal( snd, snd->rate, snd->width, rate, width ))
|
||||||
|
|
||||||
if( result )
|
|
||||||
{
|
{
|
||||||
Mem_Free( snd->buffer ); // free original image buffer
|
Mem_Free( snd->buffer ); // free original image buffer
|
||||||
snd->buffer = Sound_Copy( snd->size ); // unzone buffer (don't touch sound.tempbuffer)
|
snd->buffer = Sound_Copy( snd->size ); // unzone buffer (don't touch image.tempbuffer)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// not resampled
|
||||||
|
result = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*wav = snd;
|
*wav = snd;
|
||||||
|
|
||||||
return result;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
qboolean Sound_SupportedFileFormat( const char *fileext )
|
qboolean Sound_SupportedFileFormat( const char *fileext )
|
||||||
|
|||||||
@@ -23,11 +23,6 @@ static const byte *iff_end;
|
|||||||
static const byte *iff_lastChunk;
|
static const byte *iff_lastChunk;
|
||||||
static int iff_chunkLen;
|
static int iff_chunkLen;
|
||||||
|
|
||||||
static int IsFourCC( const byte *ptr, const byte *fourcc )
|
|
||||||
{
|
|
||||||
return 0 == memcmp( ptr, fourcc, 4 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=================
|
=================
|
||||||
GetLittleShort
|
GetLittleShort
|
||||||
@@ -91,21 +86,7 @@ static void FindNextChunk( const char *filename, const char *name )
|
|||||||
|
|
||||||
if( iff_chunkLen > remaining )
|
if( iff_chunkLen > remaining )
|
||||||
{
|
{
|
||||||
// only print this warning if selected chunk is truncated
|
Con_DPrintf( "%s: '%s' truncated by %i bytes\n", __func__, filename, iff_chunkLen - remaining );
|
||||||
//
|
|
||||||
// otherwise this warning becomes misleading because some
|
|
||||||
// idiot programs like CoolEdit (i.e. Adobe Audition) don't always
|
|
||||||
// respect pad byte. The file isn't actually truncated, it just
|
|
||||||
// can't be reliably parsed as a whole
|
|
||||||
|
|
||||||
if( IsFourCC( iff_lastChunk, "RIFF" )
|
|
||||||
|| IsFourCC( iff_lastChunk, "fmt " )
|
|
||||||
|| IsFourCC( iff_lastChunk, "cue " )
|
|
||||||
|| IsFourCC( iff_lastChunk, "LIST" )
|
|
||||||
|| IsFourCC( iff_lastChunk, "data" ))
|
|
||||||
{
|
|
||||||
Con_DPrintf( "%s: '%s' truncated by %i bytes\n", __func__, filename, iff_chunkLen - remaining );
|
|
||||||
}
|
|
||||||
iff_chunkLen = remaining;
|
iff_chunkLen = remaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,9 +94,9 @@ static void FindNextChunk( const char *filename, const char *name )
|
|||||||
iff_dataPtr -= 8;
|
iff_dataPtr -= 8;
|
||||||
|
|
||||||
iff_lastChunk = iff_dataPtr + 8 + iff_chunkLen;
|
iff_lastChunk = iff_dataPtr + 8 + iff_chunkLen;
|
||||||
if(( iff_chunkLen & 1 ) && remaining )
|
if ((iff_chunkLen&1) && remaining)
|
||||||
iff_lastChunk++;
|
iff_lastChunk++;
|
||||||
if( IsFourCC( iff_dataPtr, name ))
|
if (!Q_strncmp(iff_dataPtr, name, 4))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,18 +130,15 @@ static qboolean StreamFindNextChunk( file_t *file, const char *name, int *last_c
|
|||||||
return false; // didn't find the chunk
|
return false; // didn't find the chunk
|
||||||
|
|
||||||
FS_Seek( file, 4, SEEK_CUR );
|
FS_Seek( file, 4, SEEK_CUR );
|
||||||
if( FS_Read( file, &iff_chunk_len, sizeof( iff_chunk_len )) != sizeof( iff_chunk_len ))
|
FS_Read( file, &iff_chunk_len, sizeof( iff_chunk_len ));
|
||||||
return false;
|
|
||||||
|
|
||||||
if( iff_chunk_len < 0 )
|
if( iff_chunk_len < 0 )
|
||||||
return false; // didn't find the chunk
|
return false; // didn't find the chunk
|
||||||
|
|
||||||
FS_Seek( file, -8, SEEK_CUR );
|
FS_Seek( file, -8, SEEK_CUR );
|
||||||
*last_chunk = FS_Tell( file ) + 8 + (( iff_chunk_len + 1 ) & ~1 );
|
*last_chunk = FS_Tell( file ) + 8 + (( iff_chunk_len + 1 ) & ~1 );
|
||||||
if( FS_Read( file, chunkName, sizeof( chunkName )) != sizeof( chunkName ))
|
FS_Read( file, chunkName, 4 );
|
||||||
return false;
|
|
||||||
|
|
||||||
if( IsFourCC( chunkName, name ))
|
if( !Q_strncmp( chunkName, name, 4 ))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +164,7 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
|
|||||||
// find "RIFF" chunk
|
// find "RIFF" chunk
|
||||||
FindChunk( name, "RIFF" );
|
FindChunk( name, "RIFF" );
|
||||||
|
|
||||||
if( !iff_dataPtr || !IsFourCC( iff_dataPtr + 8, "WAVE" ))
|
if( !( iff_dataPtr && !Q_strncmp( (const char *)iff_dataPtr + 8, "WAVE", 4 )))
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "Sound_LoadWAV: %s missing 'RIFF/WAVE' chunks\n", name );
|
Con_DPrintf( S_ERROR "Sound_LoadWAV: %s missing 'RIFF/WAVE' chunks\n", name );
|
||||||
return false;
|
return false;
|
||||||
@@ -245,12 +223,11 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
|
|||||||
{
|
{
|
||||||
iff_dataPtr += 32;
|
iff_dataPtr += 32;
|
||||||
sound.loopstart = GetLittleLong();
|
sound.loopstart = GetLittleLong();
|
||||||
SetBits( sound.flags, SOUND_LOOPED );
|
|
||||||
FindNextChunk( name, "LIST" ); // if the next chunk is a LIST chunk, look for a cue length marker
|
FindNextChunk( name, "LIST" ); // if the next chunk is a LIST chunk, look for a cue length marker
|
||||||
|
|
||||||
if( iff_dataPtr )
|
if( iff_dataPtr )
|
||||||
{
|
{
|
||||||
if( IsFourCC( iff_dataPtr + 28, "mark" ))
|
if( !Q_strncmp( (const char *)iff_dataPtr + 28, "mark", 4 ))
|
||||||
{
|
{
|
||||||
// this is not a proper parse, but it works with CoolEdit...
|
// this is not a proper parse, but it works with CoolEdit...
|
||||||
iff_dataPtr += 24;
|
iff_dataPtr += 24;
|
||||||
@@ -260,7 +237,7 @@ qboolean Sound_LoadWAV( const char *name, const byte *buffer, fs_offset_t filesi
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sound.loopstart = 0;
|
sound.loopstart = -1;
|
||||||
sound.samples = 0;
|
sound.samples = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -365,16 +342,8 @@ stream_t *Stream_OpenWAV( const char *filename )
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
FS_Seek( file, 4, SEEK_CUR );
|
FS_Read( file, chunkName, 4 );
|
||||||
|
if( !Q_strncmp( chunkName, "WAVE", 4 ))
|
||||||
if( FS_Read( file, chunkName, 4 ) != 4 )
|
|
||||||
{
|
|
||||||
Con_DPrintf( S_ERROR "%s: %s missing WAVE chunk, truncated\n", filename );
|
|
||||||
FS_Close( file );
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !IsFourCC( chunkName, "WAVE" ))
|
|
||||||
{
|
{
|
||||||
Con_DPrintf( S_ERROR "Stream_OpenWAV: %s missing WAVE chunk\n", filename );
|
Con_DPrintf( S_ERROR "Stream_OpenWAV: %s missing WAVE chunk\n", filename );
|
||||||
FS_Close( file );
|
FS_Close( file );
|
||||||
@@ -382,7 +351,7 @@ stream_t *Stream_OpenWAV( const char *filename )
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get "fmt " chunk
|
// get "fmt " chunk
|
||||||
iff_data = FS_Tell( file );
|
iff_data = FS_Tell( file ) + 4;
|
||||||
last_chunk = iff_data;
|
last_chunk = iff_data;
|
||||||
if( !StreamFindNextChunk( file, "fmt ", &last_chunk ))
|
if( !StreamFindNextChunk( file, "fmt ", &last_chunk ))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ typedef struct sndlib_s
|
|||||||
int rate; // num samples per second (e.g. 11025 - 11 khz)
|
int rate; // num samples per second (e.g. 11025 - 11 khz)
|
||||||
int width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2)
|
int width; // resolution - bum bits divided by 8 (8 bit is 1, 16 bit is 2)
|
||||||
int channels; // num channels (1 - mono, 2 - stereo)
|
int channels; // num channels (1 - mono, 2 - stereo)
|
||||||
uint loopstart; // start looping from
|
int loopstart; // start looping from
|
||||||
uint samples; // total samplecount in sound
|
uint samples; // total samplecount in sound
|
||||||
uint flags; // additional sound flags
|
uint flags; // additional sound flags
|
||||||
size_t size; // sound unpacked size (for bounds checking)
|
size_t size; // sound unpacked size (for bounds checking)
|
||||||
|
|||||||
@@ -135,10 +135,6 @@ void Sys_InitLog( void )
|
|||||||
mode = "a";
|
mode = "a";
|
||||||
else mode = "w";
|
else mode = "w";
|
||||||
|
|
||||||
if( Host_IsDedicated( ))
|
|
||||||
Q_strncpy( s_ld.title, XASH_DEDICATED_SERVER_NAME " " XASH_VERSION, sizeof( s_ld.title ));
|
|
||||||
else Q_strncpy( s_ld.title, XASH_ENGINE_NAME " " XASH_VERSION, sizeof( s_ld.title ));
|
|
||||||
|
|
||||||
// create log if needed
|
// create log if needed
|
||||||
if( s_ld.log_active )
|
if( s_ld.log_active )
|
||||||
{
|
{
|
||||||
@@ -146,18 +142,15 @@ void Sys_InitLog( void )
|
|||||||
|
|
||||||
if ( !s_ld.logfile )
|
if ( !s_ld.logfile )
|
||||||
{
|
{
|
||||||
Con_Reportf( S_ERROR "Sys_InitLog: can't create log file %s: %s\n", s_ld.log_path, strerror( errno ));
|
Con_Reportf( S_ERROR "Sys_InitLog: can't create log file %s: %s\n", s_ld.log_path, strerror( errno ) );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_ld.logfileno = fileno( s_ld.logfile );
|
s_ld.logfileno = fileno( s_ld.logfile );
|
||||||
|
|
||||||
// fit to 80 columns for easier read on standard terminal
|
fprintf( s_ld.logfile, "=================================================================================\n" );
|
||||||
fputs( "================================================================================\n", s_ld.logfile );
|
fprintf( s_ld.logfile, "\t%s (build %i commit %s (%s-%s)) started at %s\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildos(), Q_buildarch(), Q_timestamp( TIME_FULL ) );
|
||||||
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
fprintf( s_ld.logfile, "=================================================================================\n" );
|
||||||
fprintf( s_ld.logfile, "Game started at %s\n", Q_timestamp( TIME_FULL ));
|
|
||||||
fputs( "================================================================================\n", s_ld.logfile );
|
|
||||||
fflush( s_ld.logfile );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,11 +177,12 @@ void Sys_CloseLog( void )
|
|||||||
|
|
||||||
if( s_ld.logfile )
|
if( s_ld.logfile )
|
||||||
{
|
{
|
||||||
fputc( '\n', s_ld.logfile );
|
fprintf( s_ld.logfile, "\n");
|
||||||
fputs( "================================================================================\n", s_ld.logfile );
|
fprintf( s_ld.logfile, "=================================================================================");
|
||||||
fprintf( s_ld.logfile, "%s (%i, %s, %s, %s-%s)\n", s_ld.title, Q_buildnum(), Q_buildcommit(), Q_buildbranch(), Q_buildos(), Q_buildarch());
|
if( host.change_game ) fprintf( s_ld.logfile, "\n\t%s (build %i) %s\n", s_ld.title, Q_buildnum(), event_name );
|
||||||
fprintf( s_ld.logfile, "Stopped with reason \"%s\" at %s\n", event_name, Q_timestamp( TIME_FULL ));
|
else fprintf( s_ld.logfile, "\n\t%s (build %i) %s at %s\n", s_ld.title, Q_buildnum(), event_name, Q_timestamp( TIME_FULL ));
|
||||||
fputs( "================================================================================\n", s_ld.logfile );
|
fprintf( s_ld.logfile, "=================================================================================\n");
|
||||||
|
|
||||||
fclose( s_ld.logfile );
|
fclose( s_ld.logfile );
|
||||||
s_ld.logfile = NULL;
|
s_ld.logfile = NULL;
|
||||||
}
|
}
|
||||||
@@ -341,18 +335,15 @@ void GAME_EXPORT Con_Printf( const char *szFmt, ... )
|
|||||||
{
|
{
|
||||||
static char buffer[MAX_PRINT_MSG];
|
static char buffer[MAX_PRINT_MSG];
|
||||||
va_list args;
|
va_list args;
|
||||||
qboolean add_newline;
|
|
||||||
|
|
||||||
if( !host.allow_console )
|
if( !host.allow_console )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
va_start( args, szFmt );
|
va_start( args, szFmt );
|
||||||
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
|
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
|
||||||
va_end( args );
|
va_end( args );
|
||||||
|
|
||||||
Sys_Print( buffer );
|
Sys_Print( buffer );
|
||||||
if( add_newline )
|
|
||||||
Sys_Print( "\n" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -365,21 +356,18 @@ void GAME_EXPORT Con_DPrintf( const char *szFmt, ... )
|
|||||||
{
|
{
|
||||||
static char buffer[MAX_PRINT_MSG];
|
static char buffer[MAX_PRINT_MSG];
|
||||||
va_list args;
|
va_list args;
|
||||||
qboolean add_newline;
|
|
||||||
|
|
||||||
if( host_developer.value < DEV_NORMAL )
|
if( host_developer.value < DEV_NORMAL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
va_start( args, szFmt );
|
va_start( args, szFmt );
|
||||||
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
|
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
|
||||||
va_end( args );
|
va_end( args );
|
||||||
|
|
||||||
if( buffer[0] == '0' && buffer[1] == '\n' && buffer[2] == '\0' )
|
if( buffer[0] == '0' && buffer[1] == '\n' && buffer[2] == '\0' )
|
||||||
return; // hlrally spam
|
return; // hlrally spam
|
||||||
|
|
||||||
Sys_Print( buffer );
|
Sys_Print( buffer );
|
||||||
if( add_newline )
|
|
||||||
Sys_Print( "\n" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -392,18 +380,15 @@ void Con_Reportf( const char *szFmt, ... )
|
|||||||
{
|
{
|
||||||
static char buffer[MAX_PRINT_MSG];
|
static char buffer[MAX_PRINT_MSG];
|
||||||
va_list args;
|
va_list args;
|
||||||
qboolean add_newline;
|
|
||||||
|
|
||||||
if( host_developer.value < DEV_EXTENDED )
|
if( host_developer.value < DEV_EXTENDED )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
va_start( args, szFmt );
|
va_start( args, szFmt );
|
||||||
add_newline = Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args ) < 0;
|
Q_vsnprintf( buffer, sizeof( buffer ), szFmt, args );
|
||||||
va_end( args );
|
va_end( args );
|
||||||
|
|
||||||
Sys_Print( buffer );
|
Sys_Print( buffer );
|
||||||
if( add_newline )
|
|
||||||
Sys_Print( "\n" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ GNU General Public License for more details.
|
|||||||
#include "library.h"
|
#include "library.h"
|
||||||
#include "whereami.h"
|
#include "whereami.h"
|
||||||
|
|
||||||
int error_on_exit = 0; // arg for exit();
|
qboolean error_on_exit = false; // arg for exit();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
================
|
================
|
||||||
@@ -404,7 +404,7 @@ void Sys_Warn( const char *format, ... )
|
|||||||
Msg( "Sys_Warn: %s\n", text );
|
Msg( "Sys_Warn: %s\n", text );
|
||||||
|
|
||||||
if( !Host_IsDedicated() ) // dedicated server should not hang on messagebox
|
if( !Host_IsDedicated() ) // dedicated server should not hang on messagebox
|
||||||
Platform_MessageBox( "Xash Warning", text, true );
|
Platform_MessageBox( "Xash Warning", text, false );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -430,7 +430,7 @@ void Sys_Error( const char *error, ... )
|
|||||||
// make sure that console received last message
|
// make sure that console received last message
|
||||||
if( host.change_game ) Sys_Sleep( 200 );
|
if( host.change_game ) Sys_Sleep( 200 );
|
||||||
|
|
||||||
error_on_exit = 1;
|
error_on_exit = true;
|
||||||
host.status = HOST_ERR_FATAL;
|
host.status = HOST_ERR_FATAL;
|
||||||
va_start( argptr, error );
|
va_start( argptr, error );
|
||||||
Q_vsnprintf( text, MAX_PRINT_MSG, error, argptr );
|
Q_vsnprintf( text, MAX_PRINT_MSG, error, argptr );
|
||||||
@@ -449,7 +449,7 @@ void Sys_Error( const char *error, ... )
|
|||||||
Wcon_ShowConsole( false );
|
Wcon_ShowConsole( false );
|
||||||
#endif
|
#endif
|
||||||
Sys_Print( text );
|
Sys_Print( text );
|
||||||
Platform_MessageBox( "Xash Error", text, true );
|
Platform_MessageBox( "Xash Error", text, false );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ NOTE: never change this structure because all dll descriptions in xash code
|
|||||||
writes into struct by offsets not names
|
writes into struct by offsets not names
|
||||||
========================================================================
|
========================================================================
|
||||||
*/
|
*/
|
||||||
extern int error_on_exit;
|
|
||||||
void Sys_Sleep( int msec );
|
void Sys_Sleep( int msec );
|
||||||
double Sys_DoubleTime( void );
|
double Sys_DoubleTime( void );
|
||||||
char *Sys_GetClipboardData( void );
|
char *Sys_GetClipboardData( void );
|
||||||
|
|||||||
@@ -39,15 +39,13 @@ void Test_RunCon( void );
|
|||||||
void Test_RunVOX( void );
|
void Test_RunVOX( void );
|
||||||
void Test_RunIPFilter( void );
|
void Test_RunIPFilter( void );
|
||||||
void Test_RunGamma( void );
|
void Test_RunGamma( void );
|
||||||
void Test_RunDelta( void );
|
|
||||||
|
|
||||||
#define TEST_LIST_0 \
|
#define TEST_LIST_0 \
|
||||||
Test_RunLibCommon(); \
|
Test_RunLibCommon(); \
|
||||||
Test_RunCommon(); \
|
Test_RunCommon(); \
|
||||||
Test_RunCmd(); \
|
Test_RunCmd(); \
|
||||||
Test_RunCvar(); \
|
Test_RunCvar(); \
|
||||||
Test_RunIPFilter(); \
|
Test_RunIPFilter();
|
||||||
Test_RunDelta();
|
|
||||||
|
|
||||||
#define TEST_LIST_0_CLIENT \
|
#define TEST_LIST_0_CLIENT \
|
||||||
Test_RunCon(); \
|
Test_RunCon(); \
|
||||||
|
|||||||
@@ -20,6 +20,63 @@ GNU General Public License for more details.
|
|||||||
#include "xash3d_mathlib.h"
|
#include "xash3d_mathlib.h"
|
||||||
#include "studio.h"
|
#include "studio.h"
|
||||||
|
|
||||||
|
// just for debug
|
||||||
|
const char *et_name[] =
|
||||||
|
{
|
||||||
|
"normal",
|
||||||
|
"player",
|
||||||
|
"tempentity",
|
||||||
|
"beam",
|
||||||
|
"fragmented",
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
ENTITY LINKING
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
ClearLink
|
||||||
|
|
||||||
|
ClearLink is used for new headnodes
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
void ClearLink( link_t *l )
|
||||||
|
{
|
||||||
|
l->prev = l->next = l;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
RemoveLink
|
||||||
|
|
||||||
|
remove link from chain
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
void RemoveLink( link_t *l )
|
||||||
|
{
|
||||||
|
l->next->prev = l->prev;
|
||||||
|
l->prev->next = l->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
InsertLinkBefore
|
||||||
|
|
||||||
|
kept trigger and solid entities seperate
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
void InsertLinkBefore( link_t *l, link_t *before )
|
||||||
|
{
|
||||||
|
l->next = before;
|
||||||
|
l->prev = before->prev;
|
||||||
|
l->prev->next = l;
|
||||||
|
l->next->prev = l;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
==================
|
==================
|
||||||
World_MoveBounds
|
World_MoveBounds
|
||||||
|
|||||||
@@ -35,6 +35,13 @@ ENTITY AREA CHECKING
|
|||||||
|
|
||||||
#include "lightstyle.h"
|
#include "lightstyle.h"
|
||||||
|
|
||||||
|
extern const char *et_name[];
|
||||||
|
|
||||||
|
// linked list
|
||||||
|
void InsertLinkBefore( link_t *l, link_t *before );
|
||||||
|
void RemoveLink( link_t *l );
|
||||||
|
void ClearLink( link_t *l );
|
||||||
|
|
||||||
// trace common
|
// trace common
|
||||||
void World_MoveBounds( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, vec3_t boxmins, vec3_t boxmaxs );
|
void World_MoveBounds( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, vec3_t boxmins, vec3_t boxmaxs );
|
||||||
void World_TransformAABB( matrix4x4 transform, const vec3_t mins, const vec3_t maxs, vec3_t outmins, vec3_t outmaxs );
|
void World_TransformAABB( matrix4x4 transform, const vec3_t mins, const vec3_t maxs, vec3_t outmins, vec3_t outmaxs );
|
||||||
|
|||||||
@@ -25,39 +25,18 @@ GNU General Public License for more details.
|
|||||||
#include "platform/swap/swap.h"
|
#include "platform/swap/swap.h"
|
||||||
#define Q_malloc SWAP_Malloc
|
#define Q_malloc SWAP_Malloc
|
||||||
#define Q_free SWAP_Free
|
#define Q_free SWAP_Free
|
||||||
|
|
||||||
static void *Q_realloc( void *mem, size_t size )
|
|
||||||
{
|
|
||||||
void *newmem;
|
|
||||||
|
|
||||||
if( mem && size == 0 )
|
|
||||||
{
|
|
||||||
Q_free( mem );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
newmem = Q_malloc( size );
|
|
||||||
if( mem && newmem )
|
|
||||||
{
|
|
||||||
memcpy( newmem, mem, size );
|
|
||||||
Q_free( mem );
|
|
||||||
}
|
|
||||||
|
|
||||||
return newmem;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
#define Q_malloc malloc
|
#define Q_malloc malloc
|
||||||
#define Q_free free
|
#define Q_free free
|
||||||
#define Q_realloc realloc
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct memheader_s
|
typedef struct memheader_s
|
||||||
{
|
{
|
||||||
struct memheader_s *next; // next and previous memheaders in chain belonging to pool
|
struct memheader_s *next; // next and previous memheaders in chain belonging to pool
|
||||||
struct memheader_s *prev;
|
struct memheader_s *prev;
|
||||||
const char *filename; // file name and line where Mem_Alloc was called
|
struct mempool_s *pool; // pool this memheader belongs to
|
||||||
size_t size; // size of the memory after the header (excluding header and sentinel2)
|
size_t size; // size of the memory after the header (excluding header and sentinel2)
|
||||||
poolhandle_t poolptr; // pool this memheader belongs to
|
const char *filename; // file name and line where Mem_Alloc was called
|
||||||
int fileline;
|
int fileline;
|
||||||
#if !XASH_64BIT
|
#if !XASH_64BIT
|
||||||
uint32_t pad0; // doesn't have value, only to make Mem_Alloc return aligned addresses on ILP32
|
uint32_t pad0; // doesn't have value, only to make Mem_Alloc return aligned addresses on ILP32
|
||||||
@@ -69,34 +48,50 @@ typedef struct memheader_s
|
|||||||
|
|
||||||
typedef struct mempool_s
|
typedef struct mempool_s
|
||||||
{
|
{
|
||||||
|
uint32_t sentinel1; // should always be MEMHEADER_SENTINEL1
|
||||||
struct memheader_s *chain; // chain of individual memory allocations
|
struct memheader_s *chain; // chain of individual memory allocations
|
||||||
size_t totalsize; // total memory allocated in this pool (inside memheaders)
|
size_t totalsize; // total memory allocated in this pool (inside memheaders)
|
||||||
size_t realsize; // total memory allocated in this pool (actual malloc total)
|
size_t realsize; // total memory allocated in this pool (actual malloc total)
|
||||||
size_t lastchecksize; // updated each time the pool is displayed by memlist
|
size_t lastchecksize; // updated each time the pool is displayed by memlist
|
||||||
|
struct mempool_s *next; // linked into global mempool list
|
||||||
const char *filename; // file name and line where Mem_AllocPool was called
|
const char *filename; // file name and line where Mem_AllocPool was called
|
||||||
int fileline;
|
int fileline;
|
||||||
|
#if XASH_64BIT
|
||||||
|
poolhandle_t idx;
|
||||||
|
#endif
|
||||||
char name[64]; // name of the pool
|
char name[64]; // name of the pool
|
||||||
|
uint32_t sentinel2; // should always be MEMHEADER_SENTINEL1
|
||||||
} mempool_t;
|
} mempool_t;
|
||||||
|
|
||||||
static mempool_t *poolchain = NULL; // critical stuff
|
static mempool_t *poolchain = NULL; // critical stuff
|
||||||
static size_t poolcount = 0;
|
|
||||||
|
|
||||||
|
#if XASH_64BIT
|
||||||
// a1ba: due to mempool being passed with the model through reused 32-bit field
|
// a1ba: due to mempool being passed with the model through reused 32-bit field
|
||||||
// which makes engine incompatible with 64-bit pointers I changed mempool type
|
// which makes engine incompatible with 64-bit pointers I changed mempool type
|
||||||
// from pointer to 32-bit handle, thankfully mempool structure is private
|
// from pointer to 32-bit handle, thankfully mempool structure is private
|
||||||
|
// But! Mempools are handled through linked list so we can't index them safely
|
||||||
|
static poolhandle_t lastidx = 0;
|
||||||
|
|
||||||
static mempool_t *Mem_FindPool( poolhandle_t poolptr )
|
static mempool_t *Mem_FindPool( poolhandle_t poolptr )
|
||||||
{
|
{
|
||||||
if( likely( poolptr > 0 && poolptr <= poolcount ))
|
mempool_t *pool;
|
||||||
return &poolchain[poolptr - 1];
|
|
||||||
|
for( pool = poolchain; pool; pool = pool->next )
|
||||||
|
{
|
||||||
|
if( pool->idx == poolptr )
|
||||||
|
return pool;
|
||||||
|
}
|
||||||
|
|
||||||
Sys_Error( "%s: not allocated or double freed pool %d", __FUNCTION__, poolptr );
|
Sys_Error( "%s: not allocated or double freed pool %d", __FUNCTION__, poolptr );
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
static poolhandle_t Mem_PoolIndex( mempool_t *mempool )
|
static mempool_t *Mem_FindPool( poolhandle_t poolptr )
|
||||||
{
|
{
|
||||||
return (poolhandle_t)(mempool - poolchain) + 1;
|
return (mempool_t *)poolptr;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static inline void Mem_PoolAdd( mempool_t *pool, size_t size )
|
static inline void Mem_PoolAdd( mempool_t *pool, size_t size )
|
||||||
{
|
{
|
||||||
@@ -116,7 +111,7 @@ static inline void Mem_PoolLinkAlloc( mempool_t *pool, memheader_t *mem )
|
|||||||
if( mem->next ) mem->next->prev = mem;
|
if( mem->next ) mem->next->prev = mem;
|
||||||
pool->chain = mem;
|
pool->chain = mem;
|
||||||
mem->prev = NULL;
|
mem->prev = NULL;
|
||||||
mem->poolptr = Mem_PoolIndex( pool );
|
mem->pool = pool;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
|
static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
|
||||||
@@ -124,7 +119,7 @@ static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
|
|||||||
if( mem->next ) mem->next->prev = mem->prev;
|
if( mem->next ) mem->next->prev = mem->prev;
|
||||||
if( mem->prev ) mem->prev->next = mem->next;
|
if( mem->prev ) mem->prev->next = mem->next;
|
||||||
else pool->chain = mem->next;
|
else pool->chain = mem->next;
|
||||||
mem->poolptr = 0;
|
mem->pool = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void Mem_InitAlloc( memheader_t *mem, size_t size, const char *filename, int fileline )
|
static inline void Mem_InitAlloc( memheader_t *mem, size_t size, const char *filename, int fileline )
|
||||||
@@ -170,6 +165,23 @@ static qboolean Mem_CheckAllocHeader( const char *func, const memheader_t *mem,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static qboolean Mem_CheckPool( const char *func, const mempool_t *pool, const char *filename, int fileline )
|
||||||
|
{
|
||||||
|
if( pool->sentinel1 != MEMHEADER_SENTINEL1 )
|
||||||
|
{
|
||||||
|
Sys_Error( "%s: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)\n", func, pool->filename, pool->fileline, filename, fileline );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( pool->sentinel2 != MEMHEADER_SENTINEL1 )
|
||||||
|
{
|
||||||
|
Sys_Error( "%s: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)\n", func, pool->filename, pool->fileline, filename, fileline );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
|
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
|
||||||
{
|
{
|
||||||
memheader_t *mem;
|
memheader_t *mem;
|
||||||
@@ -178,16 +190,12 @@ void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char
|
|||||||
if( size <= 0 )
|
if( size <= 0 )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if( unlikely( !poolptr ))
|
if( !poolptr )
|
||||||
{
|
{
|
||||||
Sys_Error( "%s: pool == NULL (alloc at %s:%i)\n", __func__, filename, fileline );
|
Sys_Error( "%s: pool == NULL (alloc at %s:%i)\n", __func__, filename, fileline );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pool = Mem_FindPool( poolptr );
|
|
||||||
if( !pool )
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( byte ));
|
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( byte ));
|
||||||
if( mem == NULL )
|
if( mem == NULL )
|
||||||
{
|
{
|
||||||
@@ -197,6 +205,7 @@ void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char
|
|||||||
|
|
||||||
Mem_InitAlloc( mem, size, filename, fileline );
|
Mem_InitAlloc( mem, size, filename, fileline );
|
||||||
|
|
||||||
|
pool = Mem_FindPool( poolptr );
|
||||||
Mem_PoolAdd( pool, size );
|
Mem_PoolAdd( pool, size );
|
||||||
Mem_PoolLinkAlloc( pool, mem );
|
Mem_PoolLinkAlloc( pool, mem );
|
||||||
|
|
||||||
@@ -213,9 +222,7 @@ static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline
|
|||||||
if( !Mem_CheckAllocHeader( __func__, mem, filename, fileline ))
|
if( !Mem_CheckAllocHeader( __func__, mem, filename, fileline ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pool = Mem_FindPool( mem->poolptr );
|
pool = mem->pool;
|
||||||
if( !pool )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// unlink memheader from doubly linked list
|
// unlink memheader from doubly linked list
|
||||||
if(( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem ))
|
if(( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem ))
|
||||||
@@ -251,7 +258,7 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
|
|||||||
if( size <= 0 )
|
if( size <= 0 )
|
||||||
return data; // no need to reallocate
|
return data; // no need to reallocate
|
||||||
|
|
||||||
if( unlikely( !poolptr ))
|
if( !poolptr )
|
||||||
{
|
{
|
||||||
Sys_Error( "Mem_Realloc: pool == NULL (alloc at %s:%i)\n", filename, fileline );
|
Sys_Error( "Mem_Realloc: pool == NULL (alloc at %s:%i)\n", filename, fileline );
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -265,21 +272,25 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
|
|||||||
if( !Mem_CheckAllocHeader( "Mem_Realloc", mem, filename, fileline ))
|
if( !Mem_CheckAllocHeader( "Mem_Realloc", mem, filename, fileline ))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if( unlikely( mem->poolptr != poolptr ))
|
|
||||||
{
|
|
||||||
Sys_Error( "Mem_Realloc: pool migration is not allowed (alloc at %s:%i, realloc at %s:%i)\n",
|
|
||||||
Mem_CheckFilename( mem->filename ), mem->fileline, filename, fileline );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
oldsize = mem->size;
|
oldsize = mem->size;
|
||||||
if( size == oldsize )
|
if( size == oldsize )
|
||||||
return data;
|
return data;
|
||||||
|
|
||||||
|
#if XASH_CUSTOM_SWAP
|
||||||
|
{
|
||||||
|
char *nb = _Mem_Alloc( poolptr, size, clear, filename, fileline );
|
||||||
|
|
||||||
|
size_t newsize = mem->size < size ? mem->size : size; // upper data can be trucnated!
|
||||||
|
memcpy( nb, data, newsize );
|
||||||
|
_Mem_Free( data, filename, fileline ); // free unused old block
|
||||||
|
|
||||||
|
return nb;
|
||||||
|
}
|
||||||
|
#else // XASH_CUSTOM_SWAP
|
||||||
pool = Mem_FindPool( poolptr );
|
pool = Mem_FindPool( poolptr );
|
||||||
|
|
||||||
oldmem = (uintptr_t)mem;
|
oldmem = (uintptr_t)mem;
|
||||||
mem = Q_realloc( mem, sizeof( memheader_t ) + size + sizeof( byte ));
|
mem = realloc( mem, sizeof( memheader_t ) + size + sizeof( byte ));
|
||||||
|
|
||||||
if( mem == NULL )
|
if( mem == NULL )
|
||||||
{
|
{
|
||||||
@@ -301,7 +312,14 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
|
|||||||
}
|
}
|
||||||
else Mem_PoolSubtract( pool, oldsize - size );
|
else Mem_PoolSubtract( pool, oldsize - size );
|
||||||
|
|
||||||
if( oldmem != (uintptr_t)mem ) // just relink pointers
|
// if allocation was migrated from one pool to another
|
||||||
|
// (this is possible with original Mem_Realloc func)
|
||||||
|
if( unlikely( mem->pool != pool ))
|
||||||
|
{
|
||||||
|
Mem_PoolUnlinkAlloc( mem->pool, mem );
|
||||||
|
Mem_PoolLinkAlloc( pool, mem );
|
||||||
|
}
|
||||||
|
else if( oldmem != (uintptr_t)mem ) // just relink pointers
|
||||||
{
|
{
|
||||||
if( mem->next ) mem->next->prev = mem;
|
if( mem->next ) mem->next->prev = mem;
|
||||||
if( mem->prev ) mem->prev->next = mem;
|
if( mem->prev ) mem->prev->next = mem;
|
||||||
@@ -309,81 +327,69 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (void *)((byte *)mem + sizeof( memheader_t ));
|
return (void *)((byte *)mem + sizeof( memheader_t ));
|
||||||
}
|
#endif // XASH_CUSTOM_SWAP
|
||||||
|
|
||||||
static poolhandle_t Mem_InitPool( mempool_t *pool, const char *name, const char *filename, int fileline )
|
|
||||||
{
|
|
||||||
memset( pool, 0, sizeof( *pool ));
|
|
||||||
|
|
||||||
// fill header
|
|
||||||
pool->filename = filename;
|
|
||||||
pool->fileline = fileline;
|
|
||||||
pool->realsize = sizeof( mempool_t );
|
|
||||||
Q_strncpy( pool->name, name, sizeof( pool->name ));
|
|
||||||
|
|
||||||
return Mem_PoolIndex( pool );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
poolhandle_t _Mem_AllocPool( const char *name, const char *filename, int fileline )
|
poolhandle_t _Mem_AllocPool( const char *name, const char *filename, int fileline )
|
||||||
{
|
{
|
||||||
mempool_t *pool;
|
mempool_t *pool;
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
pool = (mempool_t *)Q_malloc( sizeof( mempool_t ));
|
||||||
{
|
|
||||||
if( pool->filename == NULL )
|
|
||||||
return Mem_InitPool( pool, name, filename, fileline );
|
|
||||||
}
|
|
||||||
|
|
||||||
pool = (mempool_t *)Q_realloc( poolchain, sizeof( *poolchain ) * ( poolcount + 1 ));
|
|
||||||
if( pool == NULL )
|
if( pool == NULL )
|
||||||
{
|
{
|
||||||
Sys_Error( "Mem_AllocPool: out of memory (allocpool at %s:%i)\n", filename, fileline );
|
Sys_Error( "Mem_AllocPool: out of memory (allocpool at %s:%i)\n", filename, fileline );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
memset( pool, 0, sizeof( mempool_t ));
|
||||||
|
|
||||||
|
// fill header
|
||||||
|
pool->sentinel1 = MEMHEADER_SENTINEL1;
|
||||||
|
pool->sentinel2 = MEMHEADER_SENTINEL1;
|
||||||
|
pool->filename = filename;
|
||||||
|
pool->fileline = fileline;
|
||||||
|
pool->chain = NULL;
|
||||||
|
pool->totalsize = 0;
|
||||||
|
pool->realsize = sizeof( mempool_t );
|
||||||
|
Q_strncpy( pool->name, name, sizeof( pool->name ));
|
||||||
|
pool->next = poolchain;
|
||||||
poolchain = pool;
|
poolchain = pool;
|
||||||
pool = &poolchain[poolcount++];
|
|
||||||
return Mem_InitPool( pool, name, filename, fileline );
|
#if XASH_64BIT
|
||||||
|
pool->idx = ++lastidx;
|
||||||
|
return pool->idx;
|
||||||
|
#else
|
||||||
|
return (poolhandle_t)pool;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline )
|
void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline )
|
||||||
{
|
{
|
||||||
mempool_t *pool;
|
mempool_t *pool;
|
||||||
|
mempool_t **chainaddress;
|
||||||
|
|
||||||
if( *poolptr && ( pool = Mem_FindPool( *poolptr )))
|
if( *poolptr && ( pool = Mem_FindPool( *poolptr )))
|
||||||
{
|
{
|
||||||
if( !pool->filename )
|
// unlink pool from chain
|
||||||
{
|
for( chainaddress = &poolchain; *chainaddress && *chainaddress != pool; chainaddress = &((*chainaddress)->next));
|
||||||
Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
|
if( *chainaddress != pool ) Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
|
||||||
*poolptr = 0;
|
Mem_CheckPool( "Mem_FreePool", pool, filename, fileline );
|
||||||
return;
|
*chainaddress = pool->next;
|
||||||
}
|
|
||||||
|
|
||||||
// free memory owned by the pool
|
// free memory owned by the pool
|
||||||
while( pool->chain )
|
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
|
||||||
Mem_FreeBlock( pool->chain, filename, fileline );
|
|
||||||
|
|
||||||
// free the pool itself
|
// free the pool itself
|
||||||
memset( pool, 0xBF, sizeof( mempool_t ));
|
memset( pool, 0xBF, sizeof( mempool_t ));
|
||||||
pool->chain = NULL;
|
Q_free( pool );
|
||||||
pool->filename = NULL; // mark as reusable
|
|
||||||
*poolptr = 0;
|
*poolptr = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline )
|
void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline )
|
||||||
{
|
{
|
||||||
mempool_t *pool;
|
mempool_t *pool = Mem_FindPool( poolptr );
|
||||||
if( unlikely( !poolptr ))
|
if( !poolptr ) Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
|
||||||
{
|
|
||||||
Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pool = Mem_FindPool( poolptr );
|
Mem_CheckPool( "Mem_FreePool", pool, filename, fileline );
|
||||||
if( !pool )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// free memory owned by the pool
|
// free memory owned by the pool
|
||||||
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
|
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
|
||||||
@@ -406,8 +412,7 @@ static qboolean Mem_CheckAlloc( mempool_t *pool, void *data )
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// search all pools
|
// search all pools
|
||||||
size_t i;
|
for( pool = poolchain; pool; pool = pool->next )
|
||||||
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
|
||||||
{
|
{
|
||||||
if( Mem_CheckAlloc( pool, data ))
|
if( Mem_CheckAlloc( pool, data ))
|
||||||
return true;
|
return true;
|
||||||
@@ -435,24 +440,23 @@ void _Mem_Check( const char *filename, int fileline )
|
|||||||
{
|
{
|
||||||
memheader_t *mem;
|
memheader_t *mem;
|
||||||
mempool_t *pool;
|
mempool_t *pool;
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
for( pool = poolchain; pool; pool = pool->next )
|
||||||
|
Mem_CheckPool( "Mem_CheckSentinels", pool, filename, fileline );
|
||||||
|
|
||||||
|
for( pool = poolchain; pool; pool = pool->next )
|
||||||
for( mem = pool->chain; mem; mem = mem->next )
|
for( mem = pool->chain; mem; mem = mem->next )
|
||||||
Mem_CheckAllocHeader( "Mem_CheckSentinels", mem, filename, fileline );
|
Mem_CheckAllocHeader( "Mem_CheckSentinels", mem, filename, fileline );
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mem_PrintStats( void )
|
void Mem_PrintStats( void )
|
||||||
{
|
{
|
||||||
size_t count = 0, size = 0, realsize = 0, i;
|
size_t count = 0, size = 0, realsize = 0;
|
||||||
mempool_t *pool;
|
mempool_t *pool;
|
||||||
|
|
||||||
Mem_Check();
|
Mem_Check();
|
||||||
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
for( pool = poolchain; pool; pool = pool->next )
|
||||||
{
|
{
|
||||||
if( !pool->filename )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
size += pool->totalsize;
|
size += pool->totalsize;
|
||||||
realsize += pool->realsize;
|
realsize += pool->realsize;
|
||||||
@@ -466,19 +470,15 @@ void Mem_PrintList( size_t minallocationsize )
|
|||||||
{
|
{
|
||||||
mempool_t *pool;
|
mempool_t *pool;
|
||||||
memheader_t *mem;
|
memheader_t *mem;
|
||||||
size_t i;
|
|
||||||
|
|
||||||
Mem_Check();
|
Mem_Check();
|
||||||
|
|
||||||
Con_Printf( "memory pool list:\n" );
|
Con_Printf( "memory pool list:\n" );
|
||||||
Con_Printf( "\t^3size\t\t\t\tname\n");
|
Con_Printf( "\t^3size\t\t\t\tname\n");
|
||||||
for( i = 0, pool = poolchain; i < poolcount; i++, pool++ )
|
for( pool = poolchain; pool; pool = pool->next )
|
||||||
{
|
{
|
||||||
long changed_size = (long)pool->totalsize - (long)pool->lastchecksize;
|
long changed_size = (long)pool->totalsize - (long)pool->lastchecksize;
|
||||||
|
|
||||||
if( !pool->filename )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// poolnames can contain color symbols, make sure what color is reset
|
// poolnames can contain color symbols, make sure what color is reset
|
||||||
if( pool->lastchecksize != 0 && changed_size != 0 )
|
if( pool->lastchecksize != 0 && changed_size != 0 )
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,10 +50,6 @@ GNU General Public License for more details.
|
|||||||
#define LUMP_SAVE_NO_DATA 7
|
#define LUMP_SAVE_NO_DATA 7
|
||||||
#define LUMP_SAVE_CORRUPTED 8
|
#define LUMP_SAVE_CORRUPTED 8
|
||||||
|
|
||||||
#ifndef ALLOC_CHECK
|
|
||||||
#define ALLOC_CHECK( x )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct areanode_s
|
typedef struct areanode_s
|
||||||
{
|
{
|
||||||
int axis; // -1 = leaf node
|
int axis; // -1 = leaf node
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ GNU General Public License for more details.
|
|||||||
*/
|
*/
|
||||||
#include "platform/platform.h"
|
#include "platform/platform.h"
|
||||||
|
|
||||||
#if !defined(XASH_DEDICATED)
|
#if !defined(XASH_DEDICATED) && XASH_SDL
|
||||||
|
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
|
|||||||
1064
engine/platform/android/android_nosdl.c
Normal file
1064
engine/platform/android/android_nosdl.c
Normal file
File diff suppressed because it is too large
Load Diff
55
engine/platform/android/android_priv.h
Normal file
55
engine/platform/android/android_priv.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
#ifndef ANDROID_PRIV_H
|
||||||
|
#define ANDROID_PRIV_H
|
||||||
|
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <android/log.h>
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
extern struct jnimethods_s
|
||||||
|
{
|
||||||
|
jclass actcls;
|
||||||
|
jclass bindcls;
|
||||||
|
JavaVM *vm;
|
||||||
|
JNIEnv *env;
|
||||||
|
jmethodID enableTextInput;
|
||||||
|
jmethodID vibrate;
|
||||||
|
jmethodID messageBox;
|
||||||
|
jmethodID notify;
|
||||||
|
jmethodID setTitle;
|
||||||
|
jmethodID setIcon;
|
||||||
|
jmethodID getAndroidId;
|
||||||
|
jmethodID saveID;
|
||||||
|
jmethodID loadID;
|
||||||
|
jmethodID showMouse;
|
||||||
|
jmethodID shellExecute;
|
||||||
|
jmethodID swapBuffers;
|
||||||
|
jmethodID toggleEGL;
|
||||||
|
jmethodID createGLContext;
|
||||||
|
jmethodID getGLAttribute;
|
||||||
|
jmethodID deleteGLContext;
|
||||||
|
jmethodID getSurface;
|
||||||
|
jmethodID preShutdown;
|
||||||
|
int width, height;
|
||||||
|
} jni;
|
||||||
|
|
||||||
|
typedef enum surfacestate_e
|
||||||
|
{
|
||||||
|
surface_pause,
|
||||||
|
surface_active,
|
||||||
|
surface_dummy,
|
||||||
|
|
||||||
|
} surfacestate_t;
|
||||||
|
|
||||||
|
|
||||||
|
extern struct jnimouse_s
|
||||||
|
{
|
||||||
|
float x, y;
|
||||||
|
} jnimouse;
|
||||||
|
|
||||||
|
//
|
||||||
|
// vid_android.c
|
||||||
|
//
|
||||||
|
void Android_UpdateSurface( surfacestate_t state );
|
||||||
|
|
||||||
|
#endif // ANDROID_PRIV_H
|
||||||
@@ -25,30 +25,36 @@
|
|||||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
#include "build.h"
|
||||||
#if defined __ANDROID__ && !defined XASH_64BIT
|
#if !XASH_64BIT
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
#include "linker.h"
|
#include "linker.h"
|
||||||
|
extern "C" {
|
||||||
|
#include "lib_android.h"
|
||||||
|
}
|
||||||
|
|
||||||
static Elf_Sym* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
|
static Elf_Sym* soinfo_elf_lookup( soinfo* si, unsigned hash, const char* name )
|
||||||
|
{
|
||||||
Elf_Sym* symtab = si->symtab;
|
Elf_Sym* symtab = si->symtab;
|
||||||
const char* strtab = si->strtab;
|
const char* strtab = si->strtab;
|
||||||
|
|
||||||
if( si->nbucket == 0 )
|
if( si->nbucket == 0 )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) {
|
for( unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n] )
|
||||||
|
{
|
||||||
Elf_Sym* s = symtab + n;
|
Elf_Sym* s = symtab + n;
|
||||||
if (strcmp(strtab + s->st_name, name)) continue;
|
if( strcmp( strtab + s->st_name, name )) continue;
|
||||||
|
|
||||||
/* only concern ourselves with global and weak symbol definitions */
|
/* only concern ourselves with global and weak symbol definitions */
|
||||||
switch (ELF_ST_BIND(s->st_info)) {
|
switch( ELF_ST_BIND( s->st_info ))
|
||||||
|
{
|
||||||
case STB_GLOBAL:
|
case STB_GLOBAL:
|
||||||
case STB_WEAK:
|
case STB_WEAK:
|
||||||
if (s->st_shndx == SHN_UNDEF) {
|
if( s->st_shndx == SHN_UNDEF )
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,11 +62,44 @@ static Elf_Sym* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned elfhash(const char* _name) {
|
static Elf_Sym* soinfo_elf_lookup_reverse(soinfo* si, size_t addr)
|
||||||
const unsigned char* name = (const unsigned char*) _name;
|
{
|
||||||
|
Elf_Sym* symtab = si->symtab;
|
||||||
|
|
||||||
|
if( si->nbucket == 0 )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for( int j = 0; j < si->nbucket; j++ )
|
||||||
|
{
|
||||||
|
for( unsigned n = si->bucket[j]; n != 0; n = si->chain[n] )
|
||||||
|
{
|
||||||
|
Elf_Sym* s = symtab + n;
|
||||||
|
if( s->st_value != addr )continue;
|
||||||
|
|
||||||
|
/* only concern ourselves with global and weak symbol definitions */
|
||||||
|
switch( ELF_ST_BIND( s->st_info ))
|
||||||
|
{
|
||||||
|
case STB_GLOBAL:
|
||||||
|
case STB_LOCAL:
|
||||||
|
case STB_WEAK:
|
||||||
|
if (s->st_shndx == SHN_UNDEF)
|
||||||
|
continue;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned elfhash( const char* _name )
|
||||||
|
{
|
||||||
|
const unsigned char* name = ( const unsigned char* ) _name;
|
||||||
unsigned h = 0, g;
|
unsigned h = 0, g;
|
||||||
|
|
||||||
while(*name) {
|
while(*name)
|
||||||
|
{
|
||||||
h = (h << 4) + *name++;
|
h = (h << 4) + *name++;
|
||||||
g = h & 0xf0000000;
|
g = h & 0xf0000000;
|
||||||
h ^= g;
|
h ^= g;
|
||||||
@@ -78,21 +117,73 @@ static unsigned elfhash(const char* _name) {
|
|||||||
Binary Interface) where in Chapter 5 it discuss resolving "Shared
|
Binary Interface) where in Chapter 5 it discuss resolving "Shared
|
||||||
Object Dependencies" in breadth first search order.
|
Object Dependencies" in breadth first search order.
|
||||||
*/
|
*/
|
||||||
static Elf_Sym* dlsym_handle_lookup(soinfo* si, const char* name) {
|
static Elf_Sym* dlsym_handle_lookup( soinfo* si, const char* name )
|
||||||
return soinfo_elf_lookup(si, elfhash(name), name);
|
{
|
||||||
|
return soinfo_elf_lookup( si, elfhash( name ), name );
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void* dlsym_weak(void* handle, const char* symbol) {
|
static int dladdr_fallback( const void *addr, Dl_info *info )
|
||||||
|
{
|
||||||
|
static soinfo *server_info;
|
||||||
|
Elf_Sym *sym;
|
||||||
|
|
||||||
|
if( !server_info )
|
||||||
|
server_info = ( soinfo* )ANDROID_GetServerLibrary();
|
||||||
|
if( !server_info )
|
||||||
|
return 0;
|
||||||
|
//__android_log_print( ANDROID_LOG_ERROR, "dladdr_fb", "%p %p\n", addr, server_info );
|
||||||
|
|
||||||
|
sym = soinfo_elf_lookup_reverse( server_info, ((char*)addr) - ((char*)server_info->base ));
|
||||||
|
//__android_log_print( ANDROID_LOG_ERROR, "dladdr_fb", "sym %p %p\n", addr, sym );
|
||||||
|
if( sym )
|
||||||
|
{
|
||||||
|
info->dli_sname = server_info->strtab + sym->st_name;
|
||||||
|
info->dli_fname = "server";
|
||||||
|
info->dli_fbase = (void*)server_info->base;
|
||||||
|
info->dli_saddr = (void*)addr;
|
||||||
|
//__android_log_print( ANDROID_LOG_ERROR, "dladdr_fb", "name %p %s\n", addr, info->dli_sname );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" int __attribute__((visibility("hidden"))) dladdr( const void *addr, Dl_info *info )
|
||||||
|
{
|
||||||
|
typedef int (*PFNDLADDR)( const void *addr, Dl_info *info );
|
||||||
|
PFNDLADDR pfn_dladdr;
|
||||||
|
|
||||||
|
if( !pfn_dladdr )
|
||||||
|
{
|
||||||
|
/* android does not have libdl, but have soinfo record for it from linker
|
||||||
|
* use dlopen to get this record directly */
|
||||||
|
void *lib = dlopen( "libdl.so", RTLD_NOW );
|
||||||
|
|
||||||
|
if( lib )
|
||||||
|
pfn_dladdr = (PFNDLADDR)dlsym( lib, "dladdr" );
|
||||||
|
if( pfn_dladdr == (PFNDLADDR)dladdr )
|
||||||
|
pfn_dladdr = 0;
|
||||||
|
if( !pfn_dladdr )
|
||||||
|
pfn_dladdr = (PFNDLADDR)dladdr_fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pfn_dladdr( addr, info );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" void* dlsym_weak( void* handle, const char* symbol ) {
|
||||||
|
|
||||||
soinfo* found = NULL;
|
soinfo* found = NULL;
|
||||||
Elf_Sym* sym = NULL;
|
Elf_Sym* sym = NULL;
|
||||||
found = reinterpret_cast<soinfo*>(handle);
|
found = reinterpret_cast<soinfo*>( handle );
|
||||||
sym = dlsym_handle_lookup(found, symbol);
|
sym = dlsym_handle_lookup( found, symbol );
|
||||||
|
|
||||||
if (sym != NULL) {
|
if ( sym != NULL ) {
|
||||||
return reinterpret_cast<void*>(sym->st_value + found->base/*load_bias*/);
|
return reinterpret_cast<void*>( sym->st_value + found->base /*load_bias*/ );
|
||||||
}
|
}
|
||||||
__android_log_print(ANDROID_LOG_ERROR, "dlsym-weak", "Failed when looking up %s\n", symbol);
|
__android_log_print( ANDROID_LOG_ERROR, "dlsym-weak", "Failed when looking up %s\n", symbol );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
453
engine/platform/android/eglutil.c
Normal file
453
engine/platform/android/eglutil.c
Normal file
@@ -0,0 +1,453 @@
|
|||||||
|
/*
|
||||||
|
eglutil.c - EGL context utility
|
||||||
|
Copyright (C) 2023 mittorn
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "platform/platform.h"
|
||||||
|
#if !defined(XASH_DEDICATED) && !XASH_SDL
|
||||||
|
#include "eglutil.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "vid_common.h"
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <EGL/eglext.h>
|
||||||
|
|
||||||
|
struct eglapi_s egl;
|
||||||
|
|
||||||
|
#undef GetProcAddress // windows.h?
|
||||||
|
#define EGL_FF(x) {"egl"#x, (void*)&egl.x}
|
||||||
|
static dllfunc_t egl_funcs[] =
|
||||||
|
{
|
||||||
|
EGL_FF(SwapInterval),
|
||||||
|
EGL_FF(SwapBuffers),
|
||||||
|
EGL_FF(GetError),
|
||||||
|
EGL_FF(GetCurrentDisplay),
|
||||||
|
EGL_FF(GetCurrentSurface),
|
||||||
|
EGL_FF(GetProcAddress),
|
||||||
|
EGL_FF(GetConfigAttrib),
|
||||||
|
EGL_FF(GetDisplay),
|
||||||
|
EGL_FF(Initialize),
|
||||||
|
EGL_FF(Terminate),
|
||||||
|
EGL_FF(QueryString),
|
||||||
|
EGL_FF(ChooseConfig),
|
||||||
|
EGL_FF(CreateWindowSurface),
|
||||||
|
EGL_FF(CreateContext),
|
||||||
|
EGL_FF(DestroyContext),
|
||||||
|
EGL_FF(MakeCurrent),
|
||||||
|
EGL_FF(BindAPI),
|
||||||
|
EGL_FF(DestroySurface),
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
#undef EGL_FF
|
||||||
|
static dll_info_t egl_info = { "libEGL.so", egl_funcs, false };
|
||||||
|
|
||||||
|
struct eglstate_s eglstate;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
===================
|
||||||
|
|
||||||
|
refapi/egl wrappers
|
||||||
|
|
||||||
|
===================
|
||||||
|
*/
|
||||||
|
|
||||||
|
int EGL_SetAttribute( int attr, int val )
|
||||||
|
{
|
||||||
|
if( attr < 0 || attr >= REF_GL_ATTRIBUTES_COUNT )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
eglstate.gl_attribs[attr] = val;
|
||||||
|
eglstate.gl_attribs_set[attr] = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define COPY_ATTR_IF_SET( refattr, attr ) \
|
||||||
|
if( eglstate.gl_attribs_set[refattr] ) \
|
||||||
|
{ \
|
||||||
|
attribs[i++] = attr; \
|
||||||
|
attribs[i++] = eglstate.gl_attribs[refattr]; \
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t EGL_GenerateConfig( EGLint *attribs, size_t size )
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
memset( attribs, 0, size * sizeof( EGLint ) );
|
||||||
|
eglstate.gles1 = false;
|
||||||
|
memset( eglstate.gl_attribs, 0, sizeof( eglstate.gl_attribs ));
|
||||||
|
memset( eglstate.gl_attribs_set, 0, sizeof( eglstate.gl_attribs_set ));
|
||||||
|
|
||||||
|
// refdll can request some attributes
|
||||||
|
ref.dllFuncs.GL_SetupAttributes( glw_state.safe );
|
||||||
|
|
||||||
|
COPY_ATTR_IF_SET( REF_GL_RED_SIZE, EGL_RED_SIZE );
|
||||||
|
COPY_ATTR_IF_SET( REF_GL_GREEN_SIZE, EGL_GREEN_SIZE );
|
||||||
|
COPY_ATTR_IF_SET( REF_GL_BLUE_SIZE, EGL_BLUE_SIZE );
|
||||||
|
COPY_ATTR_IF_SET( REF_GL_ALPHA_SIZE, EGL_ALPHA_SIZE );
|
||||||
|
COPY_ATTR_IF_SET( REF_GL_DEPTH_SIZE, EGL_DEPTH_SIZE );
|
||||||
|
COPY_ATTR_IF_SET( REF_GL_STENCIL_SIZE, EGL_STENCIL_SIZE );
|
||||||
|
COPY_ATTR_IF_SET( REF_GL_MULTISAMPLEBUFFERS, EGL_SAMPLE_BUFFERS );
|
||||||
|
COPY_ATTR_IF_SET( REF_GL_MULTISAMPLESAMPLES, EGL_SAMPLES );
|
||||||
|
|
||||||
|
if( eglstate.gl_attribs_set[REF_GL_ACCELERATED_VISUAL] )
|
||||||
|
{
|
||||||
|
attribs[i++] = EGL_CONFIG_CAVEAT;
|
||||||
|
attribs[i++] = eglstate.gl_attribs[REF_GL_ACCELERATED_VISUAL] ? EGL_NONE : EGL_DONT_CARE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BigGL support
|
||||||
|
attribs[i++] = EGL_RENDERABLE_TYPE;
|
||||||
|
eglstate.gl_api = EGL_OPENGL_ES_API;
|
||||||
|
|
||||||
|
if( eglstate.gl_attribs_set[REF_GL_CONTEXT_PROFILE_MASK] &&
|
||||||
|
!( eglstate.gl_attribs[REF_GL_CONTEXT_PROFILE_MASK] & REF_GL_CONTEXT_PROFILE_ES ))
|
||||||
|
{
|
||||||
|
attribs[i++] = EGL_OPENGL_BIT;
|
||||||
|
eglstate.gl_api = EGL_OPENGL_API;
|
||||||
|
}
|
||||||
|
else if( eglstate.gl_attribs_set[REF_GL_CONTEXT_MAJOR_VERSION] &&
|
||||||
|
eglstate.gl_attribs[REF_GL_CONTEXT_MAJOR_VERSION] >= 2 )
|
||||||
|
{
|
||||||
|
attribs[i++] = EGL_OPENGL_ES2_BIT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i--; // erase EGL_RENDERABLE_TYPE
|
||||||
|
eglstate.gles1 = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
attribs[i++] = EGL_NONE;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t EGL_GenerateContextConfig( EGLint *attribs, size_t size )
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
memset( attribs, 0, size * sizeof( EGLint ));
|
||||||
|
|
||||||
|
if( Q_strstr( eglstate.extensions, "EGL_KHR_create_context") )
|
||||||
|
{
|
||||||
|
Con_DPrintf( S_NOTE "EGL_KHR_create_context found, setting additional context flags\n");
|
||||||
|
|
||||||
|
if( eglstate.gl_attribs_set[REF_GL_CONTEXT_FLAGS] )
|
||||||
|
{
|
||||||
|
attribs[i++] = 0x30FC; // EGL_CONTEXT_FLAGS_KHR
|
||||||
|
attribs[i++] = eglstate.gl_attribs[REF_GL_CONTEXT_FLAGS] & ((REF_GL_CONTEXT_ROBUST_ACCESS_FLAG << 1) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( eglstate.gl_attribs_set[REF_GL_CONTEXT_PROFILE_MASK] )
|
||||||
|
{
|
||||||
|
int val = eglstate.gl_attribs[REF_GL_CONTEXT_PROFILE_MASK];
|
||||||
|
|
||||||
|
if( val & ( (REF_GL_CONTEXT_PROFILE_COMPATIBILITY << 1) - 1 ) )
|
||||||
|
{
|
||||||
|
attribs[i++] = 0x30FD; // EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
|
||||||
|
attribs[i++] = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
COPY_ATTR_IF_SET( REF_GL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_CLIENT_VERSION );
|
||||||
|
COPY_ATTR_IF_SET( REF_GL_CONTEXT_MINOR_VERSION, 0x30FB );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// without extension we can set only major version
|
||||||
|
COPY_ATTR_IF_SET( REF_GL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_CLIENT_VERSION );
|
||||||
|
if( eglstate.gl_attribs_set[REF_GL_CONTEXT_FLAGS] && (eglstate.gl_attribs[REF_GL_CONTEXT_FLAGS] & REF_GL_CONTEXT_DEBUG_FLAG ))
|
||||||
|
{
|
||||||
|
attribs[i++] = 0x31B0; // EGL_CONTEXT_OPENGL_DEBUG;
|
||||||
|
attribs[i++] = EGL_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
attribs[i++] = EGL_NONE;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
EGL_GetAttribute
|
||||||
|
|
||||||
|
query
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
int EGL_GetAttribute( int attr, int *val )
|
||||||
|
{
|
||||||
|
EGLBoolean ret;
|
||||||
|
|
||||||
|
if( attr < 0 || attr >= REF_GL_ATTRIBUTES_COUNT )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if( !val )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
switch( attr )
|
||||||
|
{
|
||||||
|
case REF_GL_RED_SIZE:
|
||||||
|
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_RED_SIZE, val );
|
||||||
|
return 0;
|
||||||
|
case REF_GL_GREEN_SIZE:
|
||||||
|
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_GREEN_SIZE, val );
|
||||||
|
return 0;
|
||||||
|
case REF_GL_BLUE_SIZE:
|
||||||
|
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_BLUE_SIZE, val );
|
||||||
|
return 0;
|
||||||
|
case REF_GL_ALPHA_SIZE:
|
||||||
|
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_ALPHA_SIZE, val );
|
||||||
|
return 0;
|
||||||
|
case REF_GL_DEPTH_SIZE:
|
||||||
|
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_DEPTH_SIZE, val );
|
||||||
|
return 0;
|
||||||
|
case REF_GL_STENCIL_SIZE:
|
||||||
|
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_STENCIL_SIZE, val );
|
||||||
|
return 0;
|
||||||
|
case REF_GL_MULTISAMPLESAMPLES:
|
||||||
|
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_SAMPLES, val );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
EGL_UpdateSurface
|
||||||
|
|
||||||
|
destroy old surface, recreate and make context current
|
||||||
|
must be called with valid context
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
qboolean EGL_UpdateSurface( void *window, qboolean dummy )
|
||||||
|
{
|
||||||
|
if( !eglstate.valid )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
|
||||||
|
host.status = HOST_SLEEP;
|
||||||
|
|
||||||
|
if( eglstate.surface )
|
||||||
|
{
|
||||||
|
egl.DestroySurface( eglstate.dpy, eglstate.surface );
|
||||||
|
eglstate.surface = EGL_NO_SURFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !window )
|
||||||
|
{
|
||||||
|
|
||||||
|
if( dummy && eglstate.support_surfaceless_context )
|
||||||
|
{
|
||||||
|
if( egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, eglstate.context ))
|
||||||
|
{
|
||||||
|
Con_Reportf( S_NOTE "EGL_UpdateSurface: using surfaceless mode\n" );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
|
||||||
|
eglstate.support_surfaceless_context = false;
|
||||||
|
}
|
||||||
|
Con_Reportf( S_NOTE "EGL_UpdateSurface: missing native window, detaching context\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // let platform fallback to dummy surface or pause engine
|
||||||
|
}
|
||||||
|
|
||||||
|
if(( eglstate.surface = egl.CreateWindowSurface( eglstate.dpy, eglstate.cfg, window, NULL )) == EGL_NO_SURFACE )
|
||||||
|
{
|
||||||
|
Con_Reportf( S_ERROR "eglCreateWindowSurface returned error: 0x%x\n", egl.GetError() );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !egl.MakeCurrent( eglstate.dpy, eglstate.surface, eglstate.surface, eglstate.context ))
|
||||||
|
{
|
||||||
|
Con_Reportf( S_ERROR "eglMakeCurrent returned error: 0x%x\n", egl.GetError() );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Con_DPrintf( S_NOTE "restored current context\n" );
|
||||||
|
if( !dummy)
|
||||||
|
host.status = HOST_FRAME;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
EGL_CreateContext
|
||||||
|
|
||||||
|
query attributes for ref and create context
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
qboolean EGL_CreateContext( void )
|
||||||
|
{
|
||||||
|
EGLint attribs[32+1], contextAttribs[32+1];
|
||||||
|
const size_t attribsSize = ARRAYSIZE( attribs );
|
||||||
|
size_t s1, s2;
|
||||||
|
|
||||||
|
if( !eglstate.dpy && ( eglstate.dpy = egl.GetDisplay( EGL_DEFAULT_DISPLAY )) == EGL_NO_DISPLAY )
|
||||||
|
{
|
||||||
|
Con_Reportf( S_ERROR "eglGetDisplay returned error: 0x%x\n", egl.GetError() );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
eglstate.extensions = egl.QueryString( eglstate.dpy, EGL_EXTENSIONS );
|
||||||
|
|
||||||
|
s1 = EGL_GenerateConfig(attribs, attribsSize);
|
||||||
|
s2 = EGL_GenerateContextConfig(contextAttribs, attribsSize);
|
||||||
|
|
||||||
|
|
||||||
|
if( !egl.BindAPI( eglstate.gl_api ))
|
||||||
|
{
|
||||||
|
Con_Reportf( S_ERROR "eglBindAPI returned error: 0x%x\n", egl.GetError() );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !egl.Initialize( eglstate.dpy, NULL, NULL ))
|
||||||
|
{
|
||||||
|
Con_Reportf( S_ERROR "eglInitialize returned error: 0x%x\n", egl.GetError() );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !egl.ChooseConfig( eglstate.dpy, attribs, &eglstate.cfg, 1, &eglstate.numCfg ))
|
||||||
|
{
|
||||||
|
Con_Reportf( S_ERROR "eglChooseConfig returned error: 0x%x\n", egl.GetError() );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(( eglstate.context = egl.CreateContext( eglstate.dpy, eglstate.cfg, NULL, contextAttribs )) == EGL_NO_CONTEXT )
|
||||||
|
{
|
||||||
|
Con_Reportf( S_ERROR "eglCreateContext returned error: 0x%x\n", egl.GetError() );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
eglstate.valid = true;
|
||||||
|
eglstate.imported = false;
|
||||||
|
|
||||||
|
// now check if it's safe to use surfaceless context here without surface fallback
|
||||||
|
if( eglstate.extensions && Q_strstr( eglstate.extensions, "EGL_KHR_surfaceless_context" ))
|
||||||
|
eglstate.support_surfaceless_context = true;
|
||||||
|
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===========================
|
||||||
|
EGL_ImportContext
|
||||||
|
|
||||||
|
import current egl context to use EGL functions
|
||||||
|
===========================
|
||||||
|
*/
|
||||||
|
qboolean EGL_ImportContext( void )
|
||||||
|
{
|
||||||
|
if( !egl.GetCurrentDisplay )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
eglstate.dpy = egl.GetCurrentDisplay();
|
||||||
|
|
||||||
|
if( eglstate.dpy == EGL_NO_DISPLAY )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
eglstate.surface = egl.GetCurrentSurface( EGL_DRAW );
|
||||||
|
|
||||||
|
if( eglstate.surface == EGL_NO_SURFACE )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// now check if swapBuffers does not give error
|
||||||
|
if( egl.SwapBuffers( eglstate.dpy, eglstate.surface ) == EGL_FALSE )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// double check
|
||||||
|
if( egl.GetError() != EGL_SUCCESS )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
eglstate.extensions = egl.QueryString( eglstate.dpy, EGL_EXTENSIONS );
|
||||||
|
|
||||||
|
eglstate.valid = eglstate.imported = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
EGL_Terminate
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
void EGL_Terminate( void )
|
||||||
|
{
|
||||||
|
egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
|
||||||
|
|
||||||
|
egl.DestroyContext( eglstate.dpy, eglstate.context );
|
||||||
|
|
||||||
|
egl.DestroySurface( eglstate.dpy, eglstate.surface );
|
||||||
|
|
||||||
|
egl.Terminate( eglstate.dpy );
|
||||||
|
|
||||||
|
Sys_FreeLibrary( &egl_info );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
EGL_GetProcAddress
|
||||||
|
|
||||||
|
eglGetProcAddress/dlsym wrapper
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
void *EGL_GetProcAddress( const char *name )
|
||||||
|
{
|
||||||
|
void *gles;
|
||||||
|
void *addr;
|
||||||
|
|
||||||
|
// TODO: cross-platform loading
|
||||||
|
if( eglstate.gles1 )
|
||||||
|
{
|
||||||
|
if( !eglstate.libgles1 )
|
||||||
|
eglstate.libgles1 = dlopen( "libGLESv1_CM.so", RTLD_NOW );
|
||||||
|
gles = eglstate.libgles1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( !eglstate.libgles2 )
|
||||||
|
eglstate.libgles2 = dlopen( "libGLESv2.so", RTLD_NOW );
|
||||||
|
gles = eglstate.libgles2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( gles && ( addr = dlsym( gles, name )))
|
||||||
|
return addr;
|
||||||
|
|
||||||
|
if( !egl.GetProcAddress )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return egl.GetProcAddress( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=========================
|
||||||
|
EGL_LoadLibrary
|
||||||
|
=========================
|
||||||
|
*/
|
||||||
|
void EGL_LoadLibrary( void )
|
||||||
|
{
|
||||||
|
Sys_LoadLibrary( &egl_info );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
73
engine/platform/android/eglutil.h
Normal file
73
engine/platform/android/eglutil.h
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
eglutil.h - EGL context utility
|
||||||
|
Copyright (C) 2023 mittorn
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
#ifndef EGLUTIL_H
|
||||||
|
#define EGLUTIL_H
|
||||||
|
#include "platform/platform.h"
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <EGL/eglext.h>
|
||||||
|
|
||||||
|
extern struct eglstate_s
|
||||||
|
{
|
||||||
|
qboolean valid, imported;
|
||||||
|
EGLDisplay dpy;
|
||||||
|
EGLSurface surface;
|
||||||
|
EGLContext context;
|
||||||
|
EGLConfig cfg;
|
||||||
|
EGLint numCfg;
|
||||||
|
qboolean support_surfaceless_context;
|
||||||
|
|
||||||
|
const char *extensions;
|
||||||
|
int gl_attribs[REF_GL_ATTRIBUTES_COUNT];
|
||||||
|
qboolean gl_attribs_set[REF_GL_ATTRIBUTES_COUNT];
|
||||||
|
EGLint gl_api;
|
||||||
|
qboolean gles1;
|
||||||
|
void *libgles1, *libgles2;
|
||||||
|
} eglstate;
|
||||||
|
|
||||||
|
extern struct eglapi_s
|
||||||
|
{
|
||||||
|
EGLSurface (*GetCurrentSurface)( EGLint readdraw );
|
||||||
|
EGLDisplay (*GetCurrentDisplay)( void );
|
||||||
|
EGLint (*GetError)( void );
|
||||||
|
EGLBoolean (*SwapBuffers)( EGLDisplay dpy, EGLSurface surface );
|
||||||
|
EGLBoolean (*SwapInterval)( EGLDisplay dpy, EGLint interval );
|
||||||
|
void *(*GetProcAddress)( const char *procname );
|
||||||
|
EGLBoolean (*GetConfigAttrib)( EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value );
|
||||||
|
EGLDisplay (*GetDisplay)( NativeDisplayType display );
|
||||||
|
EGLBoolean (*Initialize)( EGLDisplay dpy, EGLint *major, EGLint *minor );
|
||||||
|
EGLBoolean (*Terminate)( EGLDisplay dpy );
|
||||||
|
const char *(*QueryString)( EGLDisplay dpy, EGLint name );
|
||||||
|
EGLBoolean (*ChooseConfig)( EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config );
|
||||||
|
EGLSurface (*CreateWindowSurface)( EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list );
|
||||||
|
EGLContext (*CreateContext)( EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list );
|
||||||
|
EGLBoolean (*DestroyContext)( EGLDisplay dpy, EGLContext ctx );
|
||||||
|
EGLBoolean (*MakeCurrent)( EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx );
|
||||||
|
EGLBoolean (*BindAPI)( EGLenum api );
|
||||||
|
EGLBoolean (*DestroySurface)( EGLDisplay dpy, EGLSurface surface );
|
||||||
|
|
||||||
|
} egl;
|
||||||
|
|
||||||
|
void EGL_LoadLibrary( void );
|
||||||
|
void * EGL_GetProcAddress( const char *name );
|
||||||
|
void EGL_Terminate( void );
|
||||||
|
qboolean EGL_ImportContext( void );
|
||||||
|
qboolean EGL_CreateContext( void );
|
||||||
|
qboolean EGL_UpdateSurface( void *window, qboolean dummy );
|
||||||
|
int EGL_GetAttribute( int attr, int *val );
|
||||||
|
size_t EGL_GenerateContextConfig( EGLint *attribs, size_t size );
|
||||||
|
size_t EGL_GenerateConfig( EGLint *attribs, size_t size );
|
||||||
|
int EGL_SetAttribute( int attr, int val );
|
||||||
|
|
||||||
|
#endif // EGLUTIL_H
|
||||||
@@ -19,6 +19,12 @@ GNU General Public License for more details.
|
|||||||
#include "platform/android/lib_android.h"
|
#include "platform/android/lib_android.h"
|
||||||
#include "platform/android/dlsym-weak.h" // Android < 5.0
|
#include "platform/android/dlsym-weak.h" // Android < 5.0
|
||||||
|
|
||||||
|
void *ANDROID_GetServerLibrary( void )
|
||||||
|
{
|
||||||
|
return svgame.hInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void *ANDROID_LoadLibrary( const char *dllname )
|
void *ANDROID_LoadLibrary( const char *dllname )
|
||||||
{
|
{
|
||||||
char path[MAX_SYSPATH];
|
char path[MAX_SYSPATH];
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ GNU General Public License for more details.
|
|||||||
#define Platform_POSIX_LoadLibrary( x ) ANDROID_LoadLibrary(( x ))
|
#define Platform_POSIX_LoadLibrary( x ) ANDROID_LoadLibrary(( x ))
|
||||||
#define Platform_POSIX_GetProcAddress( x, y ) ANDROID_GetProcAddress(( x ), ( y ))
|
#define Platform_POSIX_GetProcAddress( x, y ) ANDROID_GetProcAddress(( x ), ( y ))
|
||||||
|
|
||||||
|
void *ANDROID_GetServerLibrary( void );
|
||||||
void *ANDROID_LoadLibrary( const char *dllname );
|
void *ANDROID_LoadLibrary( const char *dllname );
|
||||||
void *ANDROID_GetProcAddress( void *hInstance, const char *name );
|
void *ANDROID_GetProcAddress( void *hInstance, const char *name );
|
||||||
|
|
||||||
|
|||||||
277
engine/platform/android/snd_opensles.c
Normal file
277
engine/platform/android/snd_opensles.c
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
/*
|
||||||
|
Copyright (C) 2015 SiPlus, Chasseur de bots
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; either version 2
|
||||||
|
of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "platform/platform.h"
|
||||||
|
#if XASH_SOUND == SOUND_OPENSLES
|
||||||
|
#include <SLES/OpenSLES.h>
|
||||||
|
#include "pthread.h"
|
||||||
|
#include "sound.h"
|
||||||
|
|
||||||
|
extern dma_t dma;
|
||||||
|
|
||||||
|
static SLObjectItf snddma_android_engine = NULL;
|
||||||
|
static SLObjectItf snddma_android_outputMix = NULL;
|
||||||
|
static SLObjectItf snddma_android_player = NULL;
|
||||||
|
static SLBufferQueueItf snddma_android_bufferQueue;
|
||||||
|
static SLPlayItf snddma_android_play;
|
||||||
|
|
||||||
|
static pthread_mutex_t snddma_android_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
static int snddma_android_size;
|
||||||
|
|
||||||
|
static const SLInterfaceID *pSL_IID_ENGINE;
|
||||||
|
static const SLInterfaceID *pSL_IID_BUFFERQUEUE;
|
||||||
|
static const SLInterfaceID *pSL_IID_PLAY;
|
||||||
|
static SLresult SLAPIENTRY (*pslCreateEngine)(
|
||||||
|
SLObjectItf *pEngine,
|
||||||
|
SLuint32 numOptions,
|
||||||
|
const SLEngineOption *pEngineOptions,
|
||||||
|
SLuint32 numInterfaces,
|
||||||
|
const SLInterfaceID *pInterfaceIds,
|
||||||
|
const SLboolean * pInterfaceRequired
|
||||||
|
);
|
||||||
|
|
||||||
|
void SNDDMA_Activate( qboolean active )
|
||||||
|
{
|
||||||
|
if( !dma.initialized )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( active )
|
||||||
|
{
|
||||||
|
memset( dma.buffer, 0, snddma_android_size * 2 );
|
||||||
|
(*snddma_android_bufferQueue)->Enqueue( snddma_android_bufferQueue, dma.buffer, snddma_android_size );
|
||||||
|
(*snddma_android_play)->SetPlayState( snddma_android_play, SL_PLAYSTATE_PLAYING );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*snddma_android_play)->SetPlayState( snddma_android_play, SL_PLAYSTATE_STOPPED );
|
||||||
|
(*snddma_android_bufferQueue)->Clear( snddma_android_bufferQueue );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SNDDMA_Android_Callback( SLBufferQueueItf bq, void *context )
|
||||||
|
{
|
||||||
|
uint8_t *buffer2;
|
||||||
|
|
||||||
|
pthread_mutex_lock( &snddma_android_mutex );
|
||||||
|
|
||||||
|
buffer2 = ( uint8_t * )dma.buffer + snddma_android_size;
|
||||||
|
(*bq)->Enqueue( bq, buffer2, snddma_android_size );
|
||||||
|
memcpy( buffer2, dma.buffer, snddma_android_size );
|
||||||
|
memset( dma.buffer, 0, snddma_android_size );
|
||||||
|
dma.samplepos += dma.samples;
|
||||||
|
|
||||||
|
pthread_mutex_unlock( &snddma_android_mutex );
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *SNDDMA_Android_Init( void )
|
||||||
|
{
|
||||||
|
SLresult result;
|
||||||
|
|
||||||
|
SLEngineItf engine;
|
||||||
|
|
||||||
|
int freq;
|
||||||
|
|
||||||
|
SLDataLocator_BufferQueue sourceLocator;
|
||||||
|
SLDataFormat_PCM sourceFormat;
|
||||||
|
SLDataSource source;
|
||||||
|
|
||||||
|
SLDataLocator_OutputMix sinkLocator;
|
||||||
|
SLDataSink sink;
|
||||||
|
|
||||||
|
SLInterfaceID interfaceID;
|
||||||
|
SLboolean interfaceRequired;
|
||||||
|
|
||||||
|
int samples;
|
||||||
|
void *handle = dlopen( "libOpenSLES.so", RTLD_LAZY );
|
||||||
|
|
||||||
|
if( !handle )
|
||||||
|
return "dlopen for libOpenSLES.so";
|
||||||
|
|
||||||
|
pslCreateEngine = dlsym( handle, "slCreateEngine" );
|
||||||
|
|
||||||
|
if( !pslCreateEngine )
|
||||||
|
return "resolve slCreateEngine";
|
||||||
|
|
||||||
|
pSL_IID_ENGINE = dlsym( handle, "SL_IID_ENGINE" );
|
||||||
|
|
||||||
|
if( !pSL_IID_ENGINE )
|
||||||
|
return "resolve SL_IID_ENGINE";
|
||||||
|
|
||||||
|
pSL_IID_PLAY = dlsym( handle, "SL_IID_PLAY" );
|
||||||
|
|
||||||
|
if( !pSL_IID_PLAY )
|
||||||
|
return "resolve SL_IID_PLAY";
|
||||||
|
|
||||||
|
pSL_IID_BUFFERQUEUE = dlsym( handle, "SL_IID_BUFFERQUEUE" );
|
||||||
|
|
||||||
|
if( !pSL_IID_BUFFERQUEUE )
|
||||||
|
return "resolve SL_IID_BUFFERQUEUE";
|
||||||
|
|
||||||
|
|
||||||
|
result = pslCreateEngine( &snddma_android_engine, 0, NULL, 0, NULL, NULL );
|
||||||
|
if( result != SL_RESULT_SUCCESS ) return "slCreateEngine";
|
||||||
|
result = (*snddma_android_engine)->Realize( snddma_android_engine, SL_BOOLEAN_FALSE );
|
||||||
|
if( result != SL_RESULT_SUCCESS ) return "engine->Realize";
|
||||||
|
result = (*snddma_android_engine)->GetInterface( snddma_android_engine, *pSL_IID_ENGINE, &engine );
|
||||||
|
if( result != SL_RESULT_SUCCESS ) return "engine->GetInterface(ENGINE)";
|
||||||
|
|
||||||
|
result = (*engine)->CreateOutputMix( engine, &snddma_android_outputMix, 0, NULL, NULL );
|
||||||
|
if( result != SL_RESULT_SUCCESS ) return "engine->CreateOutputMix";
|
||||||
|
result = (*snddma_android_outputMix)->Realize( snddma_android_outputMix, SL_BOOLEAN_FALSE );
|
||||||
|
if( result != SL_RESULT_SUCCESS ) return "outputMix->Realize";
|
||||||
|
|
||||||
|
freq = SOUND_DMA_SPEED;
|
||||||
|
sourceLocator.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
|
||||||
|
sourceLocator.numBuffers = 2;
|
||||||
|
sourceFormat.formatType = SL_DATAFORMAT_PCM;
|
||||||
|
sourceFormat.numChannels = 2; // always stereo, because engine supports only stereo
|
||||||
|
sourceFormat.samplesPerSec = freq * 1000;
|
||||||
|
sourceFormat.bitsPerSample = 16; // always 16 bit audio
|
||||||
|
sourceFormat.containerSize = sourceFormat.bitsPerSample;
|
||||||
|
sourceFormat.channelMask = SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT;
|
||||||
|
sourceFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
||||||
|
source.pLocator = &sourceLocator;
|
||||||
|
source.pFormat = &sourceFormat;
|
||||||
|
|
||||||
|
sinkLocator.locatorType = SL_DATALOCATOR_OUTPUTMIX;
|
||||||
|
sinkLocator.outputMix = snddma_android_outputMix;
|
||||||
|
sink.pLocator = &sinkLocator;
|
||||||
|
sink.pFormat = NULL;
|
||||||
|
|
||||||
|
interfaceID = *pSL_IID_BUFFERQUEUE;
|
||||||
|
interfaceRequired = SL_BOOLEAN_TRUE;
|
||||||
|
|
||||||
|
result = (*engine)->CreateAudioPlayer( engine, &snddma_android_player, &source, &sink, 1, &interfaceID, &interfaceRequired );
|
||||||
|
if( result != SL_RESULT_SUCCESS ) return "engine->CreateAudioPlayer";
|
||||||
|
result = (*snddma_android_player)->Realize( snddma_android_player, SL_BOOLEAN_FALSE );
|
||||||
|
if( result != SL_RESULT_SUCCESS ) return "player->Realize";
|
||||||
|
result = (*snddma_android_player)->GetInterface( snddma_android_player, *pSL_IID_BUFFERQUEUE, &snddma_android_bufferQueue );
|
||||||
|
if( result != SL_RESULT_SUCCESS ) return "player->GetInterface(BUFFERQUEUE)";
|
||||||
|
result = (*snddma_android_player)->GetInterface( snddma_android_player, *pSL_IID_PLAY, &snddma_android_play );
|
||||||
|
if( result != SL_RESULT_SUCCESS ) return "player->GetInterface(PLAY)";
|
||||||
|
result = (*snddma_android_bufferQueue)->RegisterCallback( snddma_android_bufferQueue, SNDDMA_Android_Callback, NULL );
|
||||||
|
if( result != SL_RESULT_SUCCESS ) return "bufferQueue->RegisterCallback";
|
||||||
|
|
||||||
|
samples = s_samplecount.value;
|
||||||
|
if( !samples )
|
||||||
|
samples = 4096;
|
||||||
|
|
||||||
|
dma.format.channels = sourceFormat.numChannels;
|
||||||
|
dma.samples = samples * sourceFormat.numChannels;
|
||||||
|
dma.format.speed = freq;
|
||||||
|
snddma_android_size = dma.samples * ( sourceFormat.bitsPerSample >> 3 );
|
||||||
|
dma.buffer = Z_Malloc( snddma_android_size * 2 );
|
||||||
|
dma.samplepos = 0;
|
||||||
|
// dma.sampleframes = dma.samples / dma.format.channels;
|
||||||
|
dma.format.width = 2;
|
||||||
|
if( !dma.buffer ) return "malloc";
|
||||||
|
|
||||||
|
//snddma_android_mutex = trap_Mutex_Create();
|
||||||
|
|
||||||
|
dma.initialized = true;
|
||||||
|
|
||||||
|
SNDDMA_Activate( true );
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
qboolean SNDDMA_Init( void )
|
||||||
|
{
|
||||||
|
const char *initError;
|
||||||
|
|
||||||
|
Msg( "OpenSL ES audio device initializing...\n" );
|
||||||
|
|
||||||
|
initError = SNDDMA_Android_Init();
|
||||||
|
if( initError )
|
||||||
|
{
|
||||||
|
Msg( S_ERROR "SNDDMA_Init: %s failed.\n", initError );
|
||||||
|
SNDDMA_Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg( "OpenSL ES audio initialized.\n" );
|
||||||
|
dma.backendName = "OpenSL ES";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SNDDMA_Shutdown( void )
|
||||||
|
{
|
||||||
|
Msg( "Closing OpenSL ES audio device...\n" );
|
||||||
|
|
||||||
|
if( snddma_android_player )
|
||||||
|
{
|
||||||
|
(*snddma_android_player)->Destroy( snddma_android_player );
|
||||||
|
snddma_android_player = NULL;
|
||||||
|
}
|
||||||
|
if( snddma_android_outputMix )
|
||||||
|
{
|
||||||
|
(*snddma_android_outputMix)->Destroy( snddma_android_outputMix );
|
||||||
|
snddma_android_outputMix = NULL;
|
||||||
|
}
|
||||||
|
if( snddma_android_engine )
|
||||||
|
{
|
||||||
|
(*snddma_android_engine)->Destroy( snddma_android_engine );
|
||||||
|
snddma_android_engine = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( dma.buffer )
|
||||||
|
{
|
||||||
|
Z_Free( dma.buffer );
|
||||||
|
dma.buffer = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if( snddma_android_mutex )
|
||||||
|
//trap_Mutex_Destroy( &snddma_android_mutex );
|
||||||
|
|
||||||
|
Msg( "OpenSL ES audio device shut down.\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SNDDMA_Submit( void )
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock( &snddma_android_mutex );
|
||||||
|
}
|
||||||
|
|
||||||
|
void SNDDMA_BeginPainting( void )
|
||||||
|
{
|
||||||
|
pthread_mutex_lock( &snddma_android_mutex );
|
||||||
|
}
|
||||||
|
|
||||||
|
qboolean VoiceCapture_Init( void )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
qboolean VoiceCapture_Activate( qboolean activate )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
qboolean VoiceCapture_Lock( qboolean lock )
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VoiceCapture_Shutdown( void )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
513
engine/platform/android/vid_android.c
Normal file
513
engine/platform/android/vid_android.c
Normal file
@@ -0,0 +1,513 @@
|
|||||||
|
#include "platform/platform.h"
|
||||||
|
#if !XASH_SDL
|
||||||
|
#include "input.h"
|
||||||
|
#include "client.h"
|
||||||
|
#include "filesystem.h"
|
||||||
|
#include "platform/android/android_priv.h"
|
||||||
|
#include "vid_common.h"
|
||||||
|
#include <android/native_window.h>
|
||||||
|
#include <android/native_window_jni.h>
|
||||||
|
#include "eglutil.h"
|
||||||
|
|
||||||
|
|
||||||
|
static struct vid_android_s
|
||||||
|
{
|
||||||
|
qboolean has_context;
|
||||||
|
ANativeWindow* window;
|
||||||
|
qboolean nativeegl;
|
||||||
|
} vid_android;
|
||||||
|
|
||||||
|
static struct nw_s
|
||||||
|
{
|
||||||
|
void (*release)(ANativeWindow* window);
|
||||||
|
int32_t (*getWidth)(ANativeWindow* window);
|
||||||
|
int32_t (*getHeight)(ANativeWindow* window);
|
||||||
|
int32_t (*getFormat)(ANativeWindow* window);
|
||||||
|
int32_t (*setBuffersGeometry)(ANativeWindow* window, int32_t width, int32_t height, int32_t format);
|
||||||
|
int32_t (*lock)(ANativeWindow* window, ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
|
||||||
|
int32_t (*unlockAndPost)(ANativeWindow* window);
|
||||||
|
ANativeWindow* (*fromSurface)(JNIEnv* env, jobject surface);
|
||||||
|
} nw;
|
||||||
|
|
||||||
|
#define NW_FF(x) {"ANativeWindow_"#x, (void*)&nw.x}
|
||||||
|
|
||||||
|
|
||||||
|
static dllfunc_t android_funcs[] =
|
||||||
|
{
|
||||||
|
NW_FF(release),
|
||||||
|
NW_FF(getWidth),
|
||||||
|
NW_FF(getHeight),
|
||||||
|
NW_FF(getFormat),
|
||||||
|
NW_FF(setBuffersGeometry),
|
||||||
|
NW_FF(lock),
|
||||||
|
NW_FF(unlockAndPost),
|
||||||
|
NW_FF(fromSurface),
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
#undef NW_FF
|
||||||
|
static dll_info_t android_info = { "libandroid.so", android_funcs, false };
|
||||||
|
|
||||||
|
/*
|
||||||
|
========================
|
||||||
|
Android_SwapInterval
|
||||||
|
========================
|
||||||
|
*/
|
||||||
|
static void Android_SwapInterval( int interval )
|
||||||
|
{
|
||||||
|
if( vid_android.nativeegl && eglstate.valid )
|
||||||
|
egl.SwapInterval( eglstate.dpy, interval );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
========================
|
||||||
|
Android_SetTitle
|
||||||
|
========================
|
||||||
|
*/
|
||||||
|
static void Android_SetTitle( const char *title )
|
||||||
|
{
|
||||||
|
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.setTitle, (*jni.env)->NewStringUTF( jni.env, title ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
========================
|
||||||
|
Android_SetIcon
|
||||||
|
========================
|
||||||
|
*/
|
||||||
|
static void Android_SetIcon( const char *path )
|
||||||
|
{
|
||||||
|
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.setIcon, (*jni.env)->NewStringUTF( jni.env, path ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
========================
|
||||||
|
Android_GetScreenRes
|
||||||
|
|
||||||
|
Resolution got from last resize event
|
||||||
|
========================
|
||||||
|
*/
|
||||||
|
static void Android_GetScreenRes( int *width, int *height )
|
||||||
|
{
|
||||||
|
*width = jni.width;
|
||||||
|
*height = jni.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
========================
|
||||||
|
Android_SwapBuffers
|
||||||
|
|
||||||
|
Update screen. Use native EGL if possible
|
||||||
|
========================
|
||||||
|
*/
|
||||||
|
void GL_SwapBuffers( void )
|
||||||
|
{
|
||||||
|
if( vid_android.nativeegl && eglstate.valid )
|
||||||
|
{
|
||||||
|
egl.SwapBuffers( eglstate.dpy, eglstate.surface );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.swapBuffers );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
========================
|
||||||
|
Android_UpdateSurface
|
||||||
|
|
||||||
|
Check if we may use native EGL without jni calls
|
||||||
|
========================
|
||||||
|
*/
|
||||||
|
void Android_UpdateSurface( surfacestate_t state )
|
||||||
|
{
|
||||||
|
qboolean active = state == surface_active;
|
||||||
|
vid_android.nativeegl = false;
|
||||||
|
|
||||||
|
if( glw_state.software || ( eglstate.valid && !eglstate.imported ))
|
||||||
|
{
|
||||||
|
if( vid_android.window )
|
||||||
|
{
|
||||||
|
EGL_UpdateSurface( NULL, false );
|
||||||
|
nw.release( vid_android.window );
|
||||||
|
vid_android.window = NULL;
|
||||||
|
}
|
||||||
|
if( state == surface_dummy && glw_state.software )
|
||||||
|
return;
|
||||||
|
// first, ask EGL for surfaceless mode
|
||||||
|
if( state == surface_dummy && EGL_UpdateSurface( NULL, true ))
|
||||||
|
{
|
||||||
|
vid_android.nativeegl = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( state != surface_pause )
|
||||||
|
{
|
||||||
|
EGLint format = WINDOW_FORMAT_RGB_565;
|
||||||
|
jobject surf;
|
||||||
|
if( vid_android.window )
|
||||||
|
nw.release( vid_android.window );
|
||||||
|
surf = (*jni.env)->CallStaticObjectMethod( jni.env, jni.bindcls, jni.getSurface, state );
|
||||||
|
Con_DPrintf("Surface handle %p\n", surf);
|
||||||
|
if( surf )
|
||||||
|
{
|
||||||
|
vid_android.window = nw.fromSurface(jni.env, surf);
|
||||||
|
Con_DPrintf("NativeWindow %p\n", vid_android.window);
|
||||||
|
|
||||||
|
if( eglstate.valid )
|
||||||
|
egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_NATIVE_VISUAL_ID, &format );
|
||||||
|
|
||||||
|
nw.setBuffersGeometry(vid_android.window, 0, 0, format );
|
||||||
|
|
||||||
|
(*jni.env)->DeleteLocalRef( jni.env, surf );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( eglstate.valid && !eglstate.imported )
|
||||||
|
{
|
||||||
|
EGL_UpdateSurface( vid_android.window, state == surface_dummy );
|
||||||
|
vid_android.nativeegl = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !vid_android.has_context )
|
||||||
|
return;
|
||||||
|
|
||||||
|
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.toggleEGL, (int)state );
|
||||||
|
host.status = HOST_FRAME; // active ? HOST_FRAME : HOST_SLEEP;
|
||||||
|
|
||||||
|
// todo: check opengl context here and set HOST_SLEEP if not
|
||||||
|
|
||||||
|
if( !Sys_CheckParm("-nativeegl") || !active )
|
||||||
|
return; // enabled by user
|
||||||
|
|
||||||
|
vid_android.nativeegl = EGL_ImportContext();
|
||||||
|
if( vid_android.nativeegl )
|
||||||
|
Con_DPrintf( "nativeEGL success\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
========================
|
||||||
|
Android_GetGLAttribute
|
||||||
|
========================
|
||||||
|
*/
|
||||||
|
static int Android_GetGLAttribute( int eglAttr )
|
||||||
|
{
|
||||||
|
int ret = (*jni.env)->CallStaticIntMethod( jni.env, jni.bindcls, jni.getGLAttribute, eglAttr );
|
||||||
|
// Con_Reportf( "Android_GetGLAttribute( %i ) => %i\n", eglAttr, ret );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
qboolean R_Init_Video( const int type )
|
||||||
|
{
|
||||||
|
qboolean retval;
|
||||||
|
char buf[10]; // Sys_GetParmFromCmdLine
|
||||||
|
|
||||||
|
if( FS_FileExists( GI->iconpath, true ) )
|
||||||
|
{
|
||||||
|
// TODO: convert icon to some android-readable format and place
|
||||||
|
Android_SetIcon( FS_GetDiskPath( GI->iconpath, false ));
|
||||||
|
}
|
||||||
|
|
||||||
|
Android_SetTitle( GI->title );
|
||||||
|
|
||||||
|
VID_StartupGamma();
|
||||||
|
|
||||||
|
Sys_LoadLibrary( &android_info );
|
||||||
|
|
||||||
|
switch( type )
|
||||||
|
{
|
||||||
|
case REF_SOFTWARE:
|
||||||
|
glw_state.software = true;
|
||||||
|
break;
|
||||||
|
case REF_GL:
|
||||||
|
glw_state.software = false;
|
||||||
|
EGL_LoadLibrary();
|
||||||
|
|
||||||
|
if( !glw_state.safe && Sys_GetParmFromCmdLine( "-safegl", buf ) )
|
||||||
|
glw_state.safe = bound( SAFE_NO, Q_atoi( buf ), SAFE_DONTCARE );
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Host_Error( "Can't initialize unknown context type %d!\n", type );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( glw_state.software )
|
||||||
|
{
|
||||||
|
uint arg;
|
||||||
|
|
||||||
|
if( !nw.release )
|
||||||
|
{
|
||||||
|
Con_Reportf( S_ERROR "Native software mode unavailiable\n" );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Android_UpdateSurface( surface_active );
|
||||||
|
if( !SW_CreateBuffer( jni.width, jni.height, &arg, &arg, &arg, &arg, &arg ) )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while( !(retval = VID_SetMode()) )
|
||||||
|
{
|
||||||
|
glw_state.safe++;
|
||||||
|
if( glw_state.safe > SAFE_LAST )
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch( type )
|
||||||
|
{
|
||||||
|
case REF_GL:
|
||||||
|
// refdll also can check extensions
|
||||||
|
ref.dllFuncs.GL_InitExtensions();
|
||||||
|
break;
|
||||||
|
case REF_SOFTWARE:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
host.renderinfo_changed = false;
|
||||||
|
|
||||||
|
host.status = HOST_FRAME; // where it should we done? We have broken host.status on all non-SDL platforms!
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void R_Free_Video( void )
|
||||||
|
{
|
||||||
|
// (*jni.env)->CallStaticBooleanMethod( jni.env, jni.bindcls, jni.deleteGLContext );
|
||||||
|
|
||||||
|
// VID_DestroyWindow ();
|
||||||
|
|
||||||
|
// R_FreeVideoModes();
|
||||||
|
Sys_FreeLibrary( &android_info );
|
||||||
|
vid_android.has_context = false;
|
||||||
|
ref.dllFuncs.GL_ClearExtensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Android_GetWindow( void )
|
||||||
|
{
|
||||||
|
EGLint format;
|
||||||
|
|
||||||
|
if( !vid_android.window )
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_NATIVE_VISUAL_ID, &format) )
|
||||||
|
{
|
||||||
|
Con_Reportf( S_ERROR "eglGetConfigAttrib(VISUAL_ID) returned error: 0x%x\n", egl.GetError() );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( nw.setBuffersGeometry( vid_android.window, 0, 0, format ) )
|
||||||
|
{
|
||||||
|
Con_Reportf( S_ERROR "ANativeWindow_setBuffersGeometry returned error\n" );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vid_android.window;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
qboolean VID_SetMode( void )
|
||||||
|
{
|
||||||
|
EGLint format;
|
||||||
|
jintArray attribs, contextAttribs;
|
||||||
|
static EGLint nAttribs[32+1], nContextAttribs[32+1];
|
||||||
|
const size_t attribsSize = ARRAYSIZE( nAttribs );
|
||||||
|
size_t s1, s2;
|
||||||
|
|
||||||
|
// create context on egl side by user request
|
||||||
|
if( !vid_android.has_context && Sys_CheckParm("-egl") )
|
||||||
|
{
|
||||||
|
vid_android.has_context = vid_android.nativeegl = EGL_CreateContext();
|
||||||
|
|
||||||
|
if( vid_android.has_context )
|
||||||
|
Android_UpdateSurface( surface_active );
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( vid_android.has_context || glw_state.software )
|
||||||
|
{
|
||||||
|
R_ChangeDisplaySettings( 0, 0, WINDOW_MODE_WINDOWED ); // width and height are ignored anyway
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
s1 = EGL_GenerateConfig(nAttribs, attribsSize);
|
||||||
|
s2 = EGL_GenerateContextConfig(nContextAttribs, attribsSize);
|
||||||
|
|
||||||
|
attribs = (*jni.env)->NewIntArray( jni.env, s1 );
|
||||||
|
contextAttribs = (*jni.env)->NewIntArray( jni.env, s2 );
|
||||||
|
|
||||||
|
(*jni.env)->SetIntArrayRegion( jni.env, attribs, 0, s1, nAttribs );
|
||||||
|
(*jni.env)->SetIntArrayRegion( jni.env, contextAttribs, 0, s2, nContextAttribs );
|
||||||
|
|
||||||
|
R_ChangeDisplaySettings( 0, 0, WINDOW_MODE_WINDOWED ); // width and height are ignored anyway
|
||||||
|
|
||||||
|
|
||||||
|
if( (*jni.env)->CallStaticBooleanMethod( jni.env, jni.bindcls, jni.createGLContext, attribs, contextAttribs ) )
|
||||||
|
{
|
||||||
|
vid_android.has_context = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
rserr_t R_ChangeDisplaySettings( int width, int height, window_mode_t window_mode )
|
||||||
|
{
|
||||||
|
int render_w, render_h;
|
||||||
|
|
||||||
|
Android_GetScreenRes(&width, &height);
|
||||||
|
|
||||||
|
render_w = width;
|
||||||
|
render_h = height;
|
||||||
|
|
||||||
|
Con_Reportf( "R_ChangeDisplaySettings: forced resolution to %dx%d)\n", width, height);
|
||||||
|
|
||||||
|
VID_SetDisplayTransform( &render_w, &render_h );
|
||||||
|
|
||||||
|
R_SaveVideoMode( width, height, render_w, render_h, true );
|
||||||
|
|
||||||
|
refState.wideScreen = true; // V_AdjustFov will check for widescreen
|
||||||
|
|
||||||
|
return rserr_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GL_SetAttribute( int attr, int val )
|
||||||
|
{
|
||||||
|
return EGL_SetAttribute( attr, val );
|
||||||
|
}
|
||||||
|
|
||||||
|
int GL_GetAttribute( int attr, int *val )
|
||||||
|
{
|
||||||
|
EGLBoolean ret;
|
||||||
|
|
||||||
|
if( eglstate.valid )
|
||||||
|
return EGL_GetAttribute( attr, val );
|
||||||
|
|
||||||
|
if( attr < 0 || attr >= REF_GL_ATTRIBUTES_COUNT )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if( !val )
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
switch( attr )
|
||||||
|
{
|
||||||
|
case REF_GL_RED_SIZE:
|
||||||
|
*val = Android_GetGLAttribute( EGL_RED_SIZE );
|
||||||
|
return 0;
|
||||||
|
case REF_GL_GREEN_SIZE:
|
||||||
|
*val = Android_GetGLAttribute( EGL_GREEN_SIZE );
|
||||||
|
return 0;
|
||||||
|
case REF_GL_BLUE_SIZE:
|
||||||
|
*val = Android_GetGLAttribute( EGL_BLUE_SIZE );
|
||||||
|
return 0;
|
||||||
|
case REF_GL_ALPHA_SIZE:
|
||||||
|
*val = Android_GetGLAttribute( EGL_ALPHA_SIZE );
|
||||||
|
return 0;
|
||||||
|
case REF_GL_DEPTH_SIZE:
|
||||||
|
*val = Android_GetGLAttribute( EGL_DEPTH_SIZE );
|
||||||
|
return 0;
|
||||||
|
case REF_GL_STENCIL_SIZE:
|
||||||
|
*val = Android_GetGLAttribute( EGL_STENCIL_SIZE );
|
||||||
|
return 0;
|
||||||
|
case REF_GL_MULTISAMPLESAMPLES:
|
||||||
|
*val = Android_GetGLAttribute( EGL_SAMPLES );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int R_MaxVideoModes( void )
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vidmode_t* R_GetVideoMode( int num )
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* GL_GetProcAddress( const char *name ) // RenderAPI requirement
|
||||||
|
{
|
||||||
|
return EGL_GetProcAddress( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
void GL_UpdateSwapInterval( void )
|
||||||
|
{
|
||||||
|
// disable VSync while level is loading
|
||||||
|
if( cls.state < ca_active )
|
||||||
|
{
|
||||||
|
Android_SwapInterval( 0 );
|
||||||
|
SetBits( gl_vsync.flags, FCVAR_CHANGED );
|
||||||
|
}
|
||||||
|
else if( FBitSet( gl_vsync.flags, FCVAR_CHANGED ))
|
||||||
|
{
|
||||||
|
ClearBits( gl_vsync.flags, FCVAR_CHANGED );
|
||||||
|
Android_SwapInterval( gl_vsync.value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *SW_LockBuffer( void )
|
||||||
|
{
|
||||||
|
ANativeWindow_Buffer buffer;
|
||||||
|
if( !nw.lock || !vid_android.window )
|
||||||
|
return NULL;
|
||||||
|
if( nw.lock( vid_android.window, &buffer, NULL ) )
|
||||||
|
return NULL;
|
||||||
|
if( buffer.width < refState.width || buffer.height < refState.height )
|
||||||
|
return NULL;
|
||||||
|
return buffer.bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SW_UnlockBuffer( void )
|
||||||
|
{
|
||||||
|
if( nw.unlockAndPost )
|
||||||
|
nw.unlockAndPost( vid_android.window );
|
||||||
|
}
|
||||||
|
|
||||||
|
qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *r, uint *g, uint *b )
|
||||||
|
{
|
||||||
|
ANativeWindow_Buffer buffer;
|
||||||
|
int lock;
|
||||||
|
if( !nw.lock || !vid_android.window )
|
||||||
|
return false;
|
||||||
|
nw.unlockAndPost( vid_android.window );
|
||||||
|
|
||||||
|
if( ( lock = nw.lock( vid_android.window, &buffer, NULL ) ) )
|
||||||
|
{
|
||||||
|
Con_Printf( "SW_CreateBuffer: lock %d\n", lock );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
nw.unlockAndPost( vid_android.window );
|
||||||
|
Con_Printf( "SW_CreateBuffer: buffer %d %d %x %d %p\n", buffer.width, buffer.height, buffer.format, buffer.stride, buffer.bits );
|
||||||
|
if( width > buffer.width || height > buffer.height )
|
||||||
|
{
|
||||||
|
// resize event missed? do not resize now, wait for REAL resize event or when java code will be fixed
|
||||||
|
Con_Printf( S_ERROR "SW_CreateBuffer: buffer too small, need %dx%d, got %dx%d, java part probably sucks\n", width, height, buffer.width, buffer.height );
|
||||||
|
#if 0
|
||||||
|
if( jni.width < buffer.width )
|
||||||
|
jni.width = buffer.width;
|
||||||
|
if( jni.height < buffer.height )
|
||||||
|
jni.width = buffer.height;
|
||||||
|
VID_SetMode();
|
||||||
|
Android_UpdateSurface( true );
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if( buffer.format != WINDOW_FORMAT_RGB_565 )
|
||||||
|
{
|
||||||
|
Con_Printf( "SW_CreateBuffer: wrong format %d\n", buffer.format );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Con_Printf( "SW_CreateBuffer: ok\n" );
|
||||||
|
*stride = buffer.stride;
|
||||||
|
|
||||||
|
*bpp = 2;
|
||||||
|
*r = (((1 << 5) - 1) << (5+6));
|
||||||
|
*g = (((1 << 6) - 1) << (5));
|
||||||
|
*b = (((1 << 5) - 1) << (0));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -175,13 +175,11 @@ void Evdev_Autodetect_f( void )
|
|||||||
if( evdev.devices >= MAX_EVDEV_DEVICES )
|
if( evdev.devices >= MAX_EVDEV_DEVICES )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Q_snprintf( path, sizeof( path ), "/dev/input/%s", entry->d_name );
|
Q_snprintf( path, MAX_STRING, "/dev/input/%s", entry->d_name );
|
||||||
|
|
||||||
for( i = 0; i < evdev.devices; i++ )
|
for( i = 0; i < evdev.devices; i++ )
|
||||||
{
|
if( !Q_strncmp( evdev.paths[i], path, MAX_STRING ) )
|
||||||
if( !Q_strncmp( evdev.paths[i], path, sizeof( evdev.paths[i] ))
|
|
||||||
goto next;
|
goto next;
|
||||||
}
|
|
||||||
|
|
||||||
if( Q_strncmp( entry->d_name, "event", 5 ) )
|
if( Q_strncmp( entry->d_name, "event", 5 ) )
|
||||||
continue;
|
continue;
|
||||||
@@ -222,7 +220,7 @@ void Evdev_Autodetect_f( void )
|
|||||||
}
|
}
|
||||||
goto close;
|
goto close;
|
||||||
open:
|
open:
|
||||||
Q_strncpy( evdev.paths[evdev.devices], path, sizeof( evdev.paths[0] ));
|
Q_strncpy( evdev.paths[evdev.devices], path, MAX_STRING );
|
||||||
evdev.fds[evdev.devices++] = fd;
|
evdev.fds[evdev.devices++] = fd;
|
||||||
Con_Printf( "Opened device %s\n", path );
|
Con_Printf( "Opened device %s\n", path );
|
||||||
#if XASH_INPUT == INPUT_EVDEV
|
#if XASH_INPUT == INPUT_EVDEV
|
||||||
@@ -262,7 +260,7 @@ void Evdev_OpenDevice ( const char *path )
|
|||||||
|
|
||||||
for( i = 0; i < evdev.devices; i++ )
|
for( i = 0; i < evdev.devices; i++ )
|
||||||
{
|
{
|
||||||
if( !Q_strncmp( evdev.paths[i], path, sizeof( evdev.paths[i] )))
|
if( !Q_strncmp( evdev.paths[i], path, MAX_STRING ) )
|
||||||
{
|
{
|
||||||
Con_Printf( "device %s already open!\n", path );
|
Con_Printf( "device %s already open!\n", path );
|
||||||
return;
|
return;
|
||||||
@@ -277,7 +275,7 @@ void Evdev_OpenDevice ( const char *path )
|
|||||||
}
|
}
|
||||||
Con_Printf( "Input device #%d: %s opened sucessfully\n", evdev.devices, path );
|
Con_Printf( "Input device #%d: %s opened sucessfully\n", evdev.devices, path );
|
||||||
evdev.fds[evdev.devices] = ret;
|
evdev.fds[evdev.devices] = ret;
|
||||||
Q_strncpy( evdev.paths[evdev.devices++], path, sizeof( evdev.paths[0] ));
|
Q_strncpy( evdev.paths[evdev.devices++], path, MAX_STRING );
|
||||||
|
|
||||||
#if XASH_INPUT == INPUT_EVDEV
|
#if XASH_INPUT == INPUT_EVDEV
|
||||||
if( Sys_CheckParm( "-grab" ) )
|
if( Sys_CheckParm( "-grab" ) )
|
||||||
@@ -311,7 +309,7 @@ void Evdev_CloseDevice_f ( void )
|
|||||||
if( Q_isdigit( arg ) )
|
if( Q_isdigit( arg ) )
|
||||||
i = Q_atoi( arg );
|
i = Q_atoi( arg );
|
||||||
else for( i = 0; i < evdev.devices; i++ )
|
else for( i = 0; i < evdev.devices; i++ )
|
||||||
if( !Q_strncmp( evdev.paths[i], arg, sizeof( evdev.paths[i] )))
|
if( !Q_strncmp( evdev.paths[i], arg, MAX_STRING ) )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if( i >= evdev.devices )
|
if( i >= evdev.devices )
|
||||||
@@ -326,7 +324,7 @@ void Evdev_CloseDevice_f ( void )
|
|||||||
|
|
||||||
for( ; i < evdev.devices; i++ )
|
for( ; i < evdev.devices; i++ )
|
||||||
{
|
{
|
||||||
Q_strncpy( evdev.paths[i], evdev.paths[i+1], sizeof( evdev.paths[i] ));
|
Q_strncpy( evdev.paths[i], evdev.paths[i+1], MAX_STRING );
|
||||||
evdev.fds[i] = evdev.fds[i+1];
|
evdev.fds[i] = evdev.fds[i+1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ static pid_t gettid( void )
|
|||||||
static void *g_hsystemd;
|
static void *g_hsystemd;
|
||||||
static int (*g_pfn_sd_notify)( int unset_environment, const char *state );
|
static int (*g_pfn_sd_notify)( int unset_environment, const char *state );
|
||||||
|
|
||||||
qboolean Platform_DebuggerPresent( void )
|
qboolean Sys_DebuggerPresent( void )
|
||||||
{
|
{
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
ssize_t num_read;
|
ssize_t num_read;
|
||||||
@@ -111,11 +111,6 @@ void Linux_Init( void )
|
|||||||
if( !Host_IsDedicated( ))
|
if( !Host_IsDedicated( ))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// manpage says sd_notify will send messages to socket in NOTIFY_SOCKET
|
|
||||||
// environment variable. Check if it's available.
|
|
||||||
if( getenv( "NOTIFY_SOCKET" ) == NULL )
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(( g_hsystemd = dlopen( "libsystemd.so.0", RTLD_LAZY )) == NULL )
|
if(( g_hsystemd = dlopen( "libsystemd.so.0", RTLD_LAZY )) == NULL )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ double Platform_DoubleTime( void );
|
|||||||
void Platform_Sleep( int msec );
|
void Platform_Sleep( int msec );
|
||||||
void Platform_ShellExecute( const char *path, const char *parms );
|
void Platform_ShellExecute( const char *path, const char *parms );
|
||||||
void Platform_MessageBox( const char *title, const char *message, qboolean parentMainWindow );
|
void Platform_MessageBox( const char *title, const char *message, qboolean parentMainWindow );
|
||||||
|
qboolean Sys_DebuggerPresent( void ); // optional, see Sys_DebugBreak
|
||||||
void Platform_SetStatus( const char *status );
|
void Platform_SetStatus( const char *status );
|
||||||
qboolean Platform_DebuggerPresent( void );
|
|
||||||
|
|
||||||
// legacy iOS port functions
|
// legacy iOS port functions
|
||||||
#if TARGET_OS_IOS
|
#if TARGET_OS_IOS
|
||||||
@@ -139,15 +139,8 @@ static inline void Platform_Shutdown( void )
|
|||||||
|
|
||||||
#if XASH_SDL
|
#if XASH_SDL
|
||||||
SDLash_Shutdown( );
|
SDLash_Shutdown( );
|
||||||
#endif
|
#elif XASH_ANDROID
|
||||||
}
|
Android_Shutdown();
|
||||||
|
|
||||||
static inline qboolean Sys_DebuggerPresent( void )
|
|
||||||
{
|
|
||||||
#if XASH_LINUX || XASH_WIN32
|
|
||||||
return Platform_DebuggerPresent();
|
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -148,6 +148,7 @@ static void SDLash_KeyEvent( SDL_KeyboardEvent key )
|
|||||||
#else
|
#else
|
||||||
int keynum = key.keysym.sym;
|
int keynum = key.keysym.sym;
|
||||||
#endif
|
#endif
|
||||||
|
qboolean numLock = FBitSet( SDL_GetModState(), KMOD_NUM );
|
||||||
|
|
||||||
#if XASH_ANDROID
|
#if XASH_ANDROID
|
||||||
if( keynum == SDL_SCANCODE_VOLUMEUP || keynum == SDL_SCANCODE_VOLUMEDOWN )
|
if( keynum == SDL_SCANCODE_VOLUMEUP || keynum == SDL_SCANCODE_VOLUMEDOWN )
|
||||||
@@ -156,39 +157,32 @@ static void SDLash_KeyEvent( SDL_KeyboardEvent key )
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if( SDL_IsTextInputActive( ))
|
if( SDL_IsTextInputActive() && down && cls.key_dest != key_game )
|
||||||
{
|
{
|
||||||
// this is how engine understands ctrl+c, ctrl+v and other hotkeys
|
if( FBitSet( SDL_GetModState(), KMOD_CTRL ))
|
||||||
if( down && cls.key_dest != key_game )
|
|
||||||
{
|
{
|
||||||
if( FBitSet( SDL_GetModState(), KMOD_CTRL ))
|
if( keynum >= SDL_SCANCODE_A && keynum <= SDL_SCANCODE_Z )
|
||||||
{
|
{
|
||||||
if( keynum >= SDL_SCANCODE_A && keynum <= SDL_SCANCODE_Z )
|
keynum = keynum - SDL_SCANCODE_A + 1;
|
||||||
{
|
CL_CharEvent( keynum );
|
||||||
keynum = keynum - SDL_SCANCODE_A + 1;
|
|
||||||
CL_CharEvent( keynum );
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
|
#if !SDL_VERSION_ATLEAST( 2, 0, 0 )
|
||||||
// ignore printable keys, they are coming through SDL_TEXTINPUT
|
|
||||||
if(( keynum >= SDL_SCANCODE_A && keynum <= SDL_SCANCODE_Z )
|
|
||||||
|| ( keynum >= SDL_SCANCODE_1 && keynum <= SDL_SCANCODE_0 )
|
|
||||||
|| ( keynum >= SDL_SCANCODE_KP_1 && keynum <= SDL_SCANCODE_KP_0 ))
|
|
||||||
return;
|
|
||||||
#else
|
|
||||||
if( keynum >= SDLK_KP0 && keynum <= SDLK_KP9 )
|
if( keynum >= SDLK_KP0 && keynum <= SDLK_KP9 )
|
||||||
keynum -= SDLK_KP0 + '0';
|
keynum -= SDLK_KP0 + '0';
|
||||||
|
|
||||||
if( isprint( keynum ))
|
if( isprint( keynum ) )
|
||||||
{
|
{
|
||||||
if( FBitSet( SDL_GetModState(), KMOD_SHIFT ))
|
if( FBitSet( SDL_GetModState(), KMOD_SHIFT ))
|
||||||
|
{
|
||||||
keynum = Key_ToUpper( keynum );
|
keynum = Key_ToUpper( keynum );
|
||||||
|
}
|
||||||
|
|
||||||
CL_CharEvent( keynum );
|
CL_CharEvent( keynum );
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -204,8 +198,6 @@ static void SDLash_KeyEvent( SDL_KeyboardEvent key )
|
|||||||
else DECLARE_KEY_RANGE( SDL_SCANCODE_F1, SDL_SCANCODE_F12, K_F1 )
|
else DECLARE_KEY_RANGE( SDL_SCANCODE_F1, SDL_SCANCODE_F12, K_F1 )
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qboolean numLock = FBitSet( SDL_GetModState(), KMOD_NUM );
|
|
||||||
|
|
||||||
switch( keynum )
|
switch( keynum )
|
||||||
{
|
{
|
||||||
case SDL_SCANCODE_GRAVE: keynum = '`'; break;
|
case SDL_SCANCODE_GRAVE: keynum = '`'; break;
|
||||||
@@ -357,17 +349,16 @@ SDLash_InputEvent
|
|||||||
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
|
#if SDL_VERSION_ATLEAST( 2, 0, 0 )
|
||||||
static void SDLash_InputEvent( SDL_TextInputEvent input )
|
static void SDLash_InputEvent( SDL_TextInputEvent input )
|
||||||
{
|
{
|
||||||
const char *text;
|
char *text;
|
||||||
|
|
||||||
VGui_ReportTextInput( input.text );
|
VGui_ReportTextInput( input.text );
|
||||||
|
|
||||||
for( text = input.text; *text; text++ )
|
for( text = input.text; *text; text++ )
|
||||||
{
|
{
|
||||||
int ch = (byte)*text;
|
int ch;
|
||||||
|
|
||||||
// do not pass UTF-8 sequence into the engine, convert it here
|
if( !Q_stricmp( cl_charset.string, "utf-8" ) )
|
||||||
if( !cls.accept_utf8 )
|
ch = (unsigned char)*text;
|
||||||
ch = Con_UtfProcessCharForce( ch );
|
else
|
||||||
|
ch = Con_UtfProcessCharForce( (unsigned char)*text );
|
||||||
|
|
||||||
if( !ch )
|
if( !ch )
|
||||||
continue;
|
continue;
|
||||||
@@ -383,8 +374,14 @@ static void SDLash_ActiveEvent( int gain )
|
|||||||
{
|
{
|
||||||
host.status = HOST_FRAME;
|
host.status = HOST_FRAME;
|
||||||
if( cls.key_dest == key_game )
|
if( cls.key_dest == key_game )
|
||||||
|
{
|
||||||
IN_ActivateMouse( );
|
IN_ActivateMouse( );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( dma.initialized && snd_mute_losefocus.value )
|
||||||
|
{
|
||||||
|
SNDDMA_Activate( true );
|
||||||
|
}
|
||||||
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
|
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
|
||||||
if( vid_fullscreen.value == WINDOW_MODE_FULLSCREEN )
|
if( vid_fullscreen.value == WINDOW_MODE_FULLSCREEN )
|
||||||
VID_SetMode();
|
VID_SetMode();
|
||||||
@@ -400,8 +397,14 @@ static void SDLash_ActiveEvent( int gain )
|
|||||||
#endif
|
#endif
|
||||||
host.status = HOST_NOFOCUS;
|
host.status = HOST_NOFOCUS;
|
||||||
if( cls.key_dest == key_game )
|
if( cls.key_dest == key_game )
|
||||||
|
{
|
||||||
IN_DeactivateMouse();
|
IN_DeactivateMouse();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( dma.initialized && snd_mute_losefocus.value )
|
||||||
|
{
|
||||||
|
SNDDMA_Activate( false );
|
||||||
|
}
|
||||||
host.force_draw_version_time = host.realtime + 2.0;
|
host.force_draw_version_time = host.realtime + 2.0;
|
||||||
VID_RestoreScreenResolution();
|
VID_RestoreScreenResolution();
|
||||||
}
|
}
|
||||||
@@ -457,7 +460,7 @@ SDLash_EventFilter
|
|||||||
|
|
||||||
=============
|
=============
|
||||||
*/
|
*/
|
||||||
static void SDLash_EventHandler( SDL_Event *event )
|
static void SDLash_EventFilter( SDL_Event *event )
|
||||||
{
|
{
|
||||||
switch ( event->type )
|
switch ( event->type )
|
||||||
{
|
{
|
||||||
@@ -688,7 +691,7 @@ void Platform_RunEvents( void )
|
|||||||
SDL_Event event;
|
SDL_Event event;
|
||||||
|
|
||||||
while( !host.crashed && !host.shutdown_issued && SDL_PollEvent( &event ) )
|
while( !host.crashed && !host.shutdown_issued && SDL_PollEvent( &event ) )
|
||||||
SDLash_EventHandler( &event );
|
SDLash_EventFilter( &event );
|
||||||
|
|
||||||
#if XASH_PSVITA
|
#if XASH_PSVITA
|
||||||
PSVita_InputUpdate();
|
PSVita_InputUpdate();
|
||||||
|
|||||||
@@ -843,8 +843,6 @@ qboolean VID_CreateWindow( int width, int height, window_mode_t window_mode )
|
|||||||
#else // SDL_VERSION_ATLEAST( 2, 0, 0 )
|
#else // SDL_VERSION_ATLEAST( 2, 0, 0 )
|
||||||
Uint32 flags = 0;
|
Uint32 flags = 0;
|
||||||
|
|
||||||
Q_strncpy( wndname, GI->title, sizeof( wndname ));
|
|
||||||
|
|
||||||
if( window_mode != WINDOW_MODE_WINDOWED )
|
if( window_mode != WINDOW_MODE_WINDOWED )
|
||||||
SetBits( flags, SDL_FULLSCREEN|SDL_HWSURFACE );
|
SetBits( flags, SDL_FULLSCREEN|SDL_HWSURFACE );
|
||||||
|
|
||||||
|
|||||||
@@ -504,12 +504,12 @@ void Wcon_CreateConsole( void )
|
|||||||
|
|
||||||
if( host.type == HOST_NORMAL )
|
if( host.type == HOST_NORMAL )
|
||||||
{
|
{
|
||||||
Q_strncpy( s_wcd.title, XASH_ENGINE_NAME " " XASH_VERSION, sizeof( s_wcd.title ));
|
Q_strncpy( s_wcd.title, "Xash3D " XASH_VERSION, sizeof( s_wcd.title ));
|
||||||
Q_strncpy( s_wcd.log_path, "engine.log", sizeof( s_wcd.log_path ));
|
Q_strncpy( s_wcd.log_path, "engine.log", sizeof( s_wcd.log_path ));
|
||||||
}
|
}
|
||||||
else // dedicated console
|
else // dedicated console
|
||||||
{
|
{
|
||||||
Q_strncpy( s_wcd.title, XASH_DEDICATED_SERVER_NAME " " XASH_VERSION, sizeof( s_wcd.title ));
|
Q_strncpy( s_wcd.title, "XashDS " XASH_VERSION, sizeof( s_wcd.title ));
|
||||||
Q_strncpy( s_wcd.log_path, "dedicated.log", sizeof( s_wcd.log_path ));
|
Q_strncpy( s_wcd.log_path, "dedicated.log", sizeof( s_wcd.log_path ));
|
||||||
s_wcd.log_active = true; // always make log
|
s_wcd.log_active = true; // always make log
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ void Platform_Sleep( int msec )
|
|||||||
}
|
}
|
||||||
#endif // XASH_TIMER == TIMER_WIN32
|
#endif // XASH_TIMER == TIMER_WIN32
|
||||||
|
|
||||||
qboolean Platform_DebuggerPresent( void )
|
qboolean Sys_DebuggerPresent( void )
|
||||||
{
|
{
|
||||||
return IsDebuggerPresent();
|
return IsDebuggerPresent();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,9 +43,10 @@ extern int SV_UPDATE_BACKUP;
|
|||||||
#define SVF_MERGE_VISIBILITY BIT( 1 ) // we are do portal pass
|
#define SVF_MERGE_VISIBILITY BIT( 1 ) // we are do portal pass
|
||||||
|
|
||||||
// mapvalid flags
|
// mapvalid flags
|
||||||
#define MAP_IS_EXIST BIT( 0 )
|
#define MAP_IS_EXIST BIT( 0 )
|
||||||
#define MAP_HAS_LANDMARK BIT( 2 )
|
#define MAP_HAS_SPAWNPOINT BIT( 1 )
|
||||||
#define MAP_INVALID_VERSION BIT( 3 )
|
#define MAP_HAS_LANDMARK BIT( 2 )
|
||||||
|
#define MAP_INVALID_VERSION BIT( 3 )
|
||||||
|
|
||||||
#define SV_SPAWN_TIME 0.1
|
#define SV_SPAWN_TIME 0.1
|
||||||
|
|
||||||
@@ -329,8 +330,6 @@ typedef struct
|
|||||||
int msg_realsize; // left in bytes
|
int msg_realsize; // left in bytes
|
||||||
int msg_index; // for debug messages
|
int msg_index; // for debug messages
|
||||||
int msg_dest; // msg destination ( MSG_ONE, MSG_ALL etc )
|
int msg_dest; // msg destination ( MSG_ONE, MSG_ALL etc )
|
||||||
int msg_rewrite_index;
|
|
||||||
int msg_rewrite_pos;
|
|
||||||
qboolean msg_started; // to avoid recursive included messages
|
qboolean msg_started; // to avoid recursive included messages
|
||||||
edict_t *msg_ent; // user message member entity
|
edict_t *msg_ent; // user message member entity
|
||||||
vec3_t msg_org; // user message member origin
|
vec3_t msg_org; // user message member origin
|
||||||
@@ -394,10 +393,10 @@ typedef struct
|
|||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
|
||||||
extern server_static_t svs RENAME_SYMBOL( "svs_" ); // persistant server info
|
extern server_static_t svs; // persistant server info
|
||||||
extern server_t sv RENAME_SYMBOL( "sv_" ); // local server
|
extern server_t sv; // local server
|
||||||
extern svgame_static_t svgame; // persistant game info
|
extern svgame_static_t svgame; // persistant game info
|
||||||
extern areanode_t sv_areanodes[]; // AABB dynamic tree
|
extern areanode_t sv_areanodes[]; // AABB dynamic tree
|
||||||
|
|
||||||
extern convar_t mp_logecho;
|
extern convar_t mp_logecho;
|
||||||
extern convar_t mp_logfile;
|
extern convar_t mp_logfile;
|
||||||
@@ -475,7 +474,6 @@ extern convar_t sv_fullupdate_penalty_time;
|
|||||||
extern convar_t sv_log_outofband;
|
extern convar_t sv_log_outofband;
|
||||||
extern convar_t sv_allow_autoaim;
|
extern convar_t sv_allow_autoaim;
|
||||||
extern convar_t sv_aim;
|
extern convar_t sv_aim;
|
||||||
extern convar_t sv_allow_testpacket;
|
|
||||||
|
|
||||||
//===========================================================
|
//===========================================================
|
||||||
//
|
//
|
||||||
@@ -483,7 +481,7 @@ extern convar_t sv_allow_testpacket;
|
|||||||
//
|
//
|
||||||
void SV_FinalMessage( const char *message, qboolean reconnect );
|
void SV_FinalMessage( const char *message, qboolean reconnect );
|
||||||
void SV_KickPlayer( sv_client_t *cl, const char *fmt, ... ) _format( 2 );
|
void SV_KickPlayer( sv_client_t *cl, const char *fmt, ... ) _format( 2 );
|
||||||
void SV_DropClient( sv_client_t *cl, qboolean crash ) RENAME_SYMBOL( "SV_DropClient_" );
|
void SV_DropClient( sv_client_t *cl, qboolean crash );
|
||||||
void SV_UpdateMovevars( qboolean initialize );
|
void SV_UpdateMovevars( qboolean initialize );
|
||||||
int SV_ModelIndex( const char *name );
|
int SV_ModelIndex( const char *name );
|
||||||
int SV_SoundIndex( const char *name );
|
int SV_SoundIndex( const char *name );
|
||||||
@@ -504,7 +502,6 @@ 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 );
|
model_t *SV_ModelHandle( int modelindex );
|
||||||
void SV_DeactivateServer( void );
|
void SV_DeactivateServer( void );
|
||||||
void SV_FreeTestPacket( void );
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// sv_phys.c
|
// sv_phys.c
|
||||||
@@ -616,9 +613,11 @@ string_t SV_MakeString( const char *szValue );
|
|||||||
const char *SV_GetString( string_t iString );
|
const char *SV_GetString( string_t iString );
|
||||||
void SV_SetStringArrayMode( qboolean dynamic );
|
void SV_SetStringArrayMode( qboolean dynamic );
|
||||||
void SV_EmptyStringPool( void );
|
void SV_EmptyStringPool( void );
|
||||||
|
#ifdef XASH_64BIT
|
||||||
void SV_PrintStr64Stats_f( void );
|
void SV_PrintStr64Stats_f( void );
|
||||||
|
#endif
|
||||||
sv_client_t *SV_ClientFromEdict( const edict_t *pEdict, qboolean spawned_only );
|
sv_client_t *SV_ClientFromEdict( const edict_t *pEdict, qboolean spawned_only );
|
||||||
uint SV_MapIsValid( const char *filename, const char *landmark_name );
|
uint SV_MapIsValid( const char *filename, const char *spawn_entity, const char *landmark_name );
|
||||||
void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch );
|
void SV_StartSound( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch );
|
||||||
edict_t *SV_FindGlobalEntity( string_t classname, string_t globalname );
|
edict_t *SV_FindGlobalEntity( string_t classname, string_t globalname );
|
||||||
qboolean SV_CreateStaticEntity( struct sizebuf_s *msg, int index );
|
qboolean SV_CreateStaticEntity( struct sizebuf_s *msg, int index );
|
||||||
@@ -629,18 +628,12 @@ void SV_RestartAmbientSounds( void );
|
|||||||
void SV_RestartDecals( void );
|
void SV_RestartDecals( void );
|
||||||
void SV_RestartStaticEnts( void );
|
void SV_RestartStaticEnts( void );
|
||||||
int pfnDropToFloor( edict_t* e );
|
int pfnDropToFloor( edict_t* e );
|
||||||
|
edict_t *SV_EdictNum( int n );
|
||||||
void SV_SetModel( edict_t *ent, const char *name );
|
void SV_SetModel( edict_t *ent, const char *name );
|
||||||
int pfnDecalIndex( const char *m );
|
int pfnDecalIndex( const char *m );
|
||||||
void SV_CreateDecal( sizebuf_t *msg, const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags, float scale );
|
void SV_CreateDecal( sizebuf_t *msg, const float *origin, int decalIndex, int entityIndex, int modelIndex, int flags, float scale );
|
||||||
qboolean SV_RestoreCustomDecal( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent );
|
qboolean SV_RestoreCustomDecal( struct decallist_s *entry, edict_t *pEdict, qboolean adjacent );
|
||||||
|
|
||||||
static inline edict_t *SV_EdictNum( int n )
|
|
||||||
{
|
|
||||||
if( likely( n >= 0 && n < GI->max_edicts ))
|
|
||||||
return &svgame.edicts[n];
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// sv_log.c
|
// sv_log.c
|
||||||
//
|
//
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user