Compare commits

...

80 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
51 changed files with 3144 additions and 204 deletions

View File

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

View File

@@ -534,5 +534,14 @@ typedef struct
#define MAX_EFRAGS 8192 // Arcane Dimensions required
#define MAX_REQUESTS 64
#if ! XASH_64BIT
STATIC_ASSERT( sizeof( mextrasurf_t ) == 324, "mextrasurf_t unexpected size" );
STATIC_ASSERT( sizeof( decal_t ) == 60, "decal_t unexpected size");
STATIC_ASSERT( sizeof( mfaceinfo_t ) == 176, "mfaceinfo_t unexpected size");
#else
STATIC_ASSERT( sizeof( mextrasurf_t) == 496, "mextrasurf_t unexpected size");
STATIC_ASSERT( sizeof( decal_t ) == 88, "decal_t unexpected size");
STATIC_ASSERT( sizeof( mfaceinfo_t ) == 304, "mfaceinfo_t unexpected size");
#endif
#endif//COM_MODEL_H

View File

@@ -52,6 +52,25 @@ SETUP BACKENDS DEFINITIONS
#endif
#endif // XASH_MESSAGEBOX
#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
// we are building for Linux without SDL2, can draw only to framebuffer yet
#ifndef XASH_VIDEO
@@ -151,8 +170,6 @@ Default build-depended cvar and constant values
#define DEFAULT_MODE_WIDTH 960
#define DEFAULT_MODE_HEIGHT 544
#define DEFAULT_ALLOWCONSOLE 1
#elif XASH_ANDROID
#define DEFAULT_TOUCH_ENABLE "1"
#elif XASH_MOBILE_PLATFORM
#define DEFAULT_TOUCH_ENABLE "1"
#define DEFAULT_M_IGNORE "1"
@@ -164,6 +181,10 @@ Default build-depended cvar and constant values
#define XASH_INTERNAL_GAMELIBS
#endif // XASH_ANDROID || XASH_IOS || XASH_EMSCRIPTEN
#if XASH_ANDROID && XASH_SDL
#define XASH_ANDROID_ASSETS 1
#endif
// Defaults
#ifndef DEFAULT_TOUCH_ENABLE
#define DEFAULT_TOUCH_ENABLE "0"

View File

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

View File

@@ -28,7 +28,6 @@ GNU General Public License for more details.
#define MAX_CMD_BUFFER 8000
#define CONNECTION_PROBLEM_TIME 15.0 // 15 seconds
#define CL_CONNECTION_RETRIES 10
#define CL_TEST_RETRIES_NORESPONCE 3
#define CL_TEST_RETRIES 5
CVAR_DEFINE_AUTO( mp_decals, "300", FCVAR_ARCHIVE, "decals limit in multiplayer" );
@@ -1072,6 +1071,22 @@ static void CL_SendConnectPacket( void )
cls.timestart = Sys_DoubleTime();
}
/*
=================
CL_GetTestFragmentSize
Returns bandwidth test fragment size
=================
*/
static int CL_GetTestFragmentSize( void )
{
const int fragmentSizes[CL_TEST_RETRIES] = { 64000, 32000, 10666, 5200, 1400 };
if( cls.connect_retry >= 0 && cls.connect_retry < CL_TEST_RETRIES )
return bound( FRAGMENT_MIN_SIZE, fragmentSizes[cls.connect_retry], FRAGMENT_MAX_SIZE );
else
return FRAGMENT_MIN_SIZE;
}
/*
=================
CL_CheckForResend
@@ -1083,8 +1098,9 @@ static void CL_CheckForResend( void )
{
netadr_t adr;
net_gai_state_t res;
float resendTime;
qboolean bandwidthTest;
if( cls.internetservers_wait )
CL_SendMasterServerScanRequest();
@@ -1110,7 +1126,10 @@ static void CL_CheckForResend( void )
else if( cl_resend.value > CL_MAX_RESEND_TIME )
Cvar_SetValue( "cl_resend", CL_MAX_RESEND_TIME );
if(( host.realtime - cls.connect_time ) < cl_resend.value )
bandwidthTest = !cls.legacymode && cl_test_bandwidth.value && cls.connect_retry <= CL_TEST_RETRIES;
resendTime = bandwidthTest ? 1.0f : cl_resend.value;
if(( host.realtime - cls.connect_time ) < resendTime )
return;
res = NET_StringToAdrNB( cls.servername, &adr );
@@ -1137,10 +1156,11 @@ static void CL_CheckForResend( void )
if( adr.port == 0 ) adr.port = MSG_BigShort( PORT_SERVER );
if( cls.connect_retry == CL_TEST_RETRIES_NORESPONCE )
if( cls.connect_retry == CL_TEST_RETRIES )
{
// too many fails use default connection method
Con_Printf( "hi-speed connection is failed, use default method\n" );
Con_Printf( "Bandwidth test failed, fallback to default connecting method\n" );
Con_Printf( "Connecting to %s... (retry #%i)\n", cls.servername, cls.connect_retry + 1 );
Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" );
Cvar_SetValue( "cl_dlmax", FRAGMENT_MIN_SIZE );
cls.connect_time = host.realtime;
@@ -1148,16 +1168,15 @@ static void CL_CheckForResend( void )
return;
}
bandwidthTest = !cls.legacymode && cl_test_bandwidth.value;
cls.serveradr = adr;
cls.max_fragment_size = Q_min( FRAGMENT_MAX_SIZE, cls.max_fragment_size / (cls.connect_retry + 1));
cls.max_fragment_size = CL_GetTestFragmentSize();
cls.connect_time = host.realtime; // for retransmit requests
cls.connect_retry++;
if( bandwidthTest )
Con_Printf( "Connecting to %s... [retry #%i, max fragment size %i]\n", cls.servername, cls.connect_retry, cls.max_fragment_size );
Con_Printf( "Connecting to %s... (retry #%i, fragment size %i)\n", cls.servername, cls.connect_retry, cls.max_fragment_size );
else
Con_Printf( "Connecting to %s... [retry #%i]\n", cls.servername, cls.connect_retry );
Con_Printf( "Connecting to %s... (retry #%i)\n", cls.servername, cls.connect_retry );
if( bandwidthTest )
Netchan_OutOfBandPrint( NS_CLIENT, adr, "bandwidth %i %i\n", PROTOCOL_VERSION, cls.max_fragment_size );

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -251,6 +251,7 @@ void _Mem_Free( void *data, 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 *mem;
uintptr_t oldmem;
mempool_t *pool;
size_t oldsize;
@@ -288,17 +289,29 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
#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;
}
Mem_PoolSubtract( pool, oldsize );
Mem_PoolAdd( pool, size );
// 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 ))
@@ -306,17 +319,13 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
Mem_PoolUnlinkAlloc( mem->pool, mem );
Mem_PoolLinkAlloc( pool, mem );
}
else
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;
}
// clear new memory
if( clear && size > oldsize )
memset((byte *)mem + sizeof( memheader_t ) + oldsize, 0, size - oldsize );
return (void *)((byte *)mem + sizeof( memheader_t ));
#endif // XASH_CUSTOM_SWAP
}

View File

@@ -14,7 +14,7 @@ GNU General Public License for more details.
*/
#include "platform/platform.h"
#if !defined(XASH_DEDICATED)
#if !defined(XASH_DEDICATED) && XASH_SDL
#include "input.h"
#include "client.h"

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
* SUCH DAMAGE.
*/
#if defined __ANDROID__ && !defined XASH_64BIT
#include "build.h"
#if !XASH_64BIT
#include <string.h>
#include <android/log.h>
#include <dlfcn.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;
const char* strtab = si->strtab;
if( si->nbucket == 0 )
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;
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 */
switch (ELF_ST_BIND(s->st_info)) {
switch( ELF_ST_BIND( s->st_info ))
{
case STB_GLOBAL:
case STB_WEAK:
if (s->st_shndx == SHN_UNDEF) {
if( s->st_shndx == SHN_UNDEF )
continue;
}
return s;
}
}
@@ -56,11 +62,44 @@ static Elf_Sym* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name) {
return NULL;
}
static unsigned elfhash(const char* _name) {
const unsigned char* name = (const unsigned char*) _name;
static Elf_Sym* soinfo_elf_lookup_reverse(soinfo* si, size_t addr)
{
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;
while(*name) {
while(*name)
{
h = (h << 4) + *name++;
g = h & 0xf0000000;
h ^= g;
@@ -78,21 +117,73 @@ static unsigned elfhash(const char* _name) {
Binary Interface) where in Chapter 5 it discuss resolving "Shared
Object Dependencies" in breadth first search order.
*/
static Elf_Sym* dlsym_handle_lookup(soinfo* si, const char* name) {
return soinfo_elf_lookup(si, elfhash(name), name);
static Elf_Sym* dlsym_handle_lookup( soinfo* si, const char* 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;
Elf_Sym* sym = NULL;
found = reinterpret_cast<soinfo*>(handle);
sym = dlsym_handle_lookup(found, symbol);
found = reinterpret_cast<soinfo*>( handle );
sym = dlsym_handle_lookup( found, symbol );
if (sym != NULL) {
return reinterpret_cast<void*>(sym->st_value + found->base/*load_bias*/);
if ( sym != NULL ) {
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;
}
#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/dlsym-weak.h" // Android < 5.0
void *ANDROID_GetServerLibrary( void )
{
return svgame.hInstance;
}
void *ANDROID_LoadLibrary( const char *dllname )
{
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_GetProcAddress( x, y ) ANDROID_GetProcAddress(( x ), ( y ))
void *ANDROID_GetServerLibrary( void );
void *ANDROID_LoadLibrary( const char *dllname );
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_Init( void );
void *Android_GetNativeObject( const char *name );
int Android_GetKeyboardHeight( void );
void Android_Shutdown( void );
#endif
#if XASH_WIN32
@@ -137,6 +139,8 @@ static inline void Platform_Shutdown( void )
#if XASH_SDL
SDLash_Shutdown( );
#elif XASH_ANDROID
Android_Shutdown();
#endif
}
@@ -256,4 +260,89 @@ void VoiceCapture_Shutdown( void );
qboolean VoiceCapture_Activate( qboolean activate );
qboolean VoiceCapture_Lock( qboolean lock );
// this allows to make break in current line, without entering libc code
// libc built with -fomit-frame-pointer may just eat stack frame (hello, glibc), making entering libc even more useless
// calling syscalls directly allows to make break like if it was asm("int $3") on x86
#if XASH_LINUX && XASH_X86
#define INLINE_RAISE(x) asm volatile( "int $3;" );
#define INLINE_NANOSLEEP1() // nothing!
#elif XASH_LINUX && XASH_ARM && !XASH_64BIT
#define INLINE_RAISE(x) do \
{ \
int raise_pid = getpid(); \
int raise_tid = gettid(); \
int raise_sig = (x); \
__asm__ volatile ( \
"mov r7,#268\n\t" \
"mov r0,%0\n\t" \
"mov r1,%1\n\t" \
"mov r2,%2\n\t" \
"svc 0\n\t" \
: \
: "r"(raise_pid), "r"(raise_tid), "r"(raise_sig) \
: "r0", "r1", "r2", "r7", "memory" \
); \
} while( 0 )
#define INLINE_NANOSLEEP1() do \
{ \
struct timespec ns_t1 = {1, 0}; \
struct timespec ns_t2 = {0, 0}; \
__asm__ volatile ( \
"mov r7,#162\n\t" \
"mov r0,%0\n\t" \
"mov r1,%1\n\t" \
"svc 0\n\t" \
: \
: "r"(&ns_t1), "r"(&ns_t2) \
: "r0", "r1", "r7", "memory" \
); \
} while( 0 )
#elif XASH_LINUX && XASH_ARM && XASH_64BIT
#define INLINE_RAISE(x) do \
{ \
int raise_pid = getpid(); \
int raise_tid = gettid(); \
int raise_sig = (x); \
__asm__ volatile ( \
"mov x8,#131\n\t" \
"mov x0,%0\n\t" \
"mov x1,%1\n\t" \
"mov x2,%2\n\t" \
"svc 0\n\t" \
: \
: "r"(raise_pid), "r"(raise_tid), "r"(raise_sig) \
: "x0", "x1", "x2", "x8", "memory", "cc" \
); \
} while( 0 )
#define INLINE_NANOSLEEP1() do \
{ \
struct timespec ns_t1 = {1, 0}; \
struct timespec ns_t2 = {0, 0}; \
__asm__ volatile ( \
"mov x8,#101\n\t" \
"mov x0,%0\n\t" \
"mov x1,%1\n\t" \
"svc 0\n\t" \
: \
: "r"(&ns_t1), "r"(&ns_t2) \
: "x0", "x1", "x8", "memory", "cc" \
); \
} while( 0 )
#elif XASH_LINUX
#ifdef __NR_tgkill
#define INLINE_RAISE(x) syscall( __NR_tgkill, getpid(), gettid(), x )
#else // __NR_tgkill
#define INLINE_RAISE(x) raise(x)
#endif // __NR_tgkill
#define INLINE_NANOSLEEP1() do \
{ \
struct timespec ns_t1 = {1, 0}; \
struct timespec ns_t2 = {0, 0}; \
nanosleep( &ns_t1, &ns_t2 ); \
} while( 0 )
#else // generic
#define INLINE_RAISE(x) raise(x)
#define INLINE_NANOSLEEP1() sleep(1)
#endif // generic
#endif // PLATFORM_H

View File

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

View File

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

View File

@@ -576,10 +576,8 @@ static qboolean VID_SetScreenResolution( int width, int height, window_mode_t wi
SDL_DisplayMode got;
Uint32 wndFlags = 0;
#if !XASH_APPLE
if( vid_highdpi.value )
SetBits( wndFlags, SDL_WINDOW_ALLOW_HIGHDPI );
#endif
SDL_SetWindowBordered( host.hWnd, SDL_FALSE );

View File

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

View File

@@ -922,11 +922,11 @@ static void SV_GenerateTestPacket( void )
// testpacket already generated once, exit
// testpacket and lookup table takes ~300k of memory
// disable for low memory mode
if( svs.testpacket_buf || XASH_LOW_MEMORY >= 0 )
if( svs.testpacket_buf || XASH_LOW_MEMORY > 0 )
return;
// don't need in singleplayer with full client
if( svs.maxclients <= 1 && !Host_IsDedicated( ))
if( svs.maxclients <= 1 )
return;
file = FS_Open( "gfx.wad", "rb", false );

View File

@@ -32,6 +32,9 @@ def options(opt):
grp.add_option('--enable-engine-fuzz', action = 'store_true', dest = 'ENGINE_FUZZ', default = False,
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')
def configure(conf):
@@ -75,6 +78,8 @@ def configure(conf):
conf.define('XASH_SDL', 12)
conf.check_cfg(package='sdl', args='--cflags --libs', uselib_store='SDL2' )
conf.env.HAVE_SDL2 = True
elif conf.options.ANDROID_LEGACY:
pass #just test if it can build
else:
conf.load('sdl2')
if not conf.env.HAVE_SDL2:

View File

@@ -15,7 +15,7 @@ GNU General Public License for more details.
#include "port.h"
#if XASH_ANDROID
#if XASH_ANDROID_ASSETS
#include <sys/types.h>
#include <sys/stat.h>
@@ -328,4 +328,4 @@ void FS_InitAndroid( void )
jni.getAssets = (*jni.env)->GetMethodID( jni.env, jni.activity_class, "getAssets", "(Z)Landroid/content/res/AssetManager;" );
}
#endif // XASH_ANDROID
#endif // XASH_ANDROID_ASSETS

View File

@@ -72,7 +72,7 @@ const fs_archive_t g_archives[] =
static const fs_archive_t g_directory_archive =
{ NULL, SEARCHPATH_PLAIN, FS_AddDir_Fullpath, false };
#ifdef XASH_ANDROID
#if XASH_ANDROID_ASSETS
static const fs_archive_t g_android_archive =
{ NULL, SEARCHPATH_ANDROID_ASSETS, FS_AddAndroidAssets_Fullpath, false };
#endif
@@ -406,7 +406,7 @@ void FS_AddGameDirectory( const char *dir, uint flags )
stringlistfreecontents( &list );
#ifdef XASH_ANDROID
#if XASH_ANDROID_ASSETS
FS_AddArchive_Fullpath( &g_android_archive, dir, flags );
#endif
@@ -632,30 +632,23 @@ static void FS_InitGameInfo( gameinfo_t *GameInfo, const char *gamedir )
memset( GameInfo, 0, sizeof( *GameInfo ));
// filesystem info
Q_strncpy( GameInfo->gamefolder, gamedir, sizeof( GameInfo->gamefolder ));
Q_strncpy( GameInfo->basedir, "valve", sizeof( GameInfo->basedir ));
GameInfo->falldir[0] = 0;
Q_strncpy( GameInfo->startmap, "c0a0", sizeof( GameInfo->startmap ));
Q_strncpy( GameInfo->trainmap, "t0a0", sizeof( GameInfo->trainmap ));
Q_strncpy( GameInfo->title, "New Game", sizeof( GameInfo->title ));
GameInfo->version = 1.0f;
// .dll pathes
Q_strncpy( GameInfo->gamefolder, gamedir, sizeof( GameInfo->gamefolder ));
Q_strncpy( GameInfo->basedir, fs_basedir, sizeof( GameInfo->basedir ));
Q_strncpy( GameInfo->sp_entity, "info_player_start", sizeof( GameInfo->sp_entity ));
Q_strncpy( GameInfo->mp_entity, "info_player_deathmatch", sizeof( GameInfo->mp_entity ));
Q_strncpy( GameInfo->startmap, "newmap", sizeof( GameInfo->startmap ));
Q_strncpy( GameInfo->dll_path, "cl_dlls", sizeof( GameInfo->dll_path ));
Q_strncpy( GameInfo->game_dll, "dlls/hl.dll", sizeof( GameInfo->game_dll ));
Q_strncpy( GameInfo->game_dll_linux, "dlls/hl.so", sizeof( GameInfo->game_dll_linux ));
Q_strncpy( GameInfo->game_dll_osx, "dlls/hl.dylib", sizeof( GameInfo->game_dll_osx ));
// .ico path
Q_strncpy( GameInfo->iconpath, "game.ico", sizeof( GameInfo->iconpath ));
Q_strncpy( GameInfo->sp_entity, "info_player_start", sizeof( GameInfo->sp_entity ));
Q_strncpy( GameInfo->mp_entity, "info_player_deathmatch", sizeof( GameInfo->mp_entity ));
GameInfo->max_edicts = DEFAULT_MAX_EDICTS; // default value if not specified
GameInfo->max_tents = 500;
GameInfo->max_beams = 128;
GameInfo->max_particles = 4096;
GameInfo->version = 1.0f;
}
static void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qboolean isGameInfo )
@@ -1468,7 +1461,7 @@ qboolean FS_InitStdio( qboolean unused_set_to_true, const char *rootdir, const c
FS_InitMemory();
#ifdef XASH_ANDROID
#if XASH_ANDROID_ASSETS
FS_InitAndroid();
#endif

View File

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

View File

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

View File

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

View File

@@ -780,6 +780,7 @@ extern convar_t r_traceglow;
extern convar_t r_vbo;
extern convar_t r_vbo_dlightmode;
extern convar_t r_vbo_detail;
extern convar_t r_vbo_overbrightmode;
extern convar_t r_studio_sort_textures;
extern convar_t r_studio_drawelements;
extern convar_t r_ripple;

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_detail, "gl_vbo_detail", "0", FCVAR_ARCHIVE, "detail vbo mode (0: disable, 1: multipass, 2: singlepass, broken decal dlights)" );
CVAR_DEFINE( r_vbo_dlightmode, "gl_vbo_dlightmode", "1", FCVAR_ARCHIVE, "vbo dlight rendering mode (0-1)" );
CVAR_DEFINE( r_vbo_overbrightmode, "gl_vbo_overbrightmode", "0", FCVAR_ARCHIVE, "vbo overbright rendering mode (0-1)" );
CVAR_DEFINE_AUTO( r_ripple, "0", FCVAR_GLCONFIG, "enable software-like water texture ripple simulation" );
CVAR_DEFINE_AUTO( r_ripple_updatetime, "0.05", FCVAR_GLCONFIG, "how fast ripple simulation is" );
CVAR_DEFINE_AUTO( r_ripple_spawntime, "0.1", FCVAR_GLCONFIG, "how fast new ripples spawn" );
@@ -555,54 +556,70 @@ qboolean GL_CheckExtension( const char *name, const dllfunc_t *funcs, const char
for( func = funcs; func && func->name; func++ )
{
// functions are cleared before all the extensions are evaluated
if(( *func->func = (void *)gEngfuncs.GL_GetProcAddress( func->name )) == NULL )
{
string name;
char *end;
size_t i = 0;
string name;
char *end;
size_t i = 0;
qboolean first_try = true;
// NULL means just func->name, but empty suffix cuts ARB suffix if present
#ifdef XASH_GLES
const char *suffixes[] = { "", "EXT", "OES" };
const char *suffixes[] = { "", "EXT", "OES", NULL, "ARB" };
#else
const char *suffixes[] = { "", "EXT" };
const char *suffixes[] = { NULL, "", "EXT", "ARB" };
#endif
// HACK: fix ARB names
Q_strncpy( name, func->name, sizeof( name ));
if(( end = Q_strstr( name, "ARB" )))
{
*end = '\0';
}
else // I need Q_strstrnul
{
end = name + Q_strlen( name );
i++; // skip empty suffix
}
// Remove ARB suffix
Q_strncpy( name, func->name, sizeof( name ));
if(( end = Q_strstr( name, "ARB" )))
{
*end = '\0';
}
else // I need Q_strstrnul
{
end = name + Q_strlen( name );
}
for( ; i < sizeof( suffixes ) / sizeof( suffixes[0] ); i++ )
{
void *f;
for( ; i < sizeof( suffixes ) / sizeof( suffixes[0] ); i++ )
{
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 ));
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
}
}
// not found...
if( i == sizeof( suffixes ) / sizeof( suffixes[0] ))
else
{
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
@@ -1248,6 +1265,7 @@ static void R_CheckVBO( void )
gEngfuncs.Cvar_RegisterVariable( &r_vbo );
gEngfuncs.Cvar_RegisterVariable( &r_vbo_dlightmode );
gEngfuncs.Cvar_RegisterVariable( &r_vbo_overbrightmode );
gEngfuncs.Cvar_RegisterVariable( &r_vbo_detail );
}

View File

@@ -1011,10 +1011,11 @@ static void R_CheckGamma( void )
ClearBits( gl_overbright.flags, FCVAR_CHANGED );
}
if( gl_overbright.value && FBitSet( r_vbo.flags, FCVAR_CHANGED ))
if( gl_overbright.value && ( FBitSet( r_vbo.flags, FCVAR_CHANGED ) || FBitSet( r_vbo_overbrightmode.flags, FCVAR_CHANGED ) ) )
{
rebuild = true;
ClearBits( r_vbo.flags, FCVAR_CHANGED );
ClearBits( r_vbo_overbrightmode.flags, FCVAR_CHANGED );
}
if( rebuild )

View File

@@ -718,7 +718,7 @@ static void R_BuildLightMap( msurface_t *surf, byte *dest, int stride, qboolean
tmax = ( info->lightextents[1] / sample_size ) + 1;
size = smax * tmax;
if( gl_overbright.value )
lightscale = r_vbo.value ? 171 : 256;
lightscale = (r_vbo.value && !r_vbo_overbrightmode.value) ? 171 : 256;
else lightscale = ( pow( 2.0f, 1.0f / v_lightgamma->value ) * 256 ) + 0.5;
lm = surf->samples;
@@ -927,7 +927,8 @@ static void R_BlendLightmaps( void )
if( gl_overbright.value )
{
pglBlendFunc( GL_DST_COLOR, GL_SRC_COLOR );
pglColor4f( 128.0f / 192.0f, 128.0f / 192.0f, 128.0f / 192.0f, 1.0f );
if(!( r_vbo.value && !r_vbo_overbrightmode.value ))
pglColor4f( 128.0f / 192.0f, 128.0f / 192.0f, 128.0f / 192.0f, 1.0f );
}
else
{
@@ -2189,15 +2190,30 @@ static void R_SetLightmap( void )
if( gl_overbright.value )
{
// GLfloat color[4] = { 128.0f / 192.0f, 128.0f / 192.0f, 128.0f / 192.0f, 1.0f };
if( r_vbo_overbrightmode.value == 1 )
{
GLfloat color[4] = { 128.0f / 192.0f, 128.0f / 192.0f, 128.0f / 192.0f, 1.0f };
int tmu = glState.activeTMU;
GL_SelectTexture( tmu - 1 );
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
pglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE );
pglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_CONSTANT_ARB );
pglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR );
pglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB_ARB, GL_SRC_COLOR );
pglTexEnvi( GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR );
pglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE );
// doesn't work here for some reason
pglTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color );
GL_SelectTexture( tmu );
}
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB );
pglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE );
pglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS_ARB );
pglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_TEXTURE );
pglTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE );
pglTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB );
pglTexEnvi( GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2 );
// doesn't work here for some reason
// pglTexEnvfv( GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color );
}
else
{

View File

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

View File

@@ -968,6 +968,7 @@ void R_UploadRipples( texture_t *image )
gl_texture_t *glt;
uint32_t *pixels;
int wbits, wmask, wshft;
int y;
// discard unuseful textures
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;
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 x;
for( int x = 0; x < image->width; x++ )
for( x = 0; x < image->width; x++ )
{
int rx = x << wshft;
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] );
height = h;
if (y < 0)
if( y < -h ) // out of display, out of bounds
return;
if( y < 0 )
{
skip = -y;
height += y;

View File

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

View File

@@ -64,6 +64,7 @@ CFLAGS = {
'msvc': ['/O2', '/Oy', '/Zi'],
'gcc': {
'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']
},
'clang': ['-Ofast'],
@@ -78,7 +79,11 @@ CFLAGS = {
'humanrights': {
'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'],
'gcc': ['-O3', '-fno-semantic-interposition'],
'gcc': {
'4': ['-O3'],
'3': ['-O3'],
'default': ['-O3','-fno-semantic-interposition'],
},
'default': ['-O3']
},
'debug': {
@@ -116,6 +121,22 @@ POLLY_CFLAGS = {
# 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):
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,
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):
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('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
if conf.options.BUILD_TYPE.startswith('fast'):
@@ -174,6 +203,13 @@ def get_optimization_flags(conf):
if conf.options.POLLY:
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':
# enable remote debugger
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
is_hardfloat = False
clang = False
ndk_binutils = False
def __init__(self, ctx, arch, toolchain, api):
self.ctx = ctx
@@ -214,7 +215,7 @@ class Android:
if 'CC' in environ:
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')
def cxx(self):
@@ -225,11 +226,11 @@ class Android:
if 'CXX' in environ:
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++')
def strip(self):
if self.is_host():
if self.is_host() and not self.ndk_binutils:
environ = getattr(self.ctx, 'environ', os.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(), '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):
# 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):
arch = self.arch
@@ -262,8 +276,15 @@ class Android:
def cflags(self, cxx = False):
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())]
else:
if self.is_host():
@@ -273,13 +294,18 @@ class Android:
]
cflags += ['-I%s' % (self.system_stl())]
if not self.is_clang():
cflags += ['-DANDROID', '-D__ANDROID__']
if not self.is_clang() or android_from_none:
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']:
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
# disable it here so Clang won't use it
if self.api < ANDROID_STPCPY_API_MIN:
@@ -291,7 +317,7 @@ class Android:
cflags += ['-mthumb', '-mfpu=neon', '-mcpu=cortex-a9']
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():
# Clang builtin redefine w/ different calling convention bug
@@ -316,15 +342,23 @@ class Android:
linkflags = []
if self.is_host():
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:
linkflags += ['--sysroot=%s' % (self.sysroot())]
elif self.is_host():
linkflags += ['--sysroot=%s/sysroot' % (self.gen_gcc_toolchain_path())]
if self.is_clang() or self.is_host():
linkflags += ['-fuse-ld=lld']
else: linkflags += ['-no-canonical-prefixes']
#if self.is_clang() or self.is_host():
# linkflags += ['-fuse-ld=lld']
#else:
linkflags += ['-no-canonical-prefixes']
linkflags += ['-Wl,--hash-style=sysv', '-Wl,--no-undefined']
return linkflags
@@ -528,6 +562,7 @@ def configure(conf):
conf.environ['CC'] = android.cc()
conf.environ['CXX'] = android.cxx()
conf.environ['STRIP'] = android.strip()
conf.environ['OBJCOPY'] = android.objcopy()
conf.env.CFLAGS += android.cflags()
conf.env.CXXFLAGS += android.cflags(True)
conf.env.LINKFLAGS += android.linkflags()

View File

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

50
wscript
View File

@@ -2,7 +2,7 @@
# encoding: utf-8
# a1batross, mittorn, 2018
from waflib import Build, Context, Logs
from waflib import Build, Context, Logs, Options, Configure
from waflib.Tools import waf_unit_test
import sys
import os
@@ -69,7 +69,7 @@ SUBDIRS = [
Subproject('dllemu'),
# 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/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),
@@ -104,6 +104,42 @@ REFDLLS = [
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):
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,
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:
if not i.is_exists(opt):
continue
opt.add_subproject(i.name)
process_extra_projects_opts(opt)
def configure(conf):
conf.load('fwgslib reconfigure compiler_optimizations')
@@ -197,11 +236,12 @@ def configure(conf):
if conf.env.DEST_OS == 'android':
conf.options.NO_VGUI = True # skip vgui
conf.options.NANOGL = True
conf.options.GLWES = True
conf.options.GLWES = False # deprecated
conf.options.GL4ES = True
conf.options.GLES3COMPAT = True
conf.options.GL = False
conf.define('XASH_SDLMAIN', 1)
if conf.env.HAVE_SDL2:
conf.define('XASH_SDLMAIN', 1)
elif conf.env.MAGX:
conf.options.SDL12 = True
conf.options.NO_VGUI = True
@@ -493,6 +533,7 @@ int main(void) { return !opus_custom_encoder_init((OpusCustomEncoder *)1, (const
continue
conf.add_subproject(i.name)
process_extra_projects_conf(conf)
def build(bld):
# guard rails to not let install to root
@@ -515,3 +556,4 @@ def build(bld):
if bld.env.TESTS:
bld.add_post_fun(waf_unit_test.summary)
bld.add_post_fun(waf_unit_test.set_exit_code)
process_extra_projects_bld(bld)