Compare commits

...

101 Commits

Author SHA1 Message Date
Alibek Omarov
a131a59414 engine: server: don't limit difficulty level on engine side 2024-03-03 19:01:02 +03:00
Alibek Omarov
cd7727b7de ref: gl: allow shadows, use shadows from magic's engine fork 2024-03-03 19:01:02 +03:00
Alibek Omarov
462b64b8ce ref: gl: add water warp scroll effect for compatibility with Magic-Nipples's engine fork 2024-03-03 19:01:02 +03:00
Alibek Omarov
5525af3769 engine: server: add SOLID_GIB extension from TimeWarp that disables interactions for gibs except for the solid brushes 2024-03-03 19:01:02 +03:00
Alibek Omarov
e334699c0b ref: gl: exclude SURF_REFLECT faces from VBO 2024-03-03 19:01:02 +03:00
Alibek Omarov
f5832faaa0 ref: gl: implement mirrors 2024-03-03 19:01:02 +03:00
Alibek Omarov
547a41ef2d ref: gl: mirror entities culling 2024-03-03 19:01:02 +03:00
Alibek Omarov
ab60b1e981 engine: mod_bmodel: detect reflective textures and set appropriate flags on surfaces with that textures 2024-03-03 19:01:02 +03:00
Alibek Omarov
d3e698d042 common: add mirror definitions 2024-03-03 19:01:02 +03:00
Alibek Omarov
7584bbe47e engine: client: fix sound mute when losing focus 2024-03-03 19:00:50 +03:00
Andrey Akhmichin
505b6cc264 utils: mdldec: boneweights fix. 2024-03-01 20:26:18 +03:00
Alibek Omarov
24f23908be engine: platform: stub Sys_DebuggerPresent on unsupported platforms 2024-02-27 05:17:01 +03:00
Alibek Omarov
43bd73f37b engine: platform: that's why commit --amend and/or rebase --interactive your fixes in your patches before proposing them 2024-02-27 04:59:54 +03:00
mittorn
bb2753cbfc engine/system: add asm-based raise implementation for arm and aarch64, making Sys_DebugBreak more relevant, use tgkill instead of kill 2024-02-27 04:54:55 +03:00
mittorn
5568eccc8a ref/r_sprite: move dframetype to inner block 2024-02-27 04:17:21 +03:00
mittorn
c3b2cc4423 waifulib/compiler_optimizations: disable no-semantic-interposition for gcc4 in release builds too 2024-02-27 04:16:14 +03:00
mittorn
d84130219f crashhandler: set host.crashed before messagebox to allow platform code handle crashed state in different way 2024-02-27 04:14:37 +03:00
mittorn
d97d4d6c42 filesystem: add XASH_ANDROID_ASSETS macro for aassets switch 2024-02-27 04:04:54 +03:00
mittorn
15798aaf52 ref/r_sprite: move dframetype to inner block 2024-02-27 04:04:54 +03:00
mittorn
e53892e827 ref_gl: fix loop scope in ripple code 2024-02-27 04:04:54 +03:00
mittorn
cb12af69ed gl2shim: add SOFTFP_LINK support for gles3compat 2024-02-27 04:04:54 +03:00
mittorn
e82050a4bc gl2shim: fix gcc 4.9 build 2024-02-27 04:04:54 +03:00
mittorn
e4edd2da45 platform/posix: check for non-zero dladdr ret 2024-02-27 04:04:54 +03:00
mittorn
4f80922358 waf/compiler_optimizations: remove no-semantic-interposition for gcc4 2024-02-27 04:04:54 +03:00
mittorn
ae7ed03376 ref_soft: fix crash when y < -height 2024-02-27 04:04:54 +03:00
mittorn
c082e46662 imagelib: fix for loop scope 2024-02-27 04:04:54 +03:00
mittorn
b0bbcab6b4 ref_soft,ref_gl: fix unaligned read in sprite code 2024-02-27 04:04:54 +03:00
SNMetamorph
0fc83080ec engine: server: allowed bandwidth test on listen servers 2024-02-26 19:41:32 +03:00
SNMetamorph
73883b504f engine: client: improved bandwidth test logic 2024-02-26 19:41:32 +03:00
SNMetamorph
8efc9d74e8 engine: server: fixed test packet buffer was not being created 2024-02-26 19:41:32 +03:00
mittorn
373321ff00 ref/gl: do not set type on 1D textures on GLES (will fallback to 2D) 2024-02-26 16:08:37 +03:00
Alibek Omarov
a508467aac engine: client: silently ignore if server didn't sent local player info in delta at spawn
The bug happens somewhere in server, not sure where or how. Remove Host_Error so mods
can be played again.
2024-02-26 11:48:46 +03:00
Alibek Omarov
abbe993e80 3rdparty: gl4es: update 2024-02-26 11:20:04 +03:00
Alibek Omarov
c644e4d569 3rdparty: nanogl: update, fix link error with missing glTexEnvfv 2024-02-26 11:06:09 +03:00
Alibek Omarov
c200e008f1 wscript: disable gl-wes-v2 renderer from Android builds 2024-02-26 10:55:42 +03:00
Alibek Omarov
e95a2da6d0 engine: platform: sdl: slightly rework previous patch to not call SDL each frame and check for NULL pointers 2024-02-23 20:55:32 +03:00
Alibek Omarov
8afca1a79c engine: server: allow starting game from custom map 2024-02-23 20:54:32 +03:00
Alibek Omarov
827c9ca857 filesystem: restore original Xash behavior with unreferenced keys in gameinfo.txt/liblist.gam 2024-02-23 20:54:32 +03:00
Alibek Omarov
2416635ba3 common: validate extended surfaces size 2024-02-23 20:54:32 +03:00
Alibek Omarov
39eec89580 engine: increase elights limit up to 128 2024-02-23 20:54:32 +03:00
Sheridan Kane Rathbun
98d88266a6 engine: platform: sdl: fix incorrect mouse cursor positioning on high-dpi displays (#1623)
Signed-off-by: SheridanR <sheridan.rathbun@gmail.com>
2024-02-23 20:54:17 +03:00
mittorn
0f3359fc05 ref_gl: do not apply overbright color if lightscale correction used 2024-02-22 21:02:34 +03:00
mittorn
6c77608c34 ref_gl: implement color-modulate overbrigths with gl_vbo using texture GL_COMBINE 2024-02-22 21:02:34 +03:00
Alibek Omarov
abdff6eff6 mainui: update 2024-02-22 15:43:49 +03:00
Alibek Omarov
95a75465c9 common: remove FORCEINLINE and NOINLINE macros, we don't use them in engine 2024-02-22 15:43:37 +03:00
Alibek Omarov
119926805f mainui: update 2024-02-21 03:39:11 +03:00
Alibek Omarov
f749b5cb4b 3rdparty: nanogl: update 2024-02-21 02:57:18 +03:00
Alibek Omarov
c29ad6b598 scripts: waifulib: compiler_optimizations: add option to use profiling 2024-02-21 02:57:07 +03:00
Alibek Omarov
4c5dfb963e engine: zone: few more tunings for realloc 2024-02-21 00:59:02 +03:00
Alibek Omarov
e11f9e05d4 engine: server: add GetNativeObject to server's PhysicsAPI 2024-02-19 17:49:37 +03:00
Alibek Omarov
5c8b5b3511 Documentation: extensions: add doc about native-object 2024-02-19 17:49:37 +03:00
Alibek Omarov
2ea7162287 engine: gameui: add GetNativeObject to extended menu API 2024-02-19 17:49:37 +03:00
Alibek Omarov
e62ab51842 engine: platforms: android: platforms aren't expected to get NULL or zero sized native object names anymore 2024-02-19 17:49:37 +03:00
Bohdan Shulyar
f1bc9b87b1 platform: android: port to SDL 2024-02-19 17:47:40 +03:00
Alibek Omarov
a9bddaac64 engine: platform: win32: do not call filesystem functions if filesystem_stdio was failed to load 2024-02-19 06:27:24 +03:00
Alibek Omarov
6cef6f6a75 engine: zone: refactoring 2024-02-19 06:13:54 +03:00
Alibek Omarov
25ea6ed500 scripts: waifulib: don't use relative path while creating ZIP file (so cwd might not be equal to sources path) 2024-02-19 05:00:12 +03:00
Alibek Omarov
3d5173f257 engine: zone: implement Mem_Realloc through standard realloc 2024-02-19 04:22:16 +03:00
Alibek Omarov
05ff0d6020 engine: cmd: remove unused global variable 2024-02-17 22:17:22 +03:00
Alibek Omarov
3cea12627e engine: client: add cl_trace_stufftext from old engine 2024-02-17 22:16:39 +03:00
Alibek Omarov
b59b7c1a8d engine: server: better error message for missing spawn functions 2024-02-17 22:15:41 +03:00
Alibek Omarov
dd2c369df3 engine: imagelib: fix integer overflow on huge images when calculating reflectivity 2024-02-17 22:14:27 +03:00
Andrey Akhmichin
8b79e49a0f engine: server: execute maps/<mapname>_unload.cfg on server deactivation. 2024-02-16 17:57:26 +03:00
Andrey Akhmichin
4ea6eba8f2 engine: server: execute maps/<mapname>_load.cfg before entities precaching. 2024-02-16 17:57:26 +03:00
Andrey Akhmichin
f649076bc3 engine: server: execute map change config file before entities precaching. 2024-02-16 17:57:26 +03:00
Andrey Akhmichin
8ecffa4663 engine: server: define new "disconcfgfile" cvar. 2024-02-16 17:57:26 +03:00
Andrey Akhmichin
e90b83849a engine: server: execute map change config file in singleplayer. 2024-02-16 17:57:26 +03:00
Andrey Akhmichin
d517b9717a engine: server: define new "_sv_override_scientist_mdl" cvar for Uplink's scientist model. 2024-02-16 17:57:26 +03:00
Alibek Omarov
2c0d6e06be engine: server: return NULL in SV_ClientBy{Id,Name} if client array isn't allocated 2024-02-15 13:56:47 +03:00
Alibek Omarov
dec71850a1 engine: console: allow changing background filtering 2024-02-13 15:34:33 +03:00
Alibek Omarov
b1860972c6 engine: font: fix inverted check, fix potential division by zero 2024-02-13 15:33:51 +03:00
Alibek Omarov
1f4c9b67da engine: server: don't init or send voice chat in singleplayer 2024-02-13 15:09:26 +03:00
Alibek Omarov
c2da125358 engine: client: as an experiment, let users override default font rendermode through hud_fontrender and con_fontrender cvars 2024-02-09 07:25:47 +03:00
Alibek Omarov
31fa990d44 engine: gamma: fix gamma changes not caught if gamma cvar was set during frame 2024-02-09 06:29:30 +03:00
Alibek Omarov
d3e60c7d84 engine: gamma: higher brightness limit for compatibility 2024-02-09 06:28:31 +03:00
Alibek Omarov
e2424b4303 engine: server: clean up userinfo and fullupdate throttle on client connect 2024-02-07 23:27:02 +03:00
Alibek Omarov
240563cd1b engine: client: set r_lighting_modulate to 0.6 and save it to config for old Xash mods that use it internally 2024-02-07 23:22:27 +03:00
Alibek Omarov
d708cd58fb mainui: update 2024-02-07 23:22:27 +03:00
Alibek Omarov
491b503f96 engine: common: optimize COM_LoadFile/COM_LoadFileForMe removing double allocation 2024-02-07 23:22:27 +03:00
Alibek Omarov
636a2228f6 filesystem: add new API function LoadFileMalloc that returns a pointer that can be freed using standard free() 2024-02-07 23:22:27 +03:00
Alibek Omarov
bb03e2597c filesystem: allow to pass custom allocation functions to LoadFile 2024-02-07 23:22:27 +03:00
Alibek Omarov
21c828ee40 engine: sounds: remove extra logging 2024-02-05 15:57:59 +03:00
Alibek Omarov
132c9de142 engine: host: add the most important command line flag help string 2024-02-05 15:28:18 +03:00
Alibek Omarov
9d9507d77f engine: change mobility API license to Unlicense, as with build.h
See GitHub issue: https://github.com/FWGS/hlsdk-portable/issues/259

Signed-off-by: Alibek Omarov <a1ba.omarov@gmail.com>
2024-02-05 15:01:03 +03:00
Alibek Omarov
7daa6c3451 engine: server: use soundlist to acquire random sounds for physics 2024-02-05 12:49:31 +03:00
Alibek Omarov
c8e1ffe0dd engine: client: use soundlist to acquire random sounds for temp entities 2024-02-05 12:49:31 +03:00
Alibek Omarov
b5f02324a6 engine: add basic sounds.lst implementation 2024-02-05 12:49:27 +03:00
Alibek Omarov
47f5dfdcfd common: define macros for color codes for easier access 2024-02-05 12:49:27 +03:00
Alibek Omarov
33da68b013 engine: client: move reseting gamma changed flag to the end of the frame for custom renderers 2024-02-05 03:41:15 +03:00
Alibek Omarov
618ec83c9d engine: client: don't trigger CheckGamma if there is no screenshot action 2024-02-05 03:40:14 +03:00
Alibek Omarov
85de61ebc8 engine: client: fix userid not being written to player info on userinfo change 2024-02-05 02:58:46 +03:00
Alibek Omarov
2feaae59f7 engine: client: bring back r_lighting_modulate, as a compatibility cvar 2024-02-02 13:52:17 +03:00
Alibek Omarov
2550d7fbd3 public: tests: remove linuxunkabi remnants 2024-02-01 02:54:22 +03:00
Alibek Omarov
565f717804 ref: add ref_null renderer that does nothing
This was sitting in my git stash for months. Let's publish it now.
2024-02-01 02:45:19 +03:00
Alibek Omarov
b56c83a2f9 Documentation: add a note about musl 2024-01-31 23:59:28 +03:00
Alibek Omarov
bf17996f72 public: remove linuxunkabi 2024-01-31 23:59:28 +03:00
Alibek Omarov
a3acb1c85b engine: gamma: validate gamma cvars in local games too 2024-01-30 17:55:36 +03:00
Alibek Omarov
d4d63301e0 mainui: update 2024-01-30 17:50:31 +03:00
Alibek Omarov
e9af0c9810 ref: gl: wscript: remove all libs dependencies from gles3compat, added by mistake 2024-01-30 17:40:59 +03:00
Alibek Omarov
131ad9c790 3rdparty: update submodules 2024-01-30 17:28:12 +03:00
Alibek Omarov
bfcaba54dc wscript: move werror flags into uselib 2024-01-30 17:24:17 +03:00
117 changed files with 3046 additions and 600 deletions

View File

@@ -24,14 +24,9 @@ jobs:
# - os: ubuntu-aarch64-20.04
# targetos: linux
# targetarch: aarch64
# - os: ubuntu-20.04
# targetos: android
# targetarch: 32
# - os: ubuntu-20.04
# targetos: android
# targetarch: 64
- os: ubuntu-20.04
targetos: android
targetarch: multiarch
# - os: ubuntu-20.04
# targetos: motomagx
# targetarch: armv6
@@ -51,7 +46,6 @@ jobs:
env:
SDL_VERSION: 2.28.5
GH_CPU_ARCH: ${{ matrix.targetarch }}
ANDROID_SDK_TOOLS_VER: 4333796
steps:
- name: Checkout
uses: actions/checkout@v3

5
.gitignore vendored
View File

@@ -54,6 +54,11 @@ CMakeFiles
Makefile
cmake_install.cmake
install_manifest.txt
CMakeLists.txt*
CMakeScripts
Testing
compile_commands.json
_deps
# makedepend
Makefile.dep
*.bak

View File

@@ -0,0 +1,25 @@
# GetNativeObject API
To be able to use platform-specific features or get optional engine interfaces, we've added a simple call to MobilityAPI on client DLL and PhysicsAPI for server DLL and extended MenuAPI for menu DLL.
It's defined like this:
```
void *pfnGetNativeObject( const char *name );
```
#### Cross-platform objects
Only these objects are guaranteed to be available on all targets.
| Object name | Interface |
|-------------|-----------|
| `VFileSystem009` | Provides C++ interface to filesystem, binary-compatible with Valve's VFileSystem009. |
| `XashFileSystemXXX` | Provides C interface to filesystem. This interface is unstable and not recommended for generic use, outside of engine internals. For more info about current version look into `filesystem.h`. |
#### Android-specific objects
| Object name | Interface |
|-------------|-----------|
| `JNIEnv` | Allows interfacing with Java Native Interface. |
| `ActivityClass` | Returns JNI object for engine Android activity class. |

View File

@@ -0,0 +1,65 @@
# sounds.lst.md
Using sounds.lst located in scripts folder, modder can override some of the hardcoded sounds in temp entities and server physics.
File format:
```
<group name>
{
<path1>
<path2>
<path3>
}
<group2 name> <path with %d> <min number> <max number>
```
* Sounds can use any supported sound format (WAV or MP3).
* The path must be relative to the sounds/ folder in the game or base directory root, addon folder, or archive root.
* Groups can be empty or omitted from the file to load no sound.
* Groups can either list a set of files or specify a format string and a range.
* Anything after // will be considered a comment and ignored.
* Behavior is undefined if the group was listed multiple times.
Currently supported groups are:
|Group name|Usage|
|----------|-----|
|`BouncePlayerShell`|Used for BOUNCE_SHELL tempentity hitsound|
|`BounceWeaponShell`|Used for BOUCNE_SHOTSHELL tempentity hitsound|
|`BounceConcrete`|Used for BOUNCE_CONCRETE tempentity hitsound|
|`BounceGlass`|Used for BOUCNE_GLASS|
|`BounceMetal`|Used for BOUNCE_METAL|
|`BounceFlesh`|Used for BOUNCE_FLESH|
|`BounceWood`|Used for BOUNCE_WOOD|
|`Ricochet`|Used for BOUNCE_SHRAP and ricochet tempentities|
|`Explode`|Used for tempentity explosions|
|`EntityWaterEnter`|Used for entity entering water|
|`EntityWaterExit`|Used for entity exiting water|
|`PlayerWaterEnter`|Used for player entering water|
|`PlayerWaterExit`|Used for player exiting water|
## Example
This example is based on defaults sounds used in Half-Life:
```
BouncePlayerShell "player/pl_shell%d.wav" 1 3
BounceWeaponShell "weapons/sshell%d.wav" 1 3
BounceConcrete "debris/concrete%d.wav" 1 3
BounceGlass "debris/glass%d.wav" 1 4
BounceMetal "debris/metal%d.wav" 1 6
BounceFlesh "debris/flesh%d.wav" 1 7
BounceWood "debris/wood%d.wav" 1 4
Ricochet "weapons/ric%d.wav" 1 5
Explode "weapons/explode%d.wav" 3 5
EntityWaterEnter "player/pl_wade%d.wav" 1 4
EntityWaterExit "player/pl_wade%d.wav" 1 4
PlayerWaterEnter
{
"player/pl_wade1.wav"
}
PlayerWaterExit
{
"player/pl_wade2.wav"
}
```

15
Documentation/musl.md Normal file
View File

@@ -0,0 +1,15 @@
# Xash3D FWGS on `musl`
Xash3D FWGS works on `musl` out of the box. However, the engine doesn't try to differentiate glibc and musl anymore. If you see error similar to:
```
Host_InitError: can't initialize cl_dlls/client.so: Error relocating valve/cl_dlls/client.so: __sprintf_chk: symbol not found
```
... or you know that the game you're running is linked against glibc, you can try using `libgcompat`, like this:
```
$ LD_PRELOAD=/lib/libgcompat.so.0 ./xash3d ...
```
It will automatically add the missing symbols that glibc binaries usually need. In the future we might automatically link engine against `libgcompat` for better compatibility with prebuilt or closed-source games, if there will be any use for this.

View File

@@ -54,6 +54,7 @@ BRUSH MODELS
#define SURF_CONVEYOR BIT( 6 ) // scrolled texture (was SURF_DRAWBACKGROUND)
#define SURF_UNDERWATER BIT( 7 ) // caustics
#define SURF_TRANSPARENT BIT( 8 ) // it's a transparent texture (was SURF_DONTWARP)
#define SURF_REFLECT BIT( 31 ) // mirrors
// lightstyle management
#define LM_STYLES 4 // MAXLIGHTMAPS

View File

@@ -228,7 +228,9 @@ typedef struct mextrasurf_s
unsigned short numverts; // world->vertexes[]
int firstvertex; // fisrt look up in tr.tbn_vectors[], then acess to world->vertexes[]
intptr_t reserved[32]; // just for future expansions or mod-makers
struct mextrasurf_s *mirrorchain; // engine-side mirrors, may be ignored in mods with custom renderers
intptr_t reserved[31]; // just for future expansions or mod-makers
} mextrasurf_t;
struct msurface_s
@@ -534,5 +536,14 @@ typedef struct
#define MAX_EFRAGS 8192 // Arcane Dimensions required
#define MAX_REQUESTS 64
#if ! XASH_64BIT
STATIC_ASSERT( sizeof( mextrasurf_t ) == 324, "mextrasurf_t unexpected size" );
STATIC_ASSERT( sizeof( decal_t ) == 60, "decal_t unexpected size");
STATIC_ASSERT( sizeof( mfaceinfo_t ) == 176, "mfaceinfo_t unexpected size");
#else
STATIC_ASSERT( sizeof( mextrasurf_t) == 496, "mextrasurf_t unexpected size");
STATIC_ASSERT( sizeof( decal_t ) == 88, "decal_t unexpected size");
STATIC_ASSERT( sizeof( mfaceinfo_t ) == 304, "mfaceinfo_t unexpected size");
#endif
#endif//COM_MODEL_H

View File

@@ -92,6 +92,7 @@
#define SOLID_BSP 4 // bsp clip, touch on edge, block
#define SOLID_CUSTOM 5 // call external callbacks for tracing
#define SOLID_PORTAL 6 // borrowed from FTE
#define SOLID_GIB 7 // do not block, only collide with solid brushes
// edict->deadflag values
#define DEAD_NO 0 // alive
@@ -114,6 +115,8 @@
#define EF_LIGHT 64 // rocket flare glow sprite
#define EF_NODRAW 128 // don't draw entity
#define EF_NOREFLECT (1U<<24) // Entity won't reflecting in mirrors
#define EF_REFLECTONLY (1U<<25) // Entity will be drawing only in mirrors
#define EF_WATERSIDES (1U<<26) // Do not remove sides for func_water entity
#define EF_FULLBRIGHT (1U<<27) // Just get fullbright
#define EF_NOSHADOW (1U<<28) // ignore shadow for this entity

View File

@@ -164,6 +164,10 @@ Default build-depended cvar and constant values
#define XASH_INTERNAL_GAMELIBS
#endif // XASH_ANDROID || XASH_IOS || XASH_EMSCRIPTEN
#if XASH_ANDROID && XASH_SDL
#define XASH_ANDROID_ASSETS 1
#endif
// Defaults
#ifndef DEFAULT_TOUCH_ENABLE
#define DEFAULT_TOUCH_ENABLE "0"

View File

@@ -27,6 +27,7 @@ GNU General Public License for more details.
#define ENGINE_COMPUTE_STUDIO_LERP (1<<7) // enable MOVETYPE_STEP lerping back in engine
#define ENGINE_LINEAR_GAMMA_SPACE (1<<8) // disable influence of gamma/brightness cvars to textures/lightmaps, for mods with custom renderer
#define ENGINE_ALLOW_MIRRORS (1U<<30) // allow mirrors in engine renderer
#define ENGINE_STEP_POSHISTORY_LERP (1U<<31) // enable MOVETYPE_STEP interpolation based on position history. Incompatible with ENGINE_COMPUTE_STUDIO_LERP!
// adjust the mask when features will be added or removed
@@ -40,6 +41,7 @@ GNU General Public License for more details.
| ENGINE_IMPROVED_LINETRACE \
| ENGINE_COMPUTE_STUDIO_LERP \
| ENGINE_LINEAR_GAMMA_SPACE \
| ENGINE_ALLOW_MIRRORS \
| ENGINE_STEP_POSHISTORY_LERP )
#endif//FEATURES_H

View File

@@ -86,8 +86,6 @@ typedef uint64_t longtime_t;
#define NORETURN __attribute__((noreturn))
#define NONNULL __attribute__((nonnull))
#define ALLOC_CHECK(x) __attribute__((alloc_size(x)))
#define FORCEINLINE inline __attribute__((always_inline))
#define NOINLINE __attribute__((noinline))
#elif defined(_MSC_VER)
#define EXPORT __declspec( dllexport )
#define GAME_EXPORT
@@ -95,8 +93,6 @@ typedef uint64_t longtime_t;
#define NORETURN
#define NONNULL
#define ALLOC_CHECK(x)
#define FORCEINLINE __forceinline
#define NOINLINE __declspec( noinline )
#else
#define EXPORT
#define GAME_EXPORT
@@ -104,8 +100,6 @@ typedef uint64_t longtime_t;
#define NORETURN
#define NONNULL
#define ALLOC_CHECK(x)
#define FORCEINLINE
#define NOINLINE
#endif
#if ( __GNUC__ >= 3 )

View File

@@ -46,10 +46,35 @@ static int CL_LoadFontTexture( const char *fontname, uint texFlags, int *width )
return tex;
}
qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags )
static int CL_FontRenderMode( convar_t *fontrender )
{
switch((int)fontrender->value )
{
case 0:
return kRenderTransAdd;
case 1:
return kRenderTransAlpha;
case 2:
return kRenderTransTexture;
default:
Cvar_DirectSet( fontrender, fontrender->def_string );
}
return kRenderTransTexture;
}
void CL_SetFontRendermode( cl_font_t *font )
{
ref.dllFuncs.GL_SetRenderMode( CL_FontRenderMode( font->rendermode ));
}
qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, convar_t *rendermode, uint texFlags )
{
int font_width, i;
if( !rendermode )
return false;
if( font->valid )
return true; // already loaded
@@ -76,13 +101,16 @@ qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float sc
return true;
}
qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags )
qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float scale, convar_t *rendermode, uint texFlags )
{
fs_offset_t length;
qfont_t src;
byte *pfile;
int font_width, i;
if( !rendermode )
return false;
if( font->valid )
return true;
@@ -105,7 +133,7 @@ qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float
font->type = FONT_VARIABLE;
font->valid = true;
font->scale = scale;
font->scale = scale ? scale : 1.0f;
font->rendermode = rendermode;
font->charHeight = Q_rint( src.rowheight * scale );
@@ -177,7 +205,8 @@ int CL_DrawCharacter( float x, float y, int number, rgba_t color, cl_font_t *fon
return font->charWidths[number];
rc = &font->fontRc[number];
if( font->scale <= 1.0f || REF_GET_PARM( PARM_TEX_FILTERING, font->hFontTexture ))
if( font->scale <= 1.f || !REF_GET_PARM( PARM_TEX_FILTERING, font->hFontTexture ))
half = 0;
s1 = ((float)rc->left + half ) / texw;
@@ -191,7 +220,7 @@ int CL_DrawCharacter( float x, float y, int number, rgba_t color, cl_font_t *fon
SPR_AdjustSize( &x, &y, &w, &h );
if( !FBitSet( flags, FONT_DRAW_NORENDERMODE ))
ref.dllFuncs.GL_SetRenderMode( font->rendermode );
CL_SetFontRendermode( font );
// don't apply color to fixed fonts it's already colored
if( font->type != FONT_FIXED || REF_GET_PARM( PARM_TEX_GLFORMAT, font->hFontTexture ) == 0x8045 ) // GL_LUMINANCE8_ALPHA8
@@ -214,7 +243,7 @@ int CL_DrawString( float x, float y, const char *s, rgba_t color, cl_font_t *fon
Con_UtfProcessChar( 0 ); // clear utf state
if( !FBitSet( flags, FONT_DRAW_NORENDERMODE ))
ref.dllFuncs.GL_SetRenderMode( font->rendermode );
CL_SetFontRendermode( font );
Vector4Copy( color, current_color );

View File

@@ -474,8 +474,7 @@ void CL_DrawCenterPrint( void )
pText = clgame.centerPrint.message;
CL_DrawCharacterLen( font, 0, NULL, &charHeight );
ref.dllFuncs.GL_SetRenderMode( font->rendermode );
CL_SetFontRendermode( font );
for( i = 0; i < clgame.centerPrint.lines; i++ )
{
lineLength = 0;

View File

@@ -1220,6 +1220,7 @@ static ui_extendedfuncs_t gExtendedfuncs =
pfnParseFileSafe,
NET_AdrToString,
NET_CompareAdrSort,
Sys_GetNativeObject,
};
void UI_UnloadProgs( void )

View File

@@ -28,7 +28,6 @@ GNU General Public License for more details.
#define MAX_CMD_BUFFER 8000
#define CONNECTION_PROBLEM_TIME 15.0 // 15 seconds
#define CL_CONNECTION_RETRIES 10
#define CL_TEST_RETRIES_NORESPONCE 3
#define CL_TEST_RETRIES 5
CVAR_DEFINE_AUTO( mp_decals, "300", FCVAR_ARCHIVE, "decals limit in multiplayer" );
@@ -61,6 +60,7 @@ CVAR_DEFINE_AUTO( cl_smoothtime, "0.1", FCVAR_ARCHIVE, "time to smooth up" );
CVAR_DEFINE_AUTO( cl_clockreset, "0.1", FCVAR_ARCHIVE, "frametime delta maximum value before reset" );
CVAR_DEFINE_AUTO( cl_fixtimerate, "7.5", FCVAR_ARCHIVE, "time in msec to client clock adjusting" );
CVAR_DEFINE_AUTO( hud_fontscale, "1.0", FCVAR_ARCHIVE|FCVAR_LATCH, "scale hud font texture" );
CVAR_DEFINE_AUTO( hud_fontrender, "0", FCVAR_ARCHIVE, "hud font render mode (0: additive, 1: holes, 2: trans)" );
CVAR_DEFINE_AUTO( hud_scale, "0", FCVAR_ARCHIVE|FCVAR_LATCH, "scale hud at current resolution" );
CVAR_DEFINE_AUTO( hud_scale_minimal_width, "640", FCVAR_ARCHIVE|FCVAR_LATCH, "if hud_scale results in a HUD virtual screen smaller than this value, it won't be applied" );
CVAR_DEFINE_AUTO( cl_solid_players, "1", 0, "Make all players not solid (can't traceline them)" );
@@ -74,8 +74,9 @@ static CVAR_DEFINE_AUTO( cl_upmax, "1200", FCVAR_ARCHIVE, "max allowed incoming
CVAR_DEFINE_AUTO( cl_lw, "1", FCVAR_ARCHIVE|FCVAR_USERINFO, "enable client weapon predicting" );
CVAR_DEFINE_AUTO( cl_charset, "utf-8", FCVAR_ARCHIVE, "1-byte charset to use (iconv style)" );
CVAR_DEFINE_AUTO( cl_trace_messages, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable message names tracing (good for developers)");
CVAR_DEFINE_AUTO( cl_trace_events, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable events tracing (good for developers)");
CVAR_DEFINE_AUTO( cl_trace_stufftext, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable stufftext (server-to-client console commands) tracing (good for developers)" );
CVAR_DEFINE_AUTO( cl_trace_messages, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable message names tracing (good for developers)" );
CVAR_DEFINE_AUTO( cl_trace_events, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable events tracing (good for developers)" );
static CVAR_DEFINE_AUTO( cl_nat, "0", 0, "show servers running under NAT" );
CVAR_DEFINE_AUTO( hud_utf8, "0", FCVAR_ARCHIVE, "Use utf-8 encoding for hud text" );
CVAR_DEFINE_AUTO( ui_renderworld, "0", FCVAR_ARCHIVE, "render world when UI is visible" );
@@ -1070,6 +1071,22 @@ static void CL_SendConnectPacket( void )
cls.timestart = Sys_DoubleTime();
}
/*
=================
CL_GetTestFragmentSize
Returns bandwidth test fragment size
=================
*/
static int CL_GetTestFragmentSize( void )
{
const int fragmentSizes[CL_TEST_RETRIES] = { 64000, 32000, 10666, 5200, 1400 };
if( cls.connect_retry >= 0 && cls.connect_retry < CL_TEST_RETRIES )
return bound( FRAGMENT_MIN_SIZE, fragmentSizes[cls.connect_retry], FRAGMENT_MAX_SIZE );
else
return FRAGMENT_MIN_SIZE;
}
/*
=================
CL_CheckForResend
@@ -1081,8 +1098,9 @@ static void CL_CheckForResend( void )
{
netadr_t adr;
net_gai_state_t res;
float resendTime;
qboolean bandwidthTest;
if( cls.internetservers_wait )
CL_SendMasterServerScanRequest();
@@ -1108,7 +1126,10 @@ static void CL_CheckForResend( void )
else if( cl_resend.value > CL_MAX_RESEND_TIME )
Cvar_SetValue( "cl_resend", CL_MAX_RESEND_TIME );
if(( host.realtime - cls.connect_time ) < cl_resend.value )
bandwidthTest = !cls.legacymode && cl_test_bandwidth.value && cls.connect_retry <= CL_TEST_RETRIES;
resendTime = bandwidthTest ? 1.0f : cl_resend.value;
if(( host.realtime - cls.connect_time ) < resendTime )
return;
res = NET_StringToAdrNB( cls.servername, &adr );
@@ -1135,10 +1156,11 @@ static void CL_CheckForResend( void )
if( adr.port == 0 ) adr.port = MSG_BigShort( PORT_SERVER );
if( cls.connect_retry == CL_TEST_RETRIES_NORESPONCE )
if( cls.connect_retry == CL_TEST_RETRIES )
{
// too many fails use default connection method
Con_Printf( "hi-speed connection is failed, use default method\n" );
Con_Printf( "Bandwidth test failed, fallback to default connecting method\n" );
Con_Printf( "Connecting to %s... (retry #%i)\n", cls.servername, cls.connect_retry + 1 );
Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" );
Cvar_SetValue( "cl_dlmax", FRAGMENT_MIN_SIZE );
cls.connect_time = host.realtime;
@@ -1146,16 +1168,15 @@ static void CL_CheckForResend( void )
return;
}
bandwidthTest = !cls.legacymode && cl_test_bandwidth.value;
cls.serveradr = adr;
cls.max_fragment_size = Q_min( FRAGMENT_MAX_SIZE, cls.max_fragment_size / (cls.connect_retry + 1));
cls.max_fragment_size = CL_GetTestFragmentSize();
cls.connect_time = host.realtime; // for retransmit requests
cls.connect_retry++;
if( bandwidthTest )
Con_Printf( "Connecting to %s... [retry #%i, max fragment size %i]\n", cls.servername, cls.connect_retry, cls.max_fragment_size );
Con_Printf( "Connecting to %s... (retry #%i, fragment size %i)\n", cls.servername, cls.connect_retry, cls.max_fragment_size );
else
Con_Printf( "Connecting to %s... [retry #%i]\n", cls.servername, cls.connect_retry );
Con_Printf( "Connecting to %s... (retry #%i)\n", cls.servername, cls.connect_retry );
if( bandwidthTest )
Netchan_OutOfBandPrint( NS_CLIENT, adr, "bandwidth %i %i\n", PROTOCOL_VERSION, cls.max_fragment_size );
@@ -2891,6 +2912,7 @@ static void CL_InitLocal( void )
Cvar_RegisterVariable( &rcon_address );
Cvar_RegisterVariable( &cl_trace_stufftext );
Cvar_RegisterVariable( &cl_trace_messages );
Cvar_RegisterVariable( &cl_trace_events );
@@ -2926,6 +2948,7 @@ static void CL_InitLocal( void )
Cvar_RegisterVariable( &cl_clockreset );
Cvar_RegisterVariable( &cl_fixtimerate );
Cvar_RegisterVariable( &hud_fontscale );
Cvar_RegisterVariable( &hud_fontrender );
Cvar_RegisterVariable( &hud_scale );
Cvar_RegisterVariable( &hud_scale_minimal_width );
Cvar_Get( "cl_background", "0", FCVAR_READ_ONLY, "indicate what background map is running" );

View File

@@ -387,7 +387,7 @@ static void NetGraph_DrawTextFields( int x, int y, int w, wrect_t rect, int coun
// move rolling average
framerate = FRAMERATE_AVG_FRAC * host.frametime + ( 1.0f - FRAMERATE_AVG_FRAC ) * framerate;
ref.dllFuncs.GL_SetRenderMode( font->rendermode );
CL_SetFontRendermode( font );
if( framerate > 0.0f )
{

View File

@@ -1382,9 +1382,13 @@ void CL_UpdateUserinfo( sizebuf_t *msg, qboolean legacy )
if( slot >= MAX_CLIENTS )
Host_Error( "CL_ParseServerMessage: svc_updateuserinfo >= MAX_CLIENTS\n" );
player = &cl.players[slot];
if( !legacy )
id = MSG_ReadLong( msg ); // unique user ID
player = &cl.players[slot];
else
id = 0; // bogus
active = MSG_ReadOneBit( msg ) ? true : false;
if( active )
@@ -1406,6 +1410,10 @@ void CL_UpdateUserinfo( sizebuf_t *msg, qboolean legacy )
memset( player, 0, sizeof( *player ));
}
// in GoldSrc userinfo might be empty but userid is always sent as separate value
// thus avoids clean up even after client disconnect
player->userid = id;
}
/*
@@ -2321,11 +2329,18 @@ void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message )
break;
case svc_stufftext:
s = MSG_ReadString( msg );
if( cl_trace_stufftext.value )
{
size_t len = Q_strlen( s );
Con_Printf( "Stufftext: %s%c", s, len && s[len-1] == '\n' ? '\0' : '\n' );
}
#ifdef HACKS_RELATED_HLMODS
// disable Cry Of Fear antisave protection
if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS )
break; // too early
#endif
Cbuf_AddFilteredText( s );
break;
case svc_setangle:

View File

@@ -443,13 +443,17 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message )
break;
case svc_stufftext:
s = MSG_ReadString( msg );
if( cl_trace_stufftext.value )
{
size_t len = Q_strlen( s );
Con_Printf( "Stufftext: %s%c", s, len && s[len-1] == '\n' ? '\0' : '\n' );
}
#ifdef HACKS_RELATED_HLMODS
// disable Cry Of Fear antisave protection
if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS )
break; // too early
#endif
Con_Reportf( "Stufftext: %s", s );
Cbuf_AddFilteredText( s );
break;
case svc_setangle:

View File

@@ -795,25 +795,14 @@ static void CL_SetupPMove( playermove_t *pmove, const local_state_t *from, const
pmove->player_index = ps->number - 1;
// a1ba: workaround bug on old protocol where the server refuse to send
// our local player in delta. cl.playernum, in theory, must be equal
// to our local player index anyway
// a1ba: workaround bug where the server refuse to send our local player in delta
// cl.playernum, in theory, must be equal to our local player index anyway
//
// this might not be a real solution, since everything else will be bogus
// but we need to properly run prediction and avoid potential memory
// corruption
// either debug this, or remove when old protocol will be dropped!!!
if( pmove->player_index < 0 )
{
if( cls.legacymode )
{
pmove->player_index = bound( 0, cl.playernum, cl.maxclients - 1 );
}
else
{
// if this happens, record a demo and send it to a1ba
Host_Error( "%s: ps->number == %d\n", __func__, ps->number );
}
}
pmove->player_index = bound( 0, cl.playernum, cl.maxclients - 1 );
pmove->multiplayer = (cl.maxclients > 1);
pmove->runfuncs = runfuncs;

View File

@@ -288,6 +288,9 @@ void SCR_MakeScreenShot( void )
qboolean iRet = false;
int viewsize;
if( cls.scrshot_action == scrshot_inactive )
return;
if( cls.envshot_viewsize > 0 )
viewsize = cls.envshot_viewsize;
else viewsize = cl_envshot_size.value;
@@ -319,8 +322,6 @@ void SCR_MakeScreenShot( void )
if( iRet )
VID_WriteOverviewScript(); // store overview script too
break;
case scrshot_inactive:
return;
}
// report
@@ -572,15 +573,15 @@ void SCR_LoadCreditsFont( void )
"creditsfont_%s.fnt", Cvar_VariableString( "con_charset" )) > 0 )
{
if( FS_FileExists( charsetFnt, false ))
success = Con_LoadVariableWidthFont( charsetFnt, font, scale, kRenderTransAdd, TF_FONT );
success = Con_LoadVariableWidthFont( charsetFnt, font, scale, &hud_fontrender, TF_FONT );
}
}
if( !success )
success = Con_LoadVariableWidthFont( "gfx/creditsfont.fnt", font, scale, kRenderTransAdd, TF_FONT );
success = Con_LoadVariableWidthFont( "gfx/creditsfont.fnt", font, scale, &hud_fontrender, TF_FONT );
if( !success )
success = Con_LoadFixedWidthFont( "gfx/conchars", font, scale, kRenderTransAdd, TF_FONT );
success = Con_LoadFixedWidthFont( "gfx/conchars", font, scale, &hud_fontrender, TF_FONT );
// copy font size for client.dll
if( success )

View File

@@ -57,36 +57,6 @@ const char *cl_default_sprites[] =
"sprites/shellchrome.spr",
};
const char *cl_player_shell_sounds[] =
{
"player/pl_shell1.wav",
"player/pl_shell2.wav",
"player/pl_shell3.wav",
};
const char *cl_weapon_shell_sounds[] =
{
"weapons/sshell1.wav",
"weapons/sshell2.wav",
"weapons/sshell3.wav",
};
const char *cl_ricochet_sounds[] =
{
"weapons/ric1.wav",
"weapons/ric2.wav",
"weapons/ric3.wav",
"weapons/ric4.wav",
"weapons/ric5.wav",
};
const char *cl_explode_sounds[] =
{
"weapons/explode3.wav",
"weapons/explode4.wav",
"weapons/explode5.wav",
};
static void CL_PlayerDecal( int playerIndex, int textureIndex, int entityIndex, float *pos );
/*
@@ -148,6 +118,7 @@ client resources not precached by server
*/
void CL_AddClientResources( void )
{
const char *snd;
char filepath[MAX_QPATH];
int i;
@@ -163,37 +134,37 @@ void CL_AddClientResources( void )
}
// then check sounds
for( i = 0; i < ARRAYSIZE( cl_player_shell_sounds ); i++ )
for( i = 0; ( snd = SoundList_Get( BouncePlayerShell, i )); i++ )
{
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", cl_player_shell_sounds[i] );
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
if( !FS_FileExists( filepath, false ))
CL_AddClientResource( cl_player_shell_sounds[i], t_sound );
CL_AddClientResource( snd, t_sound );
}
for( i = 0; i < ARRAYSIZE( cl_weapon_shell_sounds ); i++ )
for( i = 0; ( snd = SoundList_Get( BounceWeaponShell, i )); i++ )
{
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", cl_weapon_shell_sounds[i] );
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
if( !FS_FileExists( filepath, false ))
CL_AddClientResource( cl_weapon_shell_sounds[i], t_sound );
CL_AddClientResource( snd, t_sound );
}
for( i = 0; i < ARRAYSIZE( cl_explode_sounds ); i++ )
for( i = 0; ( snd = SoundList_Get( Explode, i )); i++ )
{
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", cl_explode_sounds[i] );
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
if( !FS_FileExists( filepath, false ))
CL_AddClientResource( cl_explode_sounds[i], t_sound );
CL_AddClientResource( snd, t_sound );
}
#if 0 // ric sounds was precached by server-side
for( i = 0; i < ARRAYSIZE( cl_ricochet_sounds ); i++ )
for( i = 0; ( snd = SoundList_Get( Ricochet, i )); i++ )
{
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", cl_ricochet_sounds[i] );
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
if( !FS_FileExists( filepath, false ))
CL_AddClientResource( cl_ricochet_sounds[i], t_sound );
CL_AddClientResource( snd, t_sound );
}
#endif
}
@@ -301,7 +272,7 @@ play collide sound
static void CL_TempEntPlaySound( TEMPENTITY *pTemp, float damp )
{
float fvol;
char soundname[32];
const char *soundname = NULL;
qboolean isshellcasing = false;
int zvel;
@@ -312,36 +283,39 @@ static void CL_TempEntPlaySound( TEMPENTITY *pTemp, float damp )
switch( pTemp->hitSound )
{
case BOUNCE_GLASS:
Q_snprintf( soundname, sizeof( soundname ), "debris/glass%i.wav", COM_RandomLong( 1, 4 ));
soundname = SoundList_GetRandom( BounceGlass );
break;
case BOUNCE_METAL:
Q_snprintf( soundname, sizeof( soundname ), "debris/metal%i.wav", COM_RandomLong( 1, 6 ));
soundname = SoundList_GetRandom( BounceMetal );
break;
case BOUNCE_FLESH:
Q_snprintf( soundname, sizeof( soundname ), "debris/flesh%i.wav", COM_RandomLong( 1, 7 ));
soundname = SoundList_GetRandom( BounceFlesh );
break;
case BOUNCE_WOOD:
Q_snprintf( soundname, sizeof( soundname ), "debris/wood%i.wav", COM_RandomLong( 1, 4 ));
soundname = SoundList_GetRandom( BounceWood );
break;
case BOUNCE_SHRAP:
Q_strncpy( soundname, cl_ricochet_sounds[COM_RandomLong( 0, 4 )], sizeof( soundname ) );
soundname = SoundList_GetRandom( Ricochet );
break;
case BOUNCE_SHOTSHELL:
Q_strncpy( soundname, cl_weapon_shell_sounds[COM_RandomLong( 0, 2 )], sizeof( soundname ) );
soundname = SoundList_GetRandom( BounceWeaponShell );
isshellcasing = true; // shell casings have different playback parameters
fvol = 0.5f;
break;
case BOUNCE_SHELL:
Q_strncpy( soundname, cl_player_shell_sounds[COM_RandomLong( 0, 2 )], sizeof( soundname ) );
soundname = SoundList_GetRandom( BouncePlayerShell );
isshellcasing = true; // shell casings have different playback parameters
break;
case BOUNCE_CONCRETE:
Q_snprintf( soundname, sizeof( soundname ), "debris/concrete%i.wav", COM_RandomLong( 1, 3 ));
soundname = SoundList_GetRandom( BounceConcrete );
break;
default: // null sound
return;
}
if( !soundname )
return;
zvel = abs( pTemp->entity.baseline.origin[2] );
// only play one out of every n
@@ -1491,7 +1465,7 @@ void GAME_EXPORT R_FunnelSprite( const vec3_t org, int modelIndex, int reverse )
===============
R_SparkEffect
Create a streaks + richochet sprite
Create a streaks + ricochet sprite
===============
*/
void GAME_EXPORT R_SparkEffect( const vec3_t pos, int count, int velocityMin, int velocityMax )
@@ -1507,18 +1481,25 @@ R_RicochetSound
Make a random ricochet sound
==============
*/
static void R_RicochetSound_( const vec3_t pos, int sound )
static void R_RicochetSoundByName( const vec3_t pos, const char *name )
{
sound_t handle;
handle = S_RegisterSound( cl_ricochet_sounds[sound] );
sound_t handle;
handle = S_RegisterSound( name );
S_StartSound( pos, 0, CHAN_AUTO, handle, VOL_NORM, 1.0, 100, 0 );
}
static void R_RicochetSoundByIndex( const vec3_t pos, int idx )
{
const char *name = SoundList_Get( Ricochet, idx );
if( name )
R_RicochetSoundByName( pos, name );
}
void GAME_EXPORT R_RicochetSound( const vec3_t pos )
{
R_RicochetSound_( pos, COM_RandomLong( 0, 4 ));
const char *name = SoundList_GetRandom( Ricochet );
if( name )
R_RicochetSoundByName( pos, name );
}
/*
@@ -1665,8 +1646,12 @@ void GAME_EXPORT R_Explosion( vec3_t pos, int model, float scale, float framerat
if( !FBitSet( flags, TE_EXPLFLAG_NOSOUND ))
{
hSound = S_RegisterSound( cl_explode_sounds[COM_RandomLong( 0, 2 )] );
S_StartSound( pos, 0, CHAN_STATIC, hSound, VOL_NORM, 0.3f, PITCH_NORM, 0 );
const char *name = SoundList_GetRandom( Explode );
if( name )
{
hSound = S_RegisterSound( name );
S_StartSound( pos, 0, CHAN_STATIC, hSound, VOL_NORM, 0.3f, PITCH_NORM, 0 );
}
}
}
@@ -1909,6 +1894,7 @@ void CL_ParseTempEntity( sizebuf_t *msg )
cl_entity_t *pEnt;
dlight_t *dl;
sound_t hSound;
const char *name;
if( cls.legacymode )
iSize = MSG_ReadByte( msg );
@@ -1968,8 +1954,11 @@ void CL_ParseTempEntity( sizebuf_t *msg )
pos[2] = MSG_ReadCoord( &buf );
R_BlobExplosion( pos );
hSound = S_RegisterSound( cl_explode_sounds[0] );
S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 1.0f, PITCH_NORM, 0 );
if(( name = SoundList_Get( Explode, 0 )))
{
hSound = S_RegisterSound( name );
S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 1.0f, PITCH_NORM, 0 );
}
break;
case TE_SMOKE:
pos[0] = MSG_ReadCoord( &buf );
@@ -2022,8 +2011,11 @@ void CL_ParseTempEntity( sizebuf_t *msg )
dl->die = cl.time + 0.5;
dl->decay = 300;
hSound = S_RegisterSound( cl_explode_sounds[0] );
S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 0.6f, PITCH_NORM, 0 );
if(( name = SoundList_Get( Explode, 0 )))
{
hSound = S_RegisterSound( name );
S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 1.0f, PITCH_NORM, 0 );
}
break;
case TE_BSPDECAL:
case TE_DECAL:
@@ -2251,8 +2243,8 @@ void CL_ParseTempEntity( sizebuf_t *msg )
CL_DecalShoot( CL_DecalIndex( decalIndex ), entityIndex, 0, pos, 0 );
R_BulletImpactParticles( pos );
flags = COM_RandomLong( 0, 0x7fff );
if( flags < 0x3fff )
R_RicochetSound_( pos, flags % 5 );
if( flags < 0x3fff && ( count = SoundList_Count( Ricochet )))
R_RicochetSoundByIndex( pos, flags % count );
break;
case TE_SPRAY:
case TE_SPRITE_SPRAY:

View File

@@ -553,4 +553,6 @@ void V_PostRender( void )
ref.dllFuncs.R_AllowFog( true );
Platform_SetTimer( 0.0f );
ref.dllFuncs.R_EndFrame();
V_CheckGammaEnd();
}

View File

@@ -342,7 +342,7 @@ typedef struct
byte charWidths[256]; // scaled widths
int charHeight; // scaled height
int type; // fixed width font or variable
int rendermode; // default rendermode
convar_t *rendermode; // user-defined default rendermode
qboolean valid; // all rectangles are valid
} cl_font_t;
@@ -681,12 +681,14 @@ extern convar_t cl_draw_beams;
extern convar_t cl_clockreset;
extern convar_t cl_fixtimerate;
extern convar_t hud_fontscale;
extern convar_t hud_fontrender;
extern convar_t hud_scale;
extern convar_t hud_scale_minimal_width;
extern convar_t r_showtextures;
extern convar_t cl_bmodelinterp;
extern convar_t cl_lw; // local weapons
extern convar_t cl_charset;
extern convar_t cl_trace_stufftext;
extern convar_t cl_trace_messages;
extern convar_t cl_trace_events;
extern convar_t hud_utf8;
@@ -798,9 +800,10 @@ void CL_FireEvents( void );
// cl_font.c
//
qboolean CL_FixedFont( cl_font_t *font );
qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags );
qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags );
qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, convar_t *rendermode, uint texFlags );
qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float scale, convar_t *rendermode, uint texFlags );
void CL_FreeFont( cl_font_t *font );
void CL_SetFontRendermode( cl_font_t *font );
int CL_DrawCharacter( float x, float y, int number, rgba_t color, cl_font_t *font, int flags );
int CL_DrawString( float x, float y, const char *s, rgba_t color, cl_font_t *font, int flags );
void CL_DrawCharacterLen( cl_font_t *font, int number, int *width, int *height );

View File

@@ -25,6 +25,7 @@ GNU General Public License for more details.
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" );
CVAR_DEFINE_AUTO( con_fontsize, "1", FCVAR_ARCHIVE, "console font number (0, 1 or 2)" );
static CVAR_DEFINE_AUTO( con_fontrender, "2", FCVAR_ARCHIVE, "console font render mode (0: additive, 1: holes, 2: trans)" );
static CVAR_DEFINE_AUTO( con_charset, "cp1251", FCVAR_ARCHIVE, "console font charset (only cp1251 supported now)" );
static CVAR_DEFINE_AUTO( con_fontscale, "1.0", FCVAR_ARCHIVE, "scale font texture" );
static CVAR_DEFINE_AUTO( con_fontnum, "-1", FCVAR_ARCHIVE, "console font number (0, 1 or 2), -1 for autoselect" );
@@ -547,7 +548,7 @@ static void Con_LoadConsoleFont( int fontNumber, cl_font_t *font )
if( con_oldfont.value )
{
success = Con_LoadVariableWidthFont( "gfx/conchars.fnt", font, scale, kRenderTransTexture, TF_FONT|TF_NEAREST );
success = Con_LoadVariableWidthFont( "gfx/conchars.fnt", font, scale, &con_fontrender, TF_FONT|TF_NEAREST );
}
else
{
@@ -560,14 +561,14 @@ static void Con_LoadConsoleFont( int fontNumber, cl_font_t *font )
if( Q_snprintf( path, sizeof( path ),
"font%i_%s.fnt", fontNumber, Cvar_VariableString( "con_charset" )) > 0 )
{
success = Con_LoadVariableWidthFont( path, font, scale, kRenderTransTexture, TF_FONT|TF_NEAREST );
success = Con_LoadVariableWidthFont( path, font, scale, &con_fontrender, TF_FONT|TF_NEAREST );
}
}
if( !success )
{
Q_snprintf( path, sizeof( path ), "fonts/font%i", fontNumber );
success = Con_LoadVariableWidthFont( path, font, scale, kRenderTransTexture, TF_FONT|TF_NEAREST );
success = Con_LoadVariableWidthFont( path, font, scale, &con_fontrender, TF_FONT|TF_NEAREST );
}
}
@@ -575,7 +576,7 @@ static void Con_LoadConsoleFont( int fontNumber, cl_font_t *font )
{
// quake fixed font as fallback
// keep source to print directly into conback image
if( !Con_LoadFixedWidthFont( "gfx/conchars", font, scale, kRenderTransTexture, TF_FONT|TF_NEAREST|TF_KEEP_SOURCE ))
if( !Con_LoadFixedWidthFont( "gfx/conchars", font, scale, &con_fontrender, TF_FONT|TF_NEAREST|TF_KEEP_SOURCE ))
Con_DPrintf( S_ERROR "failed to load console font\n" );
}
}
@@ -840,6 +841,7 @@ void Con_Init( void )
Cvar_RegisterVariable( &con_fontsize );
Cvar_RegisterVariable( &con_charset );
Cvar_RegisterVariable( &con_fontscale );
Cvar_RegisterVariable( &con_fontrender );
Cvar_RegisterVariable( &con_fontnum );
Cvar_RegisterVariable( &con_color );
Cvar_RegisterVariable( &scr_drawversion );
@@ -2098,9 +2100,13 @@ void Con_RunConsole( void )
// decide on the destination height of the console
if( host.allow_console && cls.key_dest == key_console )
{
#if XASH_MOBILE_PLATFORM
con.showlines = refState.height; // always full screen on mobile devices
#else
if( cls.state < ca_active || cl.first_frame )
con.showlines = refState.height; // full screen
else con.showlines = (refState.height >> 1); // half screen
#endif
}
else con.showlines = 0; // none visible
@@ -2185,6 +2191,8 @@ INTERNAL RESOURCE
*/
void Con_VidInit( void )
{
const uint flags = TF_IMAGE|TF_ALLOW_NEAREST;
if( !con.historyLoaded )
{
Con_LoadHistory( &con.history );
@@ -2204,28 +2212,28 @@ void Con_VidInit( void )
{
// trying to load truecolor image first
if( FS_FileExists( "gfx/shell/conback.bmp", false ) || FS_FileExists( "gfx/shell/conback.tga", false ))
con.background = ref.dllFuncs.GL_LoadTexture( "gfx/shell/conback", NULL, 0, TF_IMAGE );
con.background = ref.dllFuncs.GL_LoadTexture( "gfx/shell/conback", NULL, 0, flags );
if( !con.background )
{
if( FS_FileExists( "cached/conback640", false ))
con.background = ref.dllFuncs.GL_LoadTexture( "cached/conback640", NULL, 0, TF_IMAGE );
con.background = ref.dllFuncs.GL_LoadTexture( "cached/conback640", NULL, 0, flags );
else if( FS_FileExists( "cached/conback", false ))
con.background = ref.dllFuncs.GL_LoadTexture( "cached/conback", NULL, 0, TF_IMAGE );
con.background = ref.dllFuncs.GL_LoadTexture( "cached/conback", NULL, 0, flags );
}
}
else
{
// trying to load truecolor image first
if( FS_FileExists( "gfx/shell/loading.bmp", false ) || FS_FileExists( "gfx/shell/loading.tga", false ))
con.background = ref.dllFuncs.GL_LoadTexture( "gfx/shell/loading", NULL, 0, TF_IMAGE );
con.background = ref.dllFuncs.GL_LoadTexture( "gfx/shell/loading", NULL, 0, flags );
if( !con.background )
{
if( FS_FileExists( "cached/loading640", false ))
con.background = ref.dllFuncs.GL_LoadTexture( "cached/loading640", NULL, 0, TF_IMAGE );
con.background = ref.dllFuncs.GL_LoadTexture( "cached/loading640", NULL, 0, flags );
else if( FS_FileExists( "cached/loading", false ))
con.background = ref.dllFuncs.GL_LoadTexture( "cached/loading", NULL, 0, TF_IMAGE );
con.background = ref.dllFuncs.GL_LoadTexture( "cached/loading", NULL, 0, flags );
}
}

View File

@@ -21,6 +21,7 @@ GNU General Public License for more details.
//-----------------------------------------------------------------------------
// Gamma conversion support
//-----------------------------------------------------------------------------
static qboolean gamma_rebuilt;
static byte texgammatable[256];
static uint lightgammatable[1024];
static uint lineargammatable[1024];
@@ -82,9 +83,6 @@ static void BuildGammaTable( const float gamma, const float brightness, const fl
static void V_ValidateGammaCvars( void )
{
if( Host_IsLocalGame( ))
return;
if( v_gamma.value < 1.8f )
Cvar_DirectSet( &v_gamma, "1.8" );
else if( v_gamma.value > 3.0f )
@@ -102,14 +100,13 @@ static void V_ValidateGammaCvars( void )
if( v_brightness.value < 0.0f )
Cvar_DirectSet( &v_brightness, "0" );
else if( v_brightness.value > 2.0f )
Cvar_DirectSet( &v_brightness, "2" );
else if( v_brightness.value > 3.0f )
Cvar_DirectSet( &v_brightness, "3" );
}
void V_CheckGamma( void )
{
static qboolean dirty = false;
qboolean notify_refdll = false;
// because these cvars were defined as archive
// but wasn't doing anything useful
@@ -135,20 +132,33 @@ void V_CheckGamma( void )
V_ValidateGammaCvars();
dirty = false;
gamma_rebuilt = true;
BuildGammaTable( v_gamma.value, v_brightness.value, v_texgamma.value, v_lightgamma.value );
// force refdll to recalculate lightmaps
notify_refdll = true;
if( ref.initialized )
ref.dllFuncs.R_GammaChanged( false );
}
}
// unfortunately, recalculating textures isn't possible yet
void V_CheckGammaEnd( void )
{
// don't reset changed flag if it was set during frame
// keep it for next frame
if( !gamma_rebuilt )
return;
gamma_rebuilt = false;
// keep the flags until the end of frame so client.dll will catch these changes
if( FBitSet( v_texgamma.flags|v_lightgamma.flags|v_brightness.flags|v_gamma.flags, FCVAR_CHANGED ))
{
ClearBits( v_texgamma.flags, FCVAR_CHANGED );
ClearBits( v_lightgamma.flags, FCVAR_CHANGED );
ClearBits( v_brightness.flags, FCVAR_CHANGED );
ClearBits( v_gamma.flags, FCVAR_CHANGED );
}
if( notify_refdll && ref.initialized )
ref.dllFuncs.R_GammaChanged( false );
}
void V_Init( void )

View File

@@ -2029,10 +2029,18 @@ int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx
{
touch.move_finger = touch.resize_finger = touch.look_finger = -1;
// Hack for keyboard, hope it help
// a1ba: this is absolutely horrible
if( cls.key_dest == key_console || cls.key_dest == key_message )
{
if ( type == event_down ) // don't pop it again on event_up
static float x1 = 0.0f;
x1 += dx;
if( type == event_up ) // don't show keyboard on every tap
{
Key_EnableTextInput( true, true );
x1 = 0.0f;
}
if( cls.key_dest == key_console )
{
static float y1 = 0;
@@ -2054,6 +2062,13 @@ int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx
// exit of console area
if( type == event_down && x < 0.1f && y > 0.9f )
Cbuf_AddText( "escape\n" );
// swipe from edge to exit console/chat
if(( x > 0.8f && x1 < -0.1f ) || ( x < 0.2f && x1 > 0.1f ))
{
Cbuf_AddText( "escape\n" );
x1 = 0.0f;
}
}
UI_MouseMove( TO_SCRN_X(x), TO_SCRN_Y(y) );
//MsgDev( D_NOTE, "touch %d %d\n", TO_SCRN_X(x), TO_SCRN_Y(y) );

View File

@@ -611,6 +611,7 @@ qboolean R_Init( void )
// cvars that are expected to exist by client.dll
// refdll should just get pointer to them
Cvar_Get( "r_lighting_modulate", "0.6", FCVAR_ARCHIVE, "compatibility cvar, does nothing" );
Cvar_Get( "r_drawentities", "1", FCVAR_CHEAT, "render entities" );
Cvar_Get( "cl_himodels", "1", FCVAR_ARCHIVE, "draw high-resolution player models in multiplayer" );

View File

@@ -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_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" );
CVAR_DEFINE_AUTO( snd_mute_losefocus, "1", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "silence the audio when game window loses focus" );
static 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_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" );
@@ -64,6 +64,12 @@ float S_GetMasterVolume( void )
{
float scale = 1.0f;
if( host.status == HOST_NOFOCUS && snd_mute_losefocus.value != 0.0f )
{
// we return zero volume to keep sounds running
return 0.0f;
}
if( !s_listener.inmenu && soundfade.percent != 0 )
{
scale = bound( 0.0f, soundfade.percent / 100.0f, 1.0f );

View File

@@ -221,7 +221,6 @@ extern convar_t s_musicvolume;
extern convar_t s_lerping;
extern convar_t s_test; // cvar to testify new effects
extern convar_t s_samplecount;
extern convar_t snd_mute_losefocus;
extern convar_t s_warn_late_precache;
void S_InitScaletable( void );

View File

@@ -20,8 +20,6 @@ GNU General Public License for more details.
#include "vid_common.h"
#include "platform/platform.h"
static CVAR_DEFINE( window_width, "width", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen width" );
static CVAR_DEFINE( window_height, "height", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen height" );
static CVAR_DEFINE_AUTO( vid_mode, "0", FCVAR_RENDERINFO, "current video mode index (used only for storage)" );
static CVAR_DEFINE_AUTO( vid_rotate, "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen rotation (0-3)" );
static CVAR_DEFINE_AUTO( vid_scale, "1.0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "pixel scale" );
@@ -29,6 +27,8 @@ static CVAR_DEFINE_AUTO( vid_scale, "1.0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "p
CVAR_DEFINE_AUTO( vid_highdpi, "1", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "enable High-DPI mode" );
CVAR_DEFINE_AUTO( vid_maximized, "0", FCVAR_RENDERINFO, "window maximized state, read-only" );
CVAR_DEFINE( vid_fullscreen, "fullscreen", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "fullscreen state (0 windowed, 1 fullscreen, 2 borderless)" );
CVAR_DEFINE( window_width, "width", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen width" );
CVAR_DEFINE( window_height, "height", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen height" );
CVAR_DEFINE( window_xpos, "_window_xpos", "-1", FCVAR_RENDERINFO, "window position by horizontal" );
CVAR_DEFINE( window_ypos, "_window_ypos", "-1", FCVAR_RENDERINFO, "window position by vertical" );

View File

@@ -38,6 +38,8 @@ extern glwstate_t glw_state;
extern convar_t vid_fullscreen;
extern convar_t vid_maximized;
extern convar_t vid_highdpi;
extern convar_t window_width;
extern convar_t window_height;
extern convar_t window_xpos;
extern convar_t window_ypos;
extern convar_t gl_msaa_samples;

View File

@@ -529,7 +529,6 @@ typedef struct cmd_s
static int cmd_argc;
static const char *cmd_args = NULL;
static char *cmd_argv[MAX_CMD_TOKENS];
static char cmd_tokenized[MAX_CMD_BUFFER]; // will have 0 bytes inserted
static cmd_t *cmd_functions; // possible commands to execute
/*

View File

@@ -17,15 +17,24 @@ GNU General Public License for more details.
#define COM_STRINGS_H
// default colored message headers
#define S_NOTE "^2Note:^7 "
#define S_WARN "^3Warning:^7 "
#define S_ERROR "^1Error:^7 "
#define S_USAGE "Usage: "
#define S_USAGE_INDENT " "
#define S_BLACK "^0"
#define S_RED "^1"
#define S_GREEN "^2"
#define S_YELLOW "^3"
#define S_BLUE "^4"
#define S_CYAN "^5"
#define S_MAGENTA "^6"
#define S_DEFAULT "^7"
#define S_OPENGL_NOTE "^2OpenGL Note:^7 "
#define S_OPENGL_WARN "^3OpenGL Warning:^7 "
#define S_OPENGL_ERROR "^3OpenGL Error:^7 "
#define S_NOTE S_GREEN "Note: " S_DEFAULT
#define S_WARN S_YELLOW "Warning: " S_DEFAULT
#define S_ERROR S_RED "Error: " S_DEFAULT
#define S_USAGE "Usage: "
#define S_USAGE_INDENT "\t"
#define S_OPENGL_NOTE S_GREEN "OpenGL Note: " S_DEFAULT
#define S_OPENGL_WARN S_YELLOW "OpenGL Warning: " S_DEFAULT
#define S_OPENGL_ERROR S_RED "OpenGL Error: " S_DEFAULT
// end game final default message
#define DEFAULT_ENDGAME_MESSAGE "The End"

View File

@@ -693,7 +693,7 @@ COM_LoadFileForMe
byte *GAME_EXPORT COM_LoadFileForMe( const char *filename, int *pLength )
{
string name;
byte *file, *pfile;
byte *pfile;
fs_offset_t iLength;
if( !COM_CheckString( filename ))
@@ -706,21 +706,9 @@ byte *GAME_EXPORT COM_LoadFileForMe( const char *filename, int *pLength )
Q_strncpy( name, filename, sizeof( name ));
COM_FixSlashes( name );
pfile = FS_LoadFile( name, &iLength, false );
pfile = g_fsapi.LoadFileMalloc( name, &iLength, false );
if( pLength ) *pLength = (int)iLength;
if( pfile )
{
file = malloc( iLength + 1 );
if( file != NULL )
{
memcpy( file, pfile, iLength );
file[iLength] = '\0';
}
Mem_Free( pfile );
pfile = file;
}
return pfile;
}

View File

@@ -795,6 +795,7 @@ uint ScreenGammaTable( uint );
uint LinearGammaTable( uint );
void V_Init( void );
void V_CheckGamma( void );
void V_CheckGammaEnd( void );
//
// identification.c
@@ -815,6 +816,34 @@ void NET_MasterClear( void );
void NET_MasterShutdown( void );
qboolean NET_GetMaster( netadr_t from, uint *challenge, double *last_heartbeat );
//
// sounds.c
//
typedef enum soundlst_group_e
{
BouncePlayerShell = 0,
BounceWeaponShell,
BounceConcrete,
BounceGlass,
BounceMetal,
BounceFlesh,
BounceWood,
Ricochet,
Explode,
PlayerWaterEnter,
PlayerWaterExit,
EntityWaterEnter,
EntityWaterExit,
SoundList_Groups // must be last
} soundlst_group_t;
int SoundList_Count( soundlst_group_t group );
const char *SoundList_GetRandom( soundlst_group_t group );
const char *SoundList_Get( soundlst_group_t group, int idx );
void SoundList_Init( void );
void SoundList_Shutdown( void );
#ifdef REF_DLL
#error "common.h in ref_dll"
#endif

View File

@@ -490,13 +490,14 @@ static void Sys_Crash( int signal, siginfo_t *si, void *context)
#ifdef XASH_SDL
SDL_SetWindowGrab( host.hWnd, SDL_FALSE );
#endif
host.crashed = true;
Platform_MessageBox( "Xash Error", message, false );
// log saved, now we can try to save configs and close log correctly, it may crash
if( host.type == HOST_NORMAL )
CL_Crashed();
host.status = HOST_CRASHED;
host.crashed = true;
Sys_Quit();
}

View File

@@ -109,6 +109,7 @@ static void Sys_PrintUsage( void )
O("-clockwindow <cw>", "adjust clockwindow used to ignore client commands to prevent speed hacks")
"\nGame options:\n"
O("-game <directory>", "set game directory to start engine with")
O("-dll <path> ", "override server DLL path")
#if !XASH_DEDICATED
O("-clientlib <path>", "override client DLL path")
@@ -1310,6 +1311,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
HTTP_Init();
ID_Init();
SoundList_Init();
if( Host_IsDedicated() )
{
@@ -1412,6 +1414,7 @@ void EXPORT Host_Shutdown( void )
SV_ShutdownFilter();
CL_Shutdown();
SoundList_Shutdown();
Mod_Shutdown();
NET_Shutdown();
HTTP_Shutdown();

View File

@@ -28,7 +28,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, fs_offset_t filesi
rgba_t palette[256] = { 0 };
int i, columns, column, rows, row, bpp = 1;
int cbPalBytes = 0, padSize = 0, bps = 0;
int reflectivity[3] = { 0, 0, 0 };
uint reflectivity[3] = { 0, 0, 0 };
qboolean load_qfont = false;
bmp_t bhdr;
fs_offset_t estimatedSize;

View File

@@ -70,6 +70,7 @@ static qboolean Image_KTX2Parse( const ktx2_header_t *header, const byte *buffer
ktx2_index_t index;
size_t total_size = 0;
size_t max_offset = 0;
int mip, cursor;
const byte *const levels_begin = buffer + KTX2_LEVELS_OFFSET;
// Sets image.type and image.flags
@@ -125,7 +126,7 @@ static qboolean Image_KTX2Parse( const ktx2_header_t *header, const byte *buffer
memcpy( &index, buffer + KTX2_IDENTIFIER_SIZE + sizeof( ktx2_header_t ), sizeof( index ));
for( int mip = 0; mip < header->levelCount; ++mip )
for( mip = 0; mip < header->levelCount; ++mip )
{
const uint32_t width = Q_max( 1, ( header->pixelWidth >> mip ));
const uint32_t height = Q_max( 1, ( header->pixelHeight >> mip ));
@@ -154,7 +155,7 @@ static qboolean Image_KTX2Parse( const ktx2_header_t *header, const byte *buffer
image.rgba = Mem_Malloc( host.imagepool, image.size );
memcpy( image.rgba, buffer, image.size );
for( int mip = 0, cursor = 0; mip < header->levelCount; ++mip )
for( mip = 0, cursor = 0; mip < header->levelCount; ++mip )
{
ktx2_level_t level;
memcpy( &level, levels_begin + mip * sizeof( level ), sizeof( level ));

View File

@@ -29,7 +29,7 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi
rgba_t palette[256];
byte red = 0, green = 0, blue = 0, alpha = 0;
int readpixelcount, pixelcount;
int reflectivity[3] = { 0, 0, 0 };
uint reflectivity[3] = { 0, 0, 0 };
qboolean compressed;
tga_t targa_header;

View File

@@ -360,7 +360,7 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
byte *fin, *pal;
int ofs[4], rendermode;
int i, pixels, numcolors;
int reflectivity[3] = { 0, 0, 0 };
uint reflectivity[3] = { 0, 0, 0 };
if( filesize < sizeof( mip ))
return false;

View File

@@ -2026,6 +2026,14 @@ static qboolean Mod_LooksLikeWaterTexture( const char *name )
return false;
}
static qboolean Mod_LooksLikeReflectiveTexture( const char *name )
{
if( !Q_strcmp( name, "reflect1" ) || !Q_strncmp( name, "!reflect", 8 ))
return true;
return false;
}
static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureIndex )
{
#if !XASH_DEDICATED
@@ -2480,6 +2488,13 @@ static void Mod_LoadSurfaces( model_t *mod, dbspmodel_t *bmod )
if( !Q_strncmp( tex->name, "{scroll", 7 ))
SetBits( out->flags, SURF_CONVEYOR|SURF_TRANSPARENT );
// some mods don't work with mirrors or make random surfaces reflective
if( FBitSet( host.features, ENGINE_ALLOW_MIRRORS ) && Mod_LooksLikeReflectiveTexture( tex->name ))
{
SetBits( world.flags, FWORLD_HAS_MIRRORS );
SetBits( out->flags, SURF_REFLECT );
}
if( tex->name[0] == '{' )
SetBits( out->flags, SURF_TRANSPARENT );
@@ -2697,6 +2712,9 @@ static void Mod_LoadLeafs( model_t *mod, dbspmodel_t *bmod )
{
// mark underwater surfaces
SetBits( out->firstmarksurface[j]->flags, SURF_UNDERWATER );
// underwater surfaces can't have reflection (performance)
ClearBits( out->firstmarksurface[j]->flags, SURF_REFLECT );
}
}
}

View File

@@ -127,7 +127,7 @@ GNU General Public License for more details.
#define MAX_CUSTOM (1<<MAX_CUSTOM_BITS)// 10 bits == 1024 generic file
#define MAX_USER_MESSAGES 197 // another 58 messages reserved for engine routines
#define MAX_DLIGHTS 32 // dynamic lights (rendered per one frame)
#define MAX_ELIGHTS 64 // entity only point lights
#define MAX_ELIGHTS 128 // a1ba: increased from 64 to 128, entity only point lights
#define MAX_LIGHTSTYLES 256 // a1ba: increased from 64 to 256, protocol limit
#define MAX_RENDER_DECALS 4096 // max rendering decals per a level

362
engine/common/sounds.c Normal file
View File

@@ -0,0 +1,362 @@
/*
sounds.c - sounds.lst parser
Copyright (C) 2024 Alibek Omarov
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "common.h"
enum soundlst_type_e
{
SoundList_None,
SoundList_Range,
SoundList_List
};
static const char *soundlst_groups[SoundList_Groups] =
{
"BouncePlayerShell",
"BounceWeaponShell",
"BounceConcrete",
"BounceGlass",
"BounceMetal",
"BounceFlesh",
"BounceWood",
"Ricochet",
"Explode",
"PlayerWaterEnter",
"PlayerWaterExit",
"EntityWaterEnter",
"EntityWaterExit",
};
typedef struct soundlst_s
{
enum soundlst_type_e type;
char *snd;
int min; // the string length if type is group
int max; // the string count if type is group
} soundlst_t;
soundlst_t soundlst[SoundList_Groups];
static void SoundList_Print_f( void );
static void SoundList_Free( soundlst_t *lst )
{
if( lst->snd )
Mem_Free( lst->snd );
memset( lst, 0, sizeof( *lst ));
}
void SoundList_Shutdown( void )
{
int i;
for( i = 0; i < SoundList_Groups; i++ )
SoundList_Free( &soundlst[i] );
}
int SoundList_Count( enum soundlst_group_e group )
{
soundlst_t *lst = &soundlst[group];
switch( lst->type )
{
case SoundList_Range:
return lst->max - lst->min + 1;
case SoundList_List:
return lst->max;
}
return 0;
}
const char *SoundList_Get( enum soundlst_group_e group, int i )
{
static string temp;
soundlst_t *lst = &soundlst[group];
if( i < 0 || i >= SoundList_Count( group ))
return NULL;
switch( lst->type )
{
case SoundList_Range:
Q_snprintf( temp, sizeof( temp ), lst->snd, lst->min + i );
return temp;
case SoundList_List:
return &lst->snd[i * lst->min];
}
return NULL;
}
const char *SoundList_GetRandom( enum soundlst_group_e group )
{
int count = SoundList_Count( group );
int idx = COM_RandomLong( 0, count - 1 );
// Con_Printf( "%s: %s %d %d\n", __func__, soundlst_groups[group], count, idx );
return SoundList_Get( group, idx );
}
static qboolean SoundList_ParseGroup( soundlst_t *lst, char **file )
{
string token;
int count = 0, slen = 0, i;
char *p;
p = *file;
while(( p = COM_ParseFile( p, token, sizeof( token ))))
{
int len;
if( !Q_strcmp( token, "}" ))
break;
if( !Q_strcmp( token, "{" ))
{
Con_Printf( "%s: expected '}' but got '{' during group list parse\n", __func__ );
return false;
}
else if( !COM_CheckStringEmpty( token ))
{
Con_Printf( "%s: expected '}' but got EOF during group list parse\n", __func__ );
return false;
}
len = Q_strlen( token ) + 1;
if( slen < len )
slen = len;
count++;
}
if( count == 0 ) // deactivate group
{
lst->type = SoundList_None;
lst->snd = NULL;
lst->min = lst->max = 0;
return true;
}
lst->type = SoundList_List;
lst->min = slen;
lst->max = count;
lst->snd = Mem_Malloc( host.mempool, count * slen ); // allocate single buffer for the whole group
for( i = 0; i < count; i++ )
{
*file = COM_ParseFile( *file, token, sizeof( token ));
Q_strncpy( &lst->snd[i * slen], token, slen );
}
return true;
}
static qboolean SoundList_ParseRange( soundlst_t *lst, char **file )
{
string token, snd;
char *p;
int i = 0;
lst->type = SoundList_Range;
*file = COM_ParseFile( *file, snd, sizeof( snd ));
// validate format string, count all % characters
p = snd;
i = 0;
while(( p = Q_strchr( p, '%' )))
{
// only decimal
if( p[1] != 'd' && p[1] != 'i' && p[1] != 'u' )
{
Con_Printf( "%s: invalid range string %s, only decimal numbers are allowed", __func__, snd );
return false;
}
i++;
p++;
}
// if more than one %, then it's an invalid format string
if( i != 1 )
{
Con_Printf( "%s: invalid range string %s, only single specifier is allowed\n", __func__, snd );
return false;
}
*file = COM_ParseFile( *file, token, sizeof( token ));
if( !Q_isdigit( token ))
{
Con_Printf( "%s: %s must be a digit\n", __func__, token );
return false;
}
lst->min = Q_atoi( token );
*file = COM_ParseFile( *file, token, sizeof( token ));
if( !Q_isdigit( token ))
{
Con_Printf( "%s: %s must be a digit\n", __func__, token );
return false;
}
lst->max = Q_atoi( token );
lst->snd = copystring( snd );
return true;
}
static qboolean SoundList_Parse( char *file )
{
string token;
int i;
while(( file = COM_ParseFile( file, token, sizeof( token ))))
{
soundlst_t *lst = NULL;
char *p;
for( i = 0; i < SoundList_Groups; i++ )
{
if( !Q_strcmp( token, soundlst_groups[i] ))
{
lst = &soundlst[i];
break;
}
}
if( !lst )
{
Con_Printf( "%s: unexpected token %s, must be group name\n", __func__, token );
goto cleanup;
}
p = COM_ParseFile( file, token, sizeof( token ));
// group is a range
if( !Q_strcmp( token, "{" ))
{
file = p; // advance pointer
if( !SoundList_ParseGroup( lst, &file ))
goto cleanup;
file = COM_ParseFile( file, token, sizeof( token ));
if( Q_strcmp( token, "}" ))
{
Con_Printf( "%s: unexpected token %s, must be }\n", __func__, token );
goto cleanup;
}
}
else
{
// ranges are more simple, but need to rewind pointer for them
if( !SoundList_ParseRange( lst, &file ))
goto cleanup;
}
}
if( host_developer.value >= 2 )
SoundList_Print_f();
return true;
cleanup:
SoundList_Shutdown();
return false;
}
static void SoundList_Print_f( void )
{
int i;
for( i = 0; i < SoundList_Groups; i++ )
{
soundlst_t *lst = &soundlst[i];
switch( lst->type )
{
case SoundList_Range:
Con_Reportf( "%-16s\t" S_CYAN "Range" S_DEFAULT " %s [%d; %d]\n",
soundlst_groups[i], lst->snd, lst->min, lst->max );
break;
case SoundList_List:
{
int j;
Con_Reportf( "%-16s\t" S_MAGENTA "List" S_DEFAULT " [", soundlst_groups[i] );
for( j = 0; j < lst->max; j++ )
Con_Reportf( "%s%s", &lst->snd[j * lst->min], j + 1 == lst->max ? "" : ", " );
Con_Reportf( "]\n" );
break;
}
default:
Con_Reportf( "%-16s\t" S_RED "inactive" S_DEFAULT "\n", soundlst_groups[i] );
break;
}
}
}
// I wish we had #embed already
static const char default_sounds_lst[] =
"BouncePlayerShell \"player/pl_shell%d.wav\" 1 3\n"
"BounceWeaponShell \"weapons/sshell%d.wav\" 1 3\n"
"BounceConcrete \"debris/concrete%d.wav\" 1 3\n"
"BounceGlass \"debris/glass%d.wav\" 1 4\n"
"BounceMetal \"debris/metal%d.wav\" 1 6\n"
"BounceFlesh \"debris/flesh%d.wav\" 1 7\n"
"BounceWood \"debris/wood%d.wav\" 1 4\n"
"Ricochet \"weapons/ric%d.wav\" 1 5\n"
"Explode \"weapons/explode%d.wav\" 3 5\n"
"EntityWaterEnter \"player/pl_wade%d.wav\" 1 4\n"
"EntityWaterExit \"player/pl_wade%d.wav\" 1 4\n"
"PlayerWaterEnter\n"
"{\n"
" \"player/pl_wade1.wav\"\n"
"}\n"
"\n"
"PlayerWaterExit\n"
"{\n"
" \"player/pl_wade2.wav\"\n"
"}\n";
static void SoundList_Reload_f( void )
{
qboolean load_internal = false;
char *pfile = FS_LoadFile( "scripts/sounds.lst", NULL, false );
if( pfile )
{
if( !SoundList_Parse( pfile ))
{
Con_Printf( S_ERROR "can't parse sounds.lst file, loading internal...\n" );
load_internal = true;
}
Mem_Free( pfile );
}
else load_internal = true;
if( load_internal )
SoundList_Parse( (char *)default_sounds_lst );
}
void SoundList_Init( void )
{
Cmd_AddRestrictedCommand( "host_soundlist_print", SoundList_Print_f, "print current sound list" );
Cmd_AddRestrictedCommand( "host_soundlist_reload", SoundList_Reload_f, "reload sound list" );
SoundList_Reload_f ();
}

View File

@@ -19,6 +19,10 @@ GNU General Public License for more details.
#include <stdlib.h>
#include <errno.h>
#if _MSC_VER
#include <intrin.h>
#endif
#ifdef XASH_SDL
#include <SDL.h>
#endif
@@ -68,17 +72,15 @@ Sys_DebugBreak
*/
void Sys_DebugBreak( void )
{
#if XASH_LINUX || ( XASH_WIN32 && !XASH_64BIT )
#if _MSC_VER
if( Sys_DebuggerPresent() )
_asm { int 3 }
#elif XASH_X86
if( Sys_DebuggerPresent() )
asm volatile( "int $3;" );
#else
if( Sys_DebuggerPresent() )
raise( SIGINT );
#endif
if( Sys_DebuggerPresent( ))
__debugbreak();
#else // !_MSC_VER
if( Sys_DebuggerPresent( ))
{
INLINE_RAISE( SIGINT );
INLINE_NANOSLEEP1(); // sometimes signal comes with delay, let it interrupt nanosleep
}
#endif
}

View File

@@ -93,123 +93,241 @@ static mempool_t *Mem_FindPool( poolhandle_t poolptr )
}
#endif
static inline void Mem_PoolAdd( mempool_t *pool, size_t size )
{
pool->totalsize += size;
pool->realsize += sizeof( memheader_t ) + size + sizeof( byte );
}
static inline void Mem_PoolSubtract( mempool_t *pool, size_t size )
{
pool->totalsize -= size;
pool->realsize -= sizeof( memheader_t ) + size + sizeof( byte );
}
static inline void Mem_PoolLinkAlloc( mempool_t *pool, memheader_t *mem )
{
mem->next = pool->chain;
if( mem->next ) mem->next->prev = mem;
pool->chain = mem;
mem->prev = NULL;
mem->pool = pool;
}
static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
{
if( mem->next ) mem->next->prev = mem->prev;
if( mem->prev ) mem->prev->next = mem->next;
else pool->chain = mem->next;
mem->pool = NULL;
}
static inline void Mem_InitAlloc( memheader_t *mem, size_t size, const char *filename, int fileline )
{
mem->size = size;
mem->filename = filename;
mem->fileline = fileline;
mem->sentinel1 = MEMHEADER_SENTINEL1;
*((byte *)mem + sizeof( memheader_t ) + mem->size ) = MEMHEADER_SENTINEL2;
}
static const char *Mem_CheckFilename( const char *filename )
{
static const char *dummy = "<corrupted>\0";
if( !COM_CheckString( filename ))
return dummy;
if( memchr( filename, '\0', MAX_OSPATH ) != NULL )
return filename;
return dummy;
}
static qboolean Mem_CheckAllocHeader( const char *func, const memheader_t *mem, const char *filename, int fileline )
{
const char *memfilename;
if( mem->sentinel1 != MEMHEADER_SENTINEL1 )
{
memfilename = Mem_CheckFilename( mem->filename );
Sys_Error( "%s: trashed header sentinel 1 (alloc at %s:%i, check at %s:%i)\n", func, memfilename, mem->fileline, filename, fileline );
return false;
}
if( *((byte *)mem + sizeof( memheader_t ) + mem->size ) != MEMHEADER_SENTINEL2 )
{
memfilename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
Sys_Error( "%s: trashed header sentinel 2 (alloc at %s:%i, check at %s:%i)\n", func, memfilename, mem->fileline, filename, fileline );
return false;
}
return true;
}
static qboolean Mem_CheckPool( const char *func, const mempool_t *pool, const char *filename, int fileline )
{
if( pool->sentinel1 != MEMHEADER_SENTINEL1 )
{
Sys_Error( "%s: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)\n", func, pool->filename, pool->fileline, filename, fileline );
return false;
}
if( pool->sentinel2 != MEMHEADER_SENTINEL1 )
{
Sys_Error( "%s: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)\n", func, pool->filename, pool->fileline, filename, fileline );
return false;
}
return true;
}
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
{
memheader_t *mem;
mempool_t *pool;
if( size <= 0 ) return NULL;
if( !poolptr ) Sys_Error( "Mem_Alloc: pool == NULL (alloc at %s:%i)\n", filename, fileline );
if( size <= 0 )
return NULL;
if( !poolptr )
{
Sys_Error( "%s: pool == NULL (alloc at %s:%i)\n", __func__, filename, fileline );
return NULL;
}
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( byte ));
if( mem == NULL )
{
Sys_Error( "%s: out of memory (alloc size %s at %s:%i)\n", __func__, Q_memprint( size ), filename, fileline );
return NULL;
}
Mem_InitAlloc( mem, size, filename, fileline );
pool = Mem_FindPool( poolptr );
Mem_PoolAdd( pool, size );
Mem_PoolLinkAlloc( pool, mem );
pool->totalsize += size;
// big allocations are not clumped
pool->realsize += sizeof( memheader_t ) + size + sizeof( size_t );
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( size_t ));
if( mem == NULL ) Sys_Error( "Mem_Alloc: out of memory (alloc at %s:%i)\n", filename, fileline );
mem->filename = filename;
mem->fileline = fileline;
mem->size = size;
mem->pool = pool;
mem->sentinel1 = MEMHEADER_SENTINEL1;
// we have to use only a single byte for this sentinel, because it may not be aligned
// and some platforms can't use unaligned accesses
*((byte *)mem + sizeof( memheader_t ) + mem->size ) = MEMHEADER_SENTINEL2;
// append to head of list
mem->next = pool->chain;
mem->prev = NULL;
pool->chain = mem;
if( mem->next ) mem->next->prev = mem;
if( clear )
memset((void *)((byte *)mem + sizeof( memheader_t )), 0, mem->size );
return (void *)((byte *)mem + sizeof( memheader_t ));
}
static const char *Mem_CheckFilename( const char *filename )
{
static const char *dummy = "<corrupted>\0";
const char *out = filename;
int i;
if( !COM_CheckString( out ))
return dummy;
for( i = 0; i < MAX_OSPATH; i++, out++ )
{
if( *out == '\0' )
return filename; // valid name
}
return dummy;
}
static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline )
{
mempool_t *pool;
if( mem->sentinel1 != MEMHEADER_SENTINEL1 )
{
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
Sys_Error( "Mem_Free: trashed header sentinel 1 (alloc at %s:%i, free at %s:%i)\n", mem->filename, mem->fileline, filename, fileline );
}
if( *((byte *)mem + sizeof( memheader_t ) + mem->size ) != MEMHEADER_SENTINEL2 )
{
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
Sys_Error( "Mem_Free: trashed header sentinel 2 (alloc at %s:%i, free at %s:%i)\n", mem->filename, mem->fileline, filename, fileline );
}
if( !Mem_CheckAllocHeader( __func__, mem, filename, fileline ))
return;
pool = mem->pool;
// unlink memheader from doubly linked list
if(( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem ))
Sys_Error( "Mem_Free: not allocated or double freed (free at %s:%i)\n", filename, fileline );
{
Sys_Error( "%s: not allocated or double freed (free at %s:%i)\n", __func__, filename, fileline );
return;
}
if( mem->prev ) mem->prev->next = mem->next;
else pool->chain = mem->next;
Mem_PoolSubtract( pool, mem->size );
Mem_PoolUnlinkAlloc( pool, mem );
if( mem->next )
mem->next->prev = mem->prev;
// memheader has been unlinked, do the actual free now
pool->totalsize -= mem->size;
pool->realsize -= sizeof( memheader_t ) + mem->size + sizeof( size_t );
Q_free( mem );
}
void _Mem_Free( void *data, const char *filename, int fileline )
{
if( data == NULL ) Sys_Error( "Mem_Free: data == NULL (called at %s:%i)\n", filename, fileline );
if( data == NULL )
{
Sys_Error( "Mem_Free: data == NULL (called at %s:%i)\n", filename, fileline );
return;
}
Mem_FreeBlock((memheader_t *)((byte *)data - sizeof( memheader_t )), filename, fileline );
}
void *_Mem_Realloc( poolhandle_t poolptr, void *memptr, size_t size, qboolean clear, const char *filename, int fileline )
void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clear, const char *filename, int fileline )
{
memheader_t *memhdr = NULL;
char *nb;
memheader_t *mem;
uintptr_t oldmem;
mempool_t *pool;
size_t oldsize;
if( size <= 0 ) return memptr; // no need to reallocate
if( size <= 0 )
return data; // no need to reallocate
if( memptr )
if( !poolptr )
{
memhdr = (memheader_t *)((byte *)memptr - sizeof( memheader_t ));
if( size == memhdr->size ) return memptr;
Sys_Error( "Mem_Realloc: pool == NULL (alloc at %s:%i)\n", filename, fileline );
return NULL;
}
nb = _Mem_Alloc( poolptr, size, clear, filename, fileline );
if( !data )
return _Mem_Alloc( poolptr, size, clear, filename, fileline );
if( memptr ) // first allocate?
mem = (memheader_t *)((byte *)data - sizeof( memheader_t ));
if( !Mem_CheckAllocHeader( "Mem_Realloc", mem, filename, fileline ))
return NULL;
oldsize = mem->size;
if( size == oldsize )
return data;
#if XASH_CUSTOM_SWAP
{
size_t newsize = memhdr->size < size ? memhdr->size : size; // upper data can be trucnated!
memcpy( nb, memptr, newsize );
_Mem_Free( memptr, filename, fileline ); // free unused old block
char *nb = _Mem_Alloc( poolptr, size, clear, filename, fileline );
size_t newsize = mem->size < size ? mem->size : size; // upper data can be trucnated!
memcpy( nb, data, newsize );
_Mem_Free( data, filename, fileline ); // free unused old block
return nb;
}
#else // XASH_CUSTOM_SWAP
pool = Mem_FindPool( poolptr );
oldmem = (uintptr_t)mem;
mem = realloc( mem, sizeof( memheader_t ) + size + sizeof( byte ));
if( mem == NULL )
{
Sys_Error( "Mem_Realloc: out of memory (alloc size %s at %s:%i)\n", Q_memprint( size ), filename, fileline );
return NULL;
}
return (void *)nb;
// Con_Printf( S_NOTE "%s: mem %s oldmem, size before %zu now %zu (alloc at %s:%i)\n",
// __func__, (uintptr_t)mem != oldmem ? "!=" : "==", oldsize, size, filename, fileline );
Mem_InitAlloc( mem, size, filename, fileline );
if( size > oldsize )
{
Mem_PoolAdd( pool, size - oldsize );
if( clear )
memset((byte *)mem + sizeof( memheader_t ) + oldsize, 0, size - oldsize );
}
else Mem_PoolSubtract( pool, oldsize - size );
// if allocation was migrated from one pool to another
// (this is possible with original Mem_Realloc func)
if( unlikely( mem->pool != pool ))
{
Mem_PoolUnlinkAlloc( mem->pool, mem );
Mem_PoolLinkAlloc( pool, mem );
}
else if( oldmem != (uintptr_t)mem ) // just relink pointers
{
if( mem->next ) mem->next->prev = mem;
if( mem->prev ) mem->prev->next = mem;
else pool->chain = mem;
}
return (void *)((byte *)mem + sizeof( memheader_t ));
#endif // XASH_CUSTOM_SWAP
}
poolhandle_t _Mem_AllocPool( const char *name, const char *filename, int fileline )
@@ -254,8 +372,7 @@ void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline )
// unlink pool from chain
for( chainaddress = &poolchain; *chainaddress && *chainaddress != pool; chainaddress = &((*chainaddress)->next));
if( *chainaddress != pool ) Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
if( pool->sentinel1 != MEMHEADER_SENTINEL1 ) Sys_Error( "Mem_FreePool: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
if( pool->sentinel2 != MEMHEADER_SENTINEL1 ) Sys_Error( "Mem_FreePool: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
Mem_CheckPool( "Mem_FreePool", pool, filename, fileline );
*chainaddress = pool->next;
// free memory owned by the pool
@@ -272,8 +389,7 @@ void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline )
mempool_t *pool = Mem_FindPool( poolptr );
if( !poolptr ) Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
if( pool->sentinel1 != MEMHEADER_SENTINEL1 ) Sys_Error( "Mem_EmptyPool: trashed pool sentinel 1 (allocpool at %s:%i, emptypool at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
if( pool->sentinel2 != MEMHEADER_SENTINEL1 ) Sys_Error( "Mem_EmptyPool: trashed pool sentinel 2 (allocpool at %s:%i, emptypool at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
Mem_CheckPool( "Mem_FreePool", pool, filename, fileline );
// free memory owned by the pool
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
@@ -288,14 +404,19 @@ static qboolean Mem_CheckAlloc( mempool_t *pool, void *data )
// search only one pool
target = (memheader_t *)((byte *)data - sizeof( memheader_t ));
for( header = pool->chain; header; header = header->next )
if( header == target ) return true;
{
if( header == target )
return true;
}
}
else
{
// search all pools
for( pool = poolchain; pool; pool = pool->next )
{
if( Mem_CheckAlloc( pool, data ))
return true;
}
}
return false;
}
@@ -308,49 +429,24 @@ Check pointer for memory
qboolean Mem_IsAllocatedExt( poolhandle_t poolptr, void *data )
{
mempool_t *pool = NULL;
if( poolptr ) pool = Mem_FindPool( poolptr );
if( poolptr )
pool = Mem_FindPool( poolptr );
return Mem_CheckAlloc( pool, data );
}
static void Mem_CheckHeaderSentinels( void *data, const char *filename, int fileline )
{
memheader_t *mem;
if( data == NULL )
Sys_Error( "Mem_CheckSentinels: data == NULL (sentinel check at %s:%i)\n", filename, fileline );
mem = (memheader_t *)((byte *) data - sizeof(memheader_t));
if( mem->sentinel1 != MEMHEADER_SENTINEL1 )
{
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
Sys_Error( "Mem_CheckSentinels: trashed header sentinel 1 (block allocated at %s:%i, sentinel check at %s:%i)\n", mem->filename, mem->fileline, filename, fileline );
}
if( *((byte *)mem + sizeof(memheader_t) + mem->size) != MEMHEADER_SENTINEL2 )
{
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
Sys_Error( "Mem_CheckSentinels: trashed header sentinel 2 (block allocated at %s:%i, sentinel check at %s:%i)\n", mem->filename, mem->fileline, filename, fileline );
}
}
void _Mem_Check( const char *filename, int fileline )
{
memheader_t *mem;
mempool_t *pool;
for( pool = poolchain; pool; pool = pool->next )
{
if( pool->sentinel1 != MEMHEADER_SENTINEL1 )
Sys_Error( "Mem_CheckSentinelsGlobal: trashed pool sentinel 1 (allocpool at %s:%i, sentinel check at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
if( pool->sentinel2 != MEMHEADER_SENTINEL1 )
Sys_Error( "Mem_CheckSentinelsGlobal: trashed pool sentinel 2 (allocpool at %s:%i, sentinel check at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
}
Mem_CheckPool( "Mem_CheckSentinels", pool, filename, fileline );
for( pool = poolchain; pool; pool = pool->next )
for( mem = pool->chain; mem; mem = mem->next )
Mem_CheckHeaderSentinels((void *)((byte *) mem + sizeof(memheader_t)), filename, fileline );
Mem_CheckAllocHeader( "Mem_CheckSentinels", mem, filename, fileline );
}
void Mem_PrintStats( void )
@@ -377,28 +473,31 @@ void Mem_PrintList( size_t minallocationsize )
Mem_Check();
Con_Printf( "memory pool list:\n"" ^3size name\n");
Con_Printf( "memory pool list:\n" );
Con_Printf( "\t^3size\t\t\t\tname\n");
for( pool = poolchain; pool; pool = pool->next )
{
long changed_size = (long)pool->totalsize - (long)pool->lastchecksize;
// poolnames can contain color symbols, make sure what color is reset
if( changed_size != 0 )
if( pool->lastchecksize != 0 && changed_size != 0 )
{
char sign = (changed_size < 0) ? '-' : '+';
Con_Printf( "%10s (%10s actual) %s (^7%c%s change)\n", Q_memprint( pool->totalsize ), Q_memprint( pool->realsize ),
pool->name, sign, Q_memprint( abs( changed_size )));
Con_Printf( "%10s (%10s real)\t%s (^7%c%s change)\n", Q_memprint( pool->totalsize ), Q_memprint( pool->realsize ),
pool->name, sign, Q_memprint( abs( changed_size )));
}
else
{
Con_Printf( "%5s (%5s actual) %s\n", Q_memprint( pool->totalsize ), Q_memprint( pool->realsize ), pool->name );
Con_Printf( "%10s (%10s real)\t%s\n", Q_memprint( pool->totalsize ), Q_memprint( pool->realsize ), pool->name );
}
pool->lastchecksize = pool->totalsize;
for( mem = pool->chain; mem; mem = mem->next )
{
if( mem->size >= minallocationsize )
Con_Printf( "%10s allocated at %s:%i\n", Q_memprint( mem->size ), mem->filename, mem->fileline );
}
}
}

View File

@@ -215,6 +215,7 @@ typedef struct ui_extendedfuncs_s {
// network address funcs
const char *(*pfnAdrToString)( const struct netadr_s a );
int (*pfnCompareAdr)( const void *a, const void *b ); // netadr_t
void *(*pfnGetNativeObject)( const char *name );
} ui_extendedfuncs_t;
// deprecated export from old engine

View File

@@ -2,15 +2,30 @@
mobility_int.h - interface between engine and client for mobile platforms
Copyright (C) 2015 a1batross
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This is free and unencumbered software released into the public domain.
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.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org/>
*/
#pragma once

View File

@@ -107,7 +107,10 @@ typedef struct server_physics_api_s
int (*pfnSaveFile)( const char *filename, const void *data, int len );
const byte *(*pfnLoadImagePixels)( const char *filename, int *width, int *height );
const char* (*pfnGetModelName)( int modelindex );
const char *(*pfnGetModelName)( int modelindex );
// FWGS extension
void *(*pfnGetNativeObject)( const char *object );
} server_physics_api_t;
// physic callbacks

View File

@@ -61,23 +61,16 @@ Android_GetNativeObject
void *Android_GetNativeObject( const char *name )
{
static const char *availObjects[] = { "JNIEnv", "ActivityClass", NULL };
void *object = NULL;
if( !name )
if( !strcasecmp( name, "JNIEnv" ) )
{
object = (void *)availObjects;
}
else if( !strcasecmp( name, "JNIEnv" ) )
{
object = (void *)jni.env;
return (void *)jni.env;
}
else if( !strcasecmp( name, "ActivityClass" ) )
{
object = (void *)jni.actcls;
return (void *)jni.actcls;
}
return object;
return NULL;
}
/*

View File

@@ -52,7 +52,7 @@ static pid_t gettid( void )
static void *g_hsystemd;
static int (*g_pfn_sd_notify)( int unset_environment, const char *state );
qboolean Sys_DebuggerPresent( void )
qboolean Platform_DebuggerPresent( void )
{
char buf[4096];
ssize_t num_read;

View File

@@ -34,8 +34,8 @@ double Platform_DoubleTime( void );
void Platform_Sleep( int msec );
void Platform_ShellExecute( const char *path, const char *parms );
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 );
qboolean Platform_DebuggerPresent( void );
// legacy iOS port functions
#if TARGET_OS_IOS
@@ -64,6 +64,8 @@ const char *Android_LoadID( void );
void Android_SaveID( const char *id );
void Android_Init( void );
void *Android_GetNativeObject( const char *name );
int Android_GetKeyboardHeight( void );
void Android_Shutdown( void );
#endif
#if XASH_WIN32
@@ -140,6 +142,15 @@ static inline void Platform_Shutdown( void )
#endif
}
static inline qboolean Sys_DebuggerPresent( void )
{
#if XASH_LINUX || XASH_WIN32
return Platform_DebuggerPresent();
#else
return false;
#endif
}
/*
==============================================================================
@@ -256,4 +267,89 @@ void VoiceCapture_Shutdown( void );
qboolean VoiceCapture_Activate( qboolean activate );
qboolean VoiceCapture_Lock( qboolean lock );
// this allows to make break in current line, without entering libc code
// libc built with -fomit-frame-pointer may just eat stack frame (hello, glibc), making entering libc even more useless
// calling syscalls directly allows to make break like if it was asm("int $3") on x86
#if XASH_LINUX && XASH_X86
#define INLINE_RAISE(x) asm volatile( "int $3;" );
#define INLINE_NANOSLEEP1() // nothing!
#elif XASH_LINUX && XASH_ARM && !XASH_64BIT
#define INLINE_RAISE(x) do \
{ \
int raise_pid = getpid(); \
int raise_tid = gettid(); \
int raise_sig = (x); \
__asm__ volatile ( \
"mov r7,#268\n\t" \
"mov r0,%0\n\t" \
"mov r1,%1\n\t" \
"mov r2,%2\n\t" \
"svc 0\n\t" \
: \
: "r"(raise_pid), "r"(raise_tid), "r"(raise_sig) \
: "r0", "r1", "r2", "r7", "memory" \
); \
} while( 0 )
#define INLINE_NANOSLEEP1() do \
{ \
struct timespec ns_t1 = {1, 0}; \
struct timespec ns_t2 = {0, 0}; \
__asm__ volatile ( \
"mov r7,#162\n\t" \
"mov r0,%0\n\t" \
"mov r1,%1\n\t" \
"svc 0\n\t" \
: \
: "r"(&ns_t1), "r"(&ns_t2) \
: "r0", "r1", "r7", "memory" \
); \
} while( 0 )
#elif XASH_LINUX && XASH_ARM && XASH_64BIT
#define INLINE_RAISE(x) do \
{ \
int raise_pid = getpid(); \
int raise_tid = gettid(); \
int raise_sig = (x); \
__asm__ volatile ( \
"mov x8,#131\n\t" \
"mov x0,%0\n\t" \
"mov x1,%1\n\t" \
"mov x2,%2\n\t" \
"svc 0\n\t" \
: \
: "r"(raise_pid), "r"(raise_tid), "r"(raise_sig) \
: "x0", "x1", "x2", "x8", "memory", "cc" \
); \
} while( 0 )
#define INLINE_NANOSLEEP1() do \
{ \
struct timespec ns_t1 = {1, 0}; \
struct timespec ns_t2 = {0, 0}; \
__asm__ volatile ( \
"mov x8,#101\n\t" \
"mov x0,%0\n\t" \
"mov x1,%1\n\t" \
"svc 0\n\t" \
: \
: "r"(&ns_t1), "r"(&ns_t2) \
: "x0", "x1", "x8", "memory", "cc" \
); \
} while( 0 )
#elif XASH_LINUX
#ifdef __NR_tgkill
#define INLINE_RAISE(x) syscall( __NR_tgkill, getpid(), gettid(), x )
#else // __NR_tgkill
#define INLINE_RAISE(x) raise(x)
#endif // __NR_tgkill
#define INLINE_NANOSLEEP1() do \
{ \
struct timespec ns_t1 = {1, 0}; \
struct timespec ns_t2 = {0, 0}; \
nanosleep( &ns_t1, &ns_t2 ); \
} while( 0 )
#else // generic
#define INLINE_RAISE(x) raise(x)
#define INLINE_NANOSLEEP1() sleep(1)
#endif // generic
#endif // PLATFORM_H

View File

@@ -212,8 +212,8 @@ const char *COM_NameForFunction( void *hInstance, void *function )
// NOTE: dladdr() is a glibc extension
{
Dl_info info = {0};
dladdr( (void*)function, &info );
if( info.dli_sname )
int ret = dladdr( (void*)function, &info );
if( ret && info.dli_sname )
return COM_GetPlatformNeutralName( info.dli_sname );
}
#ifdef XASH_ALLOW_SAVERESTORE_OFFSETS

View File

@@ -374,14 +374,8 @@ static void SDLash_ActiveEvent( int gain )
{
host.status = HOST_FRAME;
if( cls.key_dest == key_game )
{
IN_ActivateMouse( );
}
if( dma.initialized && snd_mute_losefocus.value )
{
SNDDMA_Activate( true );
}
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
if( vid_fullscreen.value == WINDOW_MODE_FULLSCREEN )
VID_SetMode();
@@ -397,14 +391,8 @@ static void SDLash_ActiveEvent( int gain )
#endif
host.status = HOST_NOFOCUS;
if( cls.key_dest == key_game )
{
IN_DeactivateMouse();
}
if( dma.initialized && snd_mute_losefocus.value )
{
SNDDMA_Activate( false );
}
host.force_draw_version_time = host.realtime + 2.0;
VID_RestoreScreenResolution();
}
@@ -654,7 +642,9 @@ static void SDLash_EventFilter( SDL_Event *event )
SDLash_ActiveEvent( false );
break;
case SDL_WINDOWEVENT_RESIZED:
#if !XASH_MOBILE_PLATFORM
if( vid_fullscreen.value == WINDOW_MODE_WINDOWED )
#endif
{
SDL_Window *wnd = SDL_GetWindowFromID( event->window.windowID );
VID_SaveWindowSize( event->window.data1, event->window.data2,

View File

@@ -44,6 +44,18 @@ Platform_GetMousePos
void GAME_EXPORT Platform_GetMousePos( int *x, int *y )
{
SDL_GetMouseState( x, y );
if( x && window_width.value && window_width.value != refState.width )
{
float factor = refState.width / window_width.value;
*x = *x * factor;
}
if( y && window_height.value && window_height.value != refState.height )
{
float factor = refState.height / window_height.value;
*y = *y * factor;
}
}
/*

View File

@@ -576,10 +576,8 @@ static qboolean VID_SetScreenResolution( int width, int height, window_mode_t wi
SDL_DisplayMode got;
Uint32 wndFlags = 0;
#if !XASH_APPLE
if( vid_highdpi.value )
SetBits( wndFlags, SDL_WINDOW_ALLOW_HIGHDPI );
#endif
SDL_SetWindowBordered( host.hWnd, SDL_FALSE );
@@ -744,7 +742,6 @@ qboolean VID_CreateWindow( int width, int height, window_mode_t window_mode )
if( !glw_state.software )
SetBits( wndFlags, SDL_WINDOW_OPENGL );
#if !XASH_MOBILE_PLATFORM
if( window_mode == WINDOW_MODE_WINDOWED )
{
SDL_Rect r;
@@ -787,10 +784,6 @@ qboolean VID_CreateWindow( int width, int height, window_mode_t window_mode )
SetBits( wndFlags, SDL_WINDOW_BORDERLESS );
xpos = ypos = 0;
}
#else
SetBits( wndFlags, SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_INPUT_GRABBED );
xpos = ypos = SDL_WINDOWPOS_UNDEFINED;
#endif
if( !VID_CreateWindowWithSafeGL( wndname, xpos, ypos, width, height, wndFlags ))
return false;
@@ -799,14 +792,12 @@ qboolean VID_CreateWindow( int width, int height, window_mode_t window_mode )
if( FBitSet( SDL_GetWindowFlags( host.hWnd ), SDL_WINDOW_MAXIMIZED|SDL_WINDOW_FULLSCREEN_DESKTOP ) != 0 )
SDL_GetWindowSize( host.hWnd, &width, &height );
#if !XASH_MOBILE_PLATFORM
if( window_mode != WINDOW_MODE_WINDOWED )
{
if( !VID_SetScreenResolution( width, height, window_mode ))
return false;
}
else VID_RestoreScreenResolution();
#endif
VID_SetWindowIcon( host.hWnd );
SDL_ShowWindow( host.hWnd );
@@ -1175,6 +1166,14 @@ qboolean VID_SetMode( void )
#endif // SDL_VERSION_ATLEAST( 2, 0, 0 )
}
#if XASH_MOBILE_PLATFORM
if( Q_strcmp( vid_fullscreen.string, DEFAULT_FULLSCREEN ))
{
Cvar_DirectSet( &vid_fullscreen, DEFAULT_FULLSCREEN );
Con_Reportf( S_ERROR "VID_SetMode: windowed unavailable on this platform\n" );
}
#endif
if( !FBitSet( vid_fullscreen.flags, FCVAR_CHANGED ))
Cvar_DirectSet( &vid_fullscreen, DEFAULT_FULLSCREEN );
else

View File

@@ -356,13 +356,13 @@ static void ListMissingModules( dll_user_t *hInst )
byte *data;
char buf[MAX_VA_STRING];
if ( !hInst ) return;
data = FS_LoadFile( hInst->dllName, NULL, false );
if ( !data ) return;
if( !hInst || !g_fsapi.LoadFile ) return;
data = g_fsapi.LoadFile( hInst->dllName, NULL, false );
if( !data ) return;
importDesc = GetImportDescriptor( hInst->dllName, data, &peHeader );
if ( !importDesc )
if( !importDesc )
{
Mem_Free( data );
return;

View File

@@ -41,7 +41,7 @@ void Platform_Sleep( int msec )
}
#endif // XASH_TIMER == TIMER_WIN32
qboolean Sys_DebuggerPresent( void )
qboolean Platform_DebuggerPresent( void )
{
return IsDebuggerPresent();
}

View File

@@ -77,6 +77,7 @@ GNU General Public License for more details.
#define FWORLD_CUSTOM_SKYBOX BIT( 1 )
#define FWORLD_WATERALPHA BIT( 2 )
#define FWORLD_HAS_DELUXEMAP BIT( 3 )
#define FWORLD_HAS_MIRRORS BIT( 4 )
// special rendermode for screenfade modulate
// (probably will be expanded at some point)

View File

@@ -453,6 +453,11 @@ static void SV_ConnectClient( netadr_t from )
// parse some info from the info strings (this can override cl_updaterate)
Q_strncpy( newcl->userinfo, userinfo, sizeof( newcl->userinfo ));
newcl->fullupdate_next_calltime = 0;
newcl->userinfo_next_changetime = 0;
newcl->userinfo_penalty = 0;
newcl->userinfo_change_attempts = 0;
SV_UserinfoChanged( newcl );
SV_ClearResourceLists( newcl );
#if 0
@@ -794,7 +799,7 @@ sv_client_t *SV_ClientById( int id )
ASSERT( id >= 0 );
for( i = 0, cl = svs.clients; i < svgame.globals->maxClients; i++, cl++ )
for( i = 0, cl = svs.clients; cl && i < svgame.globals->maxClients; i++, cl++ )
{
if( !cl->state )
continue;
@@ -814,7 +819,7 @@ sv_client_t *SV_ClientByName( const char *name )
if( !COM_CheckString( name ))
return NULL;
for( i = 0, cl = svs.clients; i < svgame.globals->maxClients; i++, cl++ )
for( i = 0, cl = svs.clients; cl && i < svgame.globals->maxClients; i++, cl++ )
{
if( !cl->state )
continue;
@@ -3453,7 +3458,7 @@ static void SV_ParseVoiceData( sv_client_t *cl, sizebuf_t *msg )
MSG_ReadBytes( msg, received, size );
if( !sv_voiceenable.value )
if( !sv_voiceenable.value || svs.maxclients <= 1 )
return;
for( i = 0, cur = svs.clients; i < svs.maxclients; i++, cur++ )

View File

@@ -368,13 +368,12 @@ SV_NewGame_f
*/
static void SV_NewGame_f( void )
{
if( Cmd_Argc() != 1 )
{
if( Cmd_Argc() == 1 )
COM_NewGame( GI->startmap );
else if( Cmd_Argc() == 2 )
COM_NewGame( Cmd_Argv( 1 ));
else
Con_Printf( S_USAGE "newgame\n" );
return;
}
COM_NewGame( GI->startmap );
}
/*

View File

@@ -1209,7 +1209,7 @@ static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className )
if( !SpawnEdict )
{
Con_Printf( S_ERROR "No spawn function for %s\n", STRING( className ));
Con_Printf( S_ERROR "No spawn function for \"%s\"\n", pszClassName );
// free entity immediately
SV_FreeEdict( ent );

View File

@@ -469,7 +469,8 @@ static void SV_CreateBaseline( void )
int delta_type;
int entnum;
SV_WriteVoiceCodec( &sv.signon );
if( svs.maxclients > 1 )
SV_WriteVoiceCodec( &sv.signon );
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
playermodel = SV_ModelIndex( DEFAULT_PLAYER_PATH_QUAKE );
@@ -672,14 +673,6 @@ void SV_ActivateServer( int runPhysics )
if( sv.ignored_world_decals )
Con_Printf( S_WARN "%i static decals was rejected due buffer overflow\n", sv.ignored_world_decals );
if( svs.maxclients > 1 )
{
const char *cycle = Cvar_VariableString( "mapchangecfgfile" );
if( COM_CheckString( cycle ))
Cbuf_AddTextf( "exec %s\n", cycle );
}
}
/*
@@ -692,6 +685,13 @@ deactivate server, free edicts, strings etc
void SV_DeactivateServer( void )
{
int i;
const char *cycle = Cvar_VariableString( "disconcfgfile" );
if( COM_CheckString( cycle ))
Cbuf_AddTextf( "exec %s\n", cycle );
if( COM_CheckStringEmpty( sv.name ))
Cbuf_AddTextf( "exec maps/%s_unload.cfg\n", sv.name );
if( !svs.initialized || sv.state == ss_dead )
return;
@@ -922,11 +922,11 @@ static void SV_GenerateTestPacket( void )
// testpacket already generated once, exit
// testpacket and lookup table takes ~300k of memory
// disable for low memory mode
if( svs.testpacket_buf || XASH_LOW_MEMORY >= 0 )
if( svs.testpacket_buf || XASH_LOW_MEMORY > 0 )
return;
// don't need in singleplayer with full client
if( svs.maxclients <= 1 && !Host_IsDedicated( ))
if( svs.maxclients <= 1 )
return;
file = FS_Open( "gfx.wad", "rb", false );
@@ -987,8 +987,9 @@ clients along with it.
*/
qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean background )
{
int i, current_skill;
edict_t *ent;
int i, current_skill;
edict_t *ent;
const char *cycle;
SV_SetupClients();
@@ -1006,6 +1007,13 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean ba
svs.timestart = Sys_DoubleTime();
svs.spawncount++; // any partially connected client will be restarted
cycle = Cvar_VariableString( "mapchangecfgfile" );
if( COM_CheckString( cycle ))
Cbuf_AddTextf( "exec %s\n", cycle );
Cbuf_AddTextf( "exec maps/%s_load.cfg\n", mapname );
// let's not have any servers with no name
if( !COM_CheckString( hostname.string ))
Cvar_Set( "hostname", svgame.dllFuncs.pfnGetGameDescription ? svgame.dllFuncs.pfnGetGameDescription() : FS_Title( ));
@@ -1037,7 +1045,9 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean ba
// make cvars consistant
if( coop.value ) Cvar_SetValue( "deathmatch", 0 );
current_skill = Q_rint( skill.value );
#if 0 // a1ba: don't limit the skill, it's limited in game rules anyway
current_skill = bound( 0, current_skill, 3 );
#endif
Cvar_SetValue( "skill", (float)current_skill );
// enforce hpk_maxsize

View File

@@ -75,6 +75,8 @@ CVAR_DEFINE_AUTO( skill, "1", 0, "skill level in singleplayer game" );
CVAR_DEFINE_AUTO( temp1, "0", 0, "temporary cvar that used by some mods" );
CVAR_DEFINE_AUTO( listipcfgfile, "listip.cfg", 0, "name of listip.cfg file" );
CVAR_DEFINE_AUTO( mapchangecfgfile, "", 0, "name of map change configuration file" );
CVAR_DEFINE_AUTO( disconcfgfile, "", 0, "name of disconnect configuration file" );
CVAR_DEFINE_AUTO( _sv_override_scientist_mdl, "", 0, "override default scientist model name (specially for HL25 Uplink maps)" );
// physic-related variables
CVAR_DEFINE_AUTO( sv_gravity, "800", FCVAR_MOVEVARS, "world gravity value" );
@@ -948,6 +950,8 @@ void SV_Init( void )
Cvar_RegisterVariable( &bannedcfgfile );
Cvar_RegisterVariable( &listipcfgfile );
Cvar_RegisterVariable( &mapchangecfgfile );
Cvar_RegisterVariable( &disconcfgfile );
Cvar_RegisterVariable( &_sv_override_scientist_mdl );
Cvar_RegisterVariable( &sv_voiceenable );
Cvar_RegisterVariable( &sv_voicequality );

View File

@@ -150,21 +150,9 @@ void SV_WaterMove( edict_t *ent )
if( flags & FL_INWATER )
{
// leave the water.
switch( COM_RandomLong( 0, 3 ))
{
case 0:
SV_StartSound( ent, CHAN_BODY, "player/pl_wade1.wav", 1.0f, ATTN_NORM, 0, 100 );
break;
case 1:
SV_StartSound( ent, CHAN_BODY, "player/pl_wade2.wav", 1.0f, ATTN_NORM, 0, 100 );
break;
case 2:
SV_StartSound( ent, CHAN_BODY, "player/pl_wade3.wav", 1.0f, ATTN_NORM, 0, 100 );
break;
case 3:
SV_StartSound( ent, CHAN_BODY, "player/pl_wade4.wav", 1.0f, ATTN_NORM, 0, 100 );
break;
}
const char *snd = SoundList_GetRandom( EntityWaterExit );
if( snd )
SV_StartSound( ent, CHAN_BODY, snd, 1.0f, ATTN_NORM, 0, 100 );
ent->v.flags = flags & ~FL_INWATER;
}
@@ -197,21 +185,9 @@ void SV_WaterMove( edict_t *ent )
if( watertype == CONTENTS_WATER )
{
// entering the water
switch( COM_RandomLong( 0, 3 ))
{
case 0:
SV_StartSound( ent, CHAN_BODY, "player/pl_wade1.wav", 1.0f, ATTN_NORM, 0, 100 );
break;
case 1:
SV_StartSound( ent, CHAN_BODY, "player/pl_wade2.wav", 1.0f, ATTN_NORM, 0, 100 );
break;
case 2:
SV_StartSound( ent, CHAN_BODY, "player/pl_wade3.wav", 1.0f, ATTN_NORM, 0, 100 );
break;
case 3:
SV_StartSound( ent, CHAN_BODY, "player/pl_wade4.wav", 1.0f, ATTN_NORM, 0, 100 );
break;
}
const char *snd = SoundList_GetRandom( EntityWaterEnter );
if( snd )
SV_StartSound( ent, CHAN_BODY, snd, 1.0f, ATTN_NORM, 0, 100 );
}
ent->v.flags = flags | FL_INWATER;

View File

@@ -802,7 +802,7 @@ static trace_t SV_PushEntity( edict_t *ent, const vec3_t lpush, const vec3_t apu
if( ent->v.movetype == MOVETYPE_FLYMISSILE )
type = MOVE_MISSILE;
else if( ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT )
else if( ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT || ent->v.solid == SOLID_GIB )
type = MOVE_NOMONSTERS; // only clip against bmodels
else type = MOVE_NORMAL;
@@ -878,7 +878,7 @@ static qboolean SV_CanBlock( edict_t *ent )
if( ent->v.mins[0] == ent->v.maxs[0] )
return false;
if( ent->v.solid == SOLID_NOT || ent->v.solid == SOLID_TRIGGER )
if( ent->v.solid == SOLID_NOT || ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_GIB )
{
// clear bounds for deadbody
ent->v.mins[0] = ent->v.mins[1] = 0;
@@ -1384,7 +1384,9 @@ static void SV_CheckWaterTransition( edict_t *ent )
if( ent->v.watertype == CONTENTS_EMPTY )
{
// just crossed into water
SV_StartSound( ent, CHAN_AUTO, "player/pl_wade1.wav", 1.0f, ATTN_NORM, 0, 100 );
const char *snd = SoundList_GetRandom( PlayerWaterEnter );
if( snd )
SV_StartSound( ent, CHAN_AUTO, snd, 1.0f, ATTN_NORM, 0, 100 );
ent->v.velocity[2] *= 0.5f;
}
@@ -1418,7 +1420,9 @@ static void SV_CheckWaterTransition( edict_t *ent )
if( ent->v.watertype != CONTENTS_EMPTY )
{
// just crossed into water
SV_StartSound( ent, CHAN_AUTO, "player/pl_wade2.wav", 1.0f, ATTN_NORM, 0, 100 );
const char *snd = SoundList_GetRandom( PlayerWaterExit );
if( snd )
SV_StartSound( ent, CHAN_AUTO, snd, 1.0f, ATTN_NORM, 0, 100 );
}
ent->v.watertype = CONTENTS_EMPTY;
ent->v.waterlevel = 0;
@@ -2118,6 +2122,7 @@ static server_physics_api_t gPhysicsAPI =
COM_SaveFile,
pfnLoadImagePixels,
pfnGetModelName,
Sys_GetNativeObject
};
/*

View File

@@ -1069,7 +1069,7 @@ static qboolean SV_ClipToEntity( edict_t *touch, moveclip_t *clip )
return true;
}
if( touch == clip->passedict || touch->v.solid == SOLID_NOT )
if( touch == clip->passedict || touch->v.solid == SOLID_NOT || touch->v.solid == SOLID_GIB )
return true;
if( touch->v.solid == SOLID_TRIGGER )

View File

@@ -125,7 +125,7 @@ def build(bld):
bld(name = 'engine_includes', export_includes = '. common common/imagelib', use = 'filesystem_includes')
is_cxx_link = False
libs = [ 'engine_includes', 'public', 'dllemu' ]
libs = [ 'engine_includes', 'public', 'dllemu', 'werror' ]
# basic build: dedicated only
source = bld.path.ant_glob([
@@ -237,7 +237,8 @@ def build(bld):
app_name = 'xash3d-fwgs'
)
else:
if bld.env.DISABLE_LAUNCHER:
# always build as shared library on Android
if bld.env.DISABLE_LAUNCHER and bld.env.DEST_OS != "android":
install_path = bld.env.BINDIR
program = 'cxxprogram' if is_cxx_link else 'cprogram'
if bld.env.STATIC:

View File

@@ -15,7 +15,7 @@ GNU General Public License for more details.
#include "port.h"
#if XASH_ANDROID
#if XASH_ANDROID_ASSETS
#include <sys/types.h>
#include <sys/stat.h>
@@ -233,7 +233,7 @@ static file_t *FS_OpenFile_AndroidAssets( searchpath_t *search, const char *file
return file;
}
static byte *FS_LoadAndroidAssetsFile( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *filesize )
static byte *FS_LoadAndroidAssetsFile( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *filesize, void *( *pfnAlloc )( size_t ), void ( *pfnFree )( void * ))
{
byte *buf;
off_t size;
@@ -247,18 +247,24 @@ static byte *FS_LoadAndroidAssetsFile( searchpath_t *search, const char *path, i
size = AAsset_getLength( asset );
buf = (byte *)Mem_Malloc( fs_mempool, size + 1 );
buf = (byte *)pfnAlloc( size + 1 );
if( unlikely( !buf ))
{
Con_Reportf( "%s: can't alloc %d bytes, no free memory\n", __func__, size + 1 );
AAsset_close( asset );
return NULL;
}
buf[size] = '\0';
if( AAsset_read( asset, buf, size ) < 0 )
{
Mem_Free( buf );
pfnFree( buf );
AAsset_close( asset );
return NULL;
}
AAsset_close( asset );
if( filesize ) *filesize = size;
return buf;
@@ -322,4 +328,4 @@ void FS_InitAndroid( void )
jni.getAssets = (*jni.env)->GetMethodID( jni.env, jni.activity_class, "getAssets", "(Z)Landroid/content/res/AssetManager;" );
}
#endif // XASH_ANDROID
#endif // XASH_ANDROID_ASSETS

View File

@@ -72,7 +72,7 @@ const fs_archive_t g_archives[] =
static const fs_archive_t g_directory_archive =
{ NULL, SEARCHPATH_PLAIN, FS_AddDir_Fullpath, false };
#ifdef XASH_ANDROID
#if XASH_ANDROID_ASSETS
static const fs_archive_t g_android_archive =
{ NULL, SEARCHPATH_ANDROID_ASSETS, FS_AddAndroidAssets_Fullpath, false };
#endif
@@ -406,7 +406,7 @@ void FS_AddGameDirectory( const char *dir, uint flags )
stringlistfreecontents( &list );
#ifdef XASH_ANDROID
#if XASH_ANDROID_ASSETS
FS_AddArchive_Fullpath( &g_android_archive, dir, flags );
#endif
@@ -632,30 +632,23 @@ static void FS_InitGameInfo( gameinfo_t *GameInfo, const char *gamedir )
memset( GameInfo, 0, sizeof( *GameInfo ));
// filesystem info
Q_strncpy( GameInfo->gamefolder, gamedir, sizeof( GameInfo->gamefolder ));
Q_strncpy( GameInfo->basedir, "valve", sizeof( GameInfo->basedir ));
GameInfo->falldir[0] = 0;
Q_strncpy( GameInfo->startmap, "c0a0", sizeof( GameInfo->startmap ));
Q_strncpy( GameInfo->trainmap, "t0a0", sizeof( GameInfo->trainmap ));
Q_strncpy( GameInfo->title, "New Game", sizeof( GameInfo->title ));
GameInfo->version = 1.0f;
// .dll pathes
Q_strncpy( GameInfo->gamefolder, gamedir, sizeof( GameInfo->gamefolder ));
Q_strncpy( GameInfo->basedir, fs_basedir, sizeof( GameInfo->basedir ));
Q_strncpy( GameInfo->sp_entity, "info_player_start", sizeof( GameInfo->sp_entity ));
Q_strncpy( GameInfo->mp_entity, "info_player_deathmatch", sizeof( GameInfo->mp_entity ));
Q_strncpy( GameInfo->startmap, "newmap", sizeof( GameInfo->startmap ));
Q_strncpy( GameInfo->dll_path, "cl_dlls", sizeof( GameInfo->dll_path ));
Q_strncpy( GameInfo->game_dll, "dlls/hl.dll", sizeof( GameInfo->game_dll ));
Q_strncpy( GameInfo->game_dll_linux, "dlls/hl.so", sizeof( GameInfo->game_dll_linux ));
Q_strncpy( GameInfo->game_dll_osx, "dlls/hl.dylib", sizeof( GameInfo->game_dll_osx ));
// .ico path
Q_strncpy( GameInfo->iconpath, "game.ico", sizeof( GameInfo->iconpath ));
Q_strncpy( GameInfo->sp_entity, "info_player_start", sizeof( GameInfo->sp_entity ));
Q_strncpy( GameInfo->mp_entity, "info_player_deathmatch", sizeof( GameInfo->mp_entity ));
GameInfo->max_edicts = DEFAULT_MAX_EDICTS; // default value if not specified
GameInfo->max_tents = 500;
GameInfo->max_beams = 128;
GameInfo->max_particles = 4096;
GameInfo->version = 1.0f;
}
static void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qboolean isGameInfo )
@@ -1468,7 +1461,7 @@ qboolean FS_InitStdio( qboolean unused_set_to_true, const char *rootdir, const c
FS_InitMemory();
#ifdef XASH_ANDROID
#if XASH_ANDROID_ASSETS
FS_InitAndroid();
#endif
@@ -2419,6 +2412,16 @@ static void FS_Purge( file_t *file )
file->ungetc = EOF;
}
static void *FS_CustomAlloc( size_t size )
{
return Mem_Malloc( fs_mempool, size );
}
static void FS_CustomFree( void *data )
{
return Mem_Free( data );
}
/*
============
FS_LoadFile
@@ -2427,12 +2430,16 @@ Filename are relative to the xash directory.
Always appends a 0 byte.
============
*/
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
static byte *FS_LoadFile_( const char *path, fs_offset_t *filesizeptr, const qboolean gamedironly, const qboolean custom_alloc )
{
searchpath_t *search;
fs_offset_t filesize;
file_t *file;
byte *buf;
char netpath[MAX_SYSPATH];
int pack_ind;
void *( *pfnAlloc )( size_t ) = custom_alloc ? FS_CustomAlloc : malloc;
void ( *pfnFree )( void * ) = custom_alloc ? FS_CustomFree : free;
// some mappers used leading '/' or '\' in path to models or sounds
if( path[0] == '/' || path[0] == '\\' )
@@ -2451,27 +2458,39 @@ byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamediro
// custom load file function for compressed files
if( search->pfnLoadFile )
return search->pfnLoadFile( search, netpath, pack_ind, filesizeptr );
return search->pfnLoadFile( search, netpath, pack_ind, filesizeptr, pfnAlloc, pfnFree );
file = search->pfnOpenFile( search, netpath, "rb", pack_ind );
if( file )
if( !file ) // TODO: indicate errors
return NULL;
filesize = file->real_length;
buf = (byte *)pfnAlloc( filesize + 1 );
if( unlikely( !buf )) // TODO: indicate errors
{
fs_offset_t filesize = file->real_length;
byte *buf;
buf = (byte *)Mem_Malloc( fs_mempool, filesize + 1 );
buf[filesize] = '\0';
FS_Read( file, buf, filesize );
Con_Reportf( "%s: can't alloc %d bytes, no free memory\n", __func__, filesize + 1 );
FS_Close( file );
if( filesizeptr )
*filesizeptr = filesize;
return buf;
return NULL;
}
return NULL;
buf[filesize] = '\0';
FS_Read( file, buf, filesize );
FS_Close( file );
if( filesizeptr ) *filesizeptr = filesize;
return buf;
}
byte *FS_LoadFileMalloc( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
{
return FS_LoadFile_( path, filesizeptr, gamedironly, false );
}
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
{
return FS_LoadFile_( path, filesizeptr, gamedironly, g_engfuncs._Mem_Alloc != _Mem_Alloc );
}
qboolean CRC32_File( dword *crcvalue, const char *filename )
@@ -3020,6 +3039,7 @@ fs_api_t g_api =
(void *)FS_MountArchive_Fullpath,
FS_GetFullDiskPath,
FS_LoadFileMalloc,
};
int EXPORT GetFSAPI( int version, fs_api_t *api, fs_globals_t **globals, fs_interface_t *engfuncs );

View File

@@ -196,6 +196,9 @@ typedef struct fs_api_t
void *(*MountArchive_Fullpath)( const char *path, int flags );
qboolean (*GetFullDiskPath)( char *buffer, size_t size, const char *name, qboolean gamedironly );
// like LoadFile but returns pointer that can be free'd using standard library function
byte *(*LoadFileMalloc)( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
} fs_api_t;
typedef struct fs_interface_t

View File

@@ -103,7 +103,7 @@ typedef struct searchpath_s
int (*pfnFileTime)( struct searchpath_s *search, const char *filename );
int (*pfnFindFile)( struct searchpath_s *search, const char *path, char *fixedname, size_t len );
void (*pfnSearch)( struct searchpath_s *search, stringlist_t *list, const char *pattern, int caseinsensitive );
byte *(*pfnLoadFile)( struct searchpath_s *search, const char *path, int pack_ind, fs_offset_t *filesize );
byte *(*pfnLoadFile)( struct searchpath_s *search, const char *path, int pack_ind, fs_offset_t *filesize, void *( *pfnAlloc )( size_t ), void ( *pfnFree )( void * ));
} searchpath_t;
typedef searchpath_t *(*FS_ADDARCHIVE_FULLPATH)( const char *path, int flags );
@@ -181,6 +181,7 @@ qboolean FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize );
// file buffer ops
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
byte *FS_LoadFileMalloc( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
byte *FS_LoadDirectFile( const char *path, fs_offset_t *filesizeptr );
qboolean FS_WriteFile( const char *filename, const void *data, fs_offset_t len );

View File

@@ -591,7 +591,7 @@ W_ReadLump
reading lump into temp buffer
===========
*/
static byte *W_ReadLump( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *lumpsizeptr )
static byte *W_ReadLump( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *lumpsizeptr, void *( *pfnAlloc )( size_t ), void ( *pfnFree )( void * ))
{
const wfile_t *wad = search->wad;
const dlumpinfo_t *lump = &wad->lumps[pack_ind];
@@ -613,19 +613,25 @@ static byte *W_ReadLump( searchpath_t *search, const char *path, int pack_ind, f
return NULL;
}
buf = (byte *)Mem_Malloc( wad->mempool, lump->disksize );
buf = (byte *)pfnAlloc( lump->disksize );
if( unlikely( !buf ))
{
Con_Reportf( S_ERROR "%s: can't alloc %d bytes, no free memory\n", __func__, lump->disksize );
FS_Seek( wad->handle, oldpos, SEEK_SET );
return NULL;
}
size = FS_Read( wad->handle, buf, lump->disksize );
FS_Seek( wad->handle, oldpos, SEEK_SET );
if( size < lump->disksize )
{
Con_Reportf( S_WARN "W_ReadLump: %s is probably corrupted\n", lump->name );
FS_Seek( wad->handle, oldpos, SEEK_SET );
Mem_Free( buf );
pfnFree( buf );
return NULL;
}
if( lumpsizeptr ) *lumpsizeptr = lump->disksize;
FS_Seek( wad->handle, oldpos, SEEK_SET );
return buf;
}

View File

@@ -18,7 +18,7 @@ def configure(conf):
def build(bld):
bld(name = 'filesystem_includes', export_includes = '.')
libs = [ 'filesystem_includes', 'sdk_includes' ]
libs = [ 'filesystem_includes', 'sdk_includes', 'werror' ]
# on PSVita do not link any libraries that are already in the main executable, but add the includes target
if bld.env.DEST_OS != 'psvita':

View File

@@ -422,7 +422,7 @@ FS_LoadZIPFile
===========
*/
static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *sizeptr )
static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *sizeptr, void *( *pfnAlloc )( size_t ), void ( *pfnFree )( void * ))
{
zipfile_t *file;
byte *compressed_buffer = NULL, *decompressed_buffer = NULL;
@@ -451,11 +451,16 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
return NULL;
}*/
decompressed_buffer = pfnAlloc( file->size + 1 );
if( unlikely( !decompressed_buffer ))
{
Con_Reportf( S_ERROR "%s: can't alloc %d bytes, no free memory\n", __func__, file->size + 1 );
return NULL;
}
decompressed_buffer[file->size] = '\0';
if( file->flags == ZIP_COMPRESSION_NO_COMPRESSION )
{
decompressed_buffer = Mem_Malloc( fs_mempool, file->size + 1 );
decompressed_buffer[file->size] = '\0';
c = read( search->zip->handle, decompressed_buffer, file->size );
if( c != file->size )
{
@@ -472,7 +477,7 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
if( final_crc != file->crc32 )
{
Con_Reportf( S_ERROR "Zip_LoadFile: %s file crc32 mismatch\n", file->name );
Mem_Free( decompressed_buffer );
pfnFree( decompressed_buffer );
return NULL;
}
#endif // ENABLE_CRC_CHECK
@@ -485,8 +490,6 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
else if( file->flags == ZIP_COMPRESSION_DEFLATED )
{
compressed_buffer = Mem_Malloc( fs_mempool, file->compressed_size + 1 );
decompressed_buffer = Mem_Malloc( fs_mempool, file->size + 1 );
decompressed_buffer[file->size] = '\0';
c = read( search->zip->handle, compressed_buffer, file->compressed_size );
if( c != file->compressed_size )
@@ -529,7 +532,7 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
if( final_crc != file->crc32 )
{
Con_Reportf( S_ERROR "Zip_LoadFile: %s file crc32 mismatch\n", file->name );
Mem_Free( decompressed_buffer );
pfnFree( decompressed_buffer );
return NULL;
}
#endif
@@ -542,7 +545,7 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
{
Con_Reportf( S_ERROR "Zip_LoadFile: %s : error while file decompressing. Zlib return code %d.\n", file->name, zlib_result );
Mem_Free( compressed_buffer );
Mem_Free( decompressed_buffer );
pfnFree( decompressed_buffer );
return NULL;
}
@@ -550,6 +553,7 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
else
{
Con_Reportf( S_ERROR "Zip_LoadFile: %s : file compressed with unknown algorithm.\n", file->name );
pfnFree( decompressed_buffer );
return NULL;
}

View File

@@ -33,7 +33,7 @@ def build(bld):
bld(source = source,
target = 'xash3d', # hl.exe
features = 'c cxx cxxprogram',
use = 'sdk_includes DL USER32 SHELL32',
use = 'sdk_includes DL USER32 SHELL32 werror',
rpath = bld.env.DEFAULT_RPATH,
install_path = bld.env.BINDIR,
subsystem = bld.env.MSVC_SUBSYSTEM

View File

@@ -95,8 +95,6 @@ const char *Q_PlatformStringByID( const int platform )
return "win32";
case PLATFORM_ANDROID:
return "android";
case PLATFORM_LINUX_UNKNOWN:
return "linuxunkabi";
case PLATFORM_LINUX:
return "linux";
case PLATFORM_APPLE:

View File

@@ -69,7 +69,6 @@ Then you can use another oneliner to query all variables:
#undef XASH_IRIX
#undef XASH_JS
#undef XASH_LINUX
#undef XASH_LINUX_UNKNOWN
#undef XASH_LITTLE_ENDIAN
#undef XASH_MIPS
#undef XASH_MOBILE_PLATFORM
@@ -103,13 +102,6 @@ Then you can use another oneliner to query all variables:
#if defined __linux__
#if defined __ANDROID__
#define XASH_ANDROID 1
#else
#include <features.h>
// if our system libc has features.h header
// try to detect it to not confuse other libcs with built with glibc game libraries
#if !defined __GLIBC__
#define XASH_LINUX_UNKNOWN 1
#endif
#endif
#define XASH_LINUX 1
#elif defined __FreeBSD__

View File

@@ -41,14 +41,11 @@ GNU General Public License for more details.
#define PLATFORM_IRIX 12
#define PLATFORM_NSWITCH 13
#define PLATFORM_PSVITA 14
#define PLATFORM_LINUX_UNKNOWN 15
#if XASH_WIN32
#define XASH_PLATFORM PLATFORM_WIN32
#elif XASH_ANDROID
#define XASH_PLATFORM PLATFORM_ANDROID
#elif XASH_LINUX_UNKNOWN
#define XASH_PLATFORM PLATFORM_LINUX_UNKNOWN
#elif XASH_LINUX
#define XASH_PLATFORM PLATFORM_LINUX
#elif XASH_APPLE

View File

@@ -12,7 +12,6 @@ static struct
{
{ PLATFORM_WIN32, "win32" },
{ PLATFORM_ANDROID, "android" },
{ PLATFORM_LINUX_UNKNOWN, "linuxunkabi" },
{ PLATFORM_LINUX, "linux" },
{ PLATFORM_APPLE, "apple" },
{ PLATFORM_FREEBSD, "freebsd" },

View File

@@ -19,7 +19,7 @@ def build(bld):
bld.stlib(source = bld.path.ant_glob('*.c'),
target = 'public',
features = 'c',
use = 'sdk_includes',
use = 'sdk_includes werror',
subsystem = bld.env.MSVC_SUBSYSTEM)
if bld.env.TESTS:

View File

@@ -383,7 +383,9 @@ static gl2wrap_prog_t *GL2_GetProg( const GLuint flags )
{
if( gl2wrap_config.vao_mandatory || gl2wrap_config.incremental )
{
for( int j = 0; j < gl2wrap_config.cycle_buffers; j++ )
int j;
for( j = 0; j < gl2wrap_config.cycle_buffers; j++ )
{
pglBindVertexArray( prog->vao_begin[j] );
pglEnableVertexAttribArrayARB( prog->attridx[i] );
@@ -472,12 +474,14 @@ static void GL2_InitTriQuads( void )
static void GL2_InitIncrementalBuffer( int i, GLuint size )
{
int j;
gl2wrap.attrbufobj[i] = Mem_Calloc( r_temppool, gl2wrap_config.cycle_buffers * sizeof( GLuint ));
if( gl2wrap_config.buf_storage )
gl2wrap.mappings[i] = Mem_Calloc( r_temppool, gl2wrap_config.cycle_buffers * sizeof( void * ));
pglGenBuffersARB( gl2wrap_config.cycle_buffers, gl2wrap.attrbufobj[i] );
for( int j = 0; j < gl2wrap_config.cycle_buffers; j++ )
for( j = 0; j < gl2wrap_config.cycle_buffers; j++ )
{
rpglBindBufferARB( GL_ARRAY_BUFFER_ARB, gl2wrap.attrbufobj[i][j] );
if( gl2wrap_config.buf_storage )
@@ -628,7 +632,9 @@ int GL2_ShimInit( void )
pglGenBuffersARB( gl2wrap_config.cycle_buffers, gl2wrap.attrbufobj[i] );
if( gl2wrap_config.supports_mapbuffer )
{
for( int j = 0; j < gl2wrap_config.cycle_buffers; j++ )
int j;
for( j = 0; j < gl2wrap_config.cycle_buffers; j++ )
{
rpglBindBufferARB( GL_ARRAY_BUFFER_ARB, gl2wrap.attrbufobj[i][j] );
pglBufferDataARB( GL_ARRAY_BUFFER_ARB, MAX_BEGINEND_VERTS, NULL, GL_STREAM_DRAW_ARB );
@@ -1550,6 +1556,7 @@ static void GL2_SetupArrays( GLuint start, GLuint end )
{
gl2wrap_prog_t *prog;
unsigned int flags = gl2wrap_arrays.flags;
int i;
if( !flags )
return; // Legacy pointers not used
@@ -1573,7 +1580,7 @@ static void GL2_SetupArrays( GLuint start, GLuint end )
pglBindVertexArray( gl2wrap_arrays.vao_dynamic );
}
for( int i = 0; i < GL2_ATTR_MAX; i++ )
for( i = 0; i < GL2_ATTR_MAX; i++ )
{
if( prog->attridx[i] < 0 )
continue;

View File

@@ -12,7 +12,7 @@ def configure(conf):
def build(bld):
source = bld.path.ant_glob( [ '*.c' ] )
includes = [ '.' ]
libs = [ 'engine_includes', 'sdk_includes' ]
libs = [ 'engine_includes', 'sdk_includes', 'werror' ]
bld.env.LDFLAGS += ['-fPIC']
bld.env.CFLAGS += ['-fPIC']
bld.stlib(

View File

@@ -111,6 +111,9 @@ void GL_BackendEndFrame( void )
Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "%3i tempents\n%3i viewbeams\n%3i particles",
r_stats.c_active_tents_count, r_stats.c_view_beams_count, r_stats.c_particle_count );
break;
case 6:
Q_snprintf( r_speeds_msg, sizeof( r_speeds_msg ), "%3i mirrors\n", r_stats.c_mirror_passes );
break;
}
memset( &r_stats, 0, sizeof( r_stats ));

View File

@@ -119,6 +119,10 @@ qboolean R_BeamCull( const vec3_t start, const vec3_t end, qboolean pvsOnly )
vec3_t mins, maxs;
int i;
// support for custom mirror management
if( RI.currentbeam && R_CullEntityInMirror( RI.currentbeam ))
return true;
for( i = 0; i < 3; i++ )
{
if( start[i] < end[i] )

View File

@@ -35,6 +35,31 @@ qboolean R_CullBox( const vec3_t mins, const vec3_t maxs )
return GL_FrustumCullBox( &RI.frustum, mins, maxs, 0 );
}
/*
=================
R_CullEntityInMirror
decide whether entity should be reflected in mirror
=================
*/
qboolean R_CullEntityInMirror( cl_entity_t *e )
{
if( FBitSet( RI.params, RP_MIRRORVIEW ))
{
// cull this entity out of mirrors but not normal views
if( FBitSet( e->curstate.effects, EF_NOREFLECT ))
return true;
}
else
{
// cull this entity out of normal views but not mirrors
if( FBitSet( e->curstate.effects, EF_REFLECTONLY ))
return true;
}
return false;
}
/*
=============
R_CullModel
@@ -53,6 +78,9 @@ int R_CullModel( cl_entity_t *e, const vec3_t absmin, const vec3_t absmax )
return 1;
}
if( R_CullEntityInMirror( e ))
return 1;
if( R_CullBox( absmin, absmax ))
return 1;
@@ -98,7 +126,7 @@ int R_CullSurface( msurface_t *surf, gl_frustum_t *frustum, uint clipflags )
}
else dist = PlaneDiff( tr.modelorg, surf->plane );
if( glState.faceCull == GL_FRONT )
if( glState.faceCull == GL_FRONT || FBitSet( RI.params, RP_MIRRORVIEW ))
{
if( FBitSet( surf->flags, SURF_PLANEBACK ))
{

View File

@@ -28,6 +28,10 @@ GNU General Public License for more details.
#define XASH_GL_STATIC
#define REF_GL_KEEP_MANGLED_FUNCTIONS
#elif defined XASH_GLES3COMPAT
#ifdef SOFTFP_LINK
#undef APIENTRY
#define APIENTRY __attribute__((pcs("aapcs")))
#endif
#define XASH_GLES
#endif

View File

@@ -631,9 +631,12 @@ static void GL_SetTextureTarget( gl_texture_t *tex, rgbdata_t *pic )
pic->numMips = Q_max( 1, pic->numMips );
// trying to determine texture type
#ifndef XASH_GLES
if( pic->width > 1 && pic->height <= 1 )
tex->target = GL_TEXTURE_1D;
else if( FBitSet( pic->flags, IMAGE_CUBEMAP ))
else
#endif // just skip first condition
if( FBitSet( pic->flags, IMAGE_CUBEMAP ))
tex->target = GL_TEXTURE_CUBE_MAP_ARB;
else if( FBitSet( pic->flags, IMAGE_MULTILAYER ) && pic->depth >= 1 )
tex->target = GL_TEXTURE_2D_ARRAY_EXT;

View File

@@ -74,6 +74,8 @@ extern poolhandle_t r_temppool;
#define SUBDIVIDE_SIZE 64
#define MAX_DECAL_SURFS 4096
#define MAX_DRAW_STACK 2 // normal view and menu view
#define MAX_MIRRORS 32 // per frame
#define MAX_MIRROR_ENTITIES MAX_VISIBLE_PACKET
#define SHADEDOT_QUANT 16 // precalculated dot products for quantized angles
#define SHADE_LAMBERT 1.4953241
@@ -84,8 +86,9 @@ extern poolhandle_t r_temppool;
#define RP_ENVVIEW BIT( 0 ) // used for cubemapshot
#define RP_OLDVIEWLEAF BIT( 1 )
#define RP_CLIPPLANE BIT( 2 )
#define RP_MIRRORVIEW BIT( 3 ) // lock pvs at vieworg
#define RP_NONVIEWERREF (RP_ENVVIEW)
#define RP_NONVIEWERREF (RP_ENVVIEW|RP_MIRRORVIEW)
#define R_ModelOpaque( rm ) ( rm == kRenderNormal )
#define R_StaticEntity( ent ) ( VectorIsNull( ent->origin ) && VectorIsNull( ent->angles ))
#define RP_LOCALCLIENT( e ) ((e) != NULL && (e)->index == ( gp_cl->playernum + 1 ) && e->player )
@@ -136,6 +139,13 @@ typedef struct gltexture_s
struct gltexture_s *nextHash;
} gl_texture_t;
// mirror entity
typedef struct
{
cl_entity_t *ent;
mextrasurf_t *chain;
} gl_entity_t;
typedef struct
{
int params; // rendering parameters
@@ -200,9 +210,11 @@ typedef struct
cl_entity_t *solid_entities[MAX_VISIBLE_PACKET]; // opaque moving or alpha brushes
cl_entity_t *trans_entities[MAX_VISIBLE_PACKET]; // translucent brushes
cl_entity_t *beam_entities[MAX_VISIBLE_PACKET];
gl_entity_t mirror_entities[MAX_MIRROR_ENTITIES]; // an entities that has mirror
uint num_solid_entities;
uint num_trans_entities;
uint num_beam_entities;
uint num_mirror_entities;
} draw_list_t;
typedef struct
@@ -218,6 +230,8 @@ typedef struct
int dlightTexture; // custom dlight texture
int skyboxTextures[SKYBOX_MAX_SIDES]; // skybox sides
int cinTexture; // cinematic texture
int mirrorTextures[MAX_MIRRORS];
int num_mirrors_used;
int skytexturenum; // this not a gl_texturenum!
int skyboxbasenum; // start with 5800
@@ -280,6 +294,8 @@ typedef struct
uint c_client_ents; // entities that moved to client
double t_world_node;
double t_world_draw;
uint c_mirror_passes;
} ref_speeds_t;
extern ref_speeds_t r_stats;
@@ -324,6 +340,7 @@ qboolean R_BeamCull( const vec3_t start, const vec3_t end, qboolean pvsOnly );
//
int R_CullModel( cl_entity_t *e, const vec3_t absmin, const vec3_t absmax );
qboolean R_CullBox( const vec3_t mins, const vec3_t maxs );
qboolean R_CullEntityInMirror( cl_entity_t *e );
int R_CullSurface( msurface_t *surf, gl_frustum_t *frustum, uint clipflags );
//
@@ -496,7 +513,7 @@ void EmitWaterPolys( msurface_t *warp, qboolean reverse );
void R_InitRipples( void );
void R_ResetRipples( void );
void R_AnimateRipples( void );
void R_UploadRipples( texture_t *image );
void R_UploadRipples( texture_t *image, qboolean is_mirror );
//
// gl_vgui.c
@@ -515,7 +532,13 @@ void VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr );
void VGUI_GetTextureSizes( int *width, int *height );
int VGUI_GenerateTexture( void );
//#include "vid_common.h"
//
// gl_mirror.c
//
void R_BeginDrawMirror( msurface_t *fa );
void R_EndDrawMirror( void );
void R_DrawMirrors( void );
void R_FindMirrors( void );
//
// renderer exports
@@ -541,7 +564,6 @@ void R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, c
void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum );
qboolean R_SpeedsMessage( char *out, size_t size );
void R_SetupSky( const char *skyboxname );
qboolean R_CullBox( const vec3_t mins, const vec3_t maxs );
int R_WorldToScreen( const vec3_t point, vec3_t screen );
void R_ScreenToWorld( const vec3_t screen, vec3_t point );
qboolean R_AddEntity( struct cl_entity_s *pRefEntity, int entityType );
@@ -767,6 +789,7 @@ extern convar_t gl_test; // cvar to testify new effects
extern convar_t gl_msaa;
extern convar_t gl_stencilbits;
extern convar_t gl_overbright;
extern convar_t gl_allow_mirrors;
extern convar_t r_lighting_extended;
extern convar_t r_lighting_ambient;
@@ -780,11 +803,15 @@ extern convar_t r_traceglow;
extern convar_t r_vbo;
extern convar_t r_vbo_dlightmode;
extern convar_t r_vbo_detail;
extern convar_t r_vbo_overbrightmode;
extern convar_t r_studio_sort_textures;
extern convar_t r_studio_drawelements;
extern convar_t r_ripple;
extern convar_t r_ripple_updatetime;
extern convar_t r_ripple_spawntime;
extern convar_t r_water_warp;
extern convar_t r_water_warp_x;
extern convar_t r_water_warp_y;
//
// engine shared convars

615
ref/gl/gl_mirror.c Normal file
View File

@@ -0,0 +1,615 @@
/*
gl_mirror.c - draw reflected surfaces
Copyright (C) 2010 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "gl_local.h"
#include "mod_local.h"
#include "xash3d_mathlib.h"
static void GL_LoadTexMatrix( const matrix4x4 m )
{
pglMatrixMode( GL_TEXTURE );
GL_LoadMatrix( m );
glState.texIdentityMatrix[glState.activeTMU] = false;
}
static void Matrix4x4_CreateScale( matrix4x4 out, float x )
{
out[0][0] = x;
out[0][1] = out[0][2] = out[0][3] = 0.0f;
out[1][0] = out[1][2] = out[1][3] = 0.0f;
out[1][1] = x;
out[2][0] = out[2][1] = out[2][3] = 0.0f;
out[2][2] = x;
out[3][0] = out[3][1] = out[3][2] = 0.0f;
out[3][3] = 1.0f;
}
static void Matrix4x4_ConcatScale( matrix4x4 out, float x )
{
matrix4x4 base, temp;
Matrix4x4_Copy( base, out );
Matrix4x4_CreateScale( temp, x );
Matrix4x4_Concat( out, base, temp );
}
/*
================
R_BeginDrawMirror
Setup texture matrix for mirror texture
================
*/
void R_BeginDrawMirror( msurface_t *fa )
{
matrix4x4 m1, m2, matrix;
GLfloat genVector[4][4];
int i;
Matrix4x4_Copy( matrix, fa->info->mirrormatrix );
Matrix4x4_LoadIdentity( m1 );
Matrix4x4_ConcatScale( m1, 0.5f );
Matrix4x4_Concat( m2, m1, matrix );
Matrix4x4_LoadIdentity( m1 );
Matrix4x4_ConcatTranslate( m1, 0.5f, 0.5f, 0.5f );
Matrix4x4_Concat( matrix, m1, m2 );
for( i = 0; i < 4; i++ )
{
genVector[0][i] = i == 0 ? 1 : 0;
genVector[1][i] = i == 1 ? 1 : 0;
genVector[2][i] = i == 2 ? 1 : 0;
genVector[3][i] = i == 3 ? 1 : 0;
}
GL_TexGen( GL_S, GL_OBJECT_LINEAR );
GL_TexGen( GL_T, GL_OBJECT_LINEAR );
GL_TexGen( GL_R, GL_OBJECT_LINEAR );
GL_TexGen( GL_Q, GL_OBJECT_LINEAR );
pglTexGenfv( GL_S, GL_OBJECT_PLANE, genVector[0] );
pglTexGenfv( GL_T, GL_OBJECT_PLANE, genVector[1] );
pglTexGenfv( GL_R, GL_OBJECT_PLANE, genVector[2] );
pglTexGenfv( GL_Q, GL_OBJECT_PLANE, genVector[3] );
GL_LoadTexMatrix( matrix );
}
/*
================
R_EndDrawMirror
Restore identity texmatrix
================
*/
void R_EndDrawMirror( void )
{
GL_CleanUpTextureUnits( 0 );
pglMatrixMode( GL_MODELVIEW );
}
/*
=============================================================
MIRROR RENDERING
=============================================================
*/
/*
================
R_PlaneForMirror
Get transformed mirrorplane and entity matrix
================
*/
static void R_PlaneForMirror( msurface_t *surf, mplane_t *out, matrix4x4 m )
{
cl_entity_t *ent;
ent = RI.currententity;
// setup mirror plane
*out = *surf->plane;
if( surf->flags & SURF_PLANEBACK )
{
VectorNegate( out->normal, out->normal );
out->dist = -out->dist;
}
if( !VectorIsNull( ent->origin ) || !VectorIsNull( ent->angles ))
{
mplane_t tmp;
if( !VectorIsNull( ent->angles )) Matrix4x4_CreateFromEntity( m, ent->angles, ent->origin, 1.0f );
else Matrix4x4_CreateFromEntity( m, vec3_origin, ent->origin, 1.0f );
tmp = *out;
// transform mirror plane by entity matrix
Matrix4x4_TransformPositivePlane( m, tmp.normal, tmp.dist, out->normal, &out->dist );
}
else Matrix4x4_LoadIdentity( m );
}
/*
================
R_AllocateMirrorTexture
Allocate the screen texture and make copy
================
*/
static int R_AllocateMirrorTexture( void )
{
rgbdata_t r_screen;
int i, texture;
char txName[16];
i = tr.num_mirrors_used;
if( i >= MAX_MIRRORS )
{
gEngfuncs.Con_Printf( S_ERROR "%s: mirror textures limit exceeded!\n", __func__ );
return 0; // disable
}
texture = tr.mirrorTextures[i];
tr.num_mirrors_used++;
if( !texture )
{
// not initialized ?
memset( &r_screen, 0, sizeof( r_screen ));
Q_snprintf( txName, sizeof( txName ), "*screen%i", i );
r_screen.width = RI.viewport[2];
r_screen.height = RI.viewport[3];
r_screen.type = PF_RGBA_32;
r_screen.size = r_screen.width * r_screen.height * 4;
r_screen.flags = IMAGE_HAS_COLOR;
r_screen.buffer = NULL; // create empty texture for now
tr.mirrorTextures[i] = GL_LoadTextureInternal( txName, &r_screen, TF_IMAGE );
texture = tr.mirrorTextures[i];
}
GL_Bind( XASH_TEXTURE0, texture );
pglCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, RI.viewport[0], RI.viewport[1], RI.viewport[2], RI.viewport[3], 0 );
return texture;
}
/*
================
R_DrawMirrors
Draw all viewpasess from mirror position
Mirror textures will be drawn in normal pass
================
*/
void R_DrawMirrors( void )
{
ref_instance_t oldRI;
mplane_t plane;
msurface_t *surf, *surf2;
int i, oldframecount;
mextrasurf_t *es, *tmp, *mirrorchain;
vec3_t forward, right, up;
vec3_t origin, angles;
matrix4x4 mirrormatrix;
cl_entity_t *e;
model_t *m;
float d;
if( !tr.draw_list->num_mirror_entities ) return; // mo mirrors for this frame
oldRI = RI; // make refinst backup
oldframecount = tr.framecount;
for( i = 0; i < tr.draw_list->num_mirror_entities; i++ )
{
mirrorchain = tr.draw_list->mirror_entities[i].chain;
for( es = mirrorchain; es != NULL; es = es->mirrorchain )
{
RI.currententity = e = tr.draw_list->mirror_entities[i].ent;
RI.currentmodel = m = RI.currententity->model;
surf = es->surf;
ASSERT( RI.currententity != NULL );
ASSERT( RI.currentmodel != NULL );
// NOTE: copy mirrortexture and mirrormatrix from another surfaces
// from this entity\world that has same planes and reduce number of viewpasses
// make sure what we have one pass at least
if( es != mirrorchain )
{
for( tmp = mirrorchain; tmp != es; tmp = tmp->mirrorchain )
{
surf2 = tmp->surf;
if( !tmp->mirrortexturenum )
continue; // not filled?
if( surf->plane->dist != surf2->plane->dist )
continue;
if( !VectorCompare( surf->plane->normal, surf2->plane->normal ))
continue;
// found surface with same plane!
break;
}
if( tmp != es && tmp && tmp->mirrortexturenum )
{
// just copy reflection texture from surface with same plane
Matrix4x4_Copy( es->mirrormatrix, tmp->mirrormatrix );
es->mirrortexturenum = tmp->mirrortexturenum;
continue; // pass skiped
}
}
R_PlaneForMirror( surf, &plane, mirrormatrix );
d = -2.0f * ( DotProduct( RI.vieworg, plane.normal ) - plane.dist );
VectorMA( RI.vieworg, d, plane.normal, origin );
d = -2.0f * DotProduct( RI.vforward, plane.normal );
VectorMA( RI.vforward, d, plane.normal, forward );
VectorNormalize( forward );
d = -2.0f * DotProduct( RI.vright, plane.normal );
VectorMA( RI.vright, d, plane.normal, right );
VectorNormalize( right );
d = -2.0f * DotProduct( RI.vup, plane.normal );
VectorMA( RI.vup, d, plane.normal, up );
VectorNormalize( up );
VectorsAngles( forward, right, up, angles );
angles[ROLL] = -angles[ROLL];
RI.params = RP_MIRRORVIEW|RP_CLIPPLANE|RP_OLDVIEWLEAF;
RI.clipPlane = plane;
GL_FrustumSetPlane( &RI.frustum, FRUSTUM_NEAR, plane.normal, plane.dist );
RI.viewangles[0] = anglemod( angles[0] );
RI.viewangles[1] = anglemod( angles[1] );
RI.viewangles[2] = anglemod( angles[2] );
VectorCopy( origin, RI.vieworg );
VectorCopy( origin, RI.cullorigin );
// put pvsorigin before the mirror plane to avoid get full visibility on world mirrors
if( RI.currententity == tr.entities )
{
VectorMA( es->origin, 1.0f, plane.normal, origin );
}
else
{
Matrix4x4_VectorTransform( mirrormatrix, es->origin, origin );
VectorMA( origin, 1.0f, plane.normal, origin );
}
VectorCopy( origin, RI.pvsorigin );
if( GL_Support( GL_ARB_TEXTURE_NPOT_EXT ))
{
// allow screen size
RI.viewport[2] = bound( 96, RI.viewport[2], 1024 );
RI.viewport[3] = bound( 72, RI.viewport[3], 768 );
}
else
{
RI.viewport[2] = NearestPOW( RI.viewport[2], true );
RI.viewport[3] = NearestPOW( RI.viewport[3], true );
RI.viewport[2] = bound( 128, RI.viewport[2], 1024 );
RI.viewport[3] = bound( 64, RI.viewport[3], 512 );
}
R_RenderScene();
r_stats.c_mirror_passes++;
es->mirrortexturenum = R_AllocateMirrorTexture();
// create personal projection matrix for mirror
if( VectorIsNull( e->origin ) && VectorIsNull( e->angles ))
{
Matrix4x4_Copy( es->mirrormatrix, RI.worldviewProjectionMatrix );
}
else
{
Matrix4x4_ConcatTransforms( RI.modelviewMatrix, RI.worldviewMatrix, mirrormatrix );
Matrix4x4_Concat( es->mirrormatrix, RI.projectionMatrix, RI.modelviewMatrix );
}
RI = oldRI; // restore ref instance
}
// clear chain for this entity
for( es = mirrorchain; es != NULL; )
{
tmp = es->mirrorchain;
es->mirrorchain = NULL;
es = tmp;
}
tr.draw_list->mirror_entities[i].chain = NULL; // done
tr.draw_list->mirror_entities[i].ent = NULL;
}
RI.viewleaf = NULL; // force markleafs next frame
tr.draw_list->num_mirror_entities = 0;
tr.num_mirrors_used = 0;
}
/*
================
R_RecursiveMirrorNode
================
*/
static void R_RecursiveMirrorNode( mnode_t *node, uint clipflags )
{
int i, clipped;
msurface_t *surf, **mark;
mleaf_t *pleaf;
int c, side;
float dot;
if( node->contents == CONTENTS_SOLID )
return; // hit a solid leaf
if( node->visframe != tr.visframecount )
return;
if( clipflags )
{
for( i = 0; i < 6; i++ )
{
const mplane_t *p = &RI.frustum.planes[i];
if( !FBitSet( clipflags, BIT( i )))
continue;
clipped = BoxOnPlaneSide( node->minmaxs, node->minmaxs + 3, p );
if( clipped == 2 ) return;
if( clipped == 1 ) ClearBits( clipflags, BIT( i ));
}
}
// if a leaf node, draw stuff
if( node->contents < 0 )
{
pleaf = (mleaf_t *)node;
mark = pleaf->firstmarksurface;
c = pleaf->nummarksurfaces;
if( c )
{
do
{
(*mark)->visframe = tr.framecount;
mark++;
} while( --c );
}
return;
}
// node is just a decision point, so go down the apropriate sides
// find which side of the node we are on
dot = PlaneDiff( tr.modelorg, node->plane );
side = (dot >= 0) ? 0 : 1;
// recurse down the children, front side first
R_RecursiveMirrorNode( node->children[side], clipflags );
// draw stuff
for( c = node->numsurfaces, surf = WORLDMODEL->surfaces + node->firstsurface; c; c--, surf++ )
{
if( !FBitSet( surf->flags, SURF_REFLECT ))
continue;
if( R_CullSurface( surf, &RI.frustum, clipflags ))
continue;
surf->info->mirrorchain = tr.draw_list->mirror_entities[0].chain;
tr.draw_list->mirror_entities[0].chain = surf->info;
}
// recurse down the back side
R_RecursiveMirrorNode( node->children[!side], clipflags );
}
/*
=================
R_FindBmodelMirrors
Check all bmodel surfaces and make personal mirror chain
=================
*/
static void R_FindBmodelMirrors( cl_entity_t *e, qboolean static_entity )
{
vec3_t mins, maxs;
msurface_t *psurf;
model_t *clmodel;
qboolean rotated;
gl_frustum_t *frustum = NULL;
int i;
draw_list_t *const draw_list = tr.draw_list;
if( draw_list->num_mirror_entities >= MAX_MIRROR_ENTITIES )
return;
clmodel = e->model;
// don't draw any water reflections if we underwater
if( ENGINE_GET_PARM( PARM_WATER_LEVEL ) >= 3 && FBitSet( clmodel->flags, MODEL_LIQUID ))
return;
if( static_entity )
{
Matrix4x4_LoadIdentity( RI.objectMatrix );
if( R_CullBox( clmodel->mins, clmodel->maxs ))
return;
VectorCopy( RI.cullorigin, tr.modelorg );
frustum = &RI.frustum;
}
else
{
if( !VectorIsNull( e->angles ))
{
for( i = 0; i < 3; i++ )
{
mins[i] = e->origin[i] - clmodel->radius;
maxs[i] = e->origin[i] + clmodel->radius;
}
rotated = true;
}
else
{
VectorAdd( e->origin, clmodel->mins, mins );
VectorAdd( e->origin, clmodel->maxs, maxs );
rotated = false;
}
if( R_CullBox( mins, maxs ))
return;
if( !VectorIsNull( e->origin ) || !VectorIsNull( e->angles ))
{
if( rotated ) Matrix4x4_CreateFromEntity( RI.objectMatrix, e->angles, e->origin, 1.0f );
else Matrix4x4_CreateFromEntity( RI.objectMatrix, vec3_origin, e->origin, 1.0f );
}
else Matrix4x4_LoadIdentity( RI.objectMatrix );
e->visframe = tr.framecount; // visible
if( rotated ) Matrix4x4_VectorITransform( RI.objectMatrix, RI.cullorigin, tr.modelorg );
else VectorSubtract( RI.cullorigin, e->origin, tr.modelorg );
}
psurf = &clmodel->surfaces[clmodel->firstmodelsurface];
for( i = 0; i < clmodel->nummodelsurfaces; i++, psurf++ )
{
if( !FBitSet( psurf->flags, SURF_REFLECT ))
continue;
if( R_CullSurface( psurf, frustum, 0 ))
continue;
psurf->info->mirrorchain = draw_list->mirror_entities[draw_list->num_mirror_entities].chain;
draw_list->mirror_entities[draw_list->num_mirror_entities].chain = psurf->info;
}
// store new mirror entity
if( !static_entity && draw_list->mirror_entities[draw_list->num_mirror_entities].chain != NULL )
{
draw_list->mirror_entities[draw_list->num_mirror_entities].ent = RI.currententity;
draw_list->num_mirror_entities++;
}
}
/*
=================
R_CheckEntitiesOnList
Check all bmodels for mirror surfaces
=================
*/
static void R_CheckEntitiesOnList( void )
{
int i;
// world has mirror surfaces
if( tr.draw_list->mirror_entities[0].chain != NULL )
{
tr.draw_list->mirror_entities[0].ent = tr.entities;
tr.draw_list->num_mirror_entities++;
}
// check solid entities
for( i = 0; i < tr.draw_list->num_solid_entities; i++ )
{
RI.currententity = tr.draw_list->solid_entities[i];
RI.currentmodel = RI.currententity->model;
ASSERT( RI.currententity != NULL );
ASSERT( RI.currententity->model != NULL );
switch( RI.currentmodel->type )
{
case mod_brush:
R_FindBmodelMirrors( RI.currententity, false );
break;
}
}
// check translucent entities
for( i = 0; i < tr.draw_list->num_trans_entities; i++ )
{
RI.currententity = tr.draw_list->trans_entities[i];
RI.currentmodel = RI.currententity->model;
ASSERT( RI.currententity != NULL );
ASSERT( RI.currententity->model != NULL );
switch( RI.currentmodel->type )
{
case mod_brush:
R_FindBmodelMirrors( RI.currententity, false );
break;
}
}
}
/*
================
R_FindMirrors
Build mirror chains for this frame
================
*/
void R_FindMirrors( void )
{
if( !FBitSet( tr.world->flags, FWORLD_HAS_MIRRORS ) || RI.drawOrtho || !RI.drawWorld || RI.onlyClientDraw || !WORLDMODEL )
return;
// NOTE: we already has initial params at this point like vieworg, viewangles
// all other will be sets into R_SetupFrustum
R_FindViewLeaf ();
// player is outside world. Don't update mirrors for speedup reasons
if(( RI.viewleaf - WORLDMODEL->leafs - 1 ) == -1 )
return;
R_SetupFrustum ();
R_MarkLeaves ();
VectorCopy( RI.cullorigin, tr.modelorg );
RI.currententity = tr.entities;
RI.currentmodel = RI.currententity->model;
R_RecursiveMirrorNode( WORLDMODEL->nodes, RI.frustum.clipFlags );
R_CheckEntitiesOnList();
}

View File

@@ -20,6 +20,7 @@ CVAR_DEFINE_AUTO( gl_test, "0", 0, "engine developer cvar for quick testing new
CVAR_DEFINE_AUTO( gl_msaa, "1", FCVAR_GLCONFIG, "enable or disable multisample anti-aliasing" );
CVAR_DEFINE_AUTO( gl_stencilbits, "8", FCVAR_GLCONFIG|FCVAR_READ_ONLY, "pixelformat stencil bits (0 - auto)" );
CVAR_DEFINE_AUTO( gl_overbright, "1", FCVAR_GLCONFIG, "overbrights" );
CVAR_DEFINE_AUTO( gl_allow_mirrors, "1", FCVAR_GLCONFIG, "allow to draw mirror surfaces" );
CVAR_DEFINE_AUTO( r_lighting_extended, "1", FCVAR_GLCONFIG, "allow to get lighting from world and bmodels" );
CVAR_DEFINE_AUTO( r_lighting_ambient, "0.3", FCVAR_GLCONFIG, "map ambient lighting scale" );
CVAR_DEFINE_AUTO( r_detailtextures, "1", FCVAR_ARCHIVE, "enable detail textures support" );
@@ -32,9 +33,13 @@ CVAR_DEFINE_AUTO( gl_round_down, "2", FCVAR_GLCONFIG|FCVAR_READ_ONLY, "round tex
CVAR_DEFINE( r_vbo, "gl_vbo", "0", FCVAR_ARCHIVE, "draw world using VBO (known to be glitchy)" );
CVAR_DEFINE( r_vbo_detail, "gl_vbo_detail", "0", FCVAR_ARCHIVE, "detail vbo mode (0: disable, 1: multipass, 2: singlepass, broken decal dlights)" );
CVAR_DEFINE( r_vbo_dlightmode, "gl_vbo_dlightmode", "1", FCVAR_ARCHIVE, "vbo dlight rendering mode (0-1)" );
CVAR_DEFINE( r_vbo_overbrightmode, "gl_vbo_overbrightmode", "0", FCVAR_ARCHIVE, "vbo overbright rendering mode (0-1)" );
CVAR_DEFINE_AUTO( r_ripple, "0", FCVAR_GLCONFIG, "enable software-like water texture ripple simulation" );
CVAR_DEFINE_AUTO( r_ripple_updatetime, "0.05", FCVAR_GLCONFIG, "how fast ripple simulation is" );
CVAR_DEFINE_AUTO( r_ripple_spawntime, "0.1", FCVAR_GLCONFIG, "how fast new ripples spawn" );
CVAR_DEFINE_AUTO( r_water_warp, "1", FCVAR_GLCONFIG, "set water warp style (0: disable, 1: sine waves, 2: constant scroll)" );
CVAR_DEFINE_AUTO( r_water_warp_x, "6", FCVAR_GLCONFIG, "water warp scroll x axis speed" );
CVAR_DEFINE_AUTO( r_water_warp_y, "6", FCVAR_GLCONFIG, "water warp scroll y axis speed" );
DEFINE_ENGINE_SHARED_CVAR_LIST()
@@ -1190,6 +1195,9 @@ static void GL_InitCommands( void )
gEngfuncs.Cvar_RegisterVariable( &r_ripple );
gEngfuncs.Cvar_RegisterVariable( &r_ripple_updatetime );
gEngfuncs.Cvar_RegisterVariable( &r_ripple_spawntime );
gEngfuncs.Cvar_RegisterVariable( &r_water_warp );
gEngfuncs.Cvar_RegisterVariable( &r_water_warp_x );
gEngfuncs.Cvar_RegisterVariable( &r_water_warp_y );
gEngfuncs.Cvar_RegisterVariable( &gl_extensions );
gEngfuncs.Cvar_RegisterVariable( &gl_texture_nearest );
@@ -1206,6 +1214,7 @@ static void GL_InitCommands( void )
gEngfuncs.Cvar_RegisterVariable( &gl_stencilbits );
gEngfuncs.Cvar_RegisterVariable( &gl_round_down );
gEngfuncs.Cvar_RegisterVariable( &gl_overbright );
gEngfuncs.Cvar_RegisterVariable( &gl_allow_mirrors );
// these cvar not used by engine but some mods requires this
gEngfuncs.Cvar_RegisterVariable( &gl_polyoffset );
@@ -1248,6 +1257,7 @@ static void R_CheckVBO( void )
gEngfuncs.Cvar_RegisterVariable( &r_vbo );
gEngfuncs.Cvar_RegisterVariable( &r_vbo_dlightmode );
gEngfuncs.Cvar_RegisterVariable( &r_vbo_overbrightmode );
gEngfuncs.Cvar_RegisterVariable( &r_vbo_detail );
}

View File

@@ -218,6 +218,7 @@ void R_ClearScene( void )
tr.draw_list->num_solid_entities = 0;
tr.draw_list->num_trans_entities = 0;
tr.draw_list->num_beam_entities = 0;
tr.draw_list->num_mirror_entities = 0;
// clear the scene befor start new frame
if( gEngfuncs.drawFuncs->R_ClearScene != NULL )
@@ -1011,10 +1012,11 @@ static void R_CheckGamma( void )
ClearBits( gl_overbright.flags, FCVAR_CHANGED );
}
if( gl_overbright.value && FBitSet( r_vbo.flags, FCVAR_CHANGED ))
if( gl_overbright.value && ( FBitSet( r_vbo.flags, FCVAR_CHANGED ) || FBitSet( r_vbo_overbrightmode.flags, FCVAR_CHANGED ) ) )
{
rebuild = true;
ClearBits( r_vbo.flags, FCVAR_CHANGED );
ClearBits( r_vbo_overbrightmode.flags, FCVAR_CHANGED );
}
if( rebuild )
@@ -1126,6 +1128,14 @@ void R_RenderFrame( const ref_viewpass_t *rvp )
R_RunViewmodelEvents();
tr.realframecount++; // right called after viewmodel events
if( gl_allow_mirrors.value )
{
// render mirrors
R_FindMirrors();
R_DrawMirrors();
}
R_RenderScene();
return;

View File

@@ -718,7 +718,7 @@ static void R_BuildLightMap( msurface_t *surf, byte *dest, int stride, qboolean
tmax = ( info->lightextents[1] / sample_size ) + 1;
size = smax * tmax;
if( gl_overbright.value )
lightscale = r_vbo.value ? 171 : 256;
lightscale = (r_vbo.value && !r_vbo_overbrightmode.value) ? 171 : 256;
else lightscale = ( pow( 2.0f, 1.0f / v_lightgamma->value ) * 256 ) + 0.5;
lm = surf->samples;
@@ -927,7 +927,8 @@ static void R_BlendLightmaps( void )
if( gl_overbright.value )
{
pglBlendFunc( GL_DST_COLOR, GL_SRC_COLOR );
pglColor4f( 128.0f / 192.0f, 128.0f / 192.0f, 128.0f / 192.0f, 1.0f );
if(!( r_vbo.value && !r_vbo_overbrightmode.value ))
pglColor4f( 128.0f / 192.0f, 128.0f / 192.0f, 128.0f / 192.0f, 1.0f );
}
else
{
@@ -1141,7 +1142,7 @@ R_RenderBrushPoly
*/
static void R_RenderBrushPoly( msurface_t *fa, int cull_type )
{
qboolean is_dynamic = false;
qboolean is_dynamic = false, is_mirror = false;
int maps;
texture_t *t;
@@ -1152,15 +1153,46 @@ static void R_RenderBrushPoly( msurface_t *fa, int cull_type )
t = R_TextureAnimation( fa );
// set mirror texture
if( RP_NORMALPASS() && FBitSet( fa->flags, SURF_REFLECT ))
{
if( fa->info->mirrortexturenum )
{
GL_Bind( XASH_TEXTURE0, fa->info->mirrortexturenum );
is_mirror = true;
// reset just in case if mirror failed to render
fa->info->mirrortexturenum = 0;
// blend-in water
if( FBitSet( fa->flags, SURF_DRAWTURB ))
{
R_BeginDrawMirror( fa );
R_UploadRipples( t, true );
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
// warp texture, no lightmaps
EmitWaterPolys( fa, (cull_type == CULL_BACKSIDE));
R_EndDrawMirror();
return;
}
}
}
if( FBitSet( fa->flags, SURF_DRAWTURB ))
{
R_UploadRipples( t );
R_UploadRipples( t, false );
// warp texture, no lightmaps
EmitWaterPolys( fa, (cull_type == CULL_BACKSIDE));
return;
}
else GL_Bind( XASH_TEXTURE0, t->gl_texturenum );
else if( !is_mirror ) // already set up mirror texture
{
GL_Bind( XASH_TEXTURE0, t->gl_texturenum );
}
if( t->fb_texturenum )
{
@@ -1198,7 +1230,9 @@ static void R_RenderBrushPoly( msurface_t *fa, int cull_type )
}
}
if( is_mirror ) R_BeginDrawMirror( fa );
DrawGLPoly( fa->polys, 0.0f, 0.0f );
if( is_mirror ) R_EndDrawMirror();
if( RI.currententity->curstate.rendermode == kRenderNormal )
{
@@ -1212,6 +1246,10 @@ static void R_RenderBrushPoly( msurface_t *fa, int cull_type )
DrawSurfaceDecals( fa, true, (cull_type == CULL_BACKSIDE));
}
// NOTE: draw mirror through in mirror show dummy lightmapped texture
if( RP_NORMALPASS() && FBitSet( fa->flags, SURF_REFLECT ))
return; // no lightmaps for mirror
if( FBitSet( fa->flags, SURF_DRAWTILED ))
return; // no lightmaps anyway
@@ -1431,7 +1469,7 @@ void R_DrawWaterSurfaces( void )
continue;
// set modulate mode explicitly
R_UploadRipples( t );
R_UploadRipples( t, false );
for( ; s; s = s->texturechain )
EmitWaterPolys( s, false );
@@ -1550,6 +1588,9 @@ void R_DrawBrushModel( cl_entity_t *e )
if( clmodel->surfaces != WORLDMODEL->surfaces )
allow_vbo = false;
if( R_CullEntityInMirror( e ))
return;
if( !VectorIsNull( e->angles ))
{
for( i = 0; i < 3; i++ )
@@ -1902,7 +1943,7 @@ void R_GenerateVBO( void )
if( surf->lightmaptexturenum != k )
continue;
if( surf->flags & ( SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS ) )
if( FBitSet( surf->flags, SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS | SURF_REFLECT ))
continue;
if( R_TextureAnimation( surf ) != world->textures[j] )
@@ -1971,7 +2012,7 @@ void R_GenerateVBO( void )
if( surf->lightmaptexturenum != k )
continue;
if( surf->flags & ( SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS ) )
if( FBitSet( surf->flags, SURF_DRAWSKY | SURF_DRAWTURB | SURF_CONVEYOR | SURF_DRAWTURB_QUADS | SURF_REFLECT ))
continue;
if( R_TextureAnimation( surf ) != world->textures[j] )
@@ -2189,15 +2230,30 @@ static void R_SetLightmap( void )
if( gl_overbright.value )
{
// GLfloat color[4] = { 128.0f / 192.0f, 128.0f / 192.0f, 128.0f / 192.0f, 1.0f };
if( r_vbo_overbrightmode.value == 1 )
{
GLfloat color[4] = { 128.0f / 192.0f, 128.0f / 192.0f, 128.0f / 192.0f, 1.0f };
int tmu = glState.activeTMU;
GL_SelectTexture( tmu - 1 );
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
pglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE );
pglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_CONSTANT_ARB );
pglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
pglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
pglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR );
pglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE );
// doesn't work here for some reason
pglTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color );
GL_SelectTexture( tmu );
}
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
pglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE );
pglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB );
pglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE );
pglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE );
pglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB );
pglTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2 );
// doesn't work here for some reason
// pglTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color );
}
else
{
@@ -3805,7 +3861,14 @@ void GL_BuildLightmaps( void )
GL_FreeTexture( tr.lightmapTextures[i] );
}
for( i = 0; i < MAX_MIRRORS; i++ )
{
if( !tr.mirrorTextures[i] ) break;
GL_FreeTexture( tr.mirrorTextures[i] );
}
memset( tr.lightmapTextures, 0, sizeof( tr.lightmapTextures ));
memset( tr.mirrorTextures, 0, sizeof( tr.mirrorTextures ));
memset( &RI, 0, sizeof( RI ));
// update the lightmap blocksize
@@ -3821,6 +3884,8 @@ void GL_BuildLightmaps( void )
tr.realframecount = 1;
nColinElim = 0;
tr.num_mirrors_used = 0;
// setup the texture for dlights
R_InitDlightTexture();

View File

@@ -46,7 +46,7 @@ R_SpriteLoadFrame
upload a single frame
====================
*/
static const dframetype_t *R_SpriteLoadFrame( model_t *mod, const void *pin, mspriteframe_t **ppframe, int num )
static const byte *R_SpriteLoadFrame( model_t *mod, const void *pin, mspriteframe_t **ppframe, int num )
{
dspriteframe_t pinframe;
mspriteframe_t *pspriteframe;
@@ -82,7 +82,7 @@ static const dframetype_t *R_SpriteLoadFrame( model_t *mod, const void *pin, msp
pspriteframe->gl_texturenum = gl_texturenum;
*ppframe = pspriteframe;
return ( const dframetype_t* )(( const byte* )pin + sizeof( dspriteframe_t ) + pinframe.width * pinframe.height * bytes );
return (( const byte* )pin + sizeof( dspriteframe_t ) + pinframe.width * pinframe.height * bytes );
}
/*
@@ -92,7 +92,7 @@ R_SpriteLoadGroup
upload a group frames
====================
*/
static const dframetype_t *R_SpriteLoadGroup( model_t *mod, const void *pin, mspriteframe_t **ppframe, int framenum )
static const byte *R_SpriteLoadGroup( model_t *mod, const void *pin, mspriteframe_t **ppframe, int framenum )
{
const dspritegroup_t *pingroup;
mspritegroup_t *pspritegroup;
@@ -128,9 +128,10 @@ static const dframetype_t *R_SpriteLoadGroup( model_t *mod, const void *pin, msp
ptemp = R_SpriteLoadFrame( mod, ptemp, &pspritegroup->frames[i], framenum * 10 + i );
}
return (const dframetype_t *)ptemp;
return ptemp;
}
/*
====================
Mod_LoadSpriteModel
@@ -142,7 +143,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
{
const dsprite_t *pin;
const short *numi = NULL;
const dframetype_t *pframetype;
const byte *pframetype;
msprite_t *psprite;
int i;
@@ -152,7 +153,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
if( pin->version == SPRITE_VERSION_Q1 || pin->version == SPRITE_VERSION_32 )
numi = NULL;
else if( pin->version == SPRITE_VERSION_HL )
numi = (const short *)(void *)((const byte*)buffer + sizeof( dsprite_hl_t ));
numi = (const short *)((const byte*)buffer + sizeof( dsprite_hl_t ));
r_texFlags = texFlags;
sprite_version = pin->version;
@@ -164,7 +165,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
rgbdata_t *pal;
pal = gEngfuncs.FS_LoadImage( "#id.pal", (byte *)&i, 768 );
pframetype = (const dframetype_t *)(void *)((const byte*)buffer + sizeof( dsprite_q1_t )); // pinq1 + 1
pframetype = ((const byte*)buffer + sizeof( dsprite_q1_t )); // pinq1 + 1
gEngfuncs.FS_FreeImage( pal ); // palette installed, no reason to keep this data
}
else if( *numi == 256 )
@@ -186,7 +187,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
break;
}
pframetype = (const dframetype_t *)(void *)(src + 768);
pframetype = (const byte *)(src + 768);
gEngfuncs.FS_FreeImage( pal ); // palette installed, no reason to keep this data
}
else
@@ -200,22 +201,26 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
for( i = 0; i < mod->numframes; i++ )
{
frametype_t frametype = pframetype->type;
frametype_t frametype;
dframetype_t dframetype;
memcpy( &dframetype, pframetype, sizeof( dframetype ));
frametype = dframetype.type;
psprite->frames[i].type = (spriteframetype_t)frametype;
switch( frametype )
{
case FRAME_SINGLE:
Q_strncpy( group_suffix, "frame", sizeof( group_suffix ));
pframetype = R_SpriteLoadFrame( mod, pframetype + 1, &psprite->frames[i].frameptr, i );
pframetype = R_SpriteLoadFrame( mod, pframetype + sizeof( dframetype_t ), &psprite->frames[i].frameptr, i );
break;
case FRAME_GROUP:
Q_strncpy( group_suffix, "group", sizeof( group_suffix ));
pframetype = R_SpriteLoadGroup( mod, pframetype + 1, &psprite->frames[i].frameptr, i );
pframetype = R_SpriteLoadGroup( mod, pframetype + sizeof( dframetype_t ), &psprite->frames[i].frameptr, i );
break;
case FRAME_ANGLED:
Q_strncpy( group_suffix, "angle", sizeof( group_suffix ));
pframetype = R_SpriteLoadGroup( mod, pframetype + 1, &psprite->frames[i].frameptr, i );
pframetype = R_SpriteLoadGroup( mod, pframetype + sizeof( dframetype_t ), &psprite->frames[i].frameptr, i );
break;
}
if( pframetype == NULL ) break; // technically an error
@@ -696,6 +701,9 @@ static qboolean R_SpriteOccluded( cl_entity_t *e, vec3_t origin, float *pscale )
float blend;
vec3_t v;
if( R_CullEntityInMirror( e ))
return true;
TriWorldToScreen( origin, v );
if( v[0] < RI.viewport[0] || v[0] > RI.viewport[0] + RI.viewport[2] )

View File

@@ -32,8 +32,11 @@ typedef struct
model_t *model;
} player_model_t;
// never gonna change, just shut up const warning
cvar_t r_shadows = { (char *)"r_shadows", (char *)"0", 0 };
// never gonna change you up, never gonna override you down
// TODO: actually let client.dll override it
CVAR_DEFINE_AUTO( r_shadows, "0", FCVAR_ARCHIVE, "drop ugly shadow" );
CVAR_DEFINE_AUTO( r_shadow_alpha, "0.5", FCVAR_ARCHIVE, "ugly shadow opacity" );
CVAR_DEFINE_AUTO( r_shadow_height, "0", FCVAR_ARCHIVE, "ugly shadow height" );
static vec3_t hullcolor[8] =
{
@@ -154,8 +157,12 @@ void R_StudioInit( void )
Matrix3x4_LoadIdentity( g_studio.rotationmatrix );
// g-cont. cvar disabled by Valve
// gEngfuncs.Cvar_RegisterVariable( &r_shadows );
// a1ba: enabled since HL25
gEngfuncs.Cvar_RegisterVariable( &r_shadows );
// a1ba: TimeWarp cvars (TODO: move to client.dll)
gEngfuncs.Cvar_RegisterVariable( &r_shadow_alpha );
gEngfuncs.Cvar_RegisterVariable( &r_shadow_height );
g_studio.interpolate = true;
g_studio.framecount = 0;
@@ -2930,25 +2937,35 @@ R_StudioDrawPointsShadow
static void R_StudioDrawPointsShadow( void )
{
float *av, height;
float vec_x, vec_y;
mstudiomesh_t *pmesh;
vec3_t point;
int i, k;
pmtrace_t tr;
vec3_t trEnd;
if( FBitSet( RI.currententity->curstate.effects, EF_NOSHADOW ))
return;
VectorCopy( RI.currententity->origin, trEnd );
trEnd[2] -= 4096;
tr = gEngfuncs.CL_TraceLine( RI.currententity->origin, trEnd, PM_STUDIO_IGNORE | PM_GLASS_IGNORE );
// didn't hit floor
if( tr.fraction >= 1.0f )
return;
if( glState.stencilEnabled )
pglEnable( GL_STENCIL_TEST );
height = g_studio.lightspot[2] + 1.0f;
vec_x = -g_studio.lightvec[0] * 8.0f;
vec_y = -g_studio.lightvec[1] * 8.0f;
height = r_shadow_height.value;
for( k = 0; k < m_pSubModel->nummesh; k++ )
{
short *ptricmds;
if( FBitSet( g_studio.meshes[k].flags, STUDIO_NF_MASKED | STUDIO_NF_ADDITIVE | STUDIO_NF_FULLBRIGHT ))
continue;
pmesh = (mstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex) + k;
ptricmds = (short *)((byte *)m_pStudioHeader + pmesh->triindex);
@@ -2970,11 +2987,7 @@ static void R_StudioDrawPointsShadow( void )
for( ; i > 0; i--, ptricmds += 4 )
{
av = g_studio.verts[ptricmds[0]];
point[0] = av[0] - (vec_x * ( av[2] - g_studio.lightspot[2] ));
point[1] = av[1] - (vec_y * ( av[2] - g_studio.lightspot[2] ));
point[2] = g_studio.lightspot[2] + 1.0f;
pglVertex3fv( point );
pglVertex3f( av[0], av[1], tr.endpos[2] + height + 0.16f );
}
pglEnd();
@@ -3035,12 +3048,10 @@ static void GL_StudioDrawShadow( void )
if( r_shadows.value && g_studio.rendermode != kRenderTransAdd && !FBitSet( RI.currentmodel->flags, STUDIO_AMBIENT_LIGHT ))
{
float color = 1.0f - (tr.blend * 0.5f);
pglDisable( GL_TEXTURE_2D );
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
pglEnable( GL_BLEND );
pglColor4f( 0.0f, 0.0f, 0.0f, 1.0f - color );
pglColor4f( 0.0f, 0.0f, 0.0f, ( tr.blend - 1 ) + r_shadow_alpha.value );
pglDepthFunc( GL_LESS );
R_StudioDrawPointsShadow();

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