Compare commits

...

58 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
68 changed files with 1563 additions and 337 deletions

View File

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

5
.gitignore vendored
View File

@@ -54,6 +54,11 @@ CMakeFiles
Makefile Makefile
cmake_install.cmake cmake_install.cmake
install_manifest.txt install_manifest.txt
CMakeLists.txt*
CMakeScripts
Testing
compile_commands.json
_deps
# makedepend # makedepend
Makefile.dep Makefile.dep
*.bak *.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

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

View File

@@ -228,7 +228,9 @@ typedef struct mextrasurf_s
unsigned short numverts; // world->vertexes[] unsigned short numverts; // world->vertexes[]
int firstvertex; // fisrt look up in tr.tbn_vectors[], then acess to 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; } mextrasurf_t;
struct msurface_s struct msurface_s
@@ -534,5 +536,14 @@ typedef struct
#define MAX_EFRAGS 8192 // Arcane Dimensions required #define MAX_EFRAGS 8192 // Arcane Dimensions required
#define MAX_REQUESTS 64 #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 #endif//COM_MODEL_H

View File

@@ -92,6 +92,7 @@
#define SOLID_BSP 4 // bsp clip, touch on edge, block #define SOLID_BSP 4 // bsp clip, touch on edge, block
#define SOLID_CUSTOM 5 // call external callbacks for tracing #define SOLID_CUSTOM 5 // call external callbacks for tracing
#define SOLID_PORTAL 6 // borrowed from FTE #define SOLID_PORTAL 6 // borrowed from FTE
#define SOLID_GIB 7 // do not block, only collide with solid brushes
// edict->deadflag values // edict->deadflag values
#define DEAD_NO 0 // alive #define DEAD_NO 0 // alive
@@ -114,6 +115,8 @@
#define EF_LIGHT 64 // rocket flare glow sprite #define EF_LIGHT 64 // rocket flare glow sprite
#define EF_NODRAW 128 // don't draw entity #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_WATERSIDES (1U<<26) // Do not remove sides for func_water entity
#define EF_FULLBRIGHT (1U<<27) // Just get fullbright #define EF_FULLBRIGHT (1U<<27) // Just get fullbright
#define EF_NOSHADOW (1U<<28) // ignore shadow for this entity #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 #define XASH_INTERNAL_GAMELIBS
#endif // XASH_ANDROID || XASH_IOS || XASH_EMSCRIPTEN #endif // XASH_ANDROID || XASH_IOS || XASH_EMSCRIPTEN
#if XASH_ANDROID && XASH_SDL
#define XASH_ANDROID_ASSETS 1
#endif
// Defaults // Defaults
#ifndef DEFAULT_TOUCH_ENABLE #ifndef DEFAULT_TOUCH_ENABLE
#define DEFAULT_TOUCH_ENABLE "0" #define DEFAULT_TOUCH_ENABLE "0"

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_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_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! #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 // 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_IMPROVED_LINETRACE \
| ENGINE_COMPUTE_STUDIO_LERP \ | ENGINE_COMPUTE_STUDIO_LERP \
| ENGINE_LINEAR_GAMMA_SPACE \ | ENGINE_LINEAR_GAMMA_SPACE \
| ENGINE_ALLOW_MIRRORS \
| ENGINE_STEP_POSHISTORY_LERP ) | ENGINE_STEP_POSHISTORY_LERP )
#endif//FEATURES_H #endif//FEATURES_H

View File

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

View File

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

View File

@@ -28,7 +28,6 @@ GNU General Public License for more details.
#define MAX_CMD_BUFFER 8000 #define MAX_CMD_BUFFER 8000
#define CONNECTION_PROBLEM_TIME 15.0 // 15 seconds #define CONNECTION_PROBLEM_TIME 15.0 // 15 seconds
#define CL_CONNECTION_RETRIES 10 #define CL_CONNECTION_RETRIES 10
#define CL_TEST_RETRIES_NORESPONCE 3
#define CL_TEST_RETRIES 5 #define CL_TEST_RETRIES 5
CVAR_DEFINE_AUTO( mp_decals, "300", FCVAR_ARCHIVE, "decals limit in multiplayer" ); CVAR_DEFINE_AUTO( mp_decals, "300", FCVAR_ARCHIVE, "decals limit in multiplayer" );
@@ -1072,6 +1071,22 @@ static void CL_SendConnectPacket( void )
cls.timestart = Sys_DoubleTime(); 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 CL_CheckForResend
@@ -1083,8 +1098,9 @@ static void CL_CheckForResend( void )
{ {
netadr_t adr; netadr_t adr;
net_gai_state_t res; net_gai_state_t res;
float resendTime;
qboolean bandwidthTest; qboolean bandwidthTest;
if( cls.internetservers_wait ) if( cls.internetservers_wait )
CL_SendMasterServerScanRequest(); CL_SendMasterServerScanRequest();
@@ -1110,7 +1126,10 @@ static void CL_CheckForResend( void )
else if( cl_resend.value > CL_MAX_RESEND_TIME ) else if( cl_resend.value > CL_MAX_RESEND_TIME )
Cvar_SetValue( "cl_resend", 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; return;
res = NET_StringToAdrNB( cls.servername, &adr ); res = NET_StringToAdrNB( cls.servername, &adr );
@@ -1137,10 +1156,11 @@ static void CL_CheckForResend( void )
if( adr.port == 0 ) adr.port = MSG_BigShort( PORT_SERVER ); 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 // 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" ); Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" );
Cvar_SetValue( "cl_dlmax", FRAGMENT_MIN_SIZE ); Cvar_SetValue( "cl_dlmax", FRAGMENT_MIN_SIZE );
cls.connect_time = host.realtime; cls.connect_time = host.realtime;
@@ -1148,16 +1168,15 @@ static void CL_CheckForResend( void )
return; return;
} }
bandwidthTest = !cls.legacymode && cl_test_bandwidth.value;
cls.serveradr = adr; 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_time = host.realtime; // for retransmit requests
cls.connect_retry++; cls.connect_retry++;
if( bandwidthTest ) 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 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 ) if( bandwidthTest )
Netchan_OutOfBandPrint( NS_CLIENT, adr, "bandwidth %i %i\n", PROTOCOL_VERSION, cls.max_fragment_size ); Netchan_OutOfBandPrint( NS_CLIENT, adr, "bandwidth %i %i\n", PROTOCOL_VERSION, cls.max_fragment_size );

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; pmove->player_index = ps->number - 1;
// a1ba: workaround bug on old protocol where the server refuse to send // a1ba: workaround bug where the server refuse to send our local player in delta
// our local player in delta. cl.playernum, in theory, must be equal // cl.playernum, in theory, must be equal to our local player index anyway
// to our local player index anyway //
// this might not be a real solution, since everything else will be bogus // this might not be a real solution, since everything else will be bogus
// but we need to properly run prediction and avoid potential memory // but we need to properly run prediction and avoid potential memory
// corruption // corruption
// either debug this, or remove when old protocol will be dropped!!!
if( pmove->player_index < 0 ) if( pmove->player_index < 0 )
{ pmove->player_index = bound( 0, cl.playernum, cl.maxclients - 1 );
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->multiplayer = (cl.maxclients > 1); pmove->multiplayer = (cl.maxclients > 1);
pmove->runfuncs = runfuncs; pmove->runfuncs = runfuncs;

View File

@@ -2100,9 +2100,13 @@ void Con_RunConsole( void )
// decide on the destination height of the console // decide on the destination height of the console
if( host.allow_console && cls.key_dest == key_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 ) if( cls.state < ca_active || cl.first_frame )
con.showlines = refState.height; // full screen con.showlines = refState.height; // full screen
else con.showlines = (refState.height >> 1); // half screen else con.showlines = (refState.height >> 1); // half screen
#endif
} }
else con.showlines = 0; // none visible else con.showlines = 0; // none visible

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; touch.move_finger = touch.resize_finger = touch.look_finger = -1;
// Hack for keyboard, hope it help // Hack for keyboard, hope it help
// a1ba: this is absolutely horrible
if( cls.key_dest == key_console || cls.key_dest == key_message ) 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 ); Key_EnableTextInput( true, true );
x1 = 0.0f;
}
if( cls.key_dest == key_console ) if( cls.key_dest == key_console )
{ {
static float y1 = 0; 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 // exit of console area
if( type == event_down && x < 0.1f && y > 0.9f ) if( type == event_down && x < 0.1f && y > 0.9f )
Cbuf_AddText( "escape\n" ); 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) ); 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) ); //MsgDev( D_NOTE, "touch %d %d\n", TO_SCRN_X(x), TO_SCRN_Y(y) );

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_level, "ambient_level", "0.3", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "volume of environment noises (water and wind)" );
static CVAR_DEFINE( s_ambient_fade, "ambient_fade", "1000", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "rate of volume fading when client is moving" ); static CVAR_DEFINE( s_ambient_fade, "ambient_fade", "1000", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "rate of volume fading when client is moving" );
static CVAR_DEFINE_AUTO( s_combine_sounds, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "combine channels with same sounds" ); static CVAR_DEFINE_AUTO( s_combine_sounds, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "combine channels with same sounds" );
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_test, "0", 0, "engine developer cvar for quick testing new features" );
CVAR_DEFINE_AUTO( s_samplecount, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "sample count (0 for default value)" ); CVAR_DEFINE_AUTO( s_samplecount, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "sample count (0 for default value)" );
CVAR_DEFINE_AUTO( s_warn_late_precache, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "warn about late precached sounds on client-side" ); CVAR_DEFINE_AUTO( s_warn_late_precache, "0", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "warn about late precached sounds on client-side" );
@@ -64,6 +64,12 @@ float S_GetMasterVolume( void )
{ {
float scale = 1.0f; float scale = 1.0f;
if( host.status == HOST_NOFOCUS && snd_mute_losefocus.value != 0.0f )
{
// we return zero volume to keep sounds running
return 0.0f;
}
if( !s_listener.inmenu && soundfade.percent != 0 ) if( !s_listener.inmenu && soundfade.percent != 0 )
{ {
scale = bound( 0.0f, soundfade.percent / 100.0f, 1.0f ); scale = bound( 0.0f, soundfade.percent / 100.0f, 1.0f );

View File

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

View File

@@ -20,8 +20,6 @@ GNU General Public License for more details.
#include "vid_common.h" #include "vid_common.h"
#include "platform/platform.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_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_rotate, "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen rotation (0-3)" );
static CVAR_DEFINE_AUTO( vid_scale, "1.0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "pixel scale" ); 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_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_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( 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_xpos, "_window_xpos", "-1", FCVAR_RENDERINFO, "window position by horizontal" );
CVAR_DEFINE( window_ypos, "_window_ypos", "-1", FCVAR_RENDERINFO, "window position by vertical" ); 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_fullscreen;
extern convar_t vid_maximized; extern convar_t vid_maximized;
extern convar_t vid_highdpi; extern convar_t vid_highdpi;
extern convar_t window_width;
extern convar_t window_height;
extern convar_t window_xpos; extern convar_t window_xpos;
extern convar_t window_ypos; extern convar_t window_ypos;
extern convar_t gl_msaa_samples; extern convar_t gl_msaa_samples;

View File

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

View File

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

View File

@@ -2026,6 +2026,14 @@ static qboolean Mod_LooksLikeWaterTexture( const char *name )
return false; 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 ) static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureIndex )
{ {
#if !XASH_DEDICATED #if !XASH_DEDICATED
@@ -2480,6 +2488,13 @@ static void Mod_LoadSurfaces( model_t *mod, dbspmodel_t *bmod )
if( !Q_strncmp( tex->name, "{scroll", 7 )) if( !Q_strncmp( tex->name, "{scroll", 7 ))
SetBits( out->flags, SURF_CONVEYOR|SURF_TRANSPARENT ); 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] == '{' ) if( tex->name[0] == '{' )
SetBits( out->flags, SURF_TRANSPARENT ); SetBits( out->flags, SURF_TRANSPARENT );
@@ -2697,6 +2712,9 @@ static void Mod_LoadLeafs( model_t *mod, dbspmodel_t *bmod )
{ {
// mark underwater surfaces // mark underwater surfaces
SetBits( out->firstmarksurface[j]->flags, SURF_UNDERWATER ); 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_CUSTOM (1<<MAX_CUSTOM_BITS)// 10 bits == 1024 generic file
#define MAX_USER_MESSAGES 197 // another 58 messages reserved for engine routines #define MAX_USER_MESSAGES 197 // another 58 messages reserved for engine routines
#define MAX_DLIGHTS 32 // dynamic lights (rendered per one frame) #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_LIGHTSTYLES 256 // a1ba: increased from 64 to 256, protocol limit
#define MAX_RENDER_DECALS 4096 // max rendering decals per a level #define MAX_RENDER_DECALS 4096 // max rendering decals per a level

View File

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

View File

@@ -93,123 +93,241 @@ static mempool_t *Mem_FindPool( poolhandle_t poolptr )
} }
#endif #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 ) void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
{ {
memheader_t *mem; memheader_t *mem;
mempool_t *pool; mempool_t *pool;
if( size <= 0 ) return NULL; if( size <= 0 )
if( !poolptr ) Sys_Error( "Mem_Alloc: pool == NULL (alloc at %s:%i)\n", filename, fileline ); 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 ); 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 ) if( clear )
memset((void *)((byte *)mem + sizeof( memheader_t )), 0, mem->size ); memset((void *)((byte *)mem + sizeof( memheader_t )), 0, mem->size );
return (void *)((byte *)mem + sizeof( memheader_t )); 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 ) static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline )
{ {
mempool_t *pool; mempool_t *pool;
if( mem->sentinel1 != MEMHEADER_SENTINEL1 ) if( !Mem_CheckAllocHeader( __func__, mem, filename, fileline ))
{ return;
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 );
}
pool = mem->pool; pool = mem->pool;
// unlink memheader from doubly linked list // unlink memheader from doubly linked list
if(( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem )) if(( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem ))
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; Mem_PoolSubtract( pool, mem->size );
else pool->chain = mem->next; 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 ); Q_free( mem );
} }
void _Mem_Free( void *data, const char *filename, int fileline ) 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 ); 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; memheader_t *mem;
char *nb; 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 )); Sys_Error( "Mem_Realloc: pool == NULL (alloc at %s:%i)\n", filename, fileline );
if( size == memhdr->size ) return memptr; 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! char *nb = _Mem_Alloc( poolptr, size, clear, filename, fileline );
memcpy( nb, memptr, newsize );
_Mem_Free( memptr, filename, fileline ); // free unused old block 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 ) 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 // unlink pool from chain
for( chainaddress = &poolchain; *chainaddress && *chainaddress != pool; chainaddress = &((*chainaddress)->next)); 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( *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 ); Mem_CheckPool( "Mem_FreePool", pool, 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 );
*chainaddress = pool->next; *chainaddress = pool->next;
// free memory owned by the pool // 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 ); mempool_t *pool = Mem_FindPool( poolptr );
if( !poolptr ) Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline ); 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 ); Mem_CheckPool( "Mem_FreePool", pool, 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 );
// free memory owned by the pool // free memory owned by the pool
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline ); while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
@@ -288,14 +404,19 @@ static qboolean Mem_CheckAlloc( mempool_t *pool, void *data )
// search only one pool // search only one pool
target = (memheader_t *)((byte *)data - sizeof( memheader_t )); target = (memheader_t *)((byte *)data - sizeof( memheader_t ));
for( header = pool->chain; header; header = header->next ) for( header = pool->chain; header; header = header->next )
if( header == target ) return true; {
if( header == target )
return true;
}
} }
else else
{ {
// search all pools // search all pools
for( pool = poolchain; pool; pool = pool->next ) for( pool = poolchain; pool; pool = pool->next )
{
if( Mem_CheckAlloc( pool, data )) if( Mem_CheckAlloc( pool, data ))
return true; return true;
}
} }
return false; return false;
} }
@@ -308,49 +429,24 @@ Check pointer for memory
qboolean Mem_IsAllocatedExt( poolhandle_t poolptr, void *data ) qboolean Mem_IsAllocatedExt( poolhandle_t poolptr, void *data )
{ {
mempool_t *pool = NULL; mempool_t *pool = NULL;
if( poolptr ) pool = Mem_FindPool( poolptr );
if( poolptr )
pool = Mem_FindPool( poolptr );
return Mem_CheckAlloc( pool, data ); 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 ) void _Mem_Check( const char *filename, int fileline )
{ {
memheader_t *mem; memheader_t *mem;
mempool_t *pool; mempool_t *pool;
for( pool = poolchain; pool; pool = pool->next ) for( pool = poolchain; pool; pool = pool->next )
{ Mem_CheckPool( "Mem_CheckSentinels", pool, filename, fileline );
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 );
}
for( pool = poolchain; pool; pool = pool->next ) for( pool = poolchain; pool; pool = pool->next )
for( mem = pool->chain; mem; mem = mem->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 ) void Mem_PrintStats( void )
@@ -377,28 +473,31 @@ void Mem_PrintList( size_t minallocationsize )
Mem_Check(); 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 ) for( pool = poolchain; pool; pool = pool->next )
{ {
long changed_size = (long)pool->totalsize - (long)pool->lastchecksize; long changed_size = (long)pool->totalsize - (long)pool->lastchecksize;
// poolnames can contain color symbols, make sure what color is reset // 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) ? '-' : '+'; char sign = (changed_size < 0) ? '-' : '+';
Con_Printf( "%10s (%10s actual) %s (^7%c%s change)\n", Q_memprint( pool->totalsize ), Q_memprint( pool->realsize ), 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 ))); pool->name, sign, Q_memprint( abs( changed_size )));
} }
else 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; pool->lastchecksize = pool->totalsize;
for( mem = pool->chain; mem; mem = mem->next ) for( mem = pool->chain; mem; mem = mem->next )
{
if( mem->size >= minallocationsize ) if( mem->size >= minallocationsize )
Con_Printf( "%10s allocated at %s:%i\n", Q_memprint( mem->size ), mem->filename, mem->fileline ); 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 // network address funcs
const char *(*pfnAdrToString)( const struct netadr_s a ); const char *(*pfnAdrToString)( const struct netadr_s a );
int (*pfnCompareAdr)( const void *a, const void *b ); // netadr_t int (*pfnCompareAdr)( const void *a, const void *b ); // netadr_t
void *(*pfnGetNativeObject)( const char *name );
} ui_extendedfuncs_t; } ui_extendedfuncs_t;
// deprecated export from old engine // deprecated export from old engine

View File

@@ -107,7 +107,10 @@ typedef struct server_physics_api_s
int (*pfnSaveFile)( const char *filename, const void *data, int len ); int (*pfnSaveFile)( const char *filename, const void *data, int len );
const byte *(*pfnLoadImagePixels)( const char *filename, int *width, int *height ); 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; } server_physics_api_t;
// physic callbacks // physic callbacks

View File

@@ -61,23 +61,16 @@ Android_GetNativeObject
void *Android_GetNativeObject( const char *name ) void *Android_GetNativeObject( const char *name )
{ {
static const char *availObjects[] = { "JNIEnv", "ActivityClass", NULL }; if( !strcasecmp( name, "JNIEnv" ) )
void *object = NULL;
if( !name )
{ {
object = (void *)availObjects; return (void *)jni.env;
}
else if( !strcasecmp( name, "JNIEnv" ) )
{
object = (void *)jni.env;
} }
else if( !strcasecmp( name, "ActivityClass" ) ) 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 void *g_hsystemd;
static int (*g_pfn_sd_notify)( int unset_environment, const char *state ); static int (*g_pfn_sd_notify)( int unset_environment, const char *state );
qboolean Sys_DebuggerPresent( void ) qboolean Platform_DebuggerPresent( void )
{ {
char buf[4096]; char buf[4096];
ssize_t num_read; ssize_t num_read;

View File

@@ -34,8 +34,8 @@ double Platform_DoubleTime( void );
void Platform_Sleep( int msec ); void Platform_Sleep( int msec );
void Platform_ShellExecute( const char *path, const char *parms ); void Platform_ShellExecute( const char *path, const char *parms );
void Platform_MessageBox( const char *title, const char *message, qboolean parentMainWindow ); void Platform_MessageBox( const char *title, const char *message, qboolean parentMainWindow );
qboolean Sys_DebuggerPresent( void ); // optional, see Sys_DebugBreak
void Platform_SetStatus( const char *status ); void Platform_SetStatus( const char *status );
qboolean Platform_DebuggerPresent( void );
// legacy iOS port functions // legacy iOS port functions
#if TARGET_OS_IOS #if TARGET_OS_IOS
@@ -64,6 +64,8 @@ const char *Android_LoadID( void );
void Android_SaveID( const char *id ); void Android_SaveID( const char *id );
void Android_Init( void ); void Android_Init( void );
void *Android_GetNativeObject( const char *name ); void *Android_GetNativeObject( const char *name );
int Android_GetKeyboardHeight( void );
void Android_Shutdown( void );
#endif #endif
#if XASH_WIN32 #if XASH_WIN32
@@ -140,6 +142,15 @@ static inline void Platform_Shutdown( void )
#endif #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_Activate( qboolean activate );
qboolean VoiceCapture_Lock( qboolean lock ); 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 #endif // PLATFORM_H

View File

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

View File

@@ -374,14 +374,8 @@ static void SDLash_ActiveEvent( int gain )
{ {
host.status = HOST_FRAME; host.status = HOST_FRAME;
if( cls.key_dest == key_game ) if( cls.key_dest == key_game )
{
IN_ActivateMouse( ); IN_ActivateMouse( );
}
if( dma.initialized && snd_mute_losefocus.value )
{
SNDDMA_Activate( true );
}
host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME; host.force_draw_version_time = host.realtime + FORCE_DRAW_VERSION_TIME;
if( vid_fullscreen.value == WINDOW_MODE_FULLSCREEN ) if( vid_fullscreen.value == WINDOW_MODE_FULLSCREEN )
VID_SetMode(); VID_SetMode();
@@ -397,14 +391,8 @@ static void SDLash_ActiveEvent( int gain )
#endif #endif
host.status = HOST_NOFOCUS; host.status = HOST_NOFOCUS;
if( cls.key_dest == key_game ) if( cls.key_dest == key_game )
{
IN_DeactivateMouse(); IN_DeactivateMouse();
}
if( dma.initialized && snd_mute_losefocus.value )
{
SNDDMA_Activate( false );
}
host.force_draw_version_time = host.realtime + 2.0; host.force_draw_version_time = host.realtime + 2.0;
VID_RestoreScreenResolution(); VID_RestoreScreenResolution();
} }
@@ -654,7 +642,9 @@ static void SDLash_EventFilter( SDL_Event *event )
SDLash_ActiveEvent( false ); SDLash_ActiveEvent( false );
break; break;
case SDL_WINDOWEVENT_RESIZED: case SDL_WINDOWEVENT_RESIZED:
#if !XASH_MOBILE_PLATFORM
if( vid_fullscreen.value == WINDOW_MODE_WINDOWED ) if( vid_fullscreen.value == WINDOW_MODE_WINDOWED )
#endif
{ {
SDL_Window *wnd = SDL_GetWindowFromID( event->window.windowID ); SDL_Window *wnd = SDL_GetWindowFromID( event->window.windowID );
VID_SaveWindowSize( event->window.data1, event->window.data2, 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 ) void GAME_EXPORT Platform_GetMousePos( int *x, int *y )
{ {
SDL_GetMouseState( x, 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; SDL_DisplayMode got;
Uint32 wndFlags = 0; Uint32 wndFlags = 0;
#if !XASH_APPLE
if( vid_highdpi.value ) if( vid_highdpi.value )
SetBits( wndFlags, SDL_WINDOW_ALLOW_HIGHDPI ); SetBits( wndFlags, SDL_WINDOW_ALLOW_HIGHDPI );
#endif
SDL_SetWindowBordered( host.hWnd, SDL_FALSE ); 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 ) if( !glw_state.software )
SetBits( wndFlags, SDL_WINDOW_OPENGL ); SetBits( wndFlags, SDL_WINDOW_OPENGL );
#if !XASH_MOBILE_PLATFORM
if( window_mode == WINDOW_MODE_WINDOWED ) if( window_mode == WINDOW_MODE_WINDOWED )
{ {
SDL_Rect r; SDL_Rect r;
@@ -787,10 +784,6 @@ qboolean VID_CreateWindow( int width, int height, window_mode_t window_mode )
SetBits( wndFlags, SDL_WINDOW_BORDERLESS ); SetBits( wndFlags, SDL_WINDOW_BORDERLESS );
xpos = ypos = 0; 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 )) if( !VID_CreateWindowWithSafeGL( wndname, xpos, ypos, width, height, wndFlags ))
return false; 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 ) if( FBitSet( SDL_GetWindowFlags( host.hWnd ), SDL_WINDOW_MAXIMIZED|SDL_WINDOW_FULLSCREEN_DESKTOP ) != 0 )
SDL_GetWindowSize( host.hWnd, &width, &height ); SDL_GetWindowSize( host.hWnd, &width, &height );
#if !XASH_MOBILE_PLATFORM
if( window_mode != WINDOW_MODE_WINDOWED ) if( window_mode != WINDOW_MODE_WINDOWED )
{ {
if( !VID_SetScreenResolution( width, height, window_mode )) if( !VID_SetScreenResolution( width, height, window_mode ))
return false; return false;
} }
else VID_RestoreScreenResolution(); else VID_RestoreScreenResolution();
#endif
VID_SetWindowIcon( host.hWnd ); VID_SetWindowIcon( host.hWnd );
SDL_ShowWindow( host.hWnd ); SDL_ShowWindow( host.hWnd );
@@ -1175,6 +1166,14 @@ qboolean VID_SetMode( void )
#endif // SDL_VERSION_ATLEAST( 2, 0, 0 ) #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 )) if( !FBitSet( vid_fullscreen.flags, FCVAR_CHANGED ))
Cvar_DirectSet( &vid_fullscreen, DEFAULT_FULLSCREEN ); Cvar_DirectSet( &vid_fullscreen, DEFAULT_FULLSCREEN );
else else

View File

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

View File

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

View File

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

View File

@@ -368,13 +368,12 @@ SV_NewGame_f
*/ */
static void SV_NewGame_f( void ) 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" ); Con_Printf( S_USAGE "newgame\n" );
return;
}
COM_NewGame( GI->startmap );
} }
/* /*

View File

@@ -922,11 +922,11 @@ static void SV_GenerateTestPacket( void )
// testpacket already generated once, exit // testpacket already generated once, exit
// testpacket and lookup table takes ~300k of memory // testpacket and lookup table takes ~300k of memory
// disable for low memory mode // disable for low memory mode
if( svs.testpacket_buf || XASH_LOW_MEMORY >= 0 ) if( svs.testpacket_buf || XASH_LOW_MEMORY > 0 )
return; return;
// don't need in singleplayer with full client // don't need in singleplayer with full client
if( svs.maxclients <= 1 && !Host_IsDedicated( )) if( svs.maxclients <= 1 )
return; return;
file = FS_Open( "gfx.wad", "rb", false ); file = FS_Open( "gfx.wad", "rb", false );
@@ -1045,7 +1045,9 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean ba
// make cvars consistant // make cvars consistant
if( coop.value ) Cvar_SetValue( "deathmatch", 0 ); if( coop.value ) Cvar_SetValue( "deathmatch", 0 );
current_skill = Q_rint( skill.value ); 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 ); current_skill = bound( 0, current_skill, 3 );
#endif
Cvar_SetValue( "skill", (float)current_skill ); Cvar_SetValue( "skill", (float)current_skill );
// enforce hpk_maxsize // enforce hpk_maxsize

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 ) if( ent->v.movetype == MOVETYPE_FLYMISSILE )
type = MOVE_MISSILE; 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 type = MOVE_NOMONSTERS; // only clip against bmodels
else type = MOVE_NORMAL; else type = MOVE_NORMAL;
@@ -878,7 +878,7 @@ static qboolean SV_CanBlock( edict_t *ent )
if( ent->v.mins[0] == ent->v.maxs[0] ) if( ent->v.mins[0] == ent->v.maxs[0] )
return false; 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 // clear bounds for deadbody
ent->v.mins[0] = ent->v.mins[1] = 0; ent->v.mins[0] = ent->v.mins[1] = 0;
@@ -2122,6 +2122,7 @@ static server_physics_api_t gPhysicsAPI =
COM_SaveFile, COM_SaveFile,
pfnLoadImagePixels, pfnLoadImagePixels,
pfnGetModelName, pfnGetModelName,
Sys_GetNativeObject
}; };
/* /*

View File

@@ -1069,7 +1069,7 @@ static qboolean SV_ClipToEntity( edict_t *touch, moveclip_t *clip )
return true; 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; return true;
if( touch->v.solid == SOLID_TRIGGER ) if( touch->v.solid == SOLID_TRIGGER )

View File

@@ -237,7 +237,8 @@ def build(bld):
app_name = 'xash3d-fwgs' app_name = 'xash3d-fwgs'
) )
else: 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 install_path = bld.env.BINDIR
program = 'cxxprogram' if is_cxx_link else 'cprogram' program = 'cxxprogram' if is_cxx_link else 'cprogram'
if bld.env.STATIC: if bld.env.STATIC:

View File

@@ -15,7 +15,7 @@ GNU General Public License for more details.
#include "port.h" #include "port.h"
#if XASH_ANDROID #if XASH_ANDROID_ASSETS
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@@ -328,4 +328,4 @@ void FS_InitAndroid( void )
jni.getAssets = (*jni.env)->GetMethodID( jni.env, jni.activity_class, "getAssets", "(Z)Landroid/content/res/AssetManager;" ); 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 = static const fs_archive_t g_directory_archive =
{ NULL, SEARCHPATH_PLAIN, FS_AddDir_Fullpath, false }; { NULL, SEARCHPATH_PLAIN, FS_AddDir_Fullpath, false };
#ifdef XASH_ANDROID #if XASH_ANDROID_ASSETS
static const fs_archive_t g_android_archive = static const fs_archive_t g_android_archive =
{ NULL, SEARCHPATH_ANDROID_ASSETS, FS_AddAndroidAssets_Fullpath, false }; { NULL, SEARCHPATH_ANDROID_ASSETS, FS_AddAndroidAssets_Fullpath, false };
#endif #endif
@@ -406,7 +406,7 @@ void FS_AddGameDirectory( const char *dir, uint flags )
stringlistfreecontents( &list ); stringlistfreecontents( &list );
#ifdef XASH_ANDROID #if XASH_ANDROID_ASSETS
FS_AddArchive_Fullpath( &g_android_archive, dir, flags ); FS_AddArchive_Fullpath( &g_android_archive, dir, flags );
#endif #endif
@@ -632,30 +632,23 @@ static void FS_InitGameInfo( gameinfo_t *GameInfo, const char *gamedir )
memset( GameInfo, 0, sizeof( *GameInfo )); memset( GameInfo, 0, sizeof( *GameInfo ));
// filesystem info // 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 )); Q_strncpy( GameInfo->title, "New Game", sizeof( GameInfo->title ));
GameInfo->version = 1.0f; Q_strncpy( GameInfo->gamefolder, gamedir, sizeof( GameInfo->gamefolder ));
Q_strncpy( GameInfo->basedir, fs_basedir, sizeof( GameInfo->basedir ));
// .dll pathes 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->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, "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_linux, "dlls/hl.so", sizeof( GameInfo->game_dll_linux ));
Q_strncpy( GameInfo->game_dll_osx, "dlls/hl.dylib", sizeof( GameInfo->game_dll_osx )); 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->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_edicts = DEFAULT_MAX_EDICTS; // default value if not specified
GameInfo->max_tents = 500; GameInfo->max_tents = 500;
GameInfo->max_beams = 128; GameInfo->max_beams = 128;
GameInfo->max_particles = 4096; GameInfo->max_particles = 4096;
GameInfo->version = 1.0f;
} }
static void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qboolean isGameInfo ) static void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qboolean isGameInfo )
@@ -1468,7 +1461,7 @@ qboolean FS_InitStdio( qboolean unused_set_to_true, const char *rootdir, const c
FS_InitMemory(); FS_InitMemory();
#ifdef XASH_ANDROID #if XASH_ANDROID_ASSETS
FS_InitAndroid(); FS_InitAndroid();
#endif #endif

View File

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

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", 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 ); r_stats.c_active_tents_count, r_stats.c_view_beams_count, r_stats.c_particle_count );
break; 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 )); 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; vec3_t mins, maxs;
int i; int i;
// support for custom mirror management
if( RI.currentbeam && R_CullEntityInMirror( RI.currentbeam ))
return true;
for( i = 0; i < 3; i++ ) for( i = 0; i < 3; i++ )
{ {
if( start[i] < end[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 ); 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 R_CullModel
@@ -53,6 +78,9 @@ int R_CullModel( cl_entity_t *e, const vec3_t absmin, const vec3_t absmax )
return 1; return 1;
} }
if( R_CullEntityInMirror( e ))
return 1;
if( R_CullBox( absmin, absmax )) if( R_CullBox( absmin, absmax ))
return 1; 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 ); 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 )) if( FBitSet( surf->flags, SURF_PLANEBACK ))
{ {

View File

@@ -28,6 +28,10 @@ GNU General Public License for more details.
#define XASH_GL_STATIC #define XASH_GL_STATIC
#define REF_GL_KEEP_MANGLED_FUNCTIONS #define REF_GL_KEEP_MANGLED_FUNCTIONS
#elif defined XASH_GLES3COMPAT #elif defined XASH_GLES3COMPAT
#ifdef SOFTFP_LINK
#undef APIENTRY
#define APIENTRY __attribute__((pcs("aapcs")))
#endif
#define XASH_GLES #define XASH_GLES
#endif #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 ); pic->numMips = Q_max( 1, pic->numMips );
// trying to determine texture type // trying to determine texture type
#ifndef XASH_GLES
if( pic->width > 1 && pic->height <= 1 ) if( pic->width > 1 && pic->height <= 1 )
tex->target = GL_TEXTURE_1D; 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; tex->target = GL_TEXTURE_CUBE_MAP_ARB;
else if( FBitSet( pic->flags, IMAGE_MULTILAYER ) && pic->depth >= 1 ) else if( FBitSet( pic->flags, IMAGE_MULTILAYER ) && pic->depth >= 1 )
tex->target = GL_TEXTURE_2D_ARRAY_EXT; tex->target = GL_TEXTURE_2D_ARRAY_EXT;

View File

@@ -74,6 +74,8 @@ extern poolhandle_t r_temppool;
#define SUBDIVIDE_SIZE 64 #define SUBDIVIDE_SIZE 64
#define MAX_DECAL_SURFS 4096 #define MAX_DECAL_SURFS 4096
#define MAX_DRAW_STACK 2 // normal view and menu view #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 SHADEDOT_QUANT 16 // precalculated dot products for quantized angles
#define SHADE_LAMBERT 1.4953241 #define SHADE_LAMBERT 1.4953241
@@ -84,8 +86,9 @@ extern poolhandle_t r_temppool;
#define RP_ENVVIEW BIT( 0 ) // used for cubemapshot #define RP_ENVVIEW BIT( 0 ) // used for cubemapshot
#define RP_OLDVIEWLEAF BIT( 1 ) #define RP_OLDVIEWLEAF BIT( 1 )
#define RP_CLIPPLANE BIT( 2 ) #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_ModelOpaque( rm ) ( rm == kRenderNormal )
#define R_StaticEntity( ent ) ( VectorIsNull( ent->origin ) && VectorIsNull( ent->angles )) #define R_StaticEntity( ent ) ( VectorIsNull( ent->origin ) && VectorIsNull( ent->angles ))
#define RP_LOCALCLIENT( e ) ((e) != NULL && (e)->index == ( gp_cl->playernum + 1 ) && e->player ) #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; struct gltexture_s *nextHash;
} gl_texture_t; } gl_texture_t;
// mirror entity
typedef struct
{
cl_entity_t *ent;
mextrasurf_t *chain;
} gl_entity_t;
typedef struct typedef struct
{ {
int params; // rendering parameters 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 *solid_entities[MAX_VISIBLE_PACKET]; // opaque moving or alpha brushes
cl_entity_t *trans_entities[MAX_VISIBLE_PACKET]; // translucent brushes cl_entity_t *trans_entities[MAX_VISIBLE_PACKET]; // translucent brushes
cl_entity_t *beam_entities[MAX_VISIBLE_PACKET]; 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_solid_entities;
uint num_trans_entities; uint num_trans_entities;
uint num_beam_entities; uint num_beam_entities;
uint num_mirror_entities;
} draw_list_t; } draw_list_t;
typedef struct typedef struct
@@ -218,6 +230,8 @@ typedef struct
int dlightTexture; // custom dlight texture int dlightTexture; // custom dlight texture
int skyboxTextures[SKYBOX_MAX_SIDES]; // skybox sides int skyboxTextures[SKYBOX_MAX_SIDES]; // skybox sides
int cinTexture; // cinematic texture int cinTexture; // cinematic texture
int mirrorTextures[MAX_MIRRORS];
int num_mirrors_used;
int skytexturenum; // this not a gl_texturenum! int skytexturenum; // this not a gl_texturenum!
int skyboxbasenum; // start with 5800 int skyboxbasenum; // start with 5800
@@ -280,6 +294,8 @@ typedef struct
uint c_client_ents; // entities that moved to client uint c_client_ents; // entities that moved to client
double t_world_node; double t_world_node;
double t_world_draw; double t_world_draw;
uint c_mirror_passes;
} ref_speeds_t; } ref_speeds_t;
extern ref_speeds_t r_stats; 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 ); 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_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 ); 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_InitRipples( void );
void R_ResetRipples( void ); void R_ResetRipples( void );
void R_AnimateRipples( void ); void R_AnimateRipples( void );
void R_UploadRipples( texture_t *image ); void R_UploadRipples( texture_t *image, qboolean is_mirror );
// //
// gl_vgui.c // 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 ); void VGUI_GetTextureSizes( int *width, int *height );
int VGUI_GenerateTexture( void ); 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 // 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 ); 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 ); qboolean R_SpeedsMessage( char *out, size_t size );
void R_SetupSky( const char *skyboxname ); 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 ); int R_WorldToScreen( const vec3_t point, vec3_t screen );
void R_ScreenToWorld( const vec3_t screen, vec3_t point ); void R_ScreenToWorld( const vec3_t screen, vec3_t point );
qboolean R_AddEntity( struct cl_entity_s *pRefEntity, int entityType ); 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_msaa;
extern convar_t gl_stencilbits; extern convar_t gl_stencilbits;
extern convar_t gl_overbright; extern convar_t gl_overbright;
extern convar_t gl_allow_mirrors;
extern convar_t r_lighting_extended; extern convar_t r_lighting_extended;
extern convar_t r_lighting_ambient; 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;
extern convar_t r_vbo_dlightmode; extern convar_t r_vbo_dlightmode;
extern convar_t r_vbo_detail; extern convar_t r_vbo_detail;
extern convar_t r_vbo_overbrightmode;
extern convar_t r_studio_sort_textures; extern convar_t r_studio_sort_textures;
extern convar_t r_studio_drawelements; extern convar_t r_studio_drawelements;
extern convar_t r_ripple; extern convar_t r_ripple;
extern convar_t r_ripple_updatetime; extern convar_t r_ripple_updatetime;
extern convar_t r_ripple_spawntime; 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 // 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_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_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_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_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_lighting_ambient, "0.3", FCVAR_GLCONFIG, "map ambient lighting scale" );
CVAR_DEFINE_AUTO( r_detailtextures, "1", FCVAR_ARCHIVE, "enable detail textures support" ); 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, "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_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_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, "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_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_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() DEFINE_ENGINE_SHARED_CVAR_LIST()
@@ -1190,6 +1195,9 @@ static void GL_InitCommands( void )
gEngfuncs.Cvar_RegisterVariable( &r_ripple ); gEngfuncs.Cvar_RegisterVariable( &r_ripple );
gEngfuncs.Cvar_RegisterVariable( &r_ripple_updatetime ); gEngfuncs.Cvar_RegisterVariable( &r_ripple_updatetime );
gEngfuncs.Cvar_RegisterVariable( &r_ripple_spawntime ); 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_extensions );
gEngfuncs.Cvar_RegisterVariable( &gl_texture_nearest ); gEngfuncs.Cvar_RegisterVariable( &gl_texture_nearest );
@@ -1206,6 +1214,7 @@ static void GL_InitCommands( void )
gEngfuncs.Cvar_RegisterVariable( &gl_stencilbits ); gEngfuncs.Cvar_RegisterVariable( &gl_stencilbits );
gEngfuncs.Cvar_RegisterVariable( &gl_round_down ); gEngfuncs.Cvar_RegisterVariable( &gl_round_down );
gEngfuncs.Cvar_RegisterVariable( &gl_overbright ); gEngfuncs.Cvar_RegisterVariable( &gl_overbright );
gEngfuncs.Cvar_RegisterVariable( &gl_allow_mirrors );
// these cvar not used by engine but some mods requires this // these cvar not used by engine but some mods requires this
gEngfuncs.Cvar_RegisterVariable( &gl_polyoffset ); gEngfuncs.Cvar_RegisterVariable( &gl_polyoffset );
@@ -1248,6 +1257,7 @@ static void R_CheckVBO( void )
gEngfuncs.Cvar_RegisterVariable( &r_vbo ); gEngfuncs.Cvar_RegisterVariable( &r_vbo );
gEngfuncs.Cvar_RegisterVariable( &r_vbo_dlightmode ); gEngfuncs.Cvar_RegisterVariable( &r_vbo_dlightmode );
gEngfuncs.Cvar_RegisterVariable( &r_vbo_overbrightmode );
gEngfuncs.Cvar_RegisterVariable( &r_vbo_detail ); 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_solid_entities = 0;
tr.draw_list->num_trans_entities = 0; tr.draw_list->num_trans_entities = 0;
tr.draw_list->num_beam_entities = 0; tr.draw_list->num_beam_entities = 0;
tr.draw_list->num_mirror_entities = 0;
// clear the scene befor start new frame // clear the scene befor start new frame
if( gEngfuncs.drawFuncs->R_ClearScene != NULL ) if( gEngfuncs.drawFuncs->R_ClearScene != NULL )
@@ -1011,10 +1012,11 @@ static void R_CheckGamma( void )
ClearBits( gl_overbright.flags, FCVAR_CHANGED ); 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; rebuild = true;
ClearBits( r_vbo.flags, FCVAR_CHANGED ); ClearBits( r_vbo.flags, FCVAR_CHANGED );
ClearBits( r_vbo_overbrightmode.flags, FCVAR_CHANGED );
} }
if( rebuild ) if( rebuild )
@@ -1126,6 +1128,14 @@ void R_RenderFrame( const ref_viewpass_t *rvp )
R_RunViewmodelEvents(); R_RunViewmodelEvents();
tr.realframecount++; // right called after viewmodel events tr.realframecount++; // right called after viewmodel events
if( gl_allow_mirrors.value )
{
// render mirrors
R_FindMirrors();
R_DrawMirrors();
}
R_RenderScene(); R_RenderScene();
return; 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; tmax = ( info->lightextents[1] / sample_size ) + 1;
size = smax * tmax; size = smax * tmax;
if( gl_overbright.value ) 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; else lightscale = ( pow( 2.0f, 1.0f / v_lightgamma->value ) * 256 ) + 0.5;
lm = surf->samples; lm = surf->samples;
@@ -927,7 +927,8 @@ static void R_BlendLightmaps( void )
if( gl_overbright.value ) if( gl_overbright.value )
{ {
pglBlendFunc( GL_DST_COLOR, GL_SRC_COLOR ); 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 else
{ {
@@ -1141,7 +1142,7 @@ R_RenderBrushPoly
*/ */
static void R_RenderBrushPoly( msurface_t *fa, int cull_type ) static void R_RenderBrushPoly( msurface_t *fa, int cull_type )
{ {
qboolean is_dynamic = false; qboolean is_dynamic = false, is_mirror = false;
int maps; int maps;
texture_t *t; texture_t *t;
@@ -1152,15 +1153,46 @@ static void R_RenderBrushPoly( msurface_t *fa, int cull_type )
t = R_TextureAnimation( fa ); 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 )) if( FBitSet( fa->flags, SURF_DRAWTURB ))
{ {
R_UploadRipples( t ); R_UploadRipples( t, false );
// warp texture, no lightmaps // warp texture, no lightmaps
EmitWaterPolys( fa, (cull_type == CULL_BACKSIDE)); EmitWaterPolys( fa, (cull_type == CULL_BACKSIDE));
return; 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 ) 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 ); DrawGLPoly( fa->polys, 0.0f, 0.0f );
if( is_mirror ) R_EndDrawMirror();
if( RI.currententity->curstate.rendermode == kRenderNormal ) 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)); 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 )) if( FBitSet( fa->flags, SURF_DRAWTILED ))
return; // no lightmaps anyway return; // no lightmaps anyway
@@ -1431,7 +1469,7 @@ void R_DrawWaterSurfaces( void )
continue; continue;
// set modulate mode explicitly // set modulate mode explicitly
R_UploadRipples( t ); R_UploadRipples( t, false );
for( ; s; s = s->texturechain ) for( ; s; s = s->texturechain )
EmitWaterPolys( s, false ); EmitWaterPolys( s, false );
@@ -1550,6 +1588,9 @@ void R_DrawBrushModel( cl_entity_t *e )
if( clmodel->surfaces != WORLDMODEL->surfaces ) if( clmodel->surfaces != WORLDMODEL->surfaces )
allow_vbo = false; allow_vbo = false;
if( R_CullEntityInMirror( e ))
return;
if( !VectorIsNull( e->angles )) if( !VectorIsNull( e->angles ))
{ {
for( i = 0; i < 3; i++ ) for( i = 0; i < 3; i++ )
@@ -1902,7 +1943,7 @@ void R_GenerateVBO( void )
if( surf->lightmaptexturenum != k ) if( surf->lightmaptexturenum != k )
continue; 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; continue;
if( R_TextureAnimation( surf ) != world->textures[j] ) if( R_TextureAnimation( surf ) != world->textures[j] )
@@ -1971,7 +2012,7 @@ void R_GenerateVBO( void )
if( surf->lightmaptexturenum != k ) if( surf->lightmaptexturenum != k )
continue; 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; continue;
if( R_TextureAnimation( surf ) != world->textures[j] ) if( R_TextureAnimation( surf ) != world->textures[j] )
@@ -2189,15 +2230,30 @@ static void R_SetLightmap( void )
if( gl_overbright.value ) 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_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
pglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE ); 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_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB );
pglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE ); 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 ); 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 else
{ {
@@ -3805,7 +3861,14 @@ void GL_BuildLightmaps( void )
GL_FreeTexture( tr.lightmapTextures[i] ); 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.lightmapTextures, 0, sizeof( tr.lightmapTextures ));
memset( tr.mirrorTextures, 0, sizeof( tr.mirrorTextures ));
memset( &RI, 0, sizeof( RI )); memset( &RI, 0, sizeof( RI ));
// update the lightmap blocksize // update the lightmap blocksize
@@ -3821,6 +3884,8 @@ void GL_BuildLightmaps( void )
tr.realframecount = 1; tr.realframecount = 1;
nColinElim = 0; nColinElim = 0;
tr.num_mirrors_used = 0;
// setup the texture for dlights // setup the texture for dlights
R_InitDlightTexture(); R_InitDlightTexture();

View File

@@ -46,7 +46,7 @@ R_SpriteLoadFrame
upload a single frame 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; dspriteframe_t pinframe;
mspriteframe_t *pspriteframe; 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; pspriteframe->gl_texturenum = gl_texturenum;
*ppframe = pspriteframe; *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 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; const dspritegroup_t *pingroup;
mspritegroup_t *pspritegroup; 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 ); ptemp = R_SpriteLoadFrame( mod, ptemp, &pspritegroup->frames[i], framenum * 10 + i );
} }
return (const dframetype_t *)ptemp; return ptemp;
} }
/* /*
==================== ====================
Mod_LoadSpriteModel Mod_LoadSpriteModel
@@ -142,7 +143,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
{ {
const dsprite_t *pin; const dsprite_t *pin;
const short *numi = NULL; const short *numi = NULL;
const dframetype_t *pframetype; const byte *pframetype;
msprite_t *psprite; msprite_t *psprite;
int i; 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 ) if( pin->version == SPRITE_VERSION_Q1 || pin->version == SPRITE_VERSION_32 )
numi = NULL; numi = NULL;
else if( pin->version == SPRITE_VERSION_HL ) 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; r_texFlags = texFlags;
sprite_version = pin->version; sprite_version = pin->version;
@@ -164,7 +165,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
rgbdata_t *pal; rgbdata_t *pal;
pal = gEngfuncs.FS_LoadImage( "#id.pal", (byte *)&i, 768 ); 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 gEngfuncs.FS_FreeImage( pal ); // palette installed, no reason to keep this data
} }
else if( *numi == 256 ) else if( *numi == 256 )
@@ -186,7 +187,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
break; 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 gEngfuncs.FS_FreeImage( pal ); // palette installed, no reason to keep this data
} }
else else
@@ -200,22 +201,26 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
for( i = 0; i < mod->numframes; i++ ) 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; psprite->frames[i].type = (spriteframetype_t)frametype;
switch( frametype ) switch( frametype )
{ {
case FRAME_SINGLE: case FRAME_SINGLE:
Q_strncpy( group_suffix, "frame", sizeof( group_suffix )); 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; break;
case FRAME_GROUP: case FRAME_GROUP:
Q_strncpy( group_suffix, "group", sizeof( group_suffix )); 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; break;
case FRAME_ANGLED: case FRAME_ANGLED:
Q_strncpy( group_suffix, "angle", sizeof( group_suffix )); 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; break;
} }
if( pframetype == NULL ) break; // technically an error 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; float blend;
vec3_t v; vec3_t v;
if( R_CullEntityInMirror( e ))
return true;
TriWorldToScreen( origin, v ); TriWorldToScreen( origin, v );
if( v[0] < RI.viewport[0] || v[0] > RI.viewport[0] + RI.viewport[2] ) 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; model_t *model;
} player_model_t; } player_model_t;
// never gonna change, just shut up const warning // never gonna change you up, never gonna override you down
cvar_t r_shadows = { (char *)"r_shadows", (char *)"0", 0 }; // 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] = static vec3_t hullcolor[8] =
{ {
@@ -154,8 +157,12 @@ void R_StudioInit( void )
Matrix3x4_LoadIdentity( g_studio.rotationmatrix ); Matrix3x4_LoadIdentity( g_studio.rotationmatrix );
// g-cont. cvar disabled by Valve // a1ba: enabled since HL25
// gEngfuncs.Cvar_RegisterVariable( &r_shadows ); 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.interpolate = true;
g_studio.framecount = 0; g_studio.framecount = 0;
@@ -2930,25 +2937,35 @@ R_StudioDrawPointsShadow
static void R_StudioDrawPointsShadow( void ) static void R_StudioDrawPointsShadow( void )
{ {
float *av, height; float *av, height;
float vec_x, vec_y;
mstudiomesh_t *pmesh; mstudiomesh_t *pmesh;
vec3_t point;
int i, k; int i, k;
pmtrace_t tr;
vec3_t trEnd;
if( FBitSet( RI.currententity->curstate.effects, EF_NOSHADOW )) if( FBitSet( RI.currententity->curstate.effects, EF_NOSHADOW ))
return; 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 ) if( glState.stencilEnabled )
pglEnable( GL_STENCIL_TEST ); pglEnable( GL_STENCIL_TEST );
height = g_studio.lightspot[2] + 1.0f; height = r_shadow_height.value;
vec_x = -g_studio.lightvec[0] * 8.0f;
vec_y = -g_studio.lightvec[1] * 8.0f;
for( k = 0; k < m_pSubModel->nummesh; k++ ) for( k = 0; k < m_pSubModel->nummesh; k++ )
{ {
short *ptricmds; 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; pmesh = (mstudiomesh_t *)((byte *)m_pStudioHeader + m_pSubModel->meshindex) + k;
ptricmds = (short *)((byte *)m_pStudioHeader + pmesh->triindex); ptricmds = (short *)((byte *)m_pStudioHeader + pmesh->triindex);
@@ -2970,11 +2987,7 @@ static void R_StudioDrawPointsShadow( void )
for( ; i > 0; i--, ptricmds += 4 ) for( ; i > 0; i--, ptricmds += 4 )
{ {
av = g_studio.verts[ptricmds[0]]; av = g_studio.verts[ptricmds[0]];
point[0] = av[0] - (vec_x * ( av[2] - g_studio.lightspot[2] )); pglVertex3f( av[0], av[1], tr.endpos[2] + height + 0.16f );
point[1] = av[1] - (vec_y * ( av[2] - g_studio.lightspot[2] ));
point[2] = g_studio.lightspot[2] + 1.0f;
pglVertex3fv( point );
} }
pglEnd(); 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 )) 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 ); pglDisable( GL_TEXTURE_2D );
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
pglEnable( GL_BLEND ); 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 ); pglDepthFunc( GL_LESS );
R_StudioDrawPointsShadow(); R_StudioDrawPointsShadow();

View File

@@ -781,7 +781,7 @@ Does a water warp on the pre-fragmented glpoly_t chain
void EmitWaterPolys( msurface_t *warp, qboolean reverse ) void EmitWaterPolys( msurface_t *warp, qboolean reverse )
{ {
float *v, nv, waveHeight; float *v, nv, waveHeight;
float s, t, os, ot; float s, t, os, ot, warp_s, warp_t;
glpoly_t *p; glpoly_t *p;
int i; int i;
@@ -822,15 +822,29 @@ void EmitWaterPolys( msurface_t *warp, qboolean reverse )
os = v[3]; os = v[3];
ot = v[4]; ot = v[4];
if( !r_ripple.value ) switch((int)r_water_warp.value )
{ {
s = os + r_turbsin[(int)((ot * 0.125f + gp_cl->time) * TURBSCALE) & 255]; case 0:
t = ot + r_turbsin[(int)((os * 0.125f + gp_cl->time) * TURBSCALE) & 255]; warp_s = warp_t = 0;
break;
case 1:
warp_s = r_turbsin[(int)((ot * 0.125f + gp_cl->time) * TURBSCALE) & 255];
warp_t = r_turbsin[(int)((os * 0.125f + gp_cl->time) * TURBSCALE) & 255];
break;
case 2:
default:
warp_s = gp_cl->time * r_water_warp_x.value;
warp_t = gp_cl->time * r_water_warp_y.value;
break;
} }
else
s = os + warp_s;
t = ot + warp_t;
if( r_ripple.value )
{ {
s = os / g_ripple.texturescale; s /= g_ripple.texturescale;
t = ot / g_ripple.texturescale; t /= g_ripple.texturescale;
} }
s *= ( 1.0f / SUBDIVIDE_SIZE ); s *= ( 1.0f / SUBDIVIDE_SIZE );
@@ -963,27 +977,29 @@ void R_AnimateRipples( void )
R_RunRipplesAnimation( g_ripple.oldbuf, g_ripple.curbuf ); R_RunRipplesAnimation( g_ripple.oldbuf, g_ripple.curbuf );
} }
void R_UploadRipples( texture_t *image ) void R_UploadRipples( texture_t *image, qboolean is_mirror )
{ {
gl_texture_t *glt; gl_texture_t *glt;
uint32_t *pixels; uint32_t *pixels;
int wbits, wmask, wshft; int wbits, wmask, wshft;
int y;
int tmu = is_mirror ? XASH_TEXTURE1 : XASH_TEXTURE0;
// discard unuseful textures // discard unuseful textures
if( !r_ripple.value || image->width > RIPPLES_CACHEWIDTH || image->width != image->height ) if( !r_ripple.value || image->width > RIPPLES_CACHEWIDTH || image->width != image->height )
{ {
GL_Bind( XASH_TEXTURE0, image->gl_texturenum ); GL_Bind( tmu, image->gl_texturenum );
return; return;
} }
glt = R_GetTexture( image->gl_texturenum ); glt = R_GetTexture( image->gl_texturenum );
if( !glt || !glt->original || !glt->original->buffer || !FBitSet( glt->flags, TF_EXPAND_SOURCE )) if( !glt || !glt->original || !glt->original->buffer || !FBitSet( glt->flags, TF_EXPAND_SOURCE ))
{ {
GL_Bind( XASH_TEXTURE0, image->gl_texturenum ); GL_Bind( tmu, image->gl_texturenum );
return; return;
} }
GL_Bind( XASH_TEXTURE0, g_ripple.rippletexturenum ); GL_Bind( tmu, g_ripple.rippletexturenum );
// no updates this frame // no updates this frame
if( !g_ripple.update && image->gl_texturenum == g_ripple.gl_texturenum ) if( !g_ripple.update && image->gl_texturenum == g_ripple.gl_texturenum )
@@ -1005,11 +1021,12 @@ void R_UploadRipples( texture_t *image )
wshft = 7 - wbits; wshft = 7 - wbits;
wmask = image->width - 1; wmask = image->width - 1;
for( int y = 0; y < image->height; y++ ) for( y = 0; y < image->height; y++ )
{ {
int ry = y << ( 7 + wshft ); int ry = y << ( 7 + wshft );
int x;
for( int x = 0; x < image->width; x++ ) for( x = 0; x < image->width; x++ )
{ {
int rx = x << wshft; int rx = x << wshft;
int val = g_ripple.curbuf[ry + rx] >> 4; int val = g_ripple.curbuf[ry + rx] >> 4;

View File

@@ -95,7 +95,11 @@ static void R_DrawStretchPicImplementation( int x, int y, int w, int h, int s1,
//gEngfuncs.Con_Printf ("pixels is %p\n", pic->pixels[0] ); //gEngfuncs.Con_Printf ("pixels is %p\n", pic->pixels[0] );
height = h; height = h;
if (y < 0)
if( y < -h ) // out of display, out of bounds
return;
if( y < 0 )
{ {
skip = -y; skip = -y;
height += y; height += y;

View File

@@ -46,7 +46,7 @@ R_SpriteLoadFrame
upload a single frame 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; dspriteframe_t pinframe;
mspriteframe_t *pspriteframe; 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; pspriteframe->gl_texturenum = gl_texturenum;
*ppframe = pspriteframe; *ppframe = pspriteframe;
return ( const dframetype_t* )(( const byte* )pin + sizeof( dspriteframe_t ) + pinframe.width * pinframe.height * bytes ); return ( const byte* )(( const byte* )pin + sizeof( dspriteframe_t ) + pinframe.width * pinframe.height * bytes );
} }
/* /*
@@ -92,7 +92,7 @@ R_SpriteLoadGroup
upload a group frames upload a group frames
==================== ====================
*/ */
static const dframetype_t *R_SpriteLoadGroup( model_t *mod, const void *pin, mspriteframe_t **ppframe, int framenum ) static const void *R_SpriteLoadGroup( model_t *mod, const void *pin, mspriteframe_t **ppframe, int framenum )
{ {
const dspritegroup_t *pingroup; const dspritegroup_t *pingroup;
mspritegroup_t *pspritegroup; mspritegroup_t *pspritegroup;
@@ -128,7 +128,7 @@ static const dframetype_t *R_SpriteLoadGroup( model_t *mod, const void *pin, msp
ptemp = R_SpriteLoadFrame( mod, ptemp, &pspritegroup->frames[i], framenum * 10 + i ); ptemp = R_SpriteLoadFrame( mod, ptemp, &pspritegroup->frames[i], framenum * 10 + i );
} }
return (const dframetype_t *)ptemp; return ptemp;
} }
/* /*
@@ -142,7 +142,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
{ {
const dsprite_t *pin; const dsprite_t *pin;
const short *numi = NULL; const short *numi = NULL;
const dframetype_t *pframetype; const byte *pframetype;
msprite_t *psprite; msprite_t *psprite;
int i; int i;
@@ -164,7 +164,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
rgbdata_t *pal; rgbdata_t *pal;
pal = gEngfuncs.FS_LoadImage( "#id.pal", (byte *)&i, 768 ); pal = gEngfuncs.FS_LoadImage( "#id.pal", (byte *)&i, 768 );
pframetype = (const dframetype_t *)((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 gEngfuncs.FS_FreeImage( pal ); // palette installed, no reason to keep this data
} }
else if( *numi == 256 ) else if( *numi == 256 )
@@ -186,7 +186,7 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
break; break;
} }
pframetype = (const dframetype_t *)(src + 768); pframetype = (const byte *)(src + 768);
gEngfuncs.FS_FreeImage( pal ); // palette installed, no reason to keep this data gEngfuncs.FS_FreeImage( pal ); // palette installed, no reason to keep this data
} }
else else
@@ -200,22 +200,26 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui
for( i = 0; i < mod->numframes; i++ ) 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; psprite->frames[i].type = (spriteframetype_t)frametype;
switch( frametype ) switch( frametype )
{ {
case FRAME_SINGLE: case FRAME_SINGLE:
Q_strncpy( group_suffix, "frame", sizeof( group_suffix )); 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; break;
case FRAME_GROUP: case FRAME_GROUP:
Q_strncpy( group_suffix, "group", sizeof( group_suffix )); 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; break;
case FRAME_ANGLED: case FRAME_ANGLED:
Q_strncpy( group_suffix, "angle", sizeof( group_suffix )); 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; break;
} }
if( pframetype == NULL ) break; // technically an error if( pframetype == NULL ) break; // technically an error

View File

@@ -7,16 +7,16 @@ export PATH=$PATH:$JAVA_HOME/bin:$ANDROID_HOME/tools:$ANDROID_HOME/tools/bin:$AN
pushd android pushd android
./gradlew assembleContinuous ./gradlew assembleDebug
pushd app/build/outputs/apk/continuous pushd app/build/outputs/apk/debug
$ANDROID_HOME/build-tools/34.0.0/apksigner sign --ks $GITHUB_WORKSPACE/android/debug.keystore --ks-key-alias androiddebugkey \ $ANDROID_HOME/build-tools/34.0.0/apksigner sign --ks $GITHUB_WORKSPACE/android/debug.keystore --ks-key-alias androiddebugkey \
--ks-pass pass:android --key-pass pass:android --out app-continuous-signed.apk app-continuous-unsigned.apk --ks-pass pass:android --key-pass pass:android --out app-debug-signed.apk app-debug.apk
popd popd
popd popd
mkdir -p artifacts/ mkdir -p artifacts/
mv android/app/build/outputs/apk/continuous/app-continuous-signed.apk artifacts/xash3d-fwgs-android.apk mv android/app/build/outputs/apk/debug/app-debug-signed.apk artifacts/xash3d-fwgs-android.apk

View File

@@ -64,6 +64,7 @@ CFLAGS = {
'msvc': ['/O2', '/Oy', '/Zi'], 'msvc': ['/O2', '/Oy', '/Zi'],
'gcc': { 'gcc': {
'3': ['-O3', '-fomit-frame-pointer'], '3': ['-O3', '-fomit-frame-pointer'],
'4': ['-Ofast', '-funsafe-math-optimizations', '-funsafe-loop-optimizations', '-fomit-frame-pointer'],
'default': ['-Ofast', '-funsafe-math-optimizations', '-funsafe-loop-optimizations', '-fomit-frame-pointer', '-fno-semantic-interposition'] 'default': ['-Ofast', '-funsafe-math-optimizations', '-funsafe-loop-optimizations', '-fomit-frame-pointer', '-fno-semantic-interposition']
}, },
'clang': ['-Ofast'], 'clang': ['-Ofast'],
@@ -78,7 +79,11 @@ CFLAGS = {
'humanrights': { 'humanrights': {
'msvc': ['/O2', '/Zi'], 'msvc': ['/O2', '/Zi'],
'owcc': ['-O3', '-foptimize-sibling-calls', '-fomit-leaf-frame-pointer', '-fomit-frame-pointer', '-fschedule-insns', '-funsafe-math-optimizations', '-funroll-loops', '-frerun-optimizer', '-finline-functions', '-finline-limit=512', '-fguess-branch-probability', '-fno-strict-aliasing', '-floop-optimize'], 'owcc': ['-O3', '-foptimize-sibling-calls', '-fomit-leaf-frame-pointer', '-fomit-frame-pointer', '-fschedule-insns', '-funsafe-math-optimizations', '-funroll-loops', '-frerun-optimizer', '-finline-functions', '-finline-limit=512', '-fguess-branch-probability', '-fno-strict-aliasing', '-floop-optimize'],
'gcc': ['-O3', '-fno-semantic-interposition'], 'gcc': {
'4': ['-O3'],
'3': ['-O3'],
'default': ['-O3','-fno-semantic-interposition'],
},
'default': ['-O3'] 'default': ['-O3']
}, },
'debug': { 'debug': {
@@ -116,6 +121,22 @@ POLLY_CFLAGS = {
# msvc sosat :( # msvc sosat :(
} }
PROFILE_GENERATE_CFLAGS = {
'gcc': ['-fprofile-generate=xash3d-prof'],
}
PROFILE_GENERATE_LINKFLAGS = {
'gcc': ['-fprofile-generate=xash3d-prof'],
}
PROFILE_USE_CFLAGS = {
'gcc': ['-fprofile-use=%s'],
}
PROFILE_USE_LINKFLAGS = {
'gcc': ['-fprofile-use=%s'],
}
def options(opt): def options(opt):
grp = opt.add_option_group('Compiler optimization options') grp = opt.add_option_group('Compiler optimization options')
@@ -128,6 +149,12 @@ def options(opt):
grp.add_option('--enable-poly-opt', action = 'store_true', dest = 'POLLY', default = False, grp.add_option('--enable-poly-opt', action = 'store_true', dest = 'POLLY', default = False,
help = 'enable polyhedral optimization if possible [default: %default]') help = 'enable polyhedral optimization if possible [default: %default]')
grp.add_option('--enable-profile', action = 'store_true', dest = 'PROFILE_GENERATE', default = False,
help = 'enable profile generating build (stored in xash3d-prof directory) [default: %default]')
grp.add_option('--use-profile', action = 'store', dest = 'PROFILE_USE', default = None,
help = 'use profile during build [default: %default]')
def configure(conf): def configure(conf):
conf.start_msg('Build type') conf.start_msg('Build type')
@@ -144,6 +171,8 @@ def configure(conf):
conf.msg('LTO build', 'yes' if conf.options.LTO else 'no') conf.msg('LTO build', 'yes' if conf.options.LTO else 'no')
conf.msg('PolyOpt build', 'yes' if conf.options.POLLY else 'no') conf.msg('PolyOpt build', 'yes' if conf.options.POLLY else 'no')
conf.msg('Generate profile', 'yes' if conf.options.PROFILE_GENERATE else 'no')
conf.msg('Use profile', conf.options.PROFILE_USE if not conf.options.PROFILE_GENERATE else 'no')
# -march=native should not be used # -march=native should not be used
if conf.options.BUILD_TYPE.startswith('fast'): if conf.options.BUILD_TYPE.startswith('fast'):
@@ -174,6 +203,13 @@ def get_optimization_flags(conf):
if conf.options.POLLY: if conf.options.POLLY:
cflags += conf.get_flags_by_compiler(POLLY_CFLAGS, conf.env.COMPILER_CC) cflags += conf.get_flags_by_compiler(POLLY_CFLAGS, conf.env.COMPILER_CC)
if conf.options.PROFILE_GENERATE:
linkflags+= conf.get_flags_by_compiler(PROFILE_GENERATE_LINKFLAGS, conf.env.COMPILER_CC)
cflags += conf.get_flags_by_compiler(PROFILE_GENERATE_CFLAGS, conf.env.COMPILER_CC)
elif conf.options.PROFILE_USE:
linkflags+= [conf.get_flags_by_compiler(PROFILE_USE_LINKFLAGS, conf.env.COMPILER_CC)[0] % conf.options.PROFILE_USE]
cflags += [conf.get_flags_by_compiler(PROFILE_USE_CFLAGS, conf.env.COMPILER_CC)[0] % conf.options.PROFILE_USE]
if conf.env.DEST_OS == 'nswitch' and conf.options.BUILD_TYPE == 'debug': if conf.env.DEST_OS == 'nswitch' and conf.options.BUILD_TYPE == 'debug':
# enable remote debugger # enable remote debugger
cflags.append('-DNSWITCH_DEBUG') cflags.append('-DNSWITCH_DEBUG')

82
scripts/waifulib/psp.py Normal file
View File

@@ -0,0 +1,82 @@
# encoding: utf-8
# psp.py -- PSP EBOOT task
# Copyright (C) 2023 Sergey Galushko
# 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.
##################################
# PSP Tools #
##################################
class psp_fixup(Task.Task):
run_str = '${FIXUP} -o ${TGT} ${SRC}'
color = 'BLUE'
class psp_prxgen(Task.Task):
run_str = '${PRXGEN} ${SRC} ${TGT}'
color = 'BLUE'
class psp_strip(Task.Task):
run_str = '${STRIP} -o ${TGT} ${SRC}'
color = 'BLUE'
class psp_mksfo(Task.Task):
run_str = '${MKSFO} -d MEMSIZE=1 ${PSP_EBOOT_TITLE} ${TGT}'
color = 'YELLOW'
class psp_packpbp(Task.Task):
run_str = '${PACK_PBP} ${TGT} ${SRC[1].abspath()} ${PSP_EBOOT_ICON} ${PSP_EBOOT_ICON1} ${PSP_EBOOT_UNKPNG} ${PSP_EBOOT_PIC1} ${PSP_EBOOT_SND0} ${SRC[0].abspath()} ${PSP_EBOOT_PSAR}'
color = 'GREEN'
@TaskGen.feature('cshlib', 'cxxshlib')
@TaskGen.after_method('apply_link')
def build_module(self):
link_output = self.link_task.outputs[0]
for d in self.env.STATIC_LINKING:
if link_output.name.startswith(d):
return
fixup_output = self.path.find_or_declare(link_output.name + '_fixup')
prxgen_output = self.path.find_or_declare(link_output.change_ext('.prx').name)
task = self.create_task('psp_fixup', src=link_output, tgt=fixup_output)
task = self.create_task('psp_prxgen', src=fixup_output, tgt=prxgen_output)
if getattr(self, 'install_path', None):
if self.bld.is_install:
for k in self.install_task.inputs:
if k == self.path.find_or_declare(link_output.name):
self.install_task.inputs.remove(k)
self.add_install_files(install_to=self.install_path, install_from=prxgen_output)
@TaskGen.feature('cprogram', 'cxxprogram', 'cprogram_static', 'cxxprogram_static')
@TaskGen.after_method('apply_link')
def build_eboot(self):
finalobj_ext = '.elf'
finalobj_tool = 'psp_strip'
if self.env.PSP_BUILD_PRX:
finalobj_ext = '.prx'
finalobj_tool = 'psp_prxgen'
link_output = self.link_task.outputs[0]
fixup_output = self.path.find_or_declare(link_output.name + '_fixup')
finalobj_output = self.path.find_or_declare(link_output.change_ext(finalobj_ext).name)
mksfo_output = self.path.find_or_declare('PARAM.SFO')
packpbp_output = self.path.find_or_declare('EBOOT.PBP')
task = self.create_task('psp_fixup', src=link_output, tgt=fixup_output)
task = self.create_task(finalobj_tool, src=fixup_output, tgt=finalobj_output)
task = self.create_task('psp_mksfo', tgt=mksfo_output)
task = self.create_task('psp_packpbp', src=[finalobj_output, mksfo_output], tgt=packpbp_output)
if getattr(self, 'install_path', None):
if getattr(self, 'install_task', None):
self.install_task.inputs = self.install_task.outputs = []
self.add_install_files(install_to=self.install_path, install_from=[packpbp_output, finalobj_output])

View File

@@ -16,7 +16,7 @@ class ziparchive(Task.Task):
return 'Creating' return 'Creating'
def run(self): def run(self):
outfile = self.outputs[0].path_from(self.outputs[0].ctx.launch_node()) outfile = self.outputs[0].abspath()
comp = zipfile.ZIP_STORED if self.compresslevel == 0 else zipfile.ZIP_DEFLATED comp = zipfile.ZIP_STORED if self.compresslevel == 0 else zipfile.ZIP_DEFLATED
with zipfile.ZipFile(outfile, mode='w', compression=comp) as zf: with zipfile.ZipFile(outfile, mode='w', compression=comp) as zf:

View File

@@ -601,6 +601,12 @@ void WriteQCScript( void )
fputs( "$scale 1.0\n", fp ); fputs( "$scale 1.0\n", fp );
fputs( "\n", fp ); fputs( "\n", fp );
if( model_hdr->flags & STUDIO_HAS_BONEINFO )
{
if( model_hdr->flags & STUDIO_HAS_BONEWEIGHTS )
fputs( "$boneweights\n\n", fp );
}
WriteBodyGroupInfo( fp ); WriteBodyGroupInfo( fp );
fprintf( fp, "$flags %u\n\n", model_hdr->flags &~( STUDIO_HAS_BONEINFO | STUDIO_HAS_BONEWEIGHTS ) ); fprintf( fp, "$flags %u\n\n", model_hdr->flags &~( STUDIO_HAS_BONEINFO | STUDIO_HAS_BONEWEIGHTS ) );
@@ -611,10 +617,6 @@ void WriteQCScript( void )
WriteSkinFamilyInfo( fp ); WriteSkinFamilyInfo( fp );
WriteTextureRenderMode( fp ); WriteTextureRenderMode( fp );
if( model_hdr->flags & ( STUDIO_HAS_BONEINFO | STUDIO_HAS_BONEWEIGHTS ) )
fputs( "$boneweights\n\n", fp );
WriteAttachmentInfo( fp ); WriteAttachmentInfo( fp );
fprintf( fp, "$bbox %f %f %f", model_hdr->min[0], model_hdr->min[1], model_hdr->min[2] ); fprintf( fp, "$bbox %f %f %f", model_hdr->min[0], model_hdr->min[1], model_hdr->min[2] );

View File

@@ -197,7 +197,7 @@ def configure(conf):
if conf.env.DEST_OS == 'android': if conf.env.DEST_OS == 'android':
conf.options.NO_VGUI = True # skip vgui conf.options.NO_VGUI = True # skip vgui
conf.options.NANOGL = True conf.options.NANOGL = True
conf.options.GLWES = True conf.options.GLWES = False # deprecated
conf.options.GL4ES = True conf.options.GL4ES = True
conf.options.GLES3COMPAT = True conf.options.GLES3COMPAT = True
conf.options.GL = False conf.options.GL = False