Compare commits

...

89 Commits

Author SHA1 Message Date
mittorn
38a3154de0 ref/gl: refactor gl extension checking again 2024-02-27 05:01:13 +03:00
mittorn
0442af7920 platform/android_nosdl/dlsym-weak: move includes/defines to the beginning 2024-02-27 05:01:13 +03:00
mittorn
42958bc746 platform/android_nosdl: use FS_GetDiskPath for icon path 2024-02-27 05:01:13 +03:00
mittorn
bd5309b018 platform/android_nosdl: fix forgotten static 2024-02-27 05:01:13 +03:00
mittorn
26cbb1d6bf platform/android_nosdl: use ARRAYSIZE 2024-02-27 05:01:13 +03:00
mittorn
d6cfc65ac0 platform/android_nosdl: remove dynamic cvars 2024-02-27 05:01:13 +03:00
mittorn
be9dda2a56 platform/android_nosdl: remove NULL native object case 2024-02-27 05:01:13 +03:00
mittorn
dbc54fb522 platform/android_nosdl: reduce unneeded logging 2024-02-27 05:01:13 +03:00
mittorn
ec92d05930 Fix wrong function name and macro on ARM target 2024-02-27 05:01:13 +03:00
mittorn
892c735c86 Replace harmless single-line pair assigns by multi-line, need more newlines! 2024-02-27 05:01:13 +03:00
mittorn
93e5faa26b Remove unused macro and spaces restored by revert 2024-02-27 05:01:13 +03:00
mittorn
4953656ee0 platform/android/dlsym-weak: do not call LoadLibrary to find server library instance 2024-02-27 05:01:13 +03:00
mittorn
96c367973a platform/android/dlsym-weak: fix code style 2024-02-27 05:01:13 +03:00
mittorn
ffe1ff326a waifulib/xcompile: make clang work with original stlport 2024-02-27 05:01:13 +03:00
mittorn
9c097976df wscript: only enable SINGLE_BINARY and XASH_SDLMAIN on android when SDL2 enabled 2024-02-27 05:01:13 +03:00
mittorn
6fec0398b6 wscript: re-enable xash-extras on android 2024-02-27 05:01:13 +03:00
mittorn
abeb267420 scripts/waifulib: save zip task to make it output reuseable 2024-02-27 05:01:13 +03:00
mittorn
9484effd4c wscript: fix options in external projects 2024-02-27 05:01:13 +03:00
mittorn
a5f3fce665 platform/android-nosdl: add workarounds for yama bullshit 2024-02-27 05:01:13 +03:00
mittorn
91d9ca7810 platform/android-nosdl: restore SIGTRAP handler 2024-02-27 05:01:13 +03:00
mittorn
0901fd94e2 platform/android-nosdl: optionally wait gdb in nativeInit, enable dumpable flag early as possible 2024-02-27 05:01:13 +03:00
mittorn
0d18753adb platform/android-nosdl: add Platform_Shutdown for preShutdown callback 2024-02-27 05:01:13 +03:00
mittorn
7841382fef platform/android-nosdl: fix declaration style (werror) 2024-02-27 05:01:13 +03:00
mittorn
e21d8df1fe platform/android-nosdl: Move all bindings to XashBindings class, workaround broken messageBox from crashhandler 2024-02-27 05:01:13 +03:00
mittorn
16aa2e919f vid/android: Remove pixelFormat selection code, it only used to set desktop bits per pixel 2024-02-27 05:01:13 +03:00
mittorn
88f76c6e1e ref_gl: workaround using fake arb functions on GLES (Mali400 has stub glBindBufferARB somehow\!) 2024-02-27 05:01:13 +03:00
mittorn
1b9af8c515 waifulib/xcompile: add objcopy tool to android configuration, allow switching to ndk binutils with host clang 2024-02-27 05:01:13 +03:00
mittorn
55943ad1ce waifulib/xcompile: disable stpcpy on host-clang 2024-02-27 05:01:13 +03:00
mittorn
313f2a86b0 waifulib/xcompile: add android-from-none for new host-clang versions, support hardfloat abi in host-clang 2024-02-27 05:01:13 +03:00
mittorn
16eeaef35c wscript: check if extra-projects was set in configuration 2024-02-27 05:01:13 +03:00
mittorn
46c82e89e1 waifu: set external waifulibs for extra-projects 2024-02-27 05:01:13 +03:00
mittorn
bb55de5963 platform/android: prevent rendering without context, fix android_sleep using surfaceless mode or dummy surface if possible 2024-02-27 05:01:13 +03:00
mittorn
d423c437ed waf/xcompile: fix ld path for host clang 2024-02-27 05:01:13 +03:00
mittorn
44b1a8e863 platform/android: implement dumb dladdr fallback (only searches in server library) 2024-02-27 05:01:13 +03:00
mittorn
06c6371e69 platform/eglutil: prevent rendering while no surface 2024-02-27 05:01:13 +03:00
mittorn
7b4fd3bcad platform/android: debug surface enabling/disabling, add notification for event_set_pause, fix wrong host.status, prevent rendering while no surface 2024-02-27 05:01:13 +03:00
mittorn
ea35863c26 platform/android: disable swbuffer resize hack, wrong buffer size really is an error that should be fixed on Activity side, not here 2024-02-27 05:01:13 +03:00
mittorn
c2e14eb3a3 platform/android: rewrite egl part to separate not android-specific file 2024-02-27 05:01:13 +03:00
mittorn
34aab39f9b waifulib/xcompile: fix host clang16 2024-02-27 05:01:13 +03:00
mittorn
30c69d3ac8 wscript: add external projects support (updated waf required) 2024-02-27 05:01:13 +03:00
mittorn
bb9775048b platform/android_nosdl: fix build (ndk10, host clang15) 2024-02-27 05:01:13 +03:00
mittorn
eed13cf9f2 waifulib/xcompile: host clang experiments (ndk ld) 2024-02-27 05:01:13 +03:00
mittorn
fbb91e547d Revert "engine: partially remove legacy Android port, in preparation of new port merge"
This reverts commit ef663a8790.
2024-02-27 05:01:13 +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
63 changed files with 3428 additions and 352 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

@@ -18,17 +18,20 @@ GNU General Public License for more details.
// video backends (XASH_VIDEO) // video backends (XASH_VIDEO)
#define VIDEO_NULL 0 #define VIDEO_NULL 0
#define VIDEO_SDL 1 #define VIDEO_SDL 1
#define VIDEO_ANDROID 2
#define VIDEO_FBDEV 3 #define VIDEO_FBDEV 3
#define VIDEO_DOS 4 #define VIDEO_DOS 4
// audio backends (XASH_SOUND) // audio backends (XASH_SOUND)
#define SOUND_NULL 0 #define SOUND_NULL 0
#define SOUND_SDL 1 #define SOUND_SDL 1
#define SOUND_OPENSLES 2
#define SOUND_ALSA 3 #define SOUND_ALSA 3
// input (XASH_INPUT) // input (XASH_INPUT)
#define INPUT_NULL 0 #define INPUT_NULL 0
#define INPUT_SDL 1 #define INPUT_SDL 1
#define INPUT_ANDROID 2
#define INPUT_EVDEV 3 #define INPUT_EVDEV 3
// timer (XASH_TIMER) // timer (XASH_TIMER)
@@ -41,6 +44,7 @@ GNU General Public License for more details.
// messageboxes (XASH_MESSAGEBOX) // messageboxes (XASH_MESSAGEBOX)
#define MSGBOX_STDERR 0 #define MSGBOX_STDERR 0
#define MSGBOX_SDL 1 #define MSGBOX_SDL 1
#define MSGBOX_ANDROID 2
#define MSGBOX_WIN32 3 #define MSGBOX_WIN32 3
#define MSGBOX_NSWITCH 4 #define MSGBOX_NSWITCH 4

View File

@@ -534,5 +534,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

@@ -52,6 +52,25 @@ SETUP BACKENDS DEFINITIONS
#endif #endif
#endif // XASH_MESSAGEBOX #endif // XASH_MESSAGEBOX
#endif #endif
#elif XASH_ANDROID
// we are building for Android platform, use Android APIs
#ifndef XASH_VIDEO
#define XASH_VIDEO VIDEO_ANDROID
#endif // XASH_VIDEO
#ifndef XASH_INPUT
#define XASH_INPUT INPUT_ANDROID
#endif // XASH_INPUT
#ifndef XASH_SOUND
#define XASH_SOUND SOUND_OPENSLES
#endif // XASH_SOUND
#ifndef XASH_MESSAGEBOX
#define XASH_MESSAGEBOX MSGBOX_ANDROID
#endif // XASH_MESSAGEBOX
#define XASH_USE_EVDEV 1
#elif XASH_LINUX #elif XASH_LINUX
// we are building for Linux without SDL2, can draw only to framebuffer yet // we are building for Linux without SDL2, can draw only to framebuffer yet
#ifndef XASH_VIDEO #ifndef XASH_VIDEO
@@ -151,8 +170,6 @@ Default build-depended cvar and constant values
#define DEFAULT_MODE_WIDTH 960 #define DEFAULT_MODE_WIDTH 960
#define DEFAULT_MODE_HEIGHT 544 #define DEFAULT_MODE_HEIGHT 544
#define DEFAULT_ALLOWCONSOLE 1 #define DEFAULT_ALLOWCONSOLE 1
#elif XASH_ANDROID
#define DEFAULT_TOUCH_ENABLE "1"
#elif XASH_MOBILE_PLATFORM #elif XASH_MOBILE_PLATFORM
#define DEFAULT_TOUCH_ENABLE "1" #define DEFAULT_TOUCH_ENABLE "1"
#define DEFAULT_M_IGNORE "1" #define DEFAULT_M_IGNORE "1"
@@ -164,6 +181,10 @@ Default build-depended cvar and constant values
#define XASH_INTERNAL_GAMELIBS #define XASH_INTERNAL_GAMELIBS
#endif // XASH_ANDROID || XASH_IOS || XASH_EMSCRIPTEN #endif // XASH_ANDROID || XASH_IOS || XASH_EMSCRIPTEN
#if XASH_ANDROID && XASH_SDL
#define XASH_ANDROID_ASSETS 1
#endif
// Defaults // Defaults
#ifndef DEFAULT_TOUCH_ENABLE #ifndef DEFAULT_TOUCH_ENABLE
#define DEFAULT_TOUCH_ENABLE "0" #define DEFAULT_TOUCH_ENABLE "0"

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

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

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

@@ -14,7 +14,7 @@ GNU General Public License for more details.
*/ */
#include "platform/platform.h" #include "platform/platform.h"
#if !defined(XASH_DEDICATED) #if !defined(XASH_DEDICATED) && XASH_SDL
#include "input.h" #include "input.h"
#include "client.h" #include "client.h"
@@ -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;
} }
/* /*

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,55 @@
#pragma once
#ifndef ANDROID_PRIV_H
#define ANDROID_PRIV_H
#include <EGL/egl.h>
#include <android/log.h>
#include <jni.h>
extern struct jnimethods_s
{
jclass actcls;
jclass bindcls;
JavaVM *vm;
JNIEnv *env;
jmethodID enableTextInput;
jmethodID vibrate;
jmethodID messageBox;
jmethodID notify;
jmethodID setTitle;
jmethodID setIcon;
jmethodID getAndroidId;
jmethodID saveID;
jmethodID loadID;
jmethodID showMouse;
jmethodID shellExecute;
jmethodID swapBuffers;
jmethodID toggleEGL;
jmethodID createGLContext;
jmethodID getGLAttribute;
jmethodID deleteGLContext;
jmethodID getSurface;
jmethodID preShutdown;
int width, height;
} jni;
typedef enum surfacestate_e
{
surface_pause,
surface_active,
surface_dummy,
} surfacestate_t;
extern struct jnimouse_s
{
float x, y;
} jnimouse;
//
// vid_android.c
//
void Android_UpdateSurface( surfacestate_t state );
#endif // ANDROID_PRIV_H

View File

@@ -25,30 +25,36 @@
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
#include "build.h"
#if defined __ANDROID__ && !defined XASH_64BIT #if !XASH_64BIT
#include <string.h> #include <string.h>
#include <android/log.h> #include <android/log.h>
#include <dlfcn.h>
#include "linker.h" #include "linker.h"
extern "C" {
#include "lib_android.h"
}
static Elf_Sym* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) { static Elf_Sym* soinfo_elf_lookup( soinfo* si, unsigned hash, const char* name )
{
Elf_Sym* symtab = si->symtab; Elf_Sym* symtab = si->symtab;
const char* strtab = si->strtab; const char* strtab = si->strtab;
if( si->nbucket == 0 ) if( si->nbucket == 0 )
return NULL; return NULL;
for (unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n]) { for( unsigned n = si->bucket[hash % si->nbucket]; n != 0; n = si->chain[n] )
{
Elf_Sym* s = symtab + n; Elf_Sym* s = symtab + n;
if (strcmp(strtab + s->st_name, name)) continue; if( strcmp( strtab + s->st_name, name )) continue;
/* only concern ourselves with global and weak symbol definitions */ /* only concern ourselves with global and weak symbol definitions */
switch (ELF_ST_BIND(s->st_info)) { switch( ELF_ST_BIND( s->st_info ))
{
case STB_GLOBAL: case STB_GLOBAL:
case STB_WEAK: case STB_WEAK:
if (s->st_shndx == SHN_UNDEF) { if( s->st_shndx == SHN_UNDEF )
continue; continue;
}
return s; return s;
} }
} }
@@ -56,11 +62,44 @@ static Elf_Sym* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
return NULL; return NULL;
} }
static unsigned elfhash(const char* _name) { static Elf_Sym* soinfo_elf_lookup_reverse(soinfo* si, size_t addr)
const unsigned char* name = (const unsigned char*) _name; {
Elf_Sym* symtab = si->symtab;
if( si->nbucket == 0 )
return NULL;
for( int j = 0; j < si->nbucket; j++ )
{
for( unsigned n = si->bucket[j]; n != 0; n = si->chain[n] )
{
Elf_Sym* s = symtab + n;
if( s->st_value != addr )continue;
/* only concern ourselves with global and weak symbol definitions */
switch( ELF_ST_BIND( s->st_info ))
{
case STB_GLOBAL:
case STB_LOCAL:
case STB_WEAK:
if (s->st_shndx == SHN_UNDEF)
continue;
return s;
}
}
}
return NULL;
}
static unsigned elfhash( const char* _name )
{
const unsigned char* name = ( const unsigned char* ) _name;
unsigned h = 0, g; unsigned h = 0, g;
while(*name) { while(*name)
{
h = (h << 4) + *name++; h = (h << 4) + *name++;
g = h & 0xf0000000; g = h & 0xf0000000;
h ^= g; h ^= g;
@@ -78,21 +117,73 @@ static unsigned elfhash(const char* _name) {
Binary Interface) where in Chapter 5 it discuss resolving "Shared Binary Interface) where in Chapter 5 it discuss resolving "Shared
Object Dependencies" in breadth first search order. Object Dependencies" in breadth first search order.
*/ */
static Elf_Sym* dlsym_handle_lookup(soinfo* si, const char* name) { static Elf_Sym* dlsym_handle_lookup( soinfo* si, const char* name )
return soinfo_elf_lookup(si, elfhash(name), name); {
return soinfo_elf_lookup( si, elfhash( name ), name );
} }
extern "C" void* dlsym_weak(void* handle, const char* symbol) { static int dladdr_fallback( const void *addr, Dl_info *info )
{
static soinfo *server_info;
Elf_Sym *sym;
if( !server_info )
server_info = ( soinfo* )ANDROID_GetServerLibrary();
if( !server_info )
return 0;
//__android_log_print( ANDROID_LOG_ERROR, "dladdr_fb", "%p %p\n", addr, server_info );
sym = soinfo_elf_lookup_reverse( server_info, ((char*)addr) - ((char*)server_info->base ));
//__android_log_print( ANDROID_LOG_ERROR, "dladdr_fb", "sym %p %p\n", addr, sym );
if( sym )
{
info->dli_sname = server_info->strtab + sym->st_name;
info->dli_fname = "server";
info->dli_fbase = (void*)server_info->base;
info->dli_saddr = (void*)addr;
//__android_log_print( ANDROID_LOG_ERROR, "dladdr_fb", "name %p %s\n", addr, info->dli_sname );
return 1;
}
return 0;
}
extern "C" int __attribute__((visibility("hidden"))) dladdr( const void *addr, Dl_info *info )
{
typedef int (*PFNDLADDR)( const void *addr, Dl_info *info );
PFNDLADDR pfn_dladdr;
if( !pfn_dladdr )
{
/* android does not have libdl, but have soinfo record for it from linker
* use dlopen to get this record directly */
void *lib = dlopen( "libdl.so", RTLD_NOW );
if( lib )
pfn_dladdr = (PFNDLADDR)dlsym( lib, "dladdr" );
if( pfn_dladdr == (PFNDLADDR)dladdr )
pfn_dladdr = 0;
if( !pfn_dladdr )
pfn_dladdr = (PFNDLADDR)dladdr_fallback;
}
return pfn_dladdr( addr, info );
}
extern "C" void* dlsym_weak( void* handle, const char* symbol ) {
soinfo* found = NULL; soinfo* found = NULL;
Elf_Sym* sym = NULL; Elf_Sym* sym = NULL;
found = reinterpret_cast<soinfo*>(handle); found = reinterpret_cast<soinfo*>( handle );
sym = dlsym_handle_lookup(found, symbol); sym = dlsym_handle_lookup( found, symbol );
if (sym != NULL) { if ( sym != NULL ) {
return reinterpret_cast<void*>(sym->st_value + found->base/*load_bias*/); return reinterpret_cast<void*>( sym->st_value + found->base /*load_bias*/ );
} }
__android_log_print(ANDROID_LOG_ERROR, "dlsym-weak", "Failed when looking up %s\n", symbol); __android_log_print( ANDROID_LOG_ERROR, "dlsym-weak", "Failed when looking up %s\n", symbol );
return NULL; return NULL;
} }
#endif #endif

View File

@@ -0,0 +1,453 @@
/*
eglutil.c - EGL context utility
Copyright (C) 2023 mittorn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "platform/platform.h"
#if !defined(XASH_DEDICATED) && !XASH_SDL
#include "eglutil.h"
#include "client.h"
#include "vid_common.h"
#include <EGL/egl.h>
#include <EGL/eglext.h>
struct eglapi_s egl;
#undef GetProcAddress // windows.h?
#define EGL_FF(x) {"egl"#x, (void*)&egl.x}
static dllfunc_t egl_funcs[] =
{
EGL_FF(SwapInterval),
EGL_FF(SwapBuffers),
EGL_FF(GetError),
EGL_FF(GetCurrentDisplay),
EGL_FF(GetCurrentSurface),
EGL_FF(GetProcAddress),
EGL_FF(GetConfigAttrib),
EGL_FF(GetDisplay),
EGL_FF(Initialize),
EGL_FF(Terminate),
EGL_FF(QueryString),
EGL_FF(ChooseConfig),
EGL_FF(CreateWindowSurface),
EGL_FF(CreateContext),
EGL_FF(DestroyContext),
EGL_FF(MakeCurrent),
EGL_FF(BindAPI),
EGL_FF(DestroySurface),
{ NULL, NULL }
};
#undef EGL_FF
static dll_info_t egl_info = { "libEGL.so", egl_funcs, false };
struct eglstate_s eglstate;
/*
===================
refapi/egl wrappers
===================
*/
int EGL_SetAttribute( int attr, int val )
{
if( attr < 0 || attr >= REF_GL_ATTRIBUTES_COUNT )
return -1;
eglstate.gl_attribs[attr] = val;
eglstate.gl_attribs_set[attr] = true;
return 0;
}
#define COPY_ATTR_IF_SET( refattr, attr ) \
if( eglstate.gl_attribs_set[refattr] ) \
{ \
attribs[i++] = attr; \
attribs[i++] = eglstate.gl_attribs[refattr]; \
}
size_t EGL_GenerateConfig( EGLint *attribs, size_t size )
{
size_t i = 0;
memset( attribs, 0, size * sizeof( EGLint ) );
eglstate.gles1 = false;
memset( eglstate.gl_attribs, 0, sizeof( eglstate.gl_attribs ));
memset( eglstate.gl_attribs_set, 0, sizeof( eglstate.gl_attribs_set ));
// refdll can request some attributes
ref.dllFuncs.GL_SetupAttributes( glw_state.safe );
COPY_ATTR_IF_SET( REF_GL_RED_SIZE, EGL_RED_SIZE );
COPY_ATTR_IF_SET( REF_GL_GREEN_SIZE, EGL_GREEN_SIZE );
COPY_ATTR_IF_SET( REF_GL_BLUE_SIZE, EGL_BLUE_SIZE );
COPY_ATTR_IF_SET( REF_GL_ALPHA_SIZE, EGL_ALPHA_SIZE );
COPY_ATTR_IF_SET( REF_GL_DEPTH_SIZE, EGL_DEPTH_SIZE );
COPY_ATTR_IF_SET( REF_GL_STENCIL_SIZE, EGL_STENCIL_SIZE );
COPY_ATTR_IF_SET( REF_GL_MULTISAMPLEBUFFERS, EGL_SAMPLE_BUFFERS );
COPY_ATTR_IF_SET( REF_GL_MULTISAMPLESAMPLES, EGL_SAMPLES );
if( eglstate.gl_attribs_set[REF_GL_ACCELERATED_VISUAL] )
{
attribs[i++] = EGL_CONFIG_CAVEAT;
attribs[i++] = eglstate.gl_attribs[REF_GL_ACCELERATED_VISUAL] ? EGL_NONE : EGL_DONT_CARE;
}
// BigGL support
attribs[i++] = EGL_RENDERABLE_TYPE;
eglstate.gl_api = EGL_OPENGL_ES_API;
if( eglstate.gl_attribs_set[REF_GL_CONTEXT_PROFILE_MASK] &&
!( eglstate.gl_attribs[REF_GL_CONTEXT_PROFILE_MASK] & REF_GL_CONTEXT_PROFILE_ES ))
{
attribs[i++] = EGL_OPENGL_BIT;
eglstate.gl_api = EGL_OPENGL_API;
}
else if( eglstate.gl_attribs_set[REF_GL_CONTEXT_MAJOR_VERSION] &&
eglstate.gl_attribs[REF_GL_CONTEXT_MAJOR_VERSION] >= 2 )
{
attribs[i++] = EGL_OPENGL_ES2_BIT;
}
else
{
i--; // erase EGL_RENDERABLE_TYPE
eglstate.gles1 = true;
}
attribs[i++] = EGL_NONE;
return i;
}
size_t EGL_GenerateContextConfig( EGLint *attribs, size_t size )
{
size_t i = 0;
memset( attribs, 0, size * sizeof( EGLint ));
if( Q_strstr( eglstate.extensions, "EGL_KHR_create_context") )
{
Con_DPrintf( S_NOTE "EGL_KHR_create_context found, setting additional context flags\n");
if( eglstate.gl_attribs_set[REF_GL_CONTEXT_FLAGS] )
{
attribs[i++] = 0x30FC; // EGL_CONTEXT_FLAGS_KHR
attribs[i++] = eglstate.gl_attribs[REF_GL_CONTEXT_FLAGS] & ((REF_GL_CONTEXT_ROBUST_ACCESS_FLAG << 1) - 1);
}
if( eglstate.gl_attribs_set[REF_GL_CONTEXT_PROFILE_MASK] )
{
int val = eglstate.gl_attribs[REF_GL_CONTEXT_PROFILE_MASK];
if( val & ( (REF_GL_CONTEXT_PROFILE_COMPATIBILITY << 1) - 1 ) )
{
attribs[i++] = 0x30FD; // EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
attribs[i++] = val;
}
}
COPY_ATTR_IF_SET( REF_GL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_CLIENT_VERSION );
COPY_ATTR_IF_SET( REF_GL_CONTEXT_MINOR_VERSION, 0x30FB );
}
else
{
// without extension we can set only major version
COPY_ATTR_IF_SET( REF_GL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_CLIENT_VERSION );
if( eglstate.gl_attribs_set[REF_GL_CONTEXT_FLAGS] && (eglstate.gl_attribs[REF_GL_CONTEXT_FLAGS] & REF_GL_CONTEXT_DEBUG_FLAG ))
{
attribs[i++] = 0x31B0; // EGL_CONTEXT_OPENGL_DEBUG;
attribs[i++] = EGL_TRUE;
}
}
attribs[i++] = EGL_NONE;
return i;
}
/*
=========================
EGL_GetAttribute
query
=========================
*/
int EGL_GetAttribute( int attr, int *val )
{
EGLBoolean ret;
if( attr < 0 || attr >= REF_GL_ATTRIBUTES_COUNT )
return -1;
if( !val )
return -1;
switch( attr )
{
case REF_GL_RED_SIZE:
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_RED_SIZE, val );
return 0;
case REF_GL_GREEN_SIZE:
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_GREEN_SIZE, val );
return 0;
case REF_GL_BLUE_SIZE:
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_BLUE_SIZE, val );
return 0;
case REF_GL_ALPHA_SIZE:
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_ALPHA_SIZE, val );
return 0;
case REF_GL_DEPTH_SIZE:
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_DEPTH_SIZE, val );
return 0;
case REF_GL_STENCIL_SIZE:
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_STENCIL_SIZE, val );
return 0;
case REF_GL_MULTISAMPLESAMPLES:
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_SAMPLES, val );
return 0;
}
return -1;
}
/*
=========================
EGL_UpdateSurface
destroy old surface, recreate and make context current
must be called with valid context
=========================
*/
qboolean EGL_UpdateSurface( void *window, qboolean dummy )
{
if( !eglstate.valid )
return false;
egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
host.status = HOST_SLEEP;
if( eglstate.surface )
{
egl.DestroySurface( eglstate.dpy, eglstate.surface );
eglstate.surface = EGL_NO_SURFACE;
}
if( !window )
{
if( dummy && eglstate.support_surfaceless_context )
{
if( egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, eglstate.context ))
{
Con_Reportf( S_NOTE "EGL_UpdateSurface: using surfaceless mode\n" );
return true;
}
else
{
egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
eglstate.support_surfaceless_context = false;
}
Con_Reportf( S_NOTE "EGL_UpdateSurface: missing native window, detaching context\n" );
}
return false; // let platform fallback to dummy surface or pause engine
}
if(( eglstate.surface = egl.CreateWindowSurface( eglstate.dpy, eglstate.cfg, window, NULL )) == EGL_NO_SURFACE )
{
Con_Reportf( S_ERROR "eglCreateWindowSurface returned error: 0x%x\n", egl.GetError() );
return false;
}
if( !egl.MakeCurrent( eglstate.dpy, eglstate.surface, eglstate.surface, eglstate.context ))
{
Con_Reportf( S_ERROR "eglMakeCurrent returned error: 0x%x\n", egl.GetError() );
return false;
}
Con_DPrintf( S_NOTE "restored current context\n" );
if( !dummy)
host.status = HOST_FRAME;
return true;
}
/*
=========================
EGL_CreateContext
query attributes for ref and create context
=========================
*/
qboolean EGL_CreateContext( void )
{
EGLint attribs[32+1], contextAttribs[32+1];
const size_t attribsSize = ARRAYSIZE( attribs );
size_t s1, s2;
if( !eglstate.dpy && ( eglstate.dpy = egl.GetDisplay( EGL_DEFAULT_DISPLAY )) == EGL_NO_DISPLAY )
{
Con_Reportf( S_ERROR "eglGetDisplay returned error: 0x%x\n", egl.GetError() );
return false;
}
eglstate.extensions = egl.QueryString( eglstate.dpy, EGL_EXTENSIONS );
s1 = EGL_GenerateConfig(attribs, attribsSize);
s2 = EGL_GenerateContextConfig(contextAttribs, attribsSize);
if( !egl.BindAPI( eglstate.gl_api ))
{
Con_Reportf( S_ERROR "eglBindAPI returned error: 0x%x\n", egl.GetError() );
return false;
}
if( !egl.Initialize( eglstate.dpy, NULL, NULL ))
{
Con_Reportf( S_ERROR "eglInitialize returned error: 0x%x\n", egl.GetError() );
return false;
}
if( !egl.ChooseConfig( eglstate.dpy, attribs, &eglstate.cfg, 1, &eglstate.numCfg ))
{
Con_Reportf( S_ERROR "eglChooseConfig returned error: 0x%x\n", egl.GetError() );
return false;
}
if(( eglstate.context = egl.CreateContext( eglstate.dpy, eglstate.cfg, NULL, contextAttribs )) == EGL_NO_CONTEXT )
{
Con_Reportf( S_ERROR "eglCreateContext returned error: 0x%x\n", egl.GetError() );
return false;
}
eglstate.valid = true;
eglstate.imported = false;
// now check if it's safe to use surfaceless context here without surface fallback
if( eglstate.extensions && Q_strstr( eglstate.extensions, "EGL_KHR_surfaceless_context" ))
eglstate.support_surfaceless_context = true;
return true;
}
/*
===========================
EGL_ImportContext
import current egl context to use EGL functions
===========================
*/
qboolean EGL_ImportContext( void )
{
if( !egl.GetCurrentDisplay )
return false;
eglstate.dpy = egl.GetCurrentDisplay();
if( eglstate.dpy == EGL_NO_DISPLAY )
return false;
eglstate.surface = egl.GetCurrentSurface( EGL_DRAW );
if( eglstate.surface == EGL_NO_SURFACE )
return false;
// now check if swapBuffers does not give error
if( egl.SwapBuffers( eglstate.dpy, eglstate.surface ) == EGL_FALSE )
return false;
// double check
if( egl.GetError() != EGL_SUCCESS )
return false;
eglstate.extensions = egl.QueryString( eglstate.dpy, EGL_EXTENSIONS );
eglstate.valid = eglstate.imported = true;
return true;
}
/*
=========================
EGL_Terminate
=========================
*/
void EGL_Terminate( void )
{
egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
egl.DestroyContext( eglstate.dpy, eglstate.context );
egl.DestroySurface( eglstate.dpy, eglstate.surface );
egl.Terminate( eglstate.dpy );
Sys_FreeLibrary( &egl_info );
}
/*
=========================
EGL_GetProcAddress
eglGetProcAddress/dlsym wrapper
=========================
*/
void *EGL_GetProcAddress( const char *name )
{
void *gles;
void *addr;
// TODO: cross-platform loading
if( eglstate.gles1 )
{
if( !eglstate.libgles1 )
eglstate.libgles1 = dlopen( "libGLESv1_CM.so", RTLD_NOW );
gles = eglstate.libgles1;
}
else
{
if( !eglstate.libgles2 )
eglstate.libgles2 = dlopen( "libGLESv2.so", RTLD_NOW );
gles = eglstate.libgles2;
}
if( gles && ( addr = dlsym( gles, name )))
return addr;
if( !egl.GetProcAddress )
return NULL;
return egl.GetProcAddress( name );
}
/*
=========================
EGL_LoadLibrary
=========================
*/
void EGL_LoadLibrary( void )
{
Sys_LoadLibrary( &egl_info );
}
#endif

View File

@@ -0,0 +1,73 @@
/*
eglutil.h - EGL context utility
Copyright (C) 2023 mittorn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef EGLUTIL_H
#define EGLUTIL_H
#include "platform/platform.h"
#include <EGL/egl.h>
#include <EGL/eglext.h>
extern struct eglstate_s
{
qboolean valid, imported;
EGLDisplay dpy;
EGLSurface surface;
EGLContext context;
EGLConfig cfg;
EGLint numCfg;
qboolean support_surfaceless_context;
const char *extensions;
int gl_attribs[REF_GL_ATTRIBUTES_COUNT];
qboolean gl_attribs_set[REF_GL_ATTRIBUTES_COUNT];
EGLint gl_api;
qboolean gles1;
void *libgles1, *libgles2;
} eglstate;
extern struct eglapi_s
{
EGLSurface (*GetCurrentSurface)( EGLint readdraw );
EGLDisplay (*GetCurrentDisplay)( void );
EGLint (*GetError)( void );
EGLBoolean (*SwapBuffers)( EGLDisplay dpy, EGLSurface surface );
EGLBoolean (*SwapInterval)( EGLDisplay dpy, EGLint interval );
void *(*GetProcAddress)( const char *procname );
EGLBoolean (*GetConfigAttrib)( EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value );
EGLDisplay (*GetDisplay)( NativeDisplayType display );
EGLBoolean (*Initialize)( EGLDisplay dpy, EGLint *major, EGLint *minor );
EGLBoolean (*Terminate)( EGLDisplay dpy );
const char *(*QueryString)( EGLDisplay dpy, EGLint name );
EGLBoolean (*ChooseConfig)( EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config );
EGLSurface (*CreateWindowSurface)( EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list );
EGLContext (*CreateContext)( EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list );
EGLBoolean (*DestroyContext)( EGLDisplay dpy, EGLContext ctx );
EGLBoolean (*MakeCurrent)( EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx );
EGLBoolean (*BindAPI)( EGLenum api );
EGLBoolean (*DestroySurface)( EGLDisplay dpy, EGLSurface surface );
} egl;
void EGL_LoadLibrary( void );
void * EGL_GetProcAddress( const char *name );
void EGL_Terminate( void );
qboolean EGL_ImportContext( void );
qboolean EGL_CreateContext( void );
qboolean EGL_UpdateSurface( void *window, qboolean dummy );
int EGL_GetAttribute( int attr, int *val );
size_t EGL_GenerateContextConfig( EGLint *attribs, size_t size );
size_t EGL_GenerateConfig( EGLint *attribs, size_t size );
int EGL_SetAttribute( int attr, int val );
#endif // EGLUTIL_H

View File

@@ -19,6 +19,12 @@ GNU General Public License for more details.
#include "platform/android/lib_android.h" #include "platform/android/lib_android.h"
#include "platform/android/dlsym-weak.h" // Android < 5.0 #include "platform/android/dlsym-weak.h" // Android < 5.0
void *ANDROID_GetServerLibrary( void )
{
return svgame.hInstance;
}
void *ANDROID_LoadLibrary( const char *dllname ) void *ANDROID_LoadLibrary( const char *dllname )
{ {
char path[MAX_SYSPATH]; char path[MAX_SYSPATH];

View File

@@ -20,6 +20,7 @@ GNU General Public License for more details.
#define Platform_POSIX_LoadLibrary( x ) ANDROID_LoadLibrary(( x )) #define Platform_POSIX_LoadLibrary( x ) ANDROID_LoadLibrary(( x ))
#define Platform_POSIX_GetProcAddress( x, y ) ANDROID_GetProcAddress(( x ), ( y )) #define Platform_POSIX_GetProcAddress( x, y ) ANDROID_GetProcAddress(( x ), ( y ))
void *ANDROID_GetServerLibrary( void );
void *ANDROID_LoadLibrary( const char *dllname ); void *ANDROID_LoadLibrary( const char *dllname );
void *ANDROID_GetProcAddress( void *hInstance, const char *name ); void *ANDROID_GetProcAddress( void *hInstance, const char *name );

View File

@@ -0,0 +1,277 @@
/*
Copyright (C) 2015 SiPlus, Chasseur de bots
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "common.h"
#include "platform/platform.h"
#if XASH_SOUND == SOUND_OPENSLES
#include <SLES/OpenSLES.h>
#include "pthread.h"
#include "sound.h"
extern dma_t dma;
static SLObjectItf snddma_android_engine = NULL;
static SLObjectItf snddma_android_outputMix = NULL;
static SLObjectItf snddma_android_player = NULL;
static SLBufferQueueItf snddma_android_bufferQueue;
static SLPlayItf snddma_android_play;
static pthread_mutex_t snddma_android_mutex = PTHREAD_MUTEX_INITIALIZER;
static int snddma_android_size;
static const SLInterfaceID *pSL_IID_ENGINE;
static const SLInterfaceID *pSL_IID_BUFFERQUEUE;
static const SLInterfaceID *pSL_IID_PLAY;
static SLresult SLAPIENTRY (*pslCreateEngine)(
SLObjectItf *pEngine,
SLuint32 numOptions,
const SLEngineOption *pEngineOptions,
SLuint32 numInterfaces,
const SLInterfaceID *pInterfaceIds,
const SLboolean * pInterfaceRequired
);
void SNDDMA_Activate( qboolean active )
{
if( !dma.initialized )
return;
if( active )
{
memset( dma.buffer, 0, snddma_android_size * 2 );
(*snddma_android_bufferQueue)->Enqueue( snddma_android_bufferQueue, dma.buffer, snddma_android_size );
(*snddma_android_play)->SetPlayState( snddma_android_play, SL_PLAYSTATE_PLAYING );
}
else
{
(*snddma_android_play)->SetPlayState( snddma_android_play, SL_PLAYSTATE_STOPPED );
(*snddma_android_bufferQueue)->Clear( snddma_android_bufferQueue );
}
}
static void SNDDMA_Android_Callback( SLBufferQueueItf bq, void *context )
{
uint8_t *buffer2;
pthread_mutex_lock( &snddma_android_mutex );
buffer2 = ( uint8_t * )dma.buffer + snddma_android_size;
(*bq)->Enqueue( bq, buffer2, snddma_android_size );
memcpy( buffer2, dma.buffer, snddma_android_size );
memset( dma.buffer, 0, snddma_android_size );
dma.samplepos += dma.samples;
pthread_mutex_unlock( &snddma_android_mutex );
}
static const char *SNDDMA_Android_Init( void )
{
SLresult result;
SLEngineItf engine;
int freq;
SLDataLocator_BufferQueue sourceLocator;
SLDataFormat_PCM sourceFormat;
SLDataSource source;
SLDataLocator_OutputMix sinkLocator;
SLDataSink sink;
SLInterfaceID interfaceID;
SLboolean interfaceRequired;
int samples;
void *handle = dlopen( "libOpenSLES.so", RTLD_LAZY );
if( !handle )
return "dlopen for libOpenSLES.so";
pslCreateEngine = dlsym( handle, "slCreateEngine" );
if( !pslCreateEngine )
return "resolve slCreateEngine";
pSL_IID_ENGINE = dlsym( handle, "SL_IID_ENGINE" );
if( !pSL_IID_ENGINE )
return "resolve SL_IID_ENGINE";
pSL_IID_PLAY = dlsym( handle, "SL_IID_PLAY" );
if( !pSL_IID_PLAY )
return "resolve SL_IID_PLAY";
pSL_IID_BUFFERQUEUE = dlsym( handle, "SL_IID_BUFFERQUEUE" );
if( !pSL_IID_BUFFERQUEUE )
return "resolve SL_IID_BUFFERQUEUE";
result = pslCreateEngine( &snddma_android_engine, 0, NULL, 0, NULL, NULL );
if( result != SL_RESULT_SUCCESS ) return "slCreateEngine";
result = (*snddma_android_engine)->Realize( snddma_android_engine, SL_BOOLEAN_FALSE );
if( result != SL_RESULT_SUCCESS ) return "engine->Realize";
result = (*snddma_android_engine)->GetInterface( snddma_android_engine, *pSL_IID_ENGINE, &engine );
if( result != SL_RESULT_SUCCESS ) return "engine->GetInterface(ENGINE)";
result = (*engine)->CreateOutputMix( engine, &snddma_android_outputMix, 0, NULL, NULL );
if( result != SL_RESULT_SUCCESS ) return "engine->CreateOutputMix";
result = (*snddma_android_outputMix)->Realize( snddma_android_outputMix, SL_BOOLEAN_FALSE );
if( result != SL_RESULT_SUCCESS ) return "outputMix->Realize";
freq = SOUND_DMA_SPEED;
sourceLocator.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
sourceLocator.numBuffers = 2;
sourceFormat.formatType = SL_DATAFORMAT_PCM;
sourceFormat.numChannels = 2; // always stereo, because engine supports only stereo
sourceFormat.samplesPerSec = freq * 1000;
sourceFormat.bitsPerSample = 16; // always 16 bit audio
sourceFormat.containerSize = sourceFormat.bitsPerSample;
sourceFormat.channelMask = SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT;
sourceFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;
source.pLocator = &sourceLocator;
source.pFormat = &sourceFormat;
sinkLocator.locatorType = SL_DATALOCATOR_OUTPUTMIX;
sinkLocator.outputMix = snddma_android_outputMix;
sink.pLocator = &sinkLocator;
sink.pFormat = NULL;
interfaceID = *pSL_IID_BUFFERQUEUE;
interfaceRequired = SL_BOOLEAN_TRUE;
result = (*engine)->CreateAudioPlayer( engine, &snddma_android_player, &source, &sink, 1, &interfaceID, &interfaceRequired );
if( result != SL_RESULT_SUCCESS ) return "engine->CreateAudioPlayer";
result = (*snddma_android_player)->Realize( snddma_android_player, SL_BOOLEAN_FALSE );
if( result != SL_RESULT_SUCCESS ) return "player->Realize";
result = (*snddma_android_player)->GetInterface( snddma_android_player, *pSL_IID_BUFFERQUEUE, &snddma_android_bufferQueue );
if( result != SL_RESULT_SUCCESS ) return "player->GetInterface(BUFFERQUEUE)";
result = (*snddma_android_player)->GetInterface( snddma_android_player, *pSL_IID_PLAY, &snddma_android_play );
if( result != SL_RESULT_SUCCESS ) return "player->GetInterface(PLAY)";
result = (*snddma_android_bufferQueue)->RegisterCallback( snddma_android_bufferQueue, SNDDMA_Android_Callback, NULL );
if( result != SL_RESULT_SUCCESS ) return "bufferQueue->RegisterCallback";
samples = s_samplecount.value;
if( !samples )
samples = 4096;
dma.format.channels = sourceFormat.numChannels;
dma.samples = samples * sourceFormat.numChannels;
dma.format.speed = freq;
snddma_android_size = dma.samples * ( sourceFormat.bitsPerSample >> 3 );
dma.buffer = Z_Malloc( snddma_android_size * 2 );
dma.samplepos = 0;
// dma.sampleframes = dma.samples / dma.format.channels;
dma.format.width = 2;
if( !dma.buffer ) return "malloc";
//snddma_android_mutex = trap_Mutex_Create();
dma.initialized = true;
SNDDMA_Activate( true );
return NULL;
}
qboolean SNDDMA_Init( void )
{
const char *initError;
Msg( "OpenSL ES audio device initializing...\n" );
initError = SNDDMA_Android_Init();
if( initError )
{
Msg( S_ERROR "SNDDMA_Init: %s failed.\n", initError );
SNDDMA_Shutdown();
return false;
}
Msg( "OpenSL ES audio initialized.\n" );
dma.backendName = "OpenSL ES";
return true;
}
void SNDDMA_Shutdown( void )
{
Msg( "Closing OpenSL ES audio device...\n" );
if( snddma_android_player )
{
(*snddma_android_player)->Destroy( snddma_android_player );
snddma_android_player = NULL;
}
if( snddma_android_outputMix )
{
(*snddma_android_outputMix)->Destroy( snddma_android_outputMix );
snddma_android_outputMix = NULL;
}
if( snddma_android_engine )
{
(*snddma_android_engine)->Destroy( snddma_android_engine );
snddma_android_engine = NULL;
}
if( dma.buffer )
{
Z_Free( dma.buffer );
dma.buffer = NULL;
}
//if( snddma_android_mutex )
//trap_Mutex_Destroy( &snddma_android_mutex );
Msg( "OpenSL ES audio device shut down.\n" );
}
void SNDDMA_Submit( void )
{
pthread_mutex_unlock( &snddma_android_mutex );
}
void SNDDMA_BeginPainting( void )
{
pthread_mutex_lock( &snddma_android_mutex );
}
qboolean VoiceCapture_Init( void )
{
return false;
}
qboolean VoiceCapture_Activate( qboolean activate )
{
return false;
}
qboolean VoiceCapture_Lock( qboolean lock )
{
return false;
}
void VoiceCapture_Shutdown( void )
{
}
#endif

View File

@@ -0,0 +1,513 @@
#include "platform/platform.h"
#if !XASH_SDL
#include "input.h"
#include "client.h"
#include "filesystem.h"
#include "platform/android/android_priv.h"
#include "vid_common.h"
#include <android/native_window.h>
#include <android/native_window_jni.h>
#include "eglutil.h"
static struct vid_android_s
{
qboolean has_context;
ANativeWindow* window;
qboolean nativeegl;
} vid_android;
static struct nw_s
{
void (*release)(ANativeWindow* window);
int32_t (*getWidth)(ANativeWindow* window);
int32_t (*getHeight)(ANativeWindow* window);
int32_t (*getFormat)(ANativeWindow* window);
int32_t (*setBuffersGeometry)(ANativeWindow* window, int32_t width, int32_t height, int32_t format);
int32_t (*lock)(ANativeWindow* window, ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
int32_t (*unlockAndPost)(ANativeWindow* window);
ANativeWindow* (*fromSurface)(JNIEnv* env, jobject surface);
} nw;
#define NW_FF(x) {"ANativeWindow_"#x, (void*)&nw.x}
static dllfunc_t android_funcs[] =
{
NW_FF(release),
NW_FF(getWidth),
NW_FF(getHeight),
NW_FF(getFormat),
NW_FF(setBuffersGeometry),
NW_FF(lock),
NW_FF(unlockAndPost),
NW_FF(fromSurface),
{ NULL, NULL }
};
#undef NW_FF
static dll_info_t android_info = { "libandroid.so", android_funcs, false };
/*
========================
Android_SwapInterval
========================
*/
static void Android_SwapInterval( int interval )
{
if( vid_android.nativeegl && eglstate.valid )
egl.SwapInterval( eglstate.dpy, interval );
}
/*
========================
Android_SetTitle
========================
*/
static void Android_SetTitle( const char *title )
{
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.setTitle, (*jni.env)->NewStringUTF( jni.env, title ) );
}
/*
========================
Android_SetIcon
========================
*/
static void Android_SetIcon( const char *path )
{
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.setIcon, (*jni.env)->NewStringUTF( jni.env, path ) );
}
/*
========================
Android_GetScreenRes
Resolution got from last resize event
========================
*/
static void Android_GetScreenRes( int *width, int *height )
{
*width = jni.width;
*height = jni.height;
}
/*
========================
Android_SwapBuffers
Update screen. Use native EGL if possible
========================
*/
void GL_SwapBuffers( void )
{
if( vid_android.nativeegl && eglstate.valid )
{
egl.SwapBuffers( eglstate.dpy, eglstate.surface );
}
else
{
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.swapBuffers );
}
}
/*
========================
Android_UpdateSurface
Check if we may use native EGL without jni calls
========================
*/
void Android_UpdateSurface( surfacestate_t state )
{
qboolean active = state == surface_active;
vid_android.nativeegl = false;
if( glw_state.software || ( eglstate.valid && !eglstate.imported ))
{
if( vid_android.window )
{
EGL_UpdateSurface( NULL, false );
nw.release( vid_android.window );
vid_android.window = NULL;
}
if( state == surface_dummy && glw_state.software )
return;
// first, ask EGL for surfaceless mode
if( state == surface_dummy && EGL_UpdateSurface( NULL, true ))
{
vid_android.nativeegl = true;
return;
}
if( state != surface_pause )
{
EGLint format = WINDOW_FORMAT_RGB_565;
jobject surf;
if( vid_android.window )
nw.release( vid_android.window );
surf = (*jni.env)->CallStaticObjectMethod( jni.env, jni.bindcls, jni.getSurface, state );
Con_DPrintf("Surface handle %p\n", surf);
if( surf )
{
vid_android.window = nw.fromSurface(jni.env, surf);
Con_DPrintf("NativeWindow %p\n", vid_android.window);
if( eglstate.valid )
egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_NATIVE_VISUAL_ID, &format );
nw.setBuffersGeometry(vid_android.window, 0, 0, format );
(*jni.env)->DeleteLocalRef( jni.env, surf );
}
}
if( eglstate.valid && !eglstate.imported )
{
EGL_UpdateSurface( vid_android.window, state == surface_dummy );
vid_android.nativeegl = true;
}
return;
}
if( !vid_android.has_context )
return;
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.toggleEGL, (int)state );
host.status = HOST_FRAME; // active ? HOST_FRAME : HOST_SLEEP;
// todo: check opengl context here and set HOST_SLEEP if not
if( !Sys_CheckParm("-nativeegl") || !active )
return; // enabled by user
vid_android.nativeegl = EGL_ImportContext();
if( vid_android.nativeegl )
Con_DPrintf( "nativeEGL success\n");
}
/*
========================
Android_GetGLAttribute
========================
*/
static int Android_GetGLAttribute( int eglAttr )
{
int ret = (*jni.env)->CallStaticIntMethod( jni.env, jni.bindcls, jni.getGLAttribute, eglAttr );
// Con_Reportf( "Android_GetGLAttribute( %i ) => %i\n", eglAttr, ret );
return ret;
}
qboolean R_Init_Video( const int type )
{
qboolean retval;
char buf[10]; // Sys_GetParmFromCmdLine
if( FS_FileExists( GI->iconpath, true ) )
{
// TODO: convert icon to some android-readable format and place
Android_SetIcon( FS_GetDiskPath( GI->iconpath, false ));
}
Android_SetTitle( GI->title );
VID_StartupGamma();
Sys_LoadLibrary( &android_info );
switch( type )
{
case REF_SOFTWARE:
glw_state.software = true;
break;
case REF_GL:
glw_state.software = false;
EGL_LoadLibrary();
if( !glw_state.safe && Sys_GetParmFromCmdLine( "-safegl", buf ) )
glw_state.safe = bound( SAFE_NO, Q_atoi( buf ), SAFE_DONTCARE );
break;
default:
Host_Error( "Can't initialize unknown context type %d!\n", type );
break;
}
if( glw_state.software )
{
uint arg;
if( !nw.release )
{
Con_Reportf( S_ERROR "Native software mode unavailiable\n" );
return false;
}
Android_UpdateSurface( surface_active );
if( !SW_CreateBuffer( jni.width, jni.height, &arg, &arg, &arg, &arg, &arg ) )
return false;
}
while( !(retval = VID_SetMode()) )
{
glw_state.safe++;
if( glw_state.safe > SAFE_LAST )
return false;
}
switch( type )
{
case REF_GL:
// refdll also can check extensions
ref.dllFuncs.GL_InitExtensions();
break;
case REF_SOFTWARE:
default:
break;
}
host.renderinfo_changed = false;
host.status = HOST_FRAME; // where it should we done? We have broken host.status on all non-SDL platforms!
return true;
}
void R_Free_Video( void )
{
// (*jni.env)->CallStaticBooleanMethod( jni.env, jni.bindcls, jni.deleteGLContext );
// VID_DestroyWindow ();
// R_FreeVideoModes();
Sys_FreeLibrary( &android_info );
vid_android.has_context = false;
ref.dllFuncs.GL_ClearExtensions();
}
void *Android_GetWindow( void )
{
EGLint format;
if( !vid_android.window )
{
return NULL;
}
if( !egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_NATIVE_VISUAL_ID, &format) )
{
Con_Reportf( S_ERROR "eglGetConfigAttrib(VISUAL_ID) returned error: 0x%x\n", egl.GetError() );
return NULL;
}
if( nw.setBuffersGeometry( vid_android.window, 0, 0, format ) )
{
Con_Reportf( S_ERROR "ANativeWindow_setBuffersGeometry returned error\n" );
return NULL;
}
return vid_android.window;
}
qboolean VID_SetMode( void )
{
EGLint format;
jintArray attribs, contextAttribs;
static EGLint nAttribs[32+1], nContextAttribs[32+1];
const size_t attribsSize = ARRAYSIZE( nAttribs );
size_t s1, s2;
// create context on egl side by user request
if( !vid_android.has_context && Sys_CheckParm("-egl") )
{
vid_android.has_context = vid_android.nativeegl = EGL_CreateContext();
if( vid_android.has_context )
Android_UpdateSurface( surface_active );
else
return false;
}
if( vid_android.has_context || glw_state.software )
{
R_ChangeDisplaySettings( 0, 0, WINDOW_MODE_WINDOWED ); // width and height are ignored anyway
return true;
}
s1 = EGL_GenerateConfig(nAttribs, attribsSize);
s2 = EGL_GenerateContextConfig(nContextAttribs, attribsSize);
attribs = (*jni.env)->NewIntArray( jni.env, s1 );
contextAttribs = (*jni.env)->NewIntArray( jni.env, s2 );
(*jni.env)->SetIntArrayRegion( jni.env, attribs, 0, s1, nAttribs );
(*jni.env)->SetIntArrayRegion( jni.env, contextAttribs, 0, s2, nContextAttribs );
R_ChangeDisplaySettings( 0, 0, WINDOW_MODE_WINDOWED ); // width and height are ignored anyway
if( (*jni.env)->CallStaticBooleanMethod( jni.env, jni.bindcls, jni.createGLContext, attribs, contextAttribs ) )
{
vid_android.has_context = true;
return true;
}
return false;
}
rserr_t R_ChangeDisplaySettings( int width, int height, window_mode_t window_mode )
{
int render_w, render_h;
Android_GetScreenRes(&width, &height);
render_w = width;
render_h = height;
Con_Reportf( "R_ChangeDisplaySettings: forced resolution to %dx%d)\n", width, height);
VID_SetDisplayTransform( &render_w, &render_h );
R_SaveVideoMode( width, height, render_w, render_h, true );
refState.wideScreen = true; // V_AdjustFov will check for widescreen
return rserr_ok;
}
int GL_SetAttribute( int attr, int val )
{
return EGL_SetAttribute( attr, val );
}
int GL_GetAttribute( int attr, int *val )
{
EGLBoolean ret;
if( eglstate.valid )
return EGL_GetAttribute( attr, val );
if( attr < 0 || attr >= REF_GL_ATTRIBUTES_COUNT )
return -1;
if( !val )
return -1;
switch( attr )
{
case REF_GL_RED_SIZE:
*val = Android_GetGLAttribute( EGL_RED_SIZE );
return 0;
case REF_GL_GREEN_SIZE:
*val = Android_GetGLAttribute( EGL_GREEN_SIZE );
return 0;
case REF_GL_BLUE_SIZE:
*val = Android_GetGLAttribute( EGL_BLUE_SIZE );
return 0;
case REF_GL_ALPHA_SIZE:
*val = Android_GetGLAttribute( EGL_ALPHA_SIZE );
return 0;
case REF_GL_DEPTH_SIZE:
*val = Android_GetGLAttribute( EGL_DEPTH_SIZE );
return 0;
case REF_GL_STENCIL_SIZE:
*val = Android_GetGLAttribute( EGL_STENCIL_SIZE );
return 0;
case REF_GL_MULTISAMPLESAMPLES:
*val = Android_GetGLAttribute( EGL_SAMPLES );
return 0;
}
return -1;
}
int R_MaxVideoModes( void )
{
return 0;
}
vidmode_t* R_GetVideoMode( int num )
{
return NULL;
}
void* GL_GetProcAddress( const char *name ) // RenderAPI requirement
{
return EGL_GetProcAddress( name );
}
void GL_UpdateSwapInterval( void )
{
// disable VSync while level is loading
if( cls.state < ca_active )
{
Android_SwapInterval( 0 );
SetBits( gl_vsync.flags, FCVAR_CHANGED );
}
else if( FBitSet( gl_vsync.flags, FCVAR_CHANGED ))
{
ClearBits( gl_vsync.flags, FCVAR_CHANGED );
Android_SwapInterval( gl_vsync.value );
}
}
void *SW_LockBuffer( void )
{
ANativeWindow_Buffer buffer;
if( !nw.lock || !vid_android.window )
return NULL;
if( nw.lock( vid_android.window, &buffer, NULL ) )
return NULL;
if( buffer.width < refState.width || buffer.height < refState.height )
return NULL;
return buffer.bits;
}
void SW_UnlockBuffer( void )
{
if( nw.unlockAndPost )
nw.unlockAndPost( vid_android.window );
}
qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *r, uint *g, uint *b )
{
ANativeWindow_Buffer buffer;
int lock;
if( !nw.lock || !vid_android.window )
return false;
nw.unlockAndPost( vid_android.window );
if( ( lock = nw.lock( vid_android.window, &buffer, NULL ) ) )
{
Con_Printf( "SW_CreateBuffer: lock %d\n", lock );
return false;
}
nw.unlockAndPost( vid_android.window );
Con_Printf( "SW_CreateBuffer: buffer %d %d %x %d %p\n", buffer.width, buffer.height, buffer.format, buffer.stride, buffer.bits );
if( width > buffer.width || height > buffer.height )
{
// resize event missed? do not resize now, wait for REAL resize event or when java code will be fixed
Con_Printf( S_ERROR "SW_CreateBuffer: buffer too small, need %dx%d, got %dx%d, java part probably sucks\n", width, height, buffer.width, buffer.height );
#if 0
if( jni.width < buffer.width )
jni.width = buffer.width;
if( jni.height < buffer.height )
jni.width = buffer.height;
VID_SetMode();
Android_UpdateSurface( true );
#endif
return false;
}
if( buffer.format != WINDOW_FORMAT_RGB_565 )
{
Con_Printf( "SW_CreateBuffer: wrong format %d\n", buffer.format );
return false;
}
Con_Printf( "SW_CreateBuffer: ok\n" );
*stride = buffer.stride;
*bpp = 2;
*r = (((1 << 5) - 1) << (5+6));
*g = (((1 << 6) - 1) << (5));
*b = (((1 << 5) - 1) << (0));
return true;
}
#endif

View File

@@ -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
@@ -137,6 +139,8 @@ static inline void Platform_Shutdown( void )
#if XASH_SDL #if XASH_SDL
SDLash_Shutdown( ); SDLash_Shutdown( );
#elif XASH_ANDROID
Android_Shutdown();
#endif #endif
} }
@@ -256,4 +260,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

@@ -654,7 +654,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

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

View File

@@ -2122,6 +2122,7 @@ static server_physics_api_t gPhysicsAPI =
COM_SaveFile, COM_SaveFile,
pfnLoadImagePixels, pfnLoadImagePixels,
pfnGetModelName, pfnGetModelName,
Sys_GetNativeObject
}; };
/* /*

View File

@@ -32,6 +32,9 @@ def options(opt):
grp.add_option('--enable-engine-fuzz', action = 'store_true', dest = 'ENGINE_FUZZ', default = False, grp.add_option('--enable-engine-fuzz', action = 'store_true', dest = 'ENGINE_FUZZ', default = False,
help = 'add LLVM libFuzzer [default: %default]' ) help = 'add LLVM libFuzzer [default: %default]' )
grp.add_option('--enable-android-legacy', action = 'store_true', dest = 'ANDROID_LEGACY', default = False,
help = 'allow build legacy android port without SDL (deprecated, need for renderers debug on ancient devices)')
opt.load('sdl2') opt.load('sdl2')
def configure(conf): def configure(conf):
@@ -75,6 +78,8 @@ def configure(conf):
conf.define('XASH_SDL', 12) conf.define('XASH_SDL', 12)
conf.check_cfg(package='sdl', args='--cflags --libs', uselib_store='SDL2' ) conf.check_cfg(package='sdl', args='--cflags --libs', uselib_store='SDL2' )
conf.env.HAVE_SDL2 = True conf.env.HAVE_SDL2 = True
elif conf.options.ANDROID_LEGACY:
pass #just test if it can build
else: else:
conf.load('sdl2') conf.load('sdl2')
if not conf.env.HAVE_SDL2: if not conf.env.HAVE_SDL2:
@@ -237,7 +242,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

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

@@ -780,6 +780,7 @@ 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;

View File

@@ -32,6 +32,7 @@ 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" );
@@ -555,54 +556,70 @@ qboolean GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char
for( func = funcs; func && func->name; func++ ) for( func = funcs; func && func->name; func++ )
{ {
// functions are cleared before all the extensions are evaluated // functions are cleared before all the extensions are evaluated
if(( *func->func = (void *)gEngfuncs.GL_GetProcAddress( func->name )) == NULL ) string name;
{ char *end;
string name; size_t i = 0;
char *end; qboolean first_try = true;
size_t i = 0; // NULL means just func->name, but empty suffix cuts ARB suffix if present
#ifdef XASH_GLES #ifdef XASH_GLES
const char *suffixes[] = { "", "EXT", "OES" }; const char *suffixes[] = { "", "EXT", "OES", NULL, "ARB" };
#else #else
const char *suffixes[] = { "", "EXT" }; const char *suffixes[] = { NULL, "", "EXT", "ARB" };
#endif #endif
// HACK: fix ARB names // Remove ARB suffix
Q_strncpy( name, func->name, sizeof( name )); Q_strncpy( name, func->name, sizeof( name ));
if(( end = Q_strstr( name, "ARB" ))) if(( end = Q_strstr( name, "ARB" )))
{ {
*end = '\0'; *end = '\0';
} }
else // I need Q_strstrnul else // I need Q_strstrnul
{ {
end = name + Q_strlen( name ); end = name + Q_strlen( name );
i++; // skip empty suffix }
}
for( ; i < sizeof( suffixes ) / sizeof( suffixes[0] ); i++ ) for( ; i < sizeof( suffixes ) / sizeof( suffixes[0] ); i++ )
{ {
void *f; void *f;
const char *pname = name;
size_t name_len = end - pname;
const char *orig_suffix = func->name + name_len;
if( suffixes[i] )
{
// if suffix is original suffix, it's handled with NULL
if( orig_suffix[0] && !Q_strcmp( orig_suffix, suffixes[i] ))
continue;
Q_strncat( name, suffixes[i], sizeof( name )); Q_strncat( name, suffixes[i], sizeof( name ));
if(( f = gEngfuncs.GL_GetProcAddress( name )))
{
// GL_GetProcAddress prints errors about missing functions, so tell user that we found it with different name
gEngfuncs.Con_Printf( S_NOTE "found %s\n", name );
*func->func = f;
break;
}
else
{
*end = '\0'; // cut suffix, try next
}
} }
else
// not found...
if( i == sizeof( suffixes ) / sizeof( suffixes[0] ))
{ {
GL_SetExtension( r_ext, false ); // if original name does not have a suffix, it will be handled with empty suffix
if( !orig_suffix[0] )
continue;
pname = func->name;
} }
if(( f = gEngfuncs.GL_GetProcAddress( pname )))
{
// if we already tried this function, notify about success after previous error from GL_GetProcAddress
if(!first_try)
gEngfuncs.Con_Printf( S_NOTE "found %s\n", pname );
first_try = false;
*func->func = f;
break;
}
else
{
*end = '\0'; // cut suffix, try next
}
}
// not found...
if( i == sizeof( suffixes ) / sizeof( suffixes[0] ))
{
GL_SetExtension( r_ext, false );
} }
} }
#endif #endif
@@ -1248,6 +1265,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

@@ -1011,10 +1011,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 )

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
{ {
@@ -2189,15 +2190,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
{ {

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

View File

@@ -968,6 +968,7 @@ void R_UploadRipples( texture_t *image )
gl_texture_t *glt; gl_texture_t *glt;
uint32_t *pixels; uint32_t *pixels;
int wbits, wmask, wshft; int wbits, wmask, wshft;
int y;
// 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 )
@@ -1005,11 +1006,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

@@ -44,6 +44,7 @@ class Android:
ndk_rev = 0 ndk_rev = 0
is_hardfloat = False is_hardfloat = False
clang = False clang = False
ndk_binutils = False
def __init__(self, ctx, arch, toolchain, api): def __init__(self, ctx, arch, toolchain, api):
self.ctx = ctx self.ctx = ctx
@@ -214,7 +215,7 @@ class Android:
if 'CC' in environ: if 'CC' in environ:
s = environ['CC'] s = environ['CC']
return '%s --target=%s%d' % (s, self.ndk_triplet(), self.api) return '%s --target=%s' % (s, self.ndk_triplet()) #%s%d' % (s, self.ndk_triplet(), self.api)
return self.gen_toolchain_path() + ('clang' if self.is_clang() else 'gcc') return self.gen_toolchain_path() + ('clang' if self.is_clang() else 'gcc')
def cxx(self): def cxx(self):
@@ -225,11 +226,11 @@ class Android:
if 'CXX' in environ: if 'CXX' in environ:
s = environ['CXX'] s = environ['CXX']
return '%s --target=%s%d' % (s, self.ndk_triplet(), self.api) return '%s --target=%s' % (s, self.ndk_triplet()) #%s%d' % (s, self.ndk_triplet(), self.api)
return self.gen_toolchain_path() + ('clang++' if self.is_clang() else 'g++') return self.gen_toolchain_path() + ('clang++' if self.is_clang() else 'g++')
def strip(self): def strip(self):
if self.is_host(): if self.is_host() and not self.ndk_binutils:
environ = getattr(self.ctx, 'environ', os.environ) environ = getattr(self.ctx, 'environ', os.environ)
if 'STRIP' in environ: if 'STRIP' in environ:
@@ -240,9 +241,22 @@ class Android:
return os.path.join(self.gen_binutils_path(), 'llvm-strip') return os.path.join(self.gen_binutils_path(), 'llvm-strip')
return os.path.join(self.gen_binutils_path(), 'strip') return os.path.join(self.gen_binutils_path(), 'strip')
def objcopy(self):
if self.is_host() and not self.ndk_binutils:
environ = getattr(self.ctx, 'environ', os.environ)
if 'OBJCOPY' in environ:
return environ['OBJCOPY']
return 'llvm-objcopy'
if self.ndk_rev >= 23:
return os.path.join(self.gen_binutils_path(), 'llvm-objcopy')
return os.path.join(self.gen_binutils_path(), 'objcopy')
def system_stl(self): def system_stl(self):
# TODO: proper STL support # TODO: proper STL support
return os.path.abspath(os.path.join(self.ndk_home, 'sources', 'cxx-stl', 'system', 'include')) #return os.path.abspath(os.path.join(self.ndk_home, 'sources', 'cxx-stl', 'system', 'include')) broken with clang-15? TODO: check different ndk versions
return os.path.abspath(os.path.join(self.ndk_home, 'sources', 'cxx-stl', 'stlport', 'stlport'))
def libsysroot(self): def libsysroot(self):
arch = self.arch arch = self.arch
@@ -262,8 +276,15 @@ class Android:
def cflags(self, cxx = False): def cflags(self, cxx = False):
cflags = [] cflags = []
android_from_none = False
if self.is_host() and self.is_arm() and self.is_hardfp():
# clang android target may change with ndk
# override target to none while compiling and
# add some android options manually
android_from_none = True
cflags += ['--target=arm-none-eabi']
if self.ndk_rev <= ANDROID_NDK_SYSROOT_FLAG_MAX: if self.ndk_rev <= ANDROID_NDK_SYSROOT_FLAG_MAX and not android_from_none:
cflags += ['--sysroot=%s' % (self.sysroot())] cflags += ['--sysroot=%s' % (self.sysroot())]
else: else:
if self.is_host(): if self.is_host():
@@ -273,13 +294,18 @@ class Android:
] ]
cflags += ['-I%s' % (self.system_stl())] cflags += ['-I%s' % (self.system_stl())]
if not self.is_clang(): if not self.is_clang() or android_from_none:
cflags += ['-DANDROID', '-D__ANDROID__'] cflags += ['-DANDROID', '-D__ANDROID__=1']
if android_from_none:
cflags += [ '-D__linux__=1', '-fPIC'] # TODO: compare with linux target?
if cxx and not self.is_clang() and self.toolchain not in ['4.8','4.9']: if cxx and not self.is_clang() and self.toolchain not in ['4.8','4.9']:
cflags += ['-fno-sized-deallocation'] cflags += ['-fno-sized-deallocation']
if self.is_clang(): if cxx and (self.is_clang() or self.is_host()):
cflags += [ '-Wno-dynamic-exception-spec', '-fno-rtti' ]
if self.is_clang() or self.is_host():
# stpcpy() isn't available in early Android versions # stpcpy() isn't available in early Android versions
# disable it here so Clang won't use it # disable it here so Clang won't use it
if self.api < ANDROID_STPCPY_API_MIN: if self.api < ANDROID_STPCPY_API_MIN:
@@ -291,7 +317,7 @@ class Android:
cflags += ['-mthumb', '-mfpu=neon', '-mcpu=cortex-a9'] cflags += ['-mthumb', '-mfpu=neon', '-mcpu=cortex-a9']
if self.is_hardfp(): if self.is_hardfp():
cflags += ['-D_NDK_MATH_NO_SOFTFP=1', '-mfloat-abi=hard', '-DLOAD_HARDFP', '-DSOFTFP_LINK'] cflags += ['-D_NDK_MATH_NO_SOFTFP=1', '-mfloat-abi=hard', '-DLOAD_HARDFP', '-DSOFTFP_LINK', '-DGLES_SOFTFLOAT']
if self.is_host(): if self.is_host():
# Clang builtin redefine w/ different calling convention bug # Clang builtin redefine w/ different calling convention bug
@@ -316,15 +342,23 @@ class Android:
linkflags = [] linkflags = []
if self.is_host(): if self.is_host():
linkflags += ['--gcc-toolchain=%s' % self.gen_gcc_toolchain_path()] linkflags += ['--gcc-toolchain=%s' % self.gen_gcc_toolchain_path()]
linkflags += ['--gcc-install-dir=%s/lib/gcc/%s/4.9/' % (self.gen_gcc_toolchain_path(), self.ndk_triplet())]
if self.ndk_binutils:
linkflags += ['-fuse-ld=%s/bin/%s-ld.bfd' % (self.gen_gcc_toolchain_path(), self.ndk_triplet())]
else:
linkflags += ['-fuse-ld=lld']
linkflags += ['--unwindlib=none']
linkflags += ['--rtlib=libgcc']
if self.ndk_rev <= ANDROID_NDK_SYSROOT_FLAG_MAX: if self.ndk_rev <= ANDROID_NDK_SYSROOT_FLAG_MAX:
linkflags += ['--sysroot=%s' % (self.sysroot())] linkflags += ['--sysroot=%s' % (self.sysroot())]
elif self.is_host(): elif self.is_host():
linkflags += ['--sysroot=%s/sysroot' % (self.gen_gcc_toolchain_path())] linkflags += ['--sysroot=%s/sysroot' % (self.gen_gcc_toolchain_path())]
if self.is_clang() or self.is_host(): #if self.is_clang() or self.is_host():
linkflags += ['-fuse-ld=lld'] # linkflags += ['-fuse-ld=lld']
else: linkflags += ['-no-canonical-prefixes'] #else:
linkflags += ['-no-canonical-prefixes']
linkflags += ['-Wl,--hash-style=sysv', '-Wl,--no-undefined'] linkflags += ['-Wl,--hash-style=sysv', '-Wl,--no-undefined']
return linkflags return linkflags
@@ -528,6 +562,7 @@ def configure(conf):
conf.environ['CC'] = android.cc() conf.environ['CC'] = android.cc()
conf.environ['CXX'] = android.cxx() conf.environ['CXX'] = android.cxx()
conf.environ['STRIP'] = android.strip() conf.environ['STRIP'] = android.strip()
conf.environ['OBJCOPY'] = android.objcopy()
conf.env.CFLAGS += android.cflags() conf.env.CFLAGS += android.cflags()
conf.env.CXXFLAGS += android.cflags(True) conf.env.CXXFLAGS += android.cflags(True)
conf.env.LINKFLAGS += android.linkflags() conf.env.LINKFLAGS += android.linkflags()

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:
@@ -44,16 +44,16 @@ def create_zip_archive(self):
self.path.get_bld().mkdir() self.path.get_bld().mkdir()
target = self.path.get_bld().make_node(self.name) target = self.path.get_bld().make_node(self.name)
tsk = self.create_task('ziparchive', files, target) self.zip_task = self.create_task('ziparchive', files, target)
setattr(tsk, 'compresslevel', compresslevel) setattr(self.zip_task, 'compresslevel', compresslevel)
setattr(tsk, 'relative_to', relative_to) setattr(self.zip_task, 'relative_to', relative_to)
try: try:
inst_to = self.install_path inst_to = self.install_path
self.install_task = self.add_install_files( self.install_task = self.add_install_files(
install_to=inst_to, install_from=target, install_to=inst_to, install_from=target,
chmod=Utils.O644, task=tsk) chmod=Utils.O644, task=self.zip_task)
except AttributeError: except AttributeError:
pass pass

50
wscript
View File

@@ -2,7 +2,7 @@
# encoding: utf-8 # encoding: utf-8
# a1batross, mittorn, 2018 # a1batross, mittorn, 2018
from waflib import Build, Context, Logs from waflib import Build, Context, Logs, Options, Configure
from waflib.Tools import waf_unit_test from waflib.Tools import waf_unit_test
import sys import sys
import os import os
@@ -69,7 +69,7 @@ SUBDIRS = [
Subproject('dllemu'), Subproject('dllemu'),
# disable only by engine feature, makes no sense to even parse subprojects in dedicated mode # disable only by engine feature, makes no sense to even parse subprojects in dedicated mode
Subproject('3rdparty/extras', lambda x: not x.env.DEDICATED and x.env.DEST_OS != 'android'), Subproject('3rdparty/extras', lambda x: not x.env.DEDICATED),
Subproject('3rdparty/nanogl', lambda x: not x.env.DEDICATED and x.env.NANOGL), Subproject('3rdparty/nanogl', lambda x: not x.env.DEDICATED and x.env.NANOGL),
Subproject('3rdparty/gl-wes-v2', lambda x: not x.env.DEDICATED and x.env.GLWES), Subproject('3rdparty/gl-wes-v2', lambda x: not x.env.DEDICATED and x.env.GLWES),
Subproject('3rdparty/gl4es', lambda x: not x.env.DEDICATED and x.env.GL4ES), Subproject('3rdparty/gl4es', lambda x: not x.env.DEDICATED and x.env.GL4ES),
@@ -104,6 +104,42 @@ REFDLLS = [
RefDll('null', False), RefDll('null', False),
] ]
def process_extra_projects_opts(ctx):
options, commands, envvars = ctx.parse_cmd_args(allow_unknown = True)
projs = options.EXTRA_PROJECTS
if not projs:
return
for proj in projs.split(','):
ctx.add_subproject(proj)
def process_extra_projects_conf(ctx):
projs = ctx.options.EXTRA_PROJECTS
if not projs:
return
ctx.env.EXTRA_PROJECTS = projs
for proj in projs.split(','):
tools_orig = ctx.tools.copy()
ctx.add_subproject(proj)
waifulib_path = os.path.join(proj, 'scripts', 'waifulib')
if os.path.isdir(waifulib_path):
for tool in ctx.tools:
if not tool in tools_orig:
if os.path.isfile(os.path.join(waifulib_path, tool['tool'] + '.py')):
tool['tooldir'] = [waifulib_path]
Logs.info('External tooldir set: ' + str(tool))
def process_extra_projects_bld(ctx):
projs = ctx.env.EXTRA_PROJECTS
if not projs:
return
for proj in projs.split(','):
ctx.add_subproject(proj)
def options(opt): def options(opt):
opt.load('reconfigure compiler_optimizations xshlib xcompile compiler_cxx compiler_c sdl2 clang_compilation_database strip_on_install waf_unit_test msdev msvs msvc subproject cmake') opt.load('reconfigure compiler_optimizations xshlib xcompile compiler_cxx compiler_c sdl2 clang_compilation_database strip_on_install waf_unit_test msdev msvs msvc subproject cmake')
@@ -154,12 +190,15 @@ def options(opt):
grp.add_option('--enable-fuzzer', action = 'store_true', dest = 'ENABLE_FUZZER', default = False, grp.add_option('--enable-fuzzer', action = 'store_true', dest = 'ENABLE_FUZZER', default = False,
help = 'enable building libFuzzer runner [default: %default]' ) help = 'enable building libFuzzer runner [default: %default]' )
grp.add_option('--extra-projects', action = 'store', dest = 'EXTRA_PROJECTS', default = '', type = 'string',
help = 'add extra projects' )
for i in SUBDIRS: for i in SUBDIRS:
if not i.is_exists(opt): if not i.is_exists(opt):
continue continue
opt.add_subproject(i.name) opt.add_subproject(i.name)
process_extra_projects_opts(opt)
def configure(conf): def configure(conf):
conf.load('fwgslib reconfigure compiler_optimizations') conf.load('fwgslib reconfigure compiler_optimizations')
@@ -197,11 +236,12 @@ 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
conf.define('XASH_SDLMAIN', 1) if conf.env.HAVE_SDL2:
conf.define('XASH_SDLMAIN', 1)
elif conf.env.MAGX: elif conf.env.MAGX:
conf.options.SDL12 = True conf.options.SDL12 = True
conf.options.NO_VGUI = True conf.options.NO_VGUI = True
@@ -493,6 +533,7 @@ int main(void) { return !opus_custom_encoder_init((OpusCustomEncoder *)1, (const
continue continue
conf.add_subproject(i.name) conf.add_subproject(i.name)
process_extra_projects_conf(conf)
def build(bld): def build(bld):
# guard rails to not let install to root # guard rails to not let install to root
@@ -515,3 +556,4 @@ def build(bld):
if bld.env.TESTS: if bld.env.TESTS:
bld.add_post_fun(waf_unit_test.summary) bld.add_post_fun(waf_unit_test.summary)
bld.add_post_fun(waf_unit_test.set_exit_code) bld.add_post_fun(waf_unit_test.set_exit_code)
process_extra_projects_bld(bld)