mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-05 11:35:05 +08:00
Compare commits
127 Commits
continuous
...
android-le
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38a3154de0 | ||
|
|
0442af7920 | ||
|
|
42958bc746 | ||
|
|
bd5309b018 | ||
|
|
26cbb1d6bf | ||
|
|
d6cfc65ac0 | ||
|
|
be9dda2a56 | ||
|
|
dbc54fb522 | ||
|
|
ec92d05930 | ||
|
|
892c735c86 | ||
|
|
93e5faa26b | ||
|
|
4953656ee0 | ||
|
|
96c367973a | ||
|
|
ffe1ff326a | ||
|
|
9c097976df | ||
|
|
6fec0398b6 | ||
|
|
abeb267420 | ||
|
|
9484effd4c | ||
|
|
a5f3fce665 | ||
|
|
91d9ca7810 | ||
|
|
0901fd94e2 | ||
|
|
0d18753adb | ||
|
|
7841382fef | ||
|
|
e21d8df1fe | ||
|
|
16aa2e919f | ||
|
|
88f76c6e1e | ||
|
|
1b9af8c515 | ||
|
|
55943ad1ce | ||
|
|
313f2a86b0 | ||
|
|
16eeaef35c | ||
|
|
46c82e89e1 | ||
|
|
bb55de5963 | ||
|
|
d423c437ed | ||
|
|
44b1a8e863 | ||
|
|
06c6371e69 | ||
|
|
7b4fd3bcad | ||
|
|
ea35863c26 | ||
|
|
c2e14eb3a3 | ||
|
|
34aab39f9b | ||
|
|
30c69d3ac8 | ||
|
|
bb9775048b | ||
|
|
eed13cf9f2 | ||
|
|
fbb91e547d | ||
|
|
43bd73f37b | ||
|
|
bb2753cbfc | ||
|
|
5568eccc8a | ||
|
|
c3b2cc4423 | ||
|
|
d84130219f | ||
|
|
d97d4d6c42 | ||
|
|
15798aaf52 | ||
|
|
e53892e827 | ||
|
|
cb12af69ed | ||
|
|
e82050a4bc | ||
|
|
e4edd2da45 | ||
|
|
4f80922358 | ||
|
|
ae7ed03376 | ||
|
|
c082e46662 | ||
|
|
b0bbcab6b4 | ||
|
|
0fc83080ec | ||
|
|
73883b504f | ||
|
|
8efc9d74e8 | ||
|
|
373321ff00 | ||
|
|
a508467aac | ||
|
|
abbe993e80 | ||
|
|
c644e4d569 | ||
|
|
c200e008f1 | ||
|
|
e95a2da6d0 | ||
|
|
8afca1a79c | ||
|
|
827c9ca857 | ||
|
|
2416635ba3 | ||
|
|
39eec89580 | ||
|
|
98d88266a6 | ||
|
|
0f3359fc05 | ||
|
|
6c77608c34 | ||
|
|
abdff6eff6 | ||
|
|
95a75465c9 | ||
|
|
119926805f | ||
|
|
f749b5cb4b | ||
|
|
c29ad6b598 | ||
|
|
4c5dfb963e | ||
|
|
e11f9e05d4 | ||
|
|
5c8b5b3511 | ||
|
|
2ea7162287 | ||
|
|
e62ab51842 | ||
|
|
f1bc9b87b1 | ||
|
|
a9bddaac64 | ||
|
|
6cef6f6a75 | ||
|
|
25ea6ed500 | ||
|
|
3d5173f257 | ||
|
|
05ff0d6020 | ||
|
|
3cea12627e | ||
|
|
b59b7c1a8d | ||
|
|
dd2c369df3 | ||
|
|
8b79e49a0f | ||
|
|
4ea6eba8f2 | ||
|
|
f649076bc3 | ||
|
|
8ecffa4663 | ||
|
|
e90b83849a | ||
|
|
d517b9717a | ||
|
|
2c0d6e06be | ||
|
|
dec71850a1 | ||
|
|
b1860972c6 | ||
|
|
1f4c9b67da | ||
|
|
c2da125358 | ||
|
|
31fa990d44 | ||
|
|
d3e60c7d84 | ||
|
|
e2424b4303 | ||
|
|
240563cd1b | ||
|
|
d708cd58fb | ||
|
|
491b503f96 | ||
|
|
636a2228f6 | ||
|
|
bb03e2597c | ||
|
|
21c828ee40 | ||
|
|
132c9de142 | ||
|
|
9d9507d77f | ||
|
|
7daa6c3451 | ||
|
|
c8e1ffe0dd | ||
|
|
b5f02324a6 | ||
|
|
47f5dfdcfd | ||
|
|
33da68b013 | ||
|
|
618ec83c9d | ||
|
|
85de61ebc8 | ||
|
|
2feaae59f7 | ||
|
|
2550d7fbd3 | ||
|
|
565f717804 | ||
|
|
b56c83a2f9 | ||
|
|
bf17996f72 |
12
.github/workflows/c-cpp.yml
vendored
12
.github/workflows/c-cpp.yml
vendored
@@ -24,14 +24,9 @@ jobs:
|
||||
# - os: ubuntu-aarch64-20.04
|
||||
# targetos: linux
|
||||
# targetarch: aarch64
|
||||
|
||||
# - os: ubuntu-20.04
|
||||
# targetos: android
|
||||
# targetarch: 32
|
||||
# - os: ubuntu-20.04
|
||||
# targetos: android
|
||||
# targetarch: 64
|
||||
|
||||
- os: ubuntu-20.04
|
||||
targetos: android
|
||||
targetarch: multiarch
|
||||
# - os: ubuntu-20.04
|
||||
# targetos: motomagx
|
||||
# targetarch: armv6
|
||||
@@ -51,7 +46,6 @@ jobs:
|
||||
env:
|
||||
SDL_VERSION: 2.28.5
|
||||
GH_CPU_ARCH: ${{ matrix.targetarch }}
|
||||
ANDROID_SDK_TOOLS_VER: 4333796
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -54,6 +54,11 @@ CMakeFiles
|
||||
Makefile
|
||||
cmake_install.cmake
|
||||
install_manifest.txt
|
||||
CMakeLists.txt*
|
||||
CMakeScripts
|
||||
Testing
|
||||
compile_commands.json
|
||||
_deps
|
||||
# makedepend
|
||||
Makefile.dep
|
||||
*.bak
|
||||
|
||||
2
3rdparty/gl4es/gl4es
vendored
2
3rdparty/gl4es/gl4es
vendored
Submodule 3rdparty/gl4es/gl4es updated: 5226f5f937...e39434a2b1
2
3rdparty/mainui
vendored
2
3rdparty/mainui
vendored
Submodule 3rdparty/mainui updated: de4402e86b...d75b7f4a57
2
3rdparty/nanogl
vendored
2
3rdparty/nanogl
vendored
Submodule 3rdparty/nanogl updated: 76393a8fde...e75792de03
25
Documentation/extensions/native-object.md
Normal file
25
Documentation/extensions/native-object.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# GetNativeObject API
|
||||
|
||||
To be able to use platform-specific features or get optional engine interfaces, we've added a simple call to MobilityAPI on client DLL and PhysicsAPI for server DLL and extended MenuAPI for menu DLL.
|
||||
|
||||
It's defined like this:
|
||||
|
||||
```
|
||||
void *pfnGetNativeObject( const char *name );
|
||||
```
|
||||
|
||||
#### Cross-platform objects
|
||||
|
||||
Only these objects are guaranteed to be available on all targets.
|
||||
|
||||
| Object name | Interface |
|
||||
|-------------|-----------|
|
||||
| `VFileSystem009` | Provides C++ interface to filesystem, binary-compatible with Valve's VFileSystem009. |
|
||||
| `XashFileSystemXXX` | Provides C interface to filesystem. This interface is unstable and not recommended for generic use, outside of engine internals. For more info about current version look into `filesystem.h`. |
|
||||
|
||||
#### Android-specific objects
|
||||
|
||||
| Object name | Interface |
|
||||
|-------------|-----------|
|
||||
| `JNIEnv` | Allows interfacing with Java Native Interface. |
|
||||
| `ActivityClass` | Returns JNI object for engine Android activity class. |
|
||||
65
Documentation/extensions/sounds.lst.md
Normal file
65
Documentation/extensions/sounds.lst.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# sounds.lst.md
|
||||
|
||||
Using sounds.lst located in scripts folder, modder can override some of the hardcoded sounds in temp entities and server physics.
|
||||
|
||||
File format:
|
||||
```
|
||||
<group name>
|
||||
{
|
||||
<path1>
|
||||
<path2>
|
||||
<path3>
|
||||
}
|
||||
|
||||
<group2 name> <path with %d> <min number> <max number>
|
||||
```
|
||||
|
||||
* Sounds can use any supported sound format (WAV or MP3).
|
||||
* The path must be relative to the sounds/ folder in the game or base directory root, addon folder, or archive root.
|
||||
* Groups can be empty or omitted from the file to load no sound.
|
||||
* Groups can either list a set of files or specify a format string and a range.
|
||||
* Anything after // will be considered a comment and ignored.
|
||||
* Behavior is undefined if the group was listed multiple times.
|
||||
|
||||
Currently supported groups are:
|
||||
|Group name|Usage|
|
||||
|----------|-----|
|
||||
|`BouncePlayerShell`|Used for BOUNCE_SHELL tempentity hitsound|
|
||||
|`BounceWeaponShell`|Used for BOUCNE_SHOTSHELL tempentity hitsound|
|
||||
|`BounceConcrete`|Used for BOUNCE_CONCRETE tempentity hitsound|
|
||||
|`BounceGlass`|Used for BOUCNE_GLASS|
|
||||
|`BounceMetal`|Used for BOUNCE_METAL|
|
||||
|`BounceFlesh`|Used for BOUNCE_FLESH|
|
||||
|`BounceWood`|Used for BOUNCE_WOOD|
|
||||
|`Ricochet`|Used for BOUNCE_SHRAP and ricochet tempentities|
|
||||
|`Explode`|Used for tempentity explosions|
|
||||
|`EntityWaterEnter`|Used for entity entering water|
|
||||
|`EntityWaterExit`|Used for entity exiting water|
|
||||
|`PlayerWaterEnter`|Used for player entering water|
|
||||
|`PlayerWaterExit`|Used for player exiting water|
|
||||
|
||||
## Example
|
||||
|
||||
This example is based on defaults sounds used in Half-Life:
|
||||
|
||||
```
|
||||
BouncePlayerShell "player/pl_shell%d.wav" 1 3
|
||||
BounceWeaponShell "weapons/sshell%d.wav" 1 3
|
||||
BounceConcrete "debris/concrete%d.wav" 1 3
|
||||
BounceGlass "debris/glass%d.wav" 1 4
|
||||
BounceMetal "debris/metal%d.wav" 1 6
|
||||
BounceFlesh "debris/flesh%d.wav" 1 7
|
||||
BounceWood "debris/wood%d.wav" 1 4
|
||||
Ricochet "weapons/ric%d.wav" 1 5
|
||||
Explode "weapons/explode%d.wav" 3 5
|
||||
EntityWaterEnter "player/pl_wade%d.wav" 1 4
|
||||
EntityWaterExit "player/pl_wade%d.wav" 1 4
|
||||
PlayerWaterEnter
|
||||
{
|
||||
"player/pl_wade1.wav"
|
||||
}
|
||||
PlayerWaterExit
|
||||
{
|
||||
"player/pl_wade2.wav"
|
||||
}
|
||||
```
|
||||
15
Documentation/musl.md
Normal file
15
Documentation/musl.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Xash3D FWGS on `musl`
|
||||
|
||||
Xash3D FWGS works on `musl` out of the box. However, the engine doesn't try to differentiate glibc and musl anymore. If you see error similar to:
|
||||
|
||||
```
|
||||
Host_InitError: can't initialize cl_dlls/client.so: Error relocating valve/cl_dlls/client.so: __sprintf_chk: symbol not found
|
||||
```
|
||||
|
||||
... or you know that the game you're running is linked against glibc, you can try using `libgcompat`, like this:
|
||||
|
||||
```
|
||||
$ LD_PRELOAD=/lib/libgcompat.so.0 ./xash3d ...
|
||||
```
|
||||
|
||||
It will automatically add the missing symbols that glibc binaries usually need. In the future we might automatically link engine against `libgcompat` for better compatibility with prebuilt or closed-source games, if there will be any use for this.
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -46,10 +46,35 @@ static int CL_LoadFontTexture( const char *fontname, uint texFlags, int *width )
|
||||
return tex;
|
||||
}
|
||||
|
||||
qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags )
|
||||
static int CL_FontRenderMode( convar_t *fontrender )
|
||||
{
|
||||
switch((int)fontrender->value )
|
||||
{
|
||||
case 0:
|
||||
return kRenderTransAdd;
|
||||
case 1:
|
||||
return kRenderTransAlpha;
|
||||
case 2:
|
||||
return kRenderTransTexture;
|
||||
default:
|
||||
Cvar_DirectSet( fontrender, fontrender->def_string );
|
||||
}
|
||||
|
||||
return kRenderTransTexture;
|
||||
}
|
||||
|
||||
void CL_SetFontRendermode( cl_font_t *font )
|
||||
{
|
||||
ref.dllFuncs.GL_SetRenderMode( CL_FontRenderMode( font->rendermode ));
|
||||
}
|
||||
|
||||
qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, convar_t *rendermode, uint texFlags )
|
||||
{
|
||||
int font_width, i;
|
||||
|
||||
if( !rendermode )
|
||||
return false;
|
||||
|
||||
if( font->valid )
|
||||
return true; // already loaded
|
||||
|
||||
@@ -76,13 +101,16 @@ qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float sc
|
||||
return true;
|
||||
}
|
||||
|
||||
qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags )
|
||||
qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float scale, convar_t *rendermode, uint texFlags )
|
||||
{
|
||||
fs_offset_t length;
|
||||
qfont_t src;
|
||||
byte *pfile;
|
||||
int font_width, i;
|
||||
|
||||
if( !rendermode )
|
||||
return false;
|
||||
|
||||
if( font->valid )
|
||||
return true;
|
||||
|
||||
@@ -105,7 +133,7 @@ qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float
|
||||
|
||||
font->type = FONT_VARIABLE;
|
||||
font->valid = true;
|
||||
font->scale = scale;
|
||||
font->scale = scale ? scale : 1.0f;
|
||||
font->rendermode = rendermode;
|
||||
font->charHeight = Q_rint( src.rowheight * scale );
|
||||
|
||||
@@ -177,7 +205,8 @@ int CL_DrawCharacter( float x, float y, int number, rgba_t color, cl_font_t *fon
|
||||
return font->charWidths[number];
|
||||
|
||||
rc = &font->fontRc[number];
|
||||
if( font->scale <= 1.0f || REF_GET_PARM( PARM_TEX_FILTERING, font->hFontTexture ))
|
||||
|
||||
if( font->scale <= 1.f || !REF_GET_PARM( PARM_TEX_FILTERING, font->hFontTexture ))
|
||||
half = 0;
|
||||
|
||||
s1 = ((float)rc->left + half ) / texw;
|
||||
@@ -191,7 +220,7 @@ int CL_DrawCharacter( float x, float y, int number, rgba_t color, cl_font_t *fon
|
||||
SPR_AdjustSize( &x, &y, &w, &h );
|
||||
|
||||
if( !FBitSet( flags, FONT_DRAW_NORENDERMODE ))
|
||||
ref.dllFuncs.GL_SetRenderMode( font->rendermode );
|
||||
CL_SetFontRendermode( font );
|
||||
|
||||
// don't apply color to fixed fonts it's already colored
|
||||
if( font->type != FONT_FIXED || REF_GET_PARM( PARM_TEX_GLFORMAT, font->hFontTexture ) == 0x8045 ) // GL_LUMINANCE8_ALPHA8
|
||||
@@ -214,7 +243,7 @@ int CL_DrawString( float x, float y, const char *s, rgba_t color, cl_font_t *fon
|
||||
Con_UtfProcessChar( 0 ); // clear utf state
|
||||
|
||||
if( !FBitSet( flags, FONT_DRAW_NORENDERMODE ))
|
||||
ref.dllFuncs.GL_SetRenderMode( font->rendermode );
|
||||
CL_SetFontRendermode( font );
|
||||
|
||||
Vector4Copy( color, current_color );
|
||||
|
||||
|
||||
@@ -474,8 +474,7 @@ void CL_DrawCenterPrint( void )
|
||||
pText = clgame.centerPrint.message;
|
||||
|
||||
CL_DrawCharacterLen( font, 0, NULL, &charHeight );
|
||||
|
||||
ref.dllFuncs.GL_SetRenderMode( font->rendermode );
|
||||
CL_SetFontRendermode( font );
|
||||
for( i = 0; i < clgame.centerPrint.lines; i++ )
|
||||
{
|
||||
lineLength = 0;
|
||||
|
||||
@@ -1220,6 +1220,7 @@ static ui_extendedfuncs_t gExtendedfuncs =
|
||||
pfnParseFileSafe,
|
||||
NET_AdrToString,
|
||||
NET_CompareAdrSort,
|
||||
Sys_GetNativeObject,
|
||||
};
|
||||
|
||||
void UI_UnloadProgs( void )
|
||||
|
||||
@@ -28,7 +28,6 @@ GNU General Public License for more details.
|
||||
#define MAX_CMD_BUFFER 8000
|
||||
#define CONNECTION_PROBLEM_TIME 15.0 // 15 seconds
|
||||
#define CL_CONNECTION_RETRIES 10
|
||||
#define CL_TEST_RETRIES_NORESPONCE 3
|
||||
#define CL_TEST_RETRIES 5
|
||||
|
||||
CVAR_DEFINE_AUTO( mp_decals, "300", FCVAR_ARCHIVE, "decals limit in multiplayer" );
|
||||
@@ -61,6 +60,7 @@ CVAR_DEFINE_AUTO( cl_smoothtime, "0.1", FCVAR_ARCHIVE, "time to smooth up" );
|
||||
CVAR_DEFINE_AUTO( cl_clockreset, "0.1", FCVAR_ARCHIVE, "frametime delta maximum value before reset" );
|
||||
CVAR_DEFINE_AUTO( cl_fixtimerate, "7.5", FCVAR_ARCHIVE, "time in msec to client clock adjusting" );
|
||||
CVAR_DEFINE_AUTO( hud_fontscale, "1.0", FCVAR_ARCHIVE|FCVAR_LATCH, "scale hud font texture" );
|
||||
CVAR_DEFINE_AUTO( hud_fontrender, "0", FCVAR_ARCHIVE, "hud font render mode (0: additive, 1: holes, 2: trans)" );
|
||||
CVAR_DEFINE_AUTO( hud_scale, "0", FCVAR_ARCHIVE|FCVAR_LATCH, "scale hud at current resolution" );
|
||||
CVAR_DEFINE_AUTO( hud_scale_minimal_width, "640", FCVAR_ARCHIVE|FCVAR_LATCH, "if hud_scale results in a HUD virtual screen smaller than this value, it won't be applied" );
|
||||
CVAR_DEFINE_AUTO( cl_solid_players, "1", 0, "Make all players not solid (can't traceline them)" );
|
||||
@@ -74,8 +74,9 @@ static CVAR_DEFINE_AUTO( cl_upmax, "1200", FCVAR_ARCHIVE, "max allowed incoming
|
||||
|
||||
CVAR_DEFINE_AUTO( cl_lw, "1", FCVAR_ARCHIVE|FCVAR_USERINFO, "enable client weapon predicting" );
|
||||
CVAR_DEFINE_AUTO( cl_charset, "utf-8", FCVAR_ARCHIVE, "1-byte charset to use (iconv style)" );
|
||||
CVAR_DEFINE_AUTO( cl_trace_messages, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable message names tracing (good for developers)");
|
||||
CVAR_DEFINE_AUTO( cl_trace_events, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable events tracing (good for developers)");
|
||||
CVAR_DEFINE_AUTO( cl_trace_stufftext, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable stufftext (server-to-client console commands) tracing (good for developers)" );
|
||||
CVAR_DEFINE_AUTO( cl_trace_messages, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable message names tracing (good for developers)" );
|
||||
CVAR_DEFINE_AUTO( cl_trace_events, "0", FCVAR_ARCHIVE|FCVAR_CHEAT, "enable events tracing (good for developers)" );
|
||||
static CVAR_DEFINE_AUTO( cl_nat, "0", 0, "show servers running under NAT" );
|
||||
CVAR_DEFINE_AUTO( hud_utf8, "0", FCVAR_ARCHIVE, "Use utf-8 encoding for hud text" );
|
||||
CVAR_DEFINE_AUTO( ui_renderworld, "0", FCVAR_ARCHIVE, "render world when UI is visible" );
|
||||
@@ -1070,6 +1071,22 @@ static void CL_SendConnectPacket( void )
|
||||
cls.timestart = Sys_DoubleTime();
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_GetTestFragmentSize
|
||||
|
||||
Returns bandwidth test fragment size
|
||||
=================
|
||||
*/
|
||||
static int CL_GetTestFragmentSize( void )
|
||||
{
|
||||
const int fragmentSizes[CL_TEST_RETRIES] = { 64000, 32000, 10666, 5200, 1400 };
|
||||
if( cls.connect_retry >= 0 && cls.connect_retry < CL_TEST_RETRIES )
|
||||
return bound( FRAGMENT_MIN_SIZE, fragmentSizes[cls.connect_retry], FRAGMENT_MAX_SIZE );
|
||||
else
|
||||
return FRAGMENT_MIN_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
CL_CheckForResend
|
||||
@@ -1081,8 +1098,9 @@ static void CL_CheckForResend( void )
|
||||
{
|
||||
netadr_t adr;
|
||||
net_gai_state_t res;
|
||||
float resendTime;
|
||||
qboolean bandwidthTest;
|
||||
|
||||
|
||||
if( cls.internetservers_wait )
|
||||
CL_SendMasterServerScanRequest();
|
||||
|
||||
@@ -1108,7 +1126,10 @@ static void CL_CheckForResend( void )
|
||||
else if( cl_resend.value > CL_MAX_RESEND_TIME )
|
||||
Cvar_SetValue( "cl_resend", CL_MAX_RESEND_TIME );
|
||||
|
||||
if(( host.realtime - cls.connect_time ) < cl_resend.value )
|
||||
bandwidthTest = !cls.legacymode && cl_test_bandwidth.value && cls.connect_retry <= CL_TEST_RETRIES;
|
||||
resendTime = bandwidthTest ? 1.0f : cl_resend.value;
|
||||
|
||||
if(( host.realtime - cls.connect_time ) < resendTime )
|
||||
return;
|
||||
|
||||
res = NET_StringToAdrNB( cls.servername, &adr );
|
||||
@@ -1135,10 +1156,11 @@ static void CL_CheckForResend( void )
|
||||
|
||||
if( adr.port == 0 ) adr.port = MSG_BigShort( PORT_SERVER );
|
||||
|
||||
if( cls.connect_retry == CL_TEST_RETRIES_NORESPONCE )
|
||||
if( cls.connect_retry == CL_TEST_RETRIES )
|
||||
{
|
||||
// too many fails use default connection method
|
||||
Con_Printf( "hi-speed connection is failed, use default method\n" );
|
||||
Con_Printf( "Bandwidth test failed, fallback to default connecting method\n" );
|
||||
Con_Printf( "Connecting to %s... (retry #%i)\n", cls.servername, cls.connect_retry + 1 );
|
||||
Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" );
|
||||
Cvar_SetValue( "cl_dlmax", FRAGMENT_MIN_SIZE );
|
||||
cls.connect_time = host.realtime;
|
||||
@@ -1146,16 +1168,15 @@ static void CL_CheckForResend( void )
|
||||
return;
|
||||
}
|
||||
|
||||
bandwidthTest = !cls.legacymode && cl_test_bandwidth.value;
|
||||
cls.serveradr = adr;
|
||||
cls.max_fragment_size = Q_min( FRAGMENT_MAX_SIZE, cls.max_fragment_size / (cls.connect_retry + 1));
|
||||
cls.max_fragment_size = CL_GetTestFragmentSize();
|
||||
cls.connect_time = host.realtime; // for retransmit requests
|
||||
cls.connect_retry++;
|
||||
|
||||
if( bandwidthTest )
|
||||
Con_Printf( "Connecting to %s... [retry #%i, max fragment size %i]\n", cls.servername, cls.connect_retry, cls.max_fragment_size );
|
||||
Con_Printf( "Connecting to %s... (retry #%i, fragment size %i)\n", cls.servername, cls.connect_retry, cls.max_fragment_size );
|
||||
else
|
||||
Con_Printf( "Connecting to %s... [retry #%i]\n", cls.servername, cls.connect_retry );
|
||||
Con_Printf( "Connecting to %s... (retry #%i)\n", cls.servername, cls.connect_retry );
|
||||
|
||||
if( bandwidthTest )
|
||||
Netchan_OutOfBandPrint( NS_CLIENT, adr, "bandwidth %i %i\n", PROTOCOL_VERSION, cls.max_fragment_size );
|
||||
@@ -2891,6 +2912,7 @@ static void CL_InitLocal( void )
|
||||
|
||||
Cvar_RegisterVariable( &rcon_address );
|
||||
|
||||
Cvar_RegisterVariable( &cl_trace_stufftext );
|
||||
Cvar_RegisterVariable( &cl_trace_messages );
|
||||
Cvar_RegisterVariable( &cl_trace_events );
|
||||
|
||||
@@ -2926,6 +2948,7 @@ static void CL_InitLocal( void )
|
||||
Cvar_RegisterVariable( &cl_clockreset );
|
||||
Cvar_RegisterVariable( &cl_fixtimerate );
|
||||
Cvar_RegisterVariable( &hud_fontscale );
|
||||
Cvar_RegisterVariable( &hud_fontrender );
|
||||
Cvar_RegisterVariable( &hud_scale );
|
||||
Cvar_RegisterVariable( &hud_scale_minimal_width );
|
||||
Cvar_Get( "cl_background", "0", FCVAR_READ_ONLY, "indicate what background map is running" );
|
||||
|
||||
@@ -387,7 +387,7 @@ static void NetGraph_DrawTextFields( int x, int y, int w, wrect_t rect, int coun
|
||||
// move rolling average
|
||||
framerate = FRAMERATE_AVG_FRAC * host.frametime + ( 1.0f - FRAMERATE_AVG_FRAC ) * framerate;
|
||||
|
||||
ref.dllFuncs.GL_SetRenderMode( font->rendermode );
|
||||
CL_SetFontRendermode( font );
|
||||
|
||||
if( framerate > 0.0f )
|
||||
{
|
||||
|
||||
@@ -1382,9 +1382,13 @@ void CL_UpdateUserinfo( sizebuf_t *msg, qboolean legacy )
|
||||
if( slot >= MAX_CLIENTS )
|
||||
Host_Error( "CL_ParseServerMessage: svc_updateuserinfo >= MAX_CLIENTS\n" );
|
||||
|
||||
player = &cl.players[slot];
|
||||
|
||||
if( !legacy )
|
||||
id = MSG_ReadLong( msg ); // unique user ID
|
||||
player = &cl.players[slot];
|
||||
else
|
||||
id = 0; // bogus
|
||||
|
||||
active = MSG_ReadOneBit( msg ) ? true : false;
|
||||
|
||||
if( active )
|
||||
@@ -1406,6 +1410,10 @@ void CL_UpdateUserinfo( sizebuf_t *msg, qboolean legacy )
|
||||
|
||||
memset( player, 0, sizeof( *player ));
|
||||
}
|
||||
|
||||
// in GoldSrc userinfo might be empty but userid is always sent as separate value
|
||||
// thus avoids clean up even after client disconnect
|
||||
player->userid = id;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2321,11 +2329,18 @@ void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message )
|
||||
break;
|
||||
case svc_stufftext:
|
||||
s = MSG_ReadString( msg );
|
||||
if( cl_trace_stufftext.value )
|
||||
{
|
||||
size_t len = Q_strlen( s );
|
||||
Con_Printf( "Stufftext: %s%c", s, len && s[len-1] == '\n' ? '\0' : '\n' );
|
||||
}
|
||||
|
||||
#ifdef HACKS_RELATED_HLMODS
|
||||
// disable Cry Of Fear antisave protection
|
||||
if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS )
|
||||
break; // too early
|
||||
#endif
|
||||
|
||||
Cbuf_AddFilteredText( s );
|
||||
break;
|
||||
case svc_setangle:
|
||||
|
||||
@@ -443,13 +443,17 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message )
|
||||
break;
|
||||
case svc_stufftext:
|
||||
s = MSG_ReadString( msg );
|
||||
if( cl_trace_stufftext.value )
|
||||
{
|
||||
size_t len = Q_strlen( s );
|
||||
Con_Printf( "Stufftext: %s%c", s, len && s[len-1] == '\n' ? '\0' : '\n' );
|
||||
}
|
||||
|
||||
#ifdef HACKS_RELATED_HLMODS
|
||||
// disable Cry Of Fear antisave protection
|
||||
if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS )
|
||||
break; // too early
|
||||
#endif
|
||||
|
||||
Con_Reportf( "Stufftext: %s", s );
|
||||
Cbuf_AddFilteredText( s );
|
||||
break;
|
||||
case svc_setangle:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -288,6 +288,9 @@ void SCR_MakeScreenShot( void )
|
||||
qboolean iRet = false;
|
||||
int viewsize;
|
||||
|
||||
if( cls.scrshot_action == scrshot_inactive )
|
||||
return;
|
||||
|
||||
if( cls.envshot_viewsize > 0 )
|
||||
viewsize = cls.envshot_viewsize;
|
||||
else viewsize = cl_envshot_size.value;
|
||||
@@ -319,8 +322,6 @@ void SCR_MakeScreenShot( void )
|
||||
if( iRet )
|
||||
VID_WriteOverviewScript(); // store overview script too
|
||||
break;
|
||||
case scrshot_inactive:
|
||||
return;
|
||||
}
|
||||
|
||||
// report
|
||||
@@ -572,15 +573,15 @@ void SCR_LoadCreditsFont( void )
|
||||
"creditsfont_%s.fnt", Cvar_VariableString( "con_charset" )) > 0 )
|
||||
{
|
||||
if( FS_FileExists( charsetFnt, false ))
|
||||
success = Con_LoadVariableWidthFont( charsetFnt, font, scale, kRenderTransAdd, TF_FONT );
|
||||
success = Con_LoadVariableWidthFont( charsetFnt, font, scale, &hud_fontrender, TF_FONT );
|
||||
}
|
||||
}
|
||||
|
||||
if( !success )
|
||||
success = Con_LoadVariableWidthFont( "gfx/creditsfont.fnt", font, scale, kRenderTransAdd, TF_FONT );
|
||||
success = Con_LoadVariableWidthFont( "gfx/creditsfont.fnt", font, scale, &hud_fontrender, TF_FONT );
|
||||
|
||||
if( !success )
|
||||
success = Con_LoadFixedWidthFont( "gfx/conchars", font, scale, kRenderTransAdd, TF_FONT );
|
||||
success = Con_LoadFixedWidthFont( "gfx/conchars", font, scale, &hud_fontrender, TF_FONT );
|
||||
|
||||
// copy font size for client.dll
|
||||
if( success )
|
||||
|
||||
@@ -57,36 +57,6 @@ const char *cl_default_sprites[] =
|
||||
"sprites/shellchrome.spr",
|
||||
};
|
||||
|
||||
const char *cl_player_shell_sounds[] =
|
||||
{
|
||||
"player/pl_shell1.wav",
|
||||
"player/pl_shell2.wav",
|
||||
"player/pl_shell3.wav",
|
||||
};
|
||||
|
||||
const char *cl_weapon_shell_sounds[] =
|
||||
{
|
||||
"weapons/sshell1.wav",
|
||||
"weapons/sshell2.wav",
|
||||
"weapons/sshell3.wav",
|
||||
};
|
||||
|
||||
const char *cl_ricochet_sounds[] =
|
||||
{
|
||||
"weapons/ric1.wav",
|
||||
"weapons/ric2.wav",
|
||||
"weapons/ric3.wav",
|
||||
"weapons/ric4.wav",
|
||||
"weapons/ric5.wav",
|
||||
};
|
||||
|
||||
const char *cl_explode_sounds[] =
|
||||
{
|
||||
"weapons/explode3.wav",
|
||||
"weapons/explode4.wav",
|
||||
"weapons/explode5.wav",
|
||||
};
|
||||
|
||||
static void CL_PlayerDecal( int playerIndex, int textureIndex, int entityIndex, float *pos );
|
||||
|
||||
/*
|
||||
@@ -148,6 +118,7 @@ client resources not precached by server
|
||||
*/
|
||||
void CL_AddClientResources( void )
|
||||
{
|
||||
const char *snd;
|
||||
char filepath[MAX_QPATH];
|
||||
int i;
|
||||
|
||||
@@ -163,37 +134,37 @@ void CL_AddClientResources( void )
|
||||
}
|
||||
|
||||
// then check sounds
|
||||
for( i = 0; i < ARRAYSIZE( cl_player_shell_sounds ); i++ )
|
||||
for( i = 0; ( snd = SoundList_Get( BouncePlayerShell, i )); i++ )
|
||||
{
|
||||
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", cl_player_shell_sounds[i] );
|
||||
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
|
||||
|
||||
if( !FS_FileExists( filepath, false ))
|
||||
CL_AddClientResource( cl_player_shell_sounds[i], t_sound );
|
||||
CL_AddClientResource( snd, t_sound );
|
||||
}
|
||||
|
||||
for( i = 0; i < ARRAYSIZE( cl_weapon_shell_sounds ); i++ )
|
||||
for( i = 0; ( snd = SoundList_Get( BounceWeaponShell, i )); i++ )
|
||||
{
|
||||
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", cl_weapon_shell_sounds[i] );
|
||||
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
|
||||
|
||||
if( !FS_FileExists( filepath, false ))
|
||||
CL_AddClientResource( cl_weapon_shell_sounds[i], t_sound );
|
||||
CL_AddClientResource( snd, t_sound );
|
||||
}
|
||||
|
||||
for( i = 0; i < ARRAYSIZE( cl_explode_sounds ); i++ )
|
||||
for( i = 0; ( snd = SoundList_Get( Explode, i )); i++ )
|
||||
{
|
||||
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", cl_explode_sounds[i] );
|
||||
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
|
||||
|
||||
if( !FS_FileExists( filepath, false ))
|
||||
CL_AddClientResource( cl_explode_sounds[i], t_sound );
|
||||
CL_AddClientResource( snd, t_sound );
|
||||
}
|
||||
|
||||
#if 0 // ric sounds was precached by server-side
|
||||
for( i = 0; i < ARRAYSIZE( cl_ricochet_sounds ); i++ )
|
||||
for( i = 0; ( snd = SoundList_Get( Ricochet, i )); i++ )
|
||||
{
|
||||
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", cl_ricochet_sounds[i] );
|
||||
Q_snprintf( filepath, sizeof( filepath ), DEFAULT_SOUNDPATH "%s", snd );
|
||||
|
||||
if( !FS_FileExists( filepath, false ))
|
||||
CL_AddClientResource( cl_ricochet_sounds[i], t_sound );
|
||||
CL_AddClientResource( snd, t_sound );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -301,7 +272,7 @@ play collide sound
|
||||
static void CL_TempEntPlaySound( TEMPENTITY *pTemp, float damp )
|
||||
{
|
||||
float fvol;
|
||||
char soundname[32];
|
||||
const char *soundname = NULL;
|
||||
qboolean isshellcasing = false;
|
||||
int zvel;
|
||||
|
||||
@@ -312,36 +283,39 @@ static void CL_TempEntPlaySound( TEMPENTITY *pTemp, float damp )
|
||||
switch( pTemp->hitSound )
|
||||
{
|
||||
case BOUNCE_GLASS:
|
||||
Q_snprintf( soundname, sizeof( soundname ), "debris/glass%i.wav", COM_RandomLong( 1, 4 ));
|
||||
soundname = SoundList_GetRandom( BounceGlass );
|
||||
break;
|
||||
case BOUNCE_METAL:
|
||||
Q_snprintf( soundname, sizeof( soundname ), "debris/metal%i.wav", COM_RandomLong( 1, 6 ));
|
||||
soundname = SoundList_GetRandom( BounceMetal );
|
||||
break;
|
||||
case BOUNCE_FLESH:
|
||||
Q_snprintf( soundname, sizeof( soundname ), "debris/flesh%i.wav", COM_RandomLong( 1, 7 ));
|
||||
soundname = SoundList_GetRandom( BounceFlesh );
|
||||
break;
|
||||
case BOUNCE_WOOD:
|
||||
Q_snprintf( soundname, sizeof( soundname ), "debris/wood%i.wav", COM_RandomLong( 1, 4 ));
|
||||
soundname = SoundList_GetRandom( BounceWood );
|
||||
break;
|
||||
case BOUNCE_SHRAP:
|
||||
Q_strncpy( soundname, cl_ricochet_sounds[COM_RandomLong( 0, 4 )], sizeof( soundname ) );
|
||||
soundname = SoundList_GetRandom( Ricochet );
|
||||
break;
|
||||
case BOUNCE_SHOTSHELL:
|
||||
Q_strncpy( soundname, cl_weapon_shell_sounds[COM_RandomLong( 0, 2 )], sizeof( soundname ) );
|
||||
soundname = SoundList_GetRandom( BounceWeaponShell );
|
||||
isshellcasing = true; // shell casings have different playback parameters
|
||||
fvol = 0.5f;
|
||||
break;
|
||||
case BOUNCE_SHELL:
|
||||
Q_strncpy( soundname, cl_player_shell_sounds[COM_RandomLong( 0, 2 )], sizeof( soundname ) );
|
||||
soundname = SoundList_GetRandom( BouncePlayerShell );
|
||||
isshellcasing = true; // shell casings have different playback parameters
|
||||
break;
|
||||
case BOUNCE_CONCRETE:
|
||||
Q_snprintf( soundname, sizeof( soundname ), "debris/concrete%i.wav", COM_RandomLong( 1, 3 ));
|
||||
soundname = SoundList_GetRandom( BounceConcrete );
|
||||
break;
|
||||
default: // null sound
|
||||
return;
|
||||
}
|
||||
|
||||
if( !soundname )
|
||||
return;
|
||||
|
||||
zvel = abs( pTemp->entity.baseline.origin[2] );
|
||||
|
||||
// only play one out of every n
|
||||
@@ -1491,7 +1465,7 @@ void GAME_EXPORT R_FunnelSprite( const vec3_t org, int modelIndex, int reverse )
|
||||
===============
|
||||
R_SparkEffect
|
||||
|
||||
Create a streaks + richochet sprite
|
||||
Create a streaks + ricochet sprite
|
||||
===============
|
||||
*/
|
||||
void GAME_EXPORT R_SparkEffect( const vec3_t pos, int count, int velocityMin, int velocityMax )
|
||||
@@ -1507,18 +1481,25 @@ R_RicochetSound
|
||||
Make a random ricochet sound
|
||||
==============
|
||||
*/
|
||||
static void R_RicochetSound_( const vec3_t pos, int sound )
|
||||
static void R_RicochetSoundByName( const vec3_t pos, const char *name )
|
||||
{
|
||||
sound_t handle;
|
||||
|
||||
handle = S_RegisterSound( cl_ricochet_sounds[sound] );
|
||||
|
||||
sound_t handle;
|
||||
handle = S_RegisterSound( name );
|
||||
S_StartSound( pos, 0, CHAN_AUTO, handle, VOL_NORM, 1.0, 100, 0 );
|
||||
}
|
||||
|
||||
static void R_RicochetSoundByIndex( const vec3_t pos, int idx )
|
||||
{
|
||||
const char *name = SoundList_Get( Ricochet, idx );
|
||||
if( name )
|
||||
R_RicochetSoundByName( pos, name );
|
||||
}
|
||||
|
||||
void GAME_EXPORT R_RicochetSound( const vec3_t pos )
|
||||
{
|
||||
R_RicochetSound_( pos, COM_RandomLong( 0, 4 ));
|
||||
const char *name = SoundList_GetRandom( Ricochet );
|
||||
if( name )
|
||||
R_RicochetSoundByName( pos, name );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1665,8 +1646,12 @@ void GAME_EXPORT R_Explosion( vec3_t pos, int model, float scale, float framerat
|
||||
|
||||
if( !FBitSet( flags, TE_EXPLFLAG_NOSOUND ))
|
||||
{
|
||||
hSound = S_RegisterSound( cl_explode_sounds[COM_RandomLong( 0, 2 )] );
|
||||
S_StartSound( pos, 0, CHAN_STATIC, hSound, VOL_NORM, 0.3f, PITCH_NORM, 0 );
|
||||
const char *name = SoundList_GetRandom( Explode );
|
||||
if( name )
|
||||
{
|
||||
hSound = S_RegisterSound( name );
|
||||
S_StartSound( pos, 0, CHAN_STATIC, hSound, VOL_NORM, 0.3f, PITCH_NORM, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1909,6 +1894,7 @@ void CL_ParseTempEntity( sizebuf_t *msg )
|
||||
cl_entity_t *pEnt;
|
||||
dlight_t *dl;
|
||||
sound_t hSound;
|
||||
const char *name;
|
||||
|
||||
if( cls.legacymode )
|
||||
iSize = MSG_ReadByte( msg );
|
||||
@@ -1968,8 +1954,11 @@ void CL_ParseTempEntity( sizebuf_t *msg )
|
||||
pos[2] = MSG_ReadCoord( &buf );
|
||||
R_BlobExplosion( pos );
|
||||
|
||||
hSound = S_RegisterSound( cl_explode_sounds[0] );
|
||||
S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 1.0f, PITCH_NORM, 0 );
|
||||
if(( name = SoundList_Get( Explode, 0 )))
|
||||
{
|
||||
hSound = S_RegisterSound( name );
|
||||
S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 1.0f, PITCH_NORM, 0 );
|
||||
}
|
||||
break;
|
||||
case TE_SMOKE:
|
||||
pos[0] = MSG_ReadCoord( &buf );
|
||||
@@ -2022,8 +2011,11 @@ void CL_ParseTempEntity( sizebuf_t *msg )
|
||||
dl->die = cl.time + 0.5;
|
||||
dl->decay = 300;
|
||||
|
||||
hSound = S_RegisterSound( cl_explode_sounds[0] );
|
||||
S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 0.6f, PITCH_NORM, 0 );
|
||||
if(( name = SoundList_Get( Explode, 0 )))
|
||||
{
|
||||
hSound = S_RegisterSound( name );
|
||||
S_StartSound( pos, -1, CHAN_AUTO, hSound, VOL_NORM, 1.0f, PITCH_NORM, 0 );
|
||||
}
|
||||
break;
|
||||
case TE_BSPDECAL:
|
||||
case TE_DECAL:
|
||||
@@ -2251,8 +2243,8 @@ void CL_ParseTempEntity( sizebuf_t *msg )
|
||||
CL_DecalShoot( CL_DecalIndex( decalIndex ), entityIndex, 0, pos, 0 );
|
||||
R_BulletImpactParticles( pos );
|
||||
flags = COM_RandomLong( 0, 0x7fff );
|
||||
if( flags < 0x3fff )
|
||||
R_RicochetSound_( pos, flags % 5 );
|
||||
if( flags < 0x3fff && ( count = SoundList_Count( Ricochet )))
|
||||
R_RicochetSoundByIndex( pos, flags % count );
|
||||
break;
|
||||
case TE_SPRAY:
|
||||
case TE_SPRITE_SPRAY:
|
||||
|
||||
@@ -553,4 +553,6 @@ void V_PostRender( void )
|
||||
ref.dllFuncs.R_AllowFog( true );
|
||||
Platform_SetTimer( 0.0f );
|
||||
ref.dllFuncs.R_EndFrame();
|
||||
|
||||
V_CheckGammaEnd();
|
||||
}
|
||||
|
||||
@@ -342,7 +342,7 @@ typedef struct
|
||||
byte charWidths[256]; // scaled widths
|
||||
int charHeight; // scaled height
|
||||
int type; // fixed width font or variable
|
||||
int rendermode; // default rendermode
|
||||
convar_t *rendermode; // user-defined default rendermode
|
||||
qboolean valid; // all rectangles are valid
|
||||
} cl_font_t;
|
||||
|
||||
@@ -681,12 +681,14 @@ extern convar_t cl_draw_beams;
|
||||
extern convar_t cl_clockreset;
|
||||
extern convar_t cl_fixtimerate;
|
||||
extern convar_t hud_fontscale;
|
||||
extern convar_t hud_fontrender;
|
||||
extern convar_t hud_scale;
|
||||
extern convar_t hud_scale_minimal_width;
|
||||
extern convar_t r_showtextures;
|
||||
extern convar_t cl_bmodelinterp;
|
||||
extern convar_t cl_lw; // local weapons
|
||||
extern convar_t cl_charset;
|
||||
extern convar_t cl_trace_stufftext;
|
||||
extern convar_t cl_trace_messages;
|
||||
extern convar_t cl_trace_events;
|
||||
extern convar_t hud_utf8;
|
||||
@@ -798,9 +800,10 @@ void CL_FireEvents( void );
|
||||
// cl_font.c
|
||||
//
|
||||
qboolean CL_FixedFont( cl_font_t *font );
|
||||
qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags );
|
||||
qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float scale, int rendermode, uint texFlags );
|
||||
qboolean Con_LoadFixedWidthFont( const char *fontname, cl_font_t *font, float scale, convar_t *rendermode, uint texFlags );
|
||||
qboolean Con_LoadVariableWidthFont( const char *fontname, cl_font_t *font, float scale, convar_t *rendermode, uint texFlags );
|
||||
void CL_FreeFont( cl_font_t *font );
|
||||
void CL_SetFontRendermode( cl_font_t *font );
|
||||
int CL_DrawCharacter( float x, float y, int number, rgba_t color, cl_font_t *font, int flags );
|
||||
int CL_DrawString( float x, float y, const char *s, rgba_t color, cl_font_t *font, int flags );
|
||||
void CL_DrawCharacterLen( cl_font_t *font, int number, int *width, int *height );
|
||||
|
||||
@@ -25,6 +25,7 @@ GNU General Public License for more details.
|
||||
static CVAR_DEFINE_AUTO( scr_conspeed, "600", FCVAR_ARCHIVE, "console moving speed" );
|
||||
static CVAR_DEFINE_AUTO( con_notifytime, "3", FCVAR_ARCHIVE, "notify time to live" );
|
||||
CVAR_DEFINE_AUTO( con_fontsize, "1", FCVAR_ARCHIVE, "console font number (0, 1 or 2)" );
|
||||
static CVAR_DEFINE_AUTO( con_fontrender, "2", FCVAR_ARCHIVE, "console font render mode (0: additive, 1: holes, 2: trans)" );
|
||||
static CVAR_DEFINE_AUTO( con_charset, "cp1251", FCVAR_ARCHIVE, "console font charset (only cp1251 supported now)" );
|
||||
static CVAR_DEFINE_AUTO( con_fontscale, "1.0", FCVAR_ARCHIVE, "scale font texture" );
|
||||
static CVAR_DEFINE_AUTO( con_fontnum, "-1", FCVAR_ARCHIVE, "console font number (0, 1 or 2), -1 for autoselect" );
|
||||
@@ -547,7 +548,7 @@ static void Con_LoadConsoleFont( int fontNumber, cl_font_t *font )
|
||||
|
||||
if( con_oldfont.value )
|
||||
{
|
||||
success = Con_LoadVariableWidthFont( "gfx/conchars.fnt", font, scale, kRenderTransTexture, TF_FONT|TF_NEAREST );
|
||||
success = Con_LoadVariableWidthFont( "gfx/conchars.fnt", font, scale, &con_fontrender, TF_FONT|TF_NEAREST );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -560,14 +561,14 @@ static void Con_LoadConsoleFont( int fontNumber, cl_font_t *font )
|
||||
if( Q_snprintf( path, sizeof( path ),
|
||||
"font%i_%s.fnt", fontNumber, Cvar_VariableString( "con_charset" )) > 0 )
|
||||
{
|
||||
success = Con_LoadVariableWidthFont( path, font, scale, kRenderTransTexture, TF_FONT|TF_NEAREST );
|
||||
success = Con_LoadVariableWidthFont( path, font, scale, &con_fontrender, TF_FONT|TF_NEAREST );
|
||||
}
|
||||
}
|
||||
|
||||
if( !success )
|
||||
{
|
||||
Q_snprintf( path, sizeof( path ), "fonts/font%i", fontNumber );
|
||||
success = Con_LoadVariableWidthFont( path, font, scale, kRenderTransTexture, TF_FONT|TF_NEAREST );
|
||||
success = Con_LoadVariableWidthFont( path, font, scale, &con_fontrender, TF_FONT|TF_NEAREST );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,7 +576,7 @@ static void Con_LoadConsoleFont( int fontNumber, cl_font_t *font )
|
||||
{
|
||||
// quake fixed font as fallback
|
||||
// keep source to print directly into conback image
|
||||
if( !Con_LoadFixedWidthFont( "gfx/conchars", font, scale, kRenderTransTexture, TF_FONT|TF_NEAREST|TF_KEEP_SOURCE ))
|
||||
if( !Con_LoadFixedWidthFont( "gfx/conchars", font, scale, &con_fontrender, TF_FONT|TF_NEAREST|TF_KEEP_SOURCE ))
|
||||
Con_DPrintf( S_ERROR "failed to load console font\n" );
|
||||
}
|
||||
}
|
||||
@@ -840,6 +841,7 @@ void Con_Init( void )
|
||||
Cvar_RegisterVariable( &con_fontsize );
|
||||
Cvar_RegisterVariable( &con_charset );
|
||||
Cvar_RegisterVariable( &con_fontscale );
|
||||
Cvar_RegisterVariable( &con_fontrender );
|
||||
Cvar_RegisterVariable( &con_fontnum );
|
||||
Cvar_RegisterVariable( &con_color );
|
||||
Cvar_RegisterVariable( &scr_drawversion );
|
||||
@@ -2098,9 +2100,13 @@ void Con_RunConsole( void )
|
||||
// decide on the destination height of the console
|
||||
if( host.allow_console && cls.key_dest == key_console )
|
||||
{
|
||||
#if XASH_MOBILE_PLATFORM
|
||||
con.showlines = refState.height; // always full screen on mobile devices
|
||||
#else
|
||||
if( cls.state < ca_active || cl.first_frame )
|
||||
con.showlines = refState.height; // full screen
|
||||
else con.showlines = (refState.height >> 1); // half screen
|
||||
#endif
|
||||
}
|
||||
else con.showlines = 0; // none visible
|
||||
|
||||
@@ -2185,6 +2191,8 @@ INTERNAL RESOURCE
|
||||
*/
|
||||
void Con_VidInit( void )
|
||||
{
|
||||
const uint flags = TF_IMAGE|TF_ALLOW_NEAREST;
|
||||
|
||||
if( !con.historyLoaded )
|
||||
{
|
||||
Con_LoadHistory( &con.history );
|
||||
@@ -2204,28 +2212,28 @@ void Con_VidInit( void )
|
||||
{
|
||||
// trying to load truecolor image first
|
||||
if( FS_FileExists( "gfx/shell/conback.bmp", false ) || FS_FileExists( "gfx/shell/conback.tga", false ))
|
||||
con.background = ref.dllFuncs.GL_LoadTexture( "gfx/shell/conback", NULL, 0, TF_IMAGE );
|
||||
con.background = ref.dllFuncs.GL_LoadTexture( "gfx/shell/conback", NULL, 0, flags );
|
||||
|
||||
if( !con.background )
|
||||
{
|
||||
if( FS_FileExists( "cached/conback640", false ))
|
||||
con.background = ref.dllFuncs.GL_LoadTexture( "cached/conback640", NULL, 0, TF_IMAGE );
|
||||
con.background = ref.dllFuncs.GL_LoadTexture( "cached/conback640", NULL, 0, flags );
|
||||
else if( FS_FileExists( "cached/conback", false ))
|
||||
con.background = ref.dllFuncs.GL_LoadTexture( "cached/conback", NULL, 0, TF_IMAGE );
|
||||
con.background = ref.dllFuncs.GL_LoadTexture( "cached/conback", NULL, 0, flags );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// trying to load truecolor image first
|
||||
if( FS_FileExists( "gfx/shell/loading.bmp", false ) || FS_FileExists( "gfx/shell/loading.tga", false ))
|
||||
con.background = ref.dllFuncs.GL_LoadTexture( "gfx/shell/loading", NULL, 0, TF_IMAGE );
|
||||
con.background = ref.dllFuncs.GL_LoadTexture( "gfx/shell/loading", NULL, 0, flags );
|
||||
|
||||
if( !con.background )
|
||||
{
|
||||
if( FS_FileExists( "cached/loading640", false ))
|
||||
con.background = ref.dllFuncs.GL_LoadTexture( "cached/loading640", NULL, 0, TF_IMAGE );
|
||||
con.background = ref.dllFuncs.GL_LoadTexture( "cached/loading640", NULL, 0, flags );
|
||||
else if( FS_FileExists( "cached/loading", false ))
|
||||
con.background = ref.dllFuncs.GL_LoadTexture( "cached/loading", NULL, 0, TF_IMAGE );
|
||||
con.background = ref.dllFuncs.GL_LoadTexture( "cached/loading", NULL, 0, flags );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ GNU General Public License for more details.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Gamma conversion support
|
||||
//-----------------------------------------------------------------------------
|
||||
static qboolean gamma_rebuilt;
|
||||
static byte texgammatable[256];
|
||||
static uint lightgammatable[1024];
|
||||
static uint lineargammatable[1024];
|
||||
@@ -99,14 +100,13 @@ static void V_ValidateGammaCvars( void )
|
||||
|
||||
if( v_brightness.value < 0.0f )
|
||||
Cvar_DirectSet( &v_brightness, "0" );
|
||||
else if( v_brightness.value > 2.0f )
|
||||
Cvar_DirectSet( &v_brightness, "2" );
|
||||
else if( v_brightness.value > 3.0f )
|
||||
Cvar_DirectSet( &v_brightness, "3" );
|
||||
}
|
||||
|
||||
void V_CheckGamma( void )
|
||||
{
|
||||
static qboolean dirty = false;
|
||||
qboolean notify_refdll = false;
|
||||
|
||||
// because these cvars were defined as archive
|
||||
// but wasn't doing anything useful
|
||||
@@ -132,20 +132,33 @@ void V_CheckGamma( void )
|
||||
V_ValidateGammaCvars();
|
||||
|
||||
dirty = false;
|
||||
gamma_rebuilt = true;
|
||||
|
||||
BuildGammaTable( v_gamma.value, v_brightness.value, v_texgamma.value, v_lightgamma.value );
|
||||
|
||||
// force refdll to recalculate lightmaps
|
||||
notify_refdll = true;
|
||||
if( ref.initialized )
|
||||
ref.dllFuncs.R_GammaChanged( false );
|
||||
}
|
||||
}
|
||||
|
||||
// unfortunately, recalculating textures isn't possible yet
|
||||
void V_CheckGammaEnd( void )
|
||||
{
|
||||
// don't reset changed flag if it was set during frame
|
||||
// keep it for next frame
|
||||
if( !gamma_rebuilt )
|
||||
return;
|
||||
|
||||
gamma_rebuilt = false;
|
||||
|
||||
// keep the flags until the end of frame so client.dll will catch these changes
|
||||
if( FBitSet( v_texgamma.flags|v_lightgamma.flags|v_brightness.flags|v_gamma.flags, FCVAR_CHANGED ))
|
||||
{
|
||||
ClearBits( v_texgamma.flags, FCVAR_CHANGED );
|
||||
ClearBits( v_lightgamma.flags, FCVAR_CHANGED );
|
||||
ClearBits( v_brightness.flags, FCVAR_CHANGED );
|
||||
ClearBits( v_gamma.flags, FCVAR_CHANGED );
|
||||
}
|
||||
|
||||
if( notify_refdll && ref.initialized )
|
||||
ref.dllFuncs.R_GammaChanged( false );
|
||||
}
|
||||
|
||||
void V_Init( void )
|
||||
|
||||
@@ -2029,10 +2029,18 @@ int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx
|
||||
{
|
||||
touch.move_finger = touch.resize_finger = touch.look_finger = -1;
|
||||
// Hack for keyboard, hope it help
|
||||
// a1ba: this is absolutely horrible
|
||||
if( cls.key_dest == key_console || cls.key_dest == key_message )
|
||||
{
|
||||
if ( type == event_down ) // don't pop it again on event_up
|
||||
static float x1 = 0.0f;
|
||||
x1 += dx;
|
||||
|
||||
if( type == event_up ) // don't show keyboard on every tap
|
||||
{
|
||||
Key_EnableTextInput( true, true );
|
||||
x1 = 0.0f;
|
||||
}
|
||||
|
||||
if( cls.key_dest == key_console )
|
||||
{
|
||||
static float y1 = 0;
|
||||
@@ -2054,6 +2062,13 @@ int IN_TouchEvent( touchEventType type, int fingerID, float x, float y, float dx
|
||||
// exit of console area
|
||||
if( type == event_down && x < 0.1f && y > 0.9f )
|
||||
Cbuf_AddText( "escape\n" );
|
||||
|
||||
// swipe from edge to exit console/chat
|
||||
if(( x > 0.8f && x1 < -0.1f ) || ( x < 0.2f && x1 > 0.1f ))
|
||||
{
|
||||
Cbuf_AddText( "escape\n" );
|
||||
x1 = 0.0f;
|
||||
}
|
||||
}
|
||||
UI_MouseMove( TO_SCRN_X(x), TO_SCRN_Y(y) );
|
||||
//MsgDev( D_NOTE, "touch %d %d\n", TO_SCRN_X(x), TO_SCRN_Y(y) );
|
||||
|
||||
@@ -611,6 +611,7 @@ qboolean R_Init( void )
|
||||
|
||||
// cvars that are expected to exist by client.dll
|
||||
// refdll should just get pointer to them
|
||||
Cvar_Get( "r_lighting_modulate", "0.6", FCVAR_ARCHIVE, "compatibility cvar, does nothing" );
|
||||
Cvar_Get( "r_drawentities", "1", FCVAR_CHEAT, "render entities" );
|
||||
Cvar_Get( "cl_himodels", "1", FCVAR_ARCHIVE, "draw high-resolution player models in multiplayer" );
|
||||
|
||||
|
||||
@@ -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" );
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -529,7 +529,6 @@ typedef struct cmd_s
|
||||
static int cmd_argc;
|
||||
static const char *cmd_args = NULL;
|
||||
static char *cmd_argv[MAX_CMD_TOKENS];
|
||||
static char cmd_tokenized[MAX_CMD_BUFFER]; // will have 0 bytes inserted
|
||||
static cmd_t *cmd_functions; // possible commands to execute
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,15 +17,24 @@ GNU General Public License for more details.
|
||||
#define COM_STRINGS_H
|
||||
|
||||
// default colored message headers
|
||||
#define S_NOTE "^2Note:^7 "
|
||||
#define S_WARN "^3Warning:^7 "
|
||||
#define S_ERROR "^1Error:^7 "
|
||||
#define S_USAGE "Usage: "
|
||||
#define S_USAGE_INDENT " "
|
||||
#define S_BLACK "^0"
|
||||
#define S_RED "^1"
|
||||
#define S_GREEN "^2"
|
||||
#define S_YELLOW "^3"
|
||||
#define S_BLUE "^4"
|
||||
#define S_CYAN "^5"
|
||||
#define S_MAGENTA "^6"
|
||||
#define S_DEFAULT "^7"
|
||||
|
||||
#define S_OPENGL_NOTE "^2OpenGL Note:^7 "
|
||||
#define S_OPENGL_WARN "^3OpenGL Warning:^7 "
|
||||
#define S_OPENGL_ERROR "^3OpenGL Error:^7 "
|
||||
#define S_NOTE S_GREEN "Note: " S_DEFAULT
|
||||
#define S_WARN S_YELLOW "Warning: " S_DEFAULT
|
||||
#define S_ERROR S_RED "Error: " S_DEFAULT
|
||||
#define S_USAGE "Usage: "
|
||||
#define S_USAGE_INDENT "\t"
|
||||
|
||||
#define S_OPENGL_NOTE S_GREEN "OpenGL Note: " S_DEFAULT
|
||||
#define S_OPENGL_WARN S_YELLOW "OpenGL Warning: " S_DEFAULT
|
||||
#define S_OPENGL_ERROR S_RED "OpenGL Error: " S_DEFAULT
|
||||
|
||||
// end game final default message
|
||||
#define DEFAULT_ENDGAME_MESSAGE "The End"
|
||||
|
||||
@@ -693,7 +693,7 @@ COM_LoadFileForMe
|
||||
byte *GAME_EXPORT COM_LoadFileForMe( const char *filename, int *pLength )
|
||||
{
|
||||
string name;
|
||||
byte *file, *pfile;
|
||||
byte *pfile;
|
||||
fs_offset_t iLength;
|
||||
|
||||
if( !COM_CheckString( filename ))
|
||||
@@ -706,21 +706,9 @@ byte *GAME_EXPORT COM_LoadFileForMe( const char *filename, int *pLength )
|
||||
Q_strncpy( name, filename, sizeof( name ));
|
||||
COM_FixSlashes( name );
|
||||
|
||||
pfile = FS_LoadFile( name, &iLength, false );
|
||||
pfile = g_fsapi.LoadFileMalloc( name, &iLength, false );
|
||||
if( pLength ) *pLength = (int)iLength;
|
||||
|
||||
if( pfile )
|
||||
{
|
||||
file = malloc( iLength + 1 );
|
||||
if( file != NULL )
|
||||
{
|
||||
memcpy( file, pfile, iLength );
|
||||
file[iLength] = '\0';
|
||||
}
|
||||
Mem_Free( pfile );
|
||||
pfile = file;
|
||||
}
|
||||
|
||||
return pfile;
|
||||
}
|
||||
|
||||
|
||||
@@ -795,6 +795,7 @@ uint ScreenGammaTable( uint );
|
||||
uint LinearGammaTable( uint );
|
||||
void V_Init( void );
|
||||
void V_CheckGamma( void );
|
||||
void V_CheckGammaEnd( void );
|
||||
|
||||
//
|
||||
// identification.c
|
||||
@@ -815,6 +816,34 @@ void NET_MasterClear( void );
|
||||
void NET_MasterShutdown( void );
|
||||
qboolean NET_GetMaster( netadr_t from, uint *challenge, double *last_heartbeat );
|
||||
|
||||
//
|
||||
// sounds.c
|
||||
//
|
||||
typedef enum soundlst_group_e
|
||||
{
|
||||
BouncePlayerShell = 0,
|
||||
BounceWeaponShell,
|
||||
BounceConcrete,
|
||||
BounceGlass,
|
||||
BounceMetal,
|
||||
BounceFlesh,
|
||||
BounceWood,
|
||||
Ricochet,
|
||||
Explode,
|
||||
PlayerWaterEnter,
|
||||
PlayerWaterExit,
|
||||
EntityWaterEnter,
|
||||
EntityWaterExit,
|
||||
|
||||
SoundList_Groups // must be last
|
||||
} soundlst_group_t;
|
||||
|
||||
int SoundList_Count( soundlst_group_t group );
|
||||
const char *SoundList_GetRandom( soundlst_group_t group );
|
||||
const char *SoundList_Get( soundlst_group_t group, int idx );
|
||||
void SoundList_Init( void );
|
||||
void SoundList_Shutdown( void );
|
||||
|
||||
#ifdef REF_DLL
|
||||
#error "common.h in ref_dll"
|
||||
#endif
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -109,6 +109,7 @@ static void Sys_PrintUsage( void )
|
||||
O("-clockwindow <cw>", "adjust clockwindow used to ignore client commands to prevent speed hacks")
|
||||
|
||||
"\nGame options:\n"
|
||||
O("-game <directory>", "set game directory to start engine with")
|
||||
O("-dll <path> ", "override server DLL path")
|
||||
#if !XASH_DEDICATED
|
||||
O("-clientlib <path>", "override client DLL path")
|
||||
@@ -1310,6 +1311,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||
|
||||
HTTP_Init();
|
||||
ID_Init();
|
||||
SoundList_Init();
|
||||
|
||||
if( Host_IsDedicated() )
|
||||
{
|
||||
@@ -1412,6 +1414,7 @@ void EXPORT Host_Shutdown( void )
|
||||
SV_ShutdownFilter();
|
||||
CL_Shutdown();
|
||||
|
||||
SoundList_Shutdown();
|
||||
Mod_Shutdown();
|
||||
NET_Shutdown();
|
||||
HTTP_Shutdown();
|
||||
|
||||
@@ -28,7 +28,7 @@ qboolean Image_LoadBMP( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
rgba_t palette[256] = { 0 };
|
||||
int i, columns, column, rows, row, bpp = 1;
|
||||
int cbPalBytes = 0, padSize = 0, bps = 0;
|
||||
int reflectivity[3] = { 0, 0, 0 };
|
||||
uint reflectivity[3] = { 0, 0, 0 };
|
||||
qboolean load_qfont = false;
|
||||
bmp_t bhdr;
|
||||
fs_offset_t estimatedSize;
|
||||
|
||||
@@ -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 ));
|
||||
|
||||
@@ -29,7 +29,7 @@ qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
rgba_t palette[256];
|
||||
byte red = 0, green = 0, blue = 0, alpha = 0;
|
||||
int readpixelcount, pixelcount;
|
||||
int reflectivity[3] = { 0, 0, 0 };
|
||||
uint reflectivity[3] = { 0, 0, 0 };
|
||||
qboolean compressed;
|
||||
tga_t targa_header;
|
||||
|
||||
|
||||
@@ -360,7 +360,7 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, fs_offset_t filesi
|
||||
byte *fin, *pal;
|
||||
int ofs[4], rendermode;
|
||||
int i, pixels, numcolors;
|
||||
int reflectivity[3] = { 0, 0, 0 };
|
||||
uint reflectivity[3] = { 0, 0, 0 };
|
||||
|
||||
if( filesize < sizeof( mip ))
|
||||
return false;
|
||||
|
||||
@@ -127,7 +127,7 @@ GNU General Public License for more details.
|
||||
#define MAX_CUSTOM (1<<MAX_CUSTOM_BITS)// 10 bits == 1024 generic file
|
||||
#define MAX_USER_MESSAGES 197 // another 58 messages reserved for engine routines
|
||||
#define MAX_DLIGHTS 32 // dynamic lights (rendered per one frame)
|
||||
#define MAX_ELIGHTS 64 // entity only point lights
|
||||
#define MAX_ELIGHTS 128 // a1ba: increased from 64 to 128, entity only point lights
|
||||
#define MAX_LIGHTSTYLES 256 // a1ba: increased from 64 to 256, protocol limit
|
||||
#define MAX_RENDER_DECALS 4096 // max rendering decals per a level
|
||||
|
||||
|
||||
362
engine/common/sounds.c
Normal file
362
engine/common/sounds.c
Normal file
@@ -0,0 +1,362 @@
|
||||
/*
|
||||
sounds.c - sounds.lst parser
|
||||
Copyright (C) 2024 Alibek Omarov
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
#include "common.h"
|
||||
|
||||
enum soundlst_type_e
|
||||
{
|
||||
SoundList_None,
|
||||
SoundList_Range,
|
||||
SoundList_List
|
||||
};
|
||||
|
||||
static const char *soundlst_groups[SoundList_Groups] =
|
||||
{
|
||||
"BouncePlayerShell",
|
||||
"BounceWeaponShell",
|
||||
"BounceConcrete",
|
||||
"BounceGlass",
|
||||
"BounceMetal",
|
||||
"BounceFlesh",
|
||||
"BounceWood",
|
||||
"Ricochet",
|
||||
"Explode",
|
||||
"PlayerWaterEnter",
|
||||
"PlayerWaterExit",
|
||||
"EntityWaterEnter",
|
||||
"EntityWaterExit",
|
||||
};
|
||||
|
||||
typedef struct soundlst_s
|
||||
{
|
||||
enum soundlst_type_e type;
|
||||
char *snd;
|
||||
int min; // the string length if type is group
|
||||
int max; // the string count if type is group
|
||||
} soundlst_t;
|
||||
|
||||
soundlst_t soundlst[SoundList_Groups];
|
||||
|
||||
static void SoundList_Print_f( void );
|
||||
static void SoundList_Free( soundlst_t *lst )
|
||||
{
|
||||
if( lst->snd )
|
||||
Mem_Free( lst->snd );
|
||||
|
||||
memset( lst, 0, sizeof( *lst ));
|
||||
}
|
||||
|
||||
void SoundList_Shutdown( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0; i < SoundList_Groups; i++ )
|
||||
SoundList_Free( &soundlst[i] );
|
||||
}
|
||||
|
||||
int SoundList_Count( enum soundlst_group_e group )
|
||||
{
|
||||
soundlst_t *lst = &soundlst[group];
|
||||
|
||||
switch( lst->type )
|
||||
{
|
||||
case SoundList_Range:
|
||||
return lst->max - lst->min + 1;
|
||||
case SoundList_List:
|
||||
return lst->max;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *SoundList_Get( enum soundlst_group_e group, int i )
|
||||
{
|
||||
static string temp;
|
||||
soundlst_t *lst = &soundlst[group];
|
||||
|
||||
if( i < 0 || i >= SoundList_Count( group ))
|
||||
return NULL;
|
||||
|
||||
switch( lst->type )
|
||||
{
|
||||
case SoundList_Range:
|
||||
Q_snprintf( temp, sizeof( temp ), lst->snd, lst->min + i );
|
||||
return temp;
|
||||
case SoundList_List:
|
||||
return &lst->snd[i * lst->min];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *SoundList_GetRandom( enum soundlst_group_e group )
|
||||
{
|
||||
int count = SoundList_Count( group );
|
||||
int idx = COM_RandomLong( 0, count - 1 );
|
||||
|
||||
// Con_Printf( "%s: %s %d %d\n", __func__, soundlst_groups[group], count, idx );
|
||||
|
||||
return SoundList_Get( group, idx );
|
||||
}
|
||||
|
||||
static qboolean SoundList_ParseGroup( soundlst_t *lst, char **file )
|
||||
{
|
||||
string token;
|
||||
int count = 0, slen = 0, i;
|
||||
char *p;
|
||||
|
||||
p = *file;
|
||||
|
||||
while(( p = COM_ParseFile( p, token, sizeof( token ))))
|
||||
{
|
||||
int len;
|
||||
|
||||
if( !Q_strcmp( token, "}" ))
|
||||
break;
|
||||
|
||||
if( !Q_strcmp( token, "{" ))
|
||||
{
|
||||
Con_Printf( "%s: expected '}' but got '{' during group list parse\n", __func__ );
|
||||
return false;
|
||||
}
|
||||
else if( !COM_CheckStringEmpty( token ))
|
||||
{
|
||||
Con_Printf( "%s: expected '}' but got EOF during group list parse\n", __func__ );
|
||||
return false;
|
||||
}
|
||||
|
||||
len = Q_strlen( token ) + 1;
|
||||
if( slen < len )
|
||||
slen = len;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if( count == 0 ) // deactivate group
|
||||
{
|
||||
lst->type = SoundList_None;
|
||||
lst->snd = NULL;
|
||||
lst->min = lst->max = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
lst->type = SoundList_List;
|
||||
lst->min = slen;
|
||||
lst->max = count;
|
||||
lst->snd = Mem_Malloc( host.mempool, count * slen ); // allocate single buffer for the whole group
|
||||
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
*file = COM_ParseFile( *file, token, sizeof( token ));
|
||||
|
||||
Q_strncpy( &lst->snd[i * slen], token, slen );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static qboolean SoundList_ParseRange( soundlst_t *lst, char **file )
|
||||
{
|
||||
string token, snd;
|
||||
char *p;
|
||||
int i = 0;
|
||||
|
||||
lst->type = SoundList_Range;
|
||||
*file = COM_ParseFile( *file, snd, sizeof( snd ));
|
||||
|
||||
// validate format string, count all % characters
|
||||
p = snd;
|
||||
i = 0;
|
||||
while(( p = Q_strchr( p, '%' )))
|
||||
{
|
||||
// only decimal
|
||||
if( p[1] != 'd' && p[1] != 'i' && p[1] != 'u' )
|
||||
{
|
||||
Con_Printf( "%s: invalid range string %s, only decimal numbers are allowed", __func__, snd );
|
||||
return false;
|
||||
}
|
||||
|
||||
i++;
|
||||
p++;
|
||||
}
|
||||
|
||||
// if more than one %, then it's an invalid format string
|
||||
if( i != 1 )
|
||||
{
|
||||
Con_Printf( "%s: invalid range string %s, only single specifier is allowed\n", __func__, snd );
|
||||
return false;
|
||||
}
|
||||
|
||||
*file = COM_ParseFile( *file, token, sizeof( token ));
|
||||
if( !Q_isdigit( token ))
|
||||
{
|
||||
Con_Printf( "%s: %s must be a digit\n", __func__, token );
|
||||
return false;
|
||||
}
|
||||
lst->min = Q_atoi( token );
|
||||
|
||||
*file = COM_ParseFile( *file, token, sizeof( token ));
|
||||
if( !Q_isdigit( token ))
|
||||
{
|
||||
Con_Printf( "%s: %s must be a digit\n", __func__, token );
|
||||
return false;
|
||||
}
|
||||
lst->max = Q_atoi( token );
|
||||
lst->snd = copystring( snd );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static qboolean SoundList_Parse( char *file )
|
||||
{
|
||||
string token;
|
||||
int i;
|
||||
|
||||
while(( file = COM_ParseFile( file, token, sizeof( token ))))
|
||||
{
|
||||
soundlst_t *lst = NULL;
|
||||
char *p;
|
||||
|
||||
for( i = 0; i < SoundList_Groups; i++ )
|
||||
{
|
||||
if( !Q_strcmp( token, soundlst_groups[i] ))
|
||||
{
|
||||
lst = &soundlst[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !lst )
|
||||
{
|
||||
Con_Printf( "%s: unexpected token %s, must be group name\n", __func__, token );
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
p = COM_ParseFile( file, token, sizeof( token ));
|
||||
|
||||
// group is a range
|
||||
if( !Q_strcmp( token, "{" ))
|
||||
{
|
||||
file = p; // advance pointer
|
||||
|
||||
if( !SoundList_ParseGroup( lst, &file ))
|
||||
goto cleanup;
|
||||
|
||||
file = COM_ParseFile( file, token, sizeof( token ));
|
||||
if( Q_strcmp( token, "}" ))
|
||||
{
|
||||
Con_Printf( "%s: unexpected token %s, must be }\n", __func__, token );
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ranges are more simple, but need to rewind pointer for them
|
||||
if( !SoundList_ParseRange( lst, &file ))
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if( host_developer.value >= 2 )
|
||||
SoundList_Print_f();
|
||||
|
||||
return true;
|
||||
|
||||
cleanup:
|
||||
SoundList_Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
static void SoundList_Print_f( void )
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0; i < SoundList_Groups; i++ )
|
||||
{
|
||||
soundlst_t *lst = &soundlst[i];
|
||||
|
||||
switch( lst->type )
|
||||
{
|
||||
case SoundList_Range:
|
||||
Con_Reportf( "%-16s\t" S_CYAN "Range" S_DEFAULT " %s [%d; %d]\n",
|
||||
soundlst_groups[i], lst->snd, lst->min, lst->max );
|
||||
break;
|
||||
case SoundList_List:
|
||||
{
|
||||
int j;
|
||||
|
||||
Con_Reportf( "%-16s\t" S_MAGENTA "List" S_DEFAULT " [", soundlst_groups[i] );
|
||||
for( j = 0; j < lst->max; j++ )
|
||||
Con_Reportf( "%s%s", &lst->snd[j * lst->min], j + 1 == lst->max ? "" : ", " );
|
||||
Con_Reportf( "]\n" );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Con_Reportf( "%-16s\t" S_RED "inactive" S_DEFAULT "\n", soundlst_groups[i] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// I wish we had #embed already
|
||||
static const char default_sounds_lst[] =
|
||||
"BouncePlayerShell \"player/pl_shell%d.wav\" 1 3\n"
|
||||
"BounceWeaponShell \"weapons/sshell%d.wav\" 1 3\n"
|
||||
"BounceConcrete \"debris/concrete%d.wav\" 1 3\n"
|
||||
"BounceGlass \"debris/glass%d.wav\" 1 4\n"
|
||||
"BounceMetal \"debris/metal%d.wav\" 1 6\n"
|
||||
"BounceFlesh \"debris/flesh%d.wav\" 1 7\n"
|
||||
"BounceWood \"debris/wood%d.wav\" 1 4\n"
|
||||
"Ricochet \"weapons/ric%d.wav\" 1 5\n"
|
||||
"Explode \"weapons/explode%d.wav\" 3 5\n"
|
||||
"EntityWaterEnter \"player/pl_wade%d.wav\" 1 4\n"
|
||||
"EntityWaterExit \"player/pl_wade%d.wav\" 1 4\n"
|
||||
"PlayerWaterEnter\n"
|
||||
"{\n"
|
||||
" \"player/pl_wade1.wav\"\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"PlayerWaterExit\n"
|
||||
"{\n"
|
||||
" \"player/pl_wade2.wav\"\n"
|
||||
"}\n";
|
||||
|
||||
static void SoundList_Reload_f( void )
|
||||
{
|
||||
qboolean load_internal = false;
|
||||
char *pfile = FS_LoadFile( "scripts/sounds.lst", NULL, false );
|
||||
|
||||
if( pfile )
|
||||
{
|
||||
if( !SoundList_Parse( pfile ))
|
||||
{
|
||||
Con_Printf( S_ERROR "can't parse sounds.lst file, loading internal...\n" );
|
||||
load_internal = true;
|
||||
}
|
||||
|
||||
Mem_Free( pfile );
|
||||
}
|
||||
else load_internal = true;
|
||||
|
||||
if( load_internal )
|
||||
SoundList_Parse( (char *)default_sounds_lst );
|
||||
}
|
||||
|
||||
void SoundList_Init( void )
|
||||
{
|
||||
Cmd_AddRestrictedCommand( "host_soundlist_print", SoundList_Print_f, "print current sound list" );
|
||||
Cmd_AddRestrictedCommand( "host_soundlist_reload", SoundList_Reload_f, "reload sound list" );
|
||||
|
||||
SoundList_Reload_f ();
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -93,123 +93,241 @@ static mempool_t *Mem_FindPool( poolhandle_t poolptr )
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void Mem_PoolAdd( mempool_t *pool, size_t size )
|
||||
{
|
||||
pool->totalsize += size;
|
||||
pool->realsize += sizeof( memheader_t ) + size + sizeof( byte );
|
||||
}
|
||||
|
||||
static inline void Mem_PoolSubtract( mempool_t *pool, size_t size )
|
||||
{
|
||||
pool->totalsize -= size;
|
||||
pool->realsize -= sizeof( memheader_t ) + size + sizeof( byte );
|
||||
}
|
||||
|
||||
static inline void Mem_PoolLinkAlloc( mempool_t *pool, memheader_t *mem )
|
||||
{
|
||||
mem->next = pool->chain;
|
||||
if( mem->next ) mem->next->prev = mem;
|
||||
pool->chain = mem;
|
||||
mem->prev = NULL;
|
||||
mem->pool = pool;
|
||||
}
|
||||
|
||||
static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
|
||||
{
|
||||
if( mem->next ) mem->next->prev = mem->prev;
|
||||
if( mem->prev ) mem->prev->next = mem->next;
|
||||
else pool->chain = mem->next;
|
||||
mem->pool = NULL;
|
||||
}
|
||||
|
||||
static inline void Mem_InitAlloc( memheader_t *mem, size_t size, const char *filename, int fileline )
|
||||
{
|
||||
mem->size = size;
|
||||
mem->filename = filename;
|
||||
mem->fileline = fileline;
|
||||
mem->sentinel1 = MEMHEADER_SENTINEL1;
|
||||
*((byte *)mem + sizeof( memheader_t ) + mem->size ) = MEMHEADER_SENTINEL2;
|
||||
}
|
||||
|
||||
static const char *Mem_CheckFilename( const char *filename )
|
||||
{
|
||||
static const char *dummy = "<corrupted>\0";
|
||||
|
||||
if( !COM_CheckString( filename ))
|
||||
return dummy;
|
||||
|
||||
if( memchr( filename, '\0', MAX_OSPATH ) != NULL )
|
||||
return filename;
|
||||
|
||||
return dummy;
|
||||
}
|
||||
|
||||
static qboolean Mem_CheckAllocHeader( const char *func, const memheader_t *mem, const char *filename, int fileline )
|
||||
{
|
||||
const char *memfilename;
|
||||
|
||||
if( mem->sentinel1 != MEMHEADER_SENTINEL1 )
|
||||
{
|
||||
memfilename = Mem_CheckFilename( mem->filename );
|
||||
Sys_Error( "%s: trashed header sentinel 1 (alloc at %s:%i, check at %s:%i)\n", func, memfilename, mem->fileline, filename, fileline );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( *((byte *)mem + sizeof( memheader_t ) + mem->size ) != MEMHEADER_SENTINEL2 )
|
||||
{
|
||||
memfilename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
|
||||
Sys_Error( "%s: trashed header sentinel 2 (alloc at %s:%i, check at %s:%i)\n", func, memfilename, mem->fileline, filename, fileline );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static qboolean Mem_CheckPool( const char *func, const mempool_t *pool, const char *filename, int fileline )
|
||||
{
|
||||
if( pool->sentinel1 != MEMHEADER_SENTINEL1 )
|
||||
{
|
||||
Sys_Error( "%s: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)\n", func, pool->filename, pool->fileline, filename, fileline );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( pool->sentinel2 != MEMHEADER_SENTINEL1 )
|
||||
{
|
||||
Sys_Error( "%s: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)\n", func, pool->filename, pool->fileline, filename, fileline );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
|
||||
{
|
||||
memheader_t *mem;
|
||||
mempool_t *pool;
|
||||
|
||||
if( size <= 0 ) return NULL;
|
||||
if( !poolptr ) Sys_Error( "Mem_Alloc: pool == NULL (alloc at %s:%i)\n", filename, fileline );
|
||||
if( size <= 0 )
|
||||
return NULL;
|
||||
|
||||
if( !poolptr )
|
||||
{
|
||||
Sys_Error( "%s: pool == NULL (alloc at %s:%i)\n", __func__, filename, fileline );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( byte ));
|
||||
if( mem == NULL )
|
||||
{
|
||||
Sys_Error( "%s: out of memory (alloc size %s at %s:%i)\n", __func__, Q_memprint( size ), filename, fileline );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Mem_InitAlloc( mem, size, filename, fileline );
|
||||
|
||||
pool = Mem_FindPool( poolptr );
|
||||
Mem_PoolAdd( pool, size );
|
||||
Mem_PoolLinkAlloc( pool, mem );
|
||||
|
||||
pool->totalsize += size;
|
||||
|
||||
// big allocations are not clumped
|
||||
pool->realsize += sizeof( memheader_t ) + size + sizeof( size_t );
|
||||
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( size_t ));
|
||||
if( mem == NULL ) Sys_Error( "Mem_Alloc: out of memory (alloc at %s:%i)\n", filename, fileline );
|
||||
|
||||
mem->filename = filename;
|
||||
mem->fileline = fileline;
|
||||
mem->size = size;
|
||||
mem->pool = pool;
|
||||
mem->sentinel1 = MEMHEADER_SENTINEL1;
|
||||
// we have to use only a single byte for this sentinel, because it may not be aligned
|
||||
// and some platforms can't use unaligned accesses
|
||||
*((byte *)mem + sizeof( memheader_t ) + mem->size ) = MEMHEADER_SENTINEL2;
|
||||
// append to head of list
|
||||
mem->next = pool->chain;
|
||||
mem->prev = NULL;
|
||||
pool->chain = mem;
|
||||
if( mem->next ) mem->next->prev = mem;
|
||||
if( clear )
|
||||
memset((void *)((byte *)mem + sizeof( memheader_t )), 0, mem->size );
|
||||
|
||||
return (void *)((byte *)mem + sizeof( memheader_t ));
|
||||
}
|
||||
|
||||
static const char *Mem_CheckFilename( const char *filename )
|
||||
{
|
||||
static const char *dummy = "<corrupted>\0";
|
||||
const char *out = filename;
|
||||
int i;
|
||||
|
||||
if( !COM_CheckString( out ))
|
||||
return dummy;
|
||||
|
||||
for( i = 0; i < MAX_OSPATH; i++, out++ )
|
||||
{
|
||||
if( *out == '\0' )
|
||||
return filename; // valid name
|
||||
}
|
||||
|
||||
return dummy;
|
||||
}
|
||||
|
||||
static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline )
|
||||
{
|
||||
mempool_t *pool;
|
||||
|
||||
if( mem->sentinel1 != MEMHEADER_SENTINEL1 )
|
||||
{
|
||||
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
|
||||
Sys_Error( "Mem_Free: trashed header sentinel 1 (alloc at %s:%i, free at %s:%i)\n", mem->filename, mem->fileline, filename, fileline );
|
||||
}
|
||||
|
||||
if( *((byte *)mem + sizeof( memheader_t ) + mem->size ) != MEMHEADER_SENTINEL2 )
|
||||
{
|
||||
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
|
||||
Sys_Error( "Mem_Free: trashed header sentinel 2 (alloc at %s:%i, free at %s:%i)\n", mem->filename, mem->fileline, filename, fileline );
|
||||
}
|
||||
if( !Mem_CheckAllocHeader( __func__, mem, filename, fileline ))
|
||||
return;
|
||||
|
||||
pool = mem->pool;
|
||||
|
||||
// unlink memheader from doubly linked list
|
||||
if(( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem ))
|
||||
Sys_Error( "Mem_Free: not allocated or double freed (free at %s:%i)\n", filename, fileline );
|
||||
{
|
||||
Sys_Error( "%s: not allocated or double freed (free at %s:%i)\n", __func__, filename, fileline );
|
||||
return;
|
||||
}
|
||||
|
||||
if( mem->prev ) mem->prev->next = mem->next;
|
||||
else pool->chain = mem->next;
|
||||
Mem_PoolSubtract( pool, mem->size );
|
||||
Mem_PoolUnlinkAlloc( pool, mem );
|
||||
|
||||
if( mem->next )
|
||||
mem->next->prev = mem->prev;
|
||||
|
||||
// memheader has been unlinked, do the actual free now
|
||||
pool->totalsize -= mem->size;
|
||||
|
||||
pool->realsize -= sizeof( memheader_t ) + mem->size + sizeof( size_t );
|
||||
Q_free( mem );
|
||||
}
|
||||
|
||||
void _Mem_Free( void *data, const char *filename, int fileline )
|
||||
{
|
||||
if( data == NULL ) Sys_Error( "Mem_Free: data == NULL (called at %s:%i)\n", filename, fileline );
|
||||
if( data == NULL )
|
||||
{
|
||||
Sys_Error( "Mem_Free: data == NULL (called at %s:%i)\n", filename, fileline );
|
||||
return;
|
||||
}
|
||||
|
||||
Mem_FreeBlock((memheader_t *)((byte *)data - sizeof( memheader_t )), filename, fileline );
|
||||
}
|
||||
|
||||
void *_Mem_Realloc( poolhandle_t poolptr, void *memptr, size_t size, qboolean clear, const char *filename, int fileline )
|
||||
void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clear, const char *filename, int fileline )
|
||||
{
|
||||
memheader_t *memhdr = NULL;
|
||||
char *nb;
|
||||
memheader_t *mem;
|
||||
uintptr_t oldmem;
|
||||
mempool_t *pool;
|
||||
size_t oldsize;
|
||||
|
||||
if( size <= 0 ) return memptr; // no need to reallocate
|
||||
if( size <= 0 )
|
||||
return data; // no need to reallocate
|
||||
|
||||
if( memptr )
|
||||
if( !poolptr )
|
||||
{
|
||||
memhdr = (memheader_t *)((byte *)memptr - sizeof( memheader_t ));
|
||||
if( size == memhdr->size ) return memptr;
|
||||
Sys_Error( "Mem_Realloc: pool == NULL (alloc at %s:%i)\n", filename, fileline );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nb = _Mem_Alloc( poolptr, size, clear, filename, fileline );
|
||||
if( !data )
|
||||
return _Mem_Alloc( poolptr, size, clear, filename, fileline );
|
||||
|
||||
if( memptr ) // first allocate?
|
||||
mem = (memheader_t *)((byte *)data - sizeof( memheader_t ));
|
||||
|
||||
if( !Mem_CheckAllocHeader( "Mem_Realloc", mem, filename, fileline ))
|
||||
return NULL;
|
||||
|
||||
oldsize = mem->size;
|
||||
if( size == oldsize )
|
||||
return data;
|
||||
|
||||
#if XASH_CUSTOM_SWAP
|
||||
{
|
||||
size_t newsize = memhdr->size < size ? memhdr->size : size; // upper data can be trucnated!
|
||||
memcpy( nb, memptr, newsize );
|
||||
_Mem_Free( memptr, filename, fileline ); // free unused old block
|
||||
char *nb = _Mem_Alloc( poolptr, size, clear, filename, fileline );
|
||||
|
||||
size_t newsize = mem->size < size ? mem->size : size; // upper data can be trucnated!
|
||||
memcpy( nb, data, newsize );
|
||||
_Mem_Free( data, filename, fileline ); // free unused old block
|
||||
|
||||
return nb;
|
||||
}
|
||||
#else // XASH_CUSTOM_SWAP
|
||||
pool = Mem_FindPool( poolptr );
|
||||
|
||||
oldmem = (uintptr_t)mem;
|
||||
mem = realloc( mem, sizeof( memheader_t ) + size + sizeof( byte ));
|
||||
|
||||
if( mem == NULL )
|
||||
{
|
||||
Sys_Error( "Mem_Realloc: out of memory (alloc size %s at %s:%i)\n", Q_memprint( size ), filename, fileline );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (void *)nb;
|
||||
// Con_Printf( S_NOTE "%s: mem %s oldmem, size before %zu now %zu (alloc at %s:%i)\n",
|
||||
// __func__, (uintptr_t)mem != oldmem ? "!=" : "==", oldsize, size, filename, fileline );
|
||||
|
||||
Mem_InitAlloc( mem, size, filename, fileline );
|
||||
|
||||
if( size > oldsize )
|
||||
{
|
||||
Mem_PoolAdd( pool, size - oldsize );
|
||||
|
||||
if( clear )
|
||||
memset((byte *)mem + sizeof( memheader_t ) + oldsize, 0, size - oldsize );
|
||||
}
|
||||
else Mem_PoolSubtract( pool, oldsize - size );
|
||||
|
||||
// if allocation was migrated from one pool to another
|
||||
// (this is possible with original Mem_Realloc func)
|
||||
if( unlikely( mem->pool != pool ))
|
||||
{
|
||||
Mem_PoolUnlinkAlloc( mem->pool, mem );
|
||||
Mem_PoolLinkAlloc( pool, mem );
|
||||
}
|
||||
else if( oldmem != (uintptr_t)mem ) // just relink pointers
|
||||
{
|
||||
if( mem->next ) mem->next->prev = mem;
|
||||
if( mem->prev ) mem->prev->next = mem;
|
||||
else pool->chain = mem;
|
||||
}
|
||||
|
||||
return (void *)((byte *)mem + sizeof( memheader_t ));
|
||||
#endif // XASH_CUSTOM_SWAP
|
||||
}
|
||||
|
||||
poolhandle_t _Mem_AllocPool( const char *name, const char *filename, int fileline )
|
||||
@@ -254,8 +372,7 @@ void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline )
|
||||
// unlink pool from chain
|
||||
for( chainaddress = &poolchain; *chainaddress && *chainaddress != pool; chainaddress = &((*chainaddress)->next));
|
||||
if( *chainaddress != pool ) Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline );
|
||||
if( pool->sentinel1 != MEMHEADER_SENTINEL1 ) Sys_Error( "Mem_FreePool: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
|
||||
if( pool->sentinel2 != MEMHEADER_SENTINEL1 ) Sys_Error( "Mem_FreePool: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
|
||||
Mem_CheckPool( "Mem_FreePool", pool, filename, fileline );
|
||||
*chainaddress = pool->next;
|
||||
|
||||
// free memory owned by the pool
|
||||
@@ -272,8 +389,7 @@ void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline )
|
||||
mempool_t *pool = Mem_FindPool( poolptr );
|
||||
if( !poolptr ) Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
|
||||
|
||||
if( pool->sentinel1 != MEMHEADER_SENTINEL1 ) Sys_Error( "Mem_EmptyPool: trashed pool sentinel 1 (allocpool at %s:%i, emptypool at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
|
||||
if( pool->sentinel2 != MEMHEADER_SENTINEL1 ) Sys_Error( "Mem_EmptyPool: trashed pool sentinel 2 (allocpool at %s:%i, emptypool at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
|
||||
Mem_CheckPool( "Mem_FreePool", pool, filename, fileline );
|
||||
|
||||
// free memory owned by the pool
|
||||
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
|
||||
@@ -288,14 +404,19 @@ static qboolean Mem_CheckAlloc( mempool_t *pool, void *data )
|
||||
// search only one pool
|
||||
target = (memheader_t *)((byte *)data - sizeof( memheader_t ));
|
||||
for( header = pool->chain; header; header = header->next )
|
||||
if( header == target ) return true;
|
||||
{
|
||||
if( header == target )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// search all pools
|
||||
for( pool = poolchain; pool; pool = pool->next )
|
||||
{
|
||||
if( Mem_CheckAlloc( pool, data ))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -308,49 +429,24 @@ Check pointer for memory
|
||||
qboolean Mem_IsAllocatedExt( poolhandle_t poolptr, void *data )
|
||||
{
|
||||
mempool_t *pool = NULL;
|
||||
if( poolptr ) pool = Mem_FindPool( poolptr );
|
||||
|
||||
if( poolptr )
|
||||
pool = Mem_FindPool( poolptr );
|
||||
|
||||
return Mem_CheckAlloc( pool, data );
|
||||
}
|
||||
|
||||
static void Mem_CheckHeaderSentinels( void *data, const char *filename, int fileline )
|
||||
{
|
||||
memheader_t *mem;
|
||||
|
||||
if( data == NULL )
|
||||
Sys_Error( "Mem_CheckSentinels: data == NULL (sentinel check at %s:%i)\n", filename, fileline );
|
||||
|
||||
mem = (memheader_t *)((byte *) data - sizeof(memheader_t));
|
||||
|
||||
if( mem->sentinel1 != MEMHEADER_SENTINEL1 )
|
||||
{
|
||||
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
|
||||
Sys_Error( "Mem_CheckSentinels: trashed header sentinel 1 (block allocated at %s:%i, sentinel check at %s:%i)\n", mem->filename, mem->fileline, filename, fileline );
|
||||
}
|
||||
|
||||
if( *((byte *)mem + sizeof(memheader_t) + mem->size) != MEMHEADER_SENTINEL2 )
|
||||
{
|
||||
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
|
||||
Sys_Error( "Mem_CheckSentinels: trashed header sentinel 2 (block allocated at %s:%i, sentinel check at %s:%i)\n", mem->filename, mem->fileline, filename, fileline );
|
||||
}
|
||||
}
|
||||
|
||||
void _Mem_Check( const char *filename, int fileline )
|
||||
{
|
||||
memheader_t *mem;
|
||||
mempool_t *pool;
|
||||
|
||||
for( pool = poolchain; pool; pool = pool->next )
|
||||
{
|
||||
if( pool->sentinel1 != MEMHEADER_SENTINEL1 )
|
||||
Sys_Error( "Mem_CheckSentinelsGlobal: trashed pool sentinel 1 (allocpool at %s:%i, sentinel check at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
|
||||
if( pool->sentinel2 != MEMHEADER_SENTINEL1 )
|
||||
Sys_Error( "Mem_CheckSentinelsGlobal: trashed pool sentinel 2 (allocpool at %s:%i, sentinel check at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
|
||||
}
|
||||
Mem_CheckPool( "Mem_CheckSentinels", pool, filename, fileline );
|
||||
|
||||
for( pool = poolchain; pool; pool = pool->next )
|
||||
for( mem = pool->chain; mem; mem = mem->next )
|
||||
Mem_CheckHeaderSentinels((void *)((byte *) mem + sizeof(memheader_t)), filename, fileline );
|
||||
Mem_CheckAllocHeader( "Mem_CheckSentinels", mem, filename, fileline );
|
||||
}
|
||||
|
||||
void Mem_PrintStats( void )
|
||||
@@ -377,28 +473,31 @@ void Mem_PrintList( size_t minallocationsize )
|
||||
|
||||
Mem_Check();
|
||||
|
||||
Con_Printf( "memory pool list:\n"" ^3size name\n");
|
||||
Con_Printf( "memory pool list:\n" );
|
||||
Con_Printf( "\t^3size\t\t\t\tname\n");
|
||||
for( pool = poolchain; pool; pool = pool->next )
|
||||
{
|
||||
long changed_size = (long)pool->totalsize - (long)pool->lastchecksize;
|
||||
|
||||
// poolnames can contain color symbols, make sure what color is reset
|
||||
if( changed_size != 0 )
|
||||
if( pool->lastchecksize != 0 && changed_size != 0 )
|
||||
{
|
||||
char sign = (changed_size < 0) ? '-' : '+';
|
||||
|
||||
Con_Printf( "%10s (%10s actual) %s (^7%c%s change)\n", Q_memprint( pool->totalsize ), Q_memprint( pool->realsize ),
|
||||
pool->name, sign, Q_memprint( abs( changed_size )));
|
||||
Con_Printf( "%10s (%10s real)\t%s (^7%c%s change)\n", Q_memprint( pool->totalsize ), Q_memprint( pool->realsize ),
|
||||
pool->name, sign, Q_memprint( abs( changed_size )));
|
||||
}
|
||||
else
|
||||
{
|
||||
Con_Printf( "%5s (%5s actual) %s\n", Q_memprint( pool->totalsize ), Q_memprint( pool->realsize ), pool->name );
|
||||
Con_Printf( "%10s (%10s real)\t%s\n", Q_memprint( pool->totalsize ), Q_memprint( pool->realsize ), pool->name );
|
||||
}
|
||||
|
||||
pool->lastchecksize = pool->totalsize;
|
||||
for( mem = pool->chain; mem; mem = mem->next )
|
||||
{
|
||||
if( mem->size >= minallocationsize )
|
||||
Con_Printf( "%10s allocated at %s:%i\n", Q_memprint( mem->size ), mem->filename, mem->fileline );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -215,6 +215,7 @@ typedef struct ui_extendedfuncs_s {
|
||||
// network address funcs
|
||||
const char *(*pfnAdrToString)( const struct netadr_s a );
|
||||
int (*pfnCompareAdr)( const void *a, const void *b ); // netadr_t
|
||||
void *(*pfnGetNativeObject)( const char *name );
|
||||
} ui_extendedfuncs_t;
|
||||
|
||||
// deprecated export from old engine
|
||||
|
||||
@@ -2,15 +2,30 @@
|
||||
mobility_int.h - interface between engine and client for mobile platforms
|
||||
Copyright (C) 2015 a1batross
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -107,7 +107,10 @@ typedef struct server_physics_api_s
|
||||
int (*pfnSaveFile)( const char *filename, const void *data, int len );
|
||||
const byte *(*pfnLoadImagePixels)( const char *filename, int *width, int *height );
|
||||
|
||||
const char* (*pfnGetModelName)( int modelindex );
|
||||
const char *(*pfnGetModelName)( int modelindex );
|
||||
|
||||
// FWGS extension
|
||||
void *(*pfnGetNativeObject)( const char *object );
|
||||
} server_physics_api_t;
|
||||
|
||||
// physic callbacks
|
||||
|
||||
@@ -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"
|
||||
@@ -61,23 +61,16 @@ Android_GetNativeObject
|
||||
|
||||
void *Android_GetNativeObject( const char *name )
|
||||
{
|
||||
static const char *availObjects[] = { "JNIEnv", "ActivityClass", NULL };
|
||||
void *object = NULL;
|
||||
|
||||
if( !name )
|
||||
if( !strcasecmp( name, "JNIEnv" ) )
|
||||
{
|
||||
object = (void *)availObjects;
|
||||
}
|
||||
else if( !strcasecmp( name, "JNIEnv" ) )
|
||||
{
|
||||
object = (void *)jni.env;
|
||||
return (void *)jni.env;
|
||||
}
|
||||
else if( !strcasecmp( name, "ActivityClass" ) )
|
||||
{
|
||||
object = (void *)jni.actcls;
|
||||
return (void *)jni.actcls;
|
||||
}
|
||||
|
||||
return object;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
1064
engine/platform/android/android_nosdl.c
Normal file
1064
engine/platform/android/android_nosdl.c
Normal file
File diff suppressed because it is too large
Load Diff
55
engine/platform/android/android_priv.h
Normal file
55
engine/platform/android/android_priv.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
#ifndef ANDROID_PRIV_H
|
||||
#define ANDROID_PRIV_H
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <android/log.h>
|
||||
#include <jni.h>
|
||||
|
||||
extern struct jnimethods_s
|
||||
{
|
||||
jclass actcls;
|
||||
jclass bindcls;
|
||||
JavaVM *vm;
|
||||
JNIEnv *env;
|
||||
jmethodID enableTextInput;
|
||||
jmethodID vibrate;
|
||||
jmethodID messageBox;
|
||||
jmethodID notify;
|
||||
jmethodID setTitle;
|
||||
jmethodID setIcon;
|
||||
jmethodID getAndroidId;
|
||||
jmethodID saveID;
|
||||
jmethodID loadID;
|
||||
jmethodID showMouse;
|
||||
jmethodID shellExecute;
|
||||
jmethodID swapBuffers;
|
||||
jmethodID toggleEGL;
|
||||
jmethodID createGLContext;
|
||||
jmethodID getGLAttribute;
|
||||
jmethodID deleteGLContext;
|
||||
jmethodID getSurface;
|
||||
jmethodID preShutdown;
|
||||
int width, height;
|
||||
} jni;
|
||||
|
||||
typedef enum surfacestate_e
|
||||
{
|
||||
surface_pause,
|
||||
surface_active,
|
||||
surface_dummy,
|
||||
|
||||
} surfacestate_t;
|
||||
|
||||
|
||||
extern struct jnimouse_s
|
||||
{
|
||||
float x, y;
|
||||
} jnimouse;
|
||||
|
||||
//
|
||||
// vid_android.c
|
||||
//
|
||||
void Android_UpdateSurface( surfacestate_t state );
|
||||
|
||||
#endif // ANDROID_PRIV_H
|
||||
@@ -25,30 +25,36 @@
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* 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
|
||||
|
||||
453
engine/platform/android/eglutil.c
Normal file
453
engine/platform/android/eglutil.c
Normal file
@@ -0,0 +1,453 @@
|
||||
/*
|
||||
eglutil.c - EGL context utility
|
||||
Copyright (C) 2023 mittorn
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "platform/platform.h"
|
||||
#if !defined(XASH_DEDICATED) && !XASH_SDL
|
||||
#include "eglutil.h"
|
||||
#include "client.h"
|
||||
#include "vid_common.h"
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
struct eglapi_s egl;
|
||||
|
||||
#undef GetProcAddress // windows.h?
|
||||
#define EGL_FF(x) {"egl"#x, (void*)&egl.x}
|
||||
static dllfunc_t egl_funcs[] =
|
||||
{
|
||||
EGL_FF(SwapInterval),
|
||||
EGL_FF(SwapBuffers),
|
||||
EGL_FF(GetError),
|
||||
EGL_FF(GetCurrentDisplay),
|
||||
EGL_FF(GetCurrentSurface),
|
||||
EGL_FF(GetProcAddress),
|
||||
EGL_FF(GetConfigAttrib),
|
||||
EGL_FF(GetDisplay),
|
||||
EGL_FF(Initialize),
|
||||
EGL_FF(Terminate),
|
||||
EGL_FF(QueryString),
|
||||
EGL_FF(ChooseConfig),
|
||||
EGL_FF(CreateWindowSurface),
|
||||
EGL_FF(CreateContext),
|
||||
EGL_FF(DestroyContext),
|
||||
EGL_FF(MakeCurrent),
|
||||
EGL_FF(BindAPI),
|
||||
EGL_FF(DestroySurface),
|
||||
{ NULL, NULL }
|
||||
};
|
||||
#undef EGL_FF
|
||||
static dll_info_t egl_info = { "libEGL.so", egl_funcs, false };
|
||||
|
||||
struct eglstate_s eglstate;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
===================
|
||||
|
||||
refapi/egl wrappers
|
||||
|
||||
===================
|
||||
*/
|
||||
|
||||
int EGL_SetAttribute( int attr, int val )
|
||||
{
|
||||
if( attr < 0 || attr >= REF_GL_ATTRIBUTES_COUNT )
|
||||
return -1;
|
||||
|
||||
eglstate.gl_attribs[attr] = val;
|
||||
eglstate.gl_attribs_set[attr] = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define COPY_ATTR_IF_SET( refattr, attr ) \
|
||||
if( eglstate.gl_attribs_set[refattr] ) \
|
||||
{ \
|
||||
attribs[i++] = attr; \
|
||||
attribs[i++] = eglstate.gl_attribs[refattr]; \
|
||||
}
|
||||
|
||||
size_t EGL_GenerateConfig( EGLint *attribs, size_t size )
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
memset( attribs, 0, size * sizeof( EGLint ) );
|
||||
eglstate.gles1 = false;
|
||||
memset( eglstate.gl_attribs, 0, sizeof( eglstate.gl_attribs ));
|
||||
memset( eglstate.gl_attribs_set, 0, sizeof( eglstate.gl_attribs_set ));
|
||||
|
||||
// refdll can request some attributes
|
||||
ref.dllFuncs.GL_SetupAttributes( glw_state.safe );
|
||||
|
||||
COPY_ATTR_IF_SET( REF_GL_RED_SIZE, EGL_RED_SIZE );
|
||||
COPY_ATTR_IF_SET( REF_GL_GREEN_SIZE, EGL_GREEN_SIZE );
|
||||
COPY_ATTR_IF_SET( REF_GL_BLUE_SIZE, EGL_BLUE_SIZE );
|
||||
COPY_ATTR_IF_SET( REF_GL_ALPHA_SIZE, EGL_ALPHA_SIZE );
|
||||
COPY_ATTR_IF_SET( REF_GL_DEPTH_SIZE, EGL_DEPTH_SIZE );
|
||||
COPY_ATTR_IF_SET( REF_GL_STENCIL_SIZE, EGL_STENCIL_SIZE );
|
||||
COPY_ATTR_IF_SET( REF_GL_MULTISAMPLEBUFFERS, EGL_SAMPLE_BUFFERS );
|
||||
COPY_ATTR_IF_SET( REF_GL_MULTISAMPLESAMPLES, EGL_SAMPLES );
|
||||
|
||||
if( eglstate.gl_attribs_set[REF_GL_ACCELERATED_VISUAL] )
|
||||
{
|
||||
attribs[i++] = EGL_CONFIG_CAVEAT;
|
||||
attribs[i++] = eglstate.gl_attribs[REF_GL_ACCELERATED_VISUAL] ? EGL_NONE : EGL_DONT_CARE;
|
||||
}
|
||||
|
||||
// BigGL support
|
||||
attribs[i++] = EGL_RENDERABLE_TYPE;
|
||||
eglstate.gl_api = EGL_OPENGL_ES_API;
|
||||
|
||||
if( eglstate.gl_attribs_set[REF_GL_CONTEXT_PROFILE_MASK] &&
|
||||
!( eglstate.gl_attribs[REF_GL_CONTEXT_PROFILE_MASK] & REF_GL_CONTEXT_PROFILE_ES ))
|
||||
{
|
||||
attribs[i++] = EGL_OPENGL_BIT;
|
||||
eglstate.gl_api = EGL_OPENGL_API;
|
||||
}
|
||||
else if( eglstate.gl_attribs_set[REF_GL_CONTEXT_MAJOR_VERSION] &&
|
||||
eglstate.gl_attribs[REF_GL_CONTEXT_MAJOR_VERSION] >= 2 )
|
||||
{
|
||||
attribs[i++] = EGL_OPENGL_ES2_BIT;
|
||||
}
|
||||
else
|
||||
{
|
||||
i--; // erase EGL_RENDERABLE_TYPE
|
||||
eglstate.gles1 = true;
|
||||
}
|
||||
|
||||
attribs[i++] = EGL_NONE;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
size_t EGL_GenerateContextConfig( EGLint *attribs, size_t size )
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
memset( attribs, 0, size * sizeof( EGLint ));
|
||||
|
||||
if( Q_strstr( eglstate.extensions, "EGL_KHR_create_context") )
|
||||
{
|
||||
Con_DPrintf( S_NOTE "EGL_KHR_create_context found, setting additional context flags\n");
|
||||
|
||||
if( eglstate.gl_attribs_set[REF_GL_CONTEXT_FLAGS] )
|
||||
{
|
||||
attribs[i++] = 0x30FC; // EGL_CONTEXT_FLAGS_KHR
|
||||
attribs[i++] = eglstate.gl_attribs[REF_GL_CONTEXT_FLAGS] & ((REF_GL_CONTEXT_ROBUST_ACCESS_FLAG << 1) - 1);
|
||||
}
|
||||
|
||||
if( eglstate.gl_attribs_set[REF_GL_CONTEXT_PROFILE_MASK] )
|
||||
{
|
||||
int val = eglstate.gl_attribs[REF_GL_CONTEXT_PROFILE_MASK];
|
||||
|
||||
if( val & ( (REF_GL_CONTEXT_PROFILE_COMPATIBILITY << 1) - 1 ) )
|
||||
{
|
||||
attribs[i++] = 0x30FD; // EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
|
||||
attribs[i++] = val;
|
||||
}
|
||||
}
|
||||
|
||||
COPY_ATTR_IF_SET( REF_GL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_CLIENT_VERSION );
|
||||
COPY_ATTR_IF_SET( REF_GL_CONTEXT_MINOR_VERSION, 0x30FB );
|
||||
}
|
||||
else
|
||||
{
|
||||
// without extension we can set only major version
|
||||
COPY_ATTR_IF_SET( REF_GL_CONTEXT_MAJOR_VERSION, EGL_CONTEXT_CLIENT_VERSION );
|
||||
if( eglstate.gl_attribs_set[REF_GL_CONTEXT_FLAGS] && (eglstate.gl_attribs[REF_GL_CONTEXT_FLAGS] & REF_GL_CONTEXT_DEBUG_FLAG ))
|
||||
{
|
||||
attribs[i++] = 0x31B0; // EGL_CONTEXT_OPENGL_DEBUG;
|
||||
attribs[i++] = EGL_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
attribs[i++] = EGL_NONE;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
=========================
|
||||
EGL_GetAttribute
|
||||
|
||||
query
|
||||
=========================
|
||||
*/
|
||||
int EGL_GetAttribute( int attr, int *val )
|
||||
{
|
||||
EGLBoolean ret;
|
||||
|
||||
if( attr < 0 || attr >= REF_GL_ATTRIBUTES_COUNT )
|
||||
return -1;
|
||||
|
||||
if( !val )
|
||||
return -1;
|
||||
|
||||
switch( attr )
|
||||
{
|
||||
case REF_GL_RED_SIZE:
|
||||
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_RED_SIZE, val );
|
||||
return 0;
|
||||
case REF_GL_GREEN_SIZE:
|
||||
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_GREEN_SIZE, val );
|
||||
return 0;
|
||||
case REF_GL_BLUE_SIZE:
|
||||
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_BLUE_SIZE, val );
|
||||
return 0;
|
||||
case REF_GL_ALPHA_SIZE:
|
||||
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_ALPHA_SIZE, val );
|
||||
return 0;
|
||||
case REF_GL_DEPTH_SIZE:
|
||||
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_DEPTH_SIZE, val );
|
||||
return 0;
|
||||
case REF_GL_STENCIL_SIZE:
|
||||
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_STENCIL_SIZE, val );
|
||||
return 0;
|
||||
case REF_GL_MULTISAMPLESAMPLES:
|
||||
ret = egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_SAMPLES, val );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=========================
|
||||
EGL_UpdateSurface
|
||||
|
||||
destroy old surface, recreate and make context current
|
||||
must be called with valid context
|
||||
=========================
|
||||
*/
|
||||
qboolean EGL_UpdateSurface( void *window, qboolean dummy )
|
||||
{
|
||||
if( !eglstate.valid )
|
||||
return false;
|
||||
|
||||
egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
|
||||
host.status = HOST_SLEEP;
|
||||
|
||||
if( eglstate.surface )
|
||||
{
|
||||
egl.DestroySurface( eglstate.dpy, eglstate.surface );
|
||||
eglstate.surface = EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
if( !window )
|
||||
{
|
||||
|
||||
if( dummy && eglstate.support_surfaceless_context )
|
||||
{
|
||||
if( egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, eglstate.context ))
|
||||
{
|
||||
Con_Reportf( S_NOTE "EGL_UpdateSurface: using surfaceless mode\n" );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
|
||||
eglstate.support_surfaceless_context = false;
|
||||
}
|
||||
Con_Reportf( S_NOTE "EGL_UpdateSurface: missing native window, detaching context\n" );
|
||||
}
|
||||
|
||||
return false; // let platform fallback to dummy surface or pause engine
|
||||
}
|
||||
|
||||
if(( eglstate.surface = egl.CreateWindowSurface( eglstate.dpy, eglstate.cfg, window, NULL )) == EGL_NO_SURFACE )
|
||||
{
|
||||
Con_Reportf( S_ERROR "eglCreateWindowSurface returned error: 0x%x\n", egl.GetError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !egl.MakeCurrent( eglstate.dpy, eglstate.surface, eglstate.surface, eglstate.context ))
|
||||
{
|
||||
Con_Reportf( S_ERROR "eglMakeCurrent returned error: 0x%x\n", egl.GetError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
Con_DPrintf( S_NOTE "restored current context\n" );
|
||||
if( !dummy)
|
||||
host.status = HOST_FRAME;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=========================
|
||||
EGL_CreateContext
|
||||
|
||||
query attributes for ref and create context
|
||||
=========================
|
||||
*/
|
||||
qboolean EGL_CreateContext( void )
|
||||
{
|
||||
EGLint attribs[32+1], contextAttribs[32+1];
|
||||
const size_t attribsSize = ARRAYSIZE( attribs );
|
||||
size_t s1, s2;
|
||||
|
||||
if( !eglstate.dpy && ( eglstate.dpy = egl.GetDisplay( EGL_DEFAULT_DISPLAY )) == EGL_NO_DISPLAY )
|
||||
{
|
||||
Con_Reportf( S_ERROR "eglGetDisplay returned error: 0x%x\n", egl.GetError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
eglstate.extensions = egl.QueryString( eglstate.dpy, EGL_EXTENSIONS );
|
||||
|
||||
s1 = EGL_GenerateConfig(attribs, attribsSize);
|
||||
s2 = EGL_GenerateContextConfig(contextAttribs, attribsSize);
|
||||
|
||||
|
||||
if( !egl.BindAPI( eglstate.gl_api ))
|
||||
{
|
||||
Con_Reportf( S_ERROR "eglBindAPI returned error: 0x%x\n", egl.GetError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !egl.Initialize( eglstate.dpy, NULL, NULL ))
|
||||
{
|
||||
Con_Reportf( S_ERROR "eglInitialize returned error: 0x%x\n", egl.GetError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( !egl.ChooseConfig( eglstate.dpy, attribs, &eglstate.cfg, 1, &eglstate.numCfg ))
|
||||
{
|
||||
Con_Reportf( S_ERROR "eglChooseConfig returned error: 0x%x\n", egl.GetError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
if(( eglstate.context = egl.CreateContext( eglstate.dpy, eglstate.cfg, NULL, contextAttribs )) == EGL_NO_CONTEXT )
|
||||
{
|
||||
Con_Reportf( S_ERROR "eglCreateContext returned error: 0x%x\n", egl.GetError() );
|
||||
return false;
|
||||
}
|
||||
|
||||
eglstate.valid = true;
|
||||
eglstate.imported = false;
|
||||
|
||||
// now check if it's safe to use surfaceless context here without surface fallback
|
||||
if( eglstate.extensions && Q_strstr( eglstate.extensions, "EGL_KHR_surfaceless_context" ))
|
||||
eglstate.support_surfaceless_context = true;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
===========================
|
||||
EGL_ImportContext
|
||||
|
||||
import current egl context to use EGL functions
|
||||
===========================
|
||||
*/
|
||||
qboolean EGL_ImportContext( void )
|
||||
{
|
||||
if( !egl.GetCurrentDisplay )
|
||||
return false;
|
||||
|
||||
eglstate.dpy = egl.GetCurrentDisplay();
|
||||
|
||||
if( eglstate.dpy == EGL_NO_DISPLAY )
|
||||
return false;
|
||||
|
||||
eglstate.surface = egl.GetCurrentSurface( EGL_DRAW );
|
||||
|
||||
if( eglstate.surface == EGL_NO_SURFACE )
|
||||
return false;
|
||||
|
||||
// now check if swapBuffers does not give error
|
||||
if( egl.SwapBuffers( eglstate.dpy, eglstate.surface ) == EGL_FALSE )
|
||||
return false;
|
||||
|
||||
// double check
|
||||
if( egl.GetError() != EGL_SUCCESS )
|
||||
return false;
|
||||
|
||||
eglstate.extensions = egl.QueryString( eglstate.dpy, EGL_EXTENSIONS );
|
||||
|
||||
eglstate.valid = eglstate.imported = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
EGL_Terminate
|
||||
=========================
|
||||
*/
|
||||
void EGL_Terminate( void )
|
||||
{
|
||||
egl.MakeCurrent( eglstate.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
|
||||
|
||||
egl.DestroyContext( eglstate.dpy, eglstate.context );
|
||||
|
||||
egl.DestroySurface( eglstate.dpy, eglstate.surface );
|
||||
|
||||
egl.Terminate( eglstate.dpy );
|
||||
|
||||
Sys_FreeLibrary( &egl_info );
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
EGL_GetProcAddress
|
||||
|
||||
eglGetProcAddress/dlsym wrapper
|
||||
=========================
|
||||
*/
|
||||
void *EGL_GetProcAddress( const char *name )
|
||||
{
|
||||
void *gles;
|
||||
void *addr;
|
||||
|
||||
// TODO: cross-platform loading
|
||||
if( eglstate.gles1 )
|
||||
{
|
||||
if( !eglstate.libgles1 )
|
||||
eglstate.libgles1 = dlopen( "libGLESv1_CM.so", RTLD_NOW );
|
||||
gles = eglstate.libgles1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( !eglstate.libgles2 )
|
||||
eglstate.libgles2 = dlopen( "libGLESv2.so", RTLD_NOW );
|
||||
gles = eglstate.libgles2;
|
||||
}
|
||||
|
||||
if( gles && ( addr = dlsym( gles, name )))
|
||||
return addr;
|
||||
|
||||
if( !egl.GetProcAddress )
|
||||
return NULL;
|
||||
|
||||
return egl.GetProcAddress( name );
|
||||
}
|
||||
|
||||
/*
|
||||
=========================
|
||||
EGL_LoadLibrary
|
||||
=========================
|
||||
*/
|
||||
void EGL_LoadLibrary( void )
|
||||
{
|
||||
Sys_LoadLibrary( &egl_info );
|
||||
}
|
||||
#endif
|
||||
73
engine/platform/android/eglutil.h
Normal file
73
engine/platform/android/eglutil.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
eglutil.h - EGL context utility
|
||||
Copyright (C) 2023 mittorn
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
#ifndef EGLUTIL_H
|
||||
#define EGLUTIL_H
|
||||
#include "platform/platform.h"
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
extern struct eglstate_s
|
||||
{
|
||||
qboolean valid, imported;
|
||||
EGLDisplay dpy;
|
||||
EGLSurface surface;
|
||||
EGLContext context;
|
||||
EGLConfig cfg;
|
||||
EGLint numCfg;
|
||||
qboolean support_surfaceless_context;
|
||||
|
||||
const char *extensions;
|
||||
int gl_attribs[REF_GL_ATTRIBUTES_COUNT];
|
||||
qboolean gl_attribs_set[REF_GL_ATTRIBUTES_COUNT];
|
||||
EGLint gl_api;
|
||||
qboolean gles1;
|
||||
void *libgles1, *libgles2;
|
||||
} eglstate;
|
||||
|
||||
extern struct eglapi_s
|
||||
{
|
||||
EGLSurface (*GetCurrentSurface)( EGLint readdraw );
|
||||
EGLDisplay (*GetCurrentDisplay)( void );
|
||||
EGLint (*GetError)( void );
|
||||
EGLBoolean (*SwapBuffers)( EGLDisplay dpy, EGLSurface surface );
|
||||
EGLBoolean (*SwapInterval)( EGLDisplay dpy, EGLint interval );
|
||||
void *(*GetProcAddress)( const char *procname );
|
||||
EGLBoolean (*GetConfigAttrib)( EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value );
|
||||
EGLDisplay (*GetDisplay)( NativeDisplayType display );
|
||||
EGLBoolean (*Initialize)( EGLDisplay dpy, EGLint *major, EGLint *minor );
|
||||
EGLBoolean (*Terminate)( EGLDisplay dpy );
|
||||
const char *(*QueryString)( EGLDisplay dpy, EGLint name );
|
||||
EGLBoolean (*ChooseConfig)( EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config );
|
||||
EGLSurface (*CreateWindowSurface)( EGLDisplay dpy, EGLConfig config, NativeWindowType window, const EGLint *attrib_list );
|
||||
EGLContext (*CreateContext)( EGLDisplay dpy, EGLConfig config, EGLContext share_list, const EGLint *attrib_list );
|
||||
EGLBoolean (*DestroyContext)( EGLDisplay dpy, EGLContext ctx );
|
||||
EGLBoolean (*MakeCurrent)( EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx );
|
||||
EGLBoolean (*BindAPI)( EGLenum api );
|
||||
EGLBoolean (*DestroySurface)( EGLDisplay dpy, EGLSurface surface );
|
||||
|
||||
} egl;
|
||||
|
||||
void EGL_LoadLibrary( void );
|
||||
void * EGL_GetProcAddress( const char *name );
|
||||
void EGL_Terminate( void );
|
||||
qboolean EGL_ImportContext( void );
|
||||
qboolean EGL_CreateContext( void );
|
||||
qboolean EGL_UpdateSurface( void *window, qboolean dummy );
|
||||
int EGL_GetAttribute( int attr, int *val );
|
||||
size_t EGL_GenerateContextConfig( EGLint *attribs, size_t size );
|
||||
size_t EGL_GenerateConfig( EGLint *attribs, size_t size );
|
||||
int EGL_SetAttribute( int attr, int val );
|
||||
|
||||
#endif // EGLUTIL_H
|
||||
@@ -19,6 +19,12 @@ GNU General Public License for more details.
|
||||
#include "platform/android/lib_android.h"
|
||||
#include "platform/android/dlsym-weak.h" // Android < 5.0
|
||||
|
||||
void *ANDROID_GetServerLibrary( void )
|
||||
{
|
||||
return svgame.hInstance;
|
||||
}
|
||||
|
||||
|
||||
void *ANDROID_LoadLibrary( const char *dllname )
|
||||
{
|
||||
char path[MAX_SYSPATH];
|
||||
|
||||
@@ -20,6 +20,7 @@ GNU General Public License for more details.
|
||||
#define Platform_POSIX_LoadLibrary( x ) ANDROID_LoadLibrary(( x ))
|
||||
#define Platform_POSIX_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 );
|
||||
|
||||
|
||||
277
engine/platform/android/snd_opensles.c
Normal file
277
engine/platform/android/snd_opensles.c
Normal file
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
Copyright (C) 2015 SiPlus, Chasseur de bots
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "platform/platform.h"
|
||||
#if XASH_SOUND == SOUND_OPENSLES
|
||||
#include <SLES/OpenSLES.h>
|
||||
#include "pthread.h"
|
||||
#include "sound.h"
|
||||
|
||||
extern dma_t dma;
|
||||
|
||||
static SLObjectItf snddma_android_engine = NULL;
|
||||
static SLObjectItf snddma_android_outputMix = NULL;
|
||||
static SLObjectItf snddma_android_player = NULL;
|
||||
static SLBufferQueueItf snddma_android_bufferQueue;
|
||||
static SLPlayItf snddma_android_play;
|
||||
|
||||
static pthread_mutex_t snddma_android_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static int snddma_android_size;
|
||||
|
||||
static const SLInterfaceID *pSL_IID_ENGINE;
|
||||
static const SLInterfaceID *pSL_IID_BUFFERQUEUE;
|
||||
static const SLInterfaceID *pSL_IID_PLAY;
|
||||
static SLresult SLAPIENTRY (*pslCreateEngine)(
|
||||
SLObjectItf *pEngine,
|
||||
SLuint32 numOptions,
|
||||
const SLEngineOption *pEngineOptions,
|
||||
SLuint32 numInterfaces,
|
||||
const SLInterfaceID *pInterfaceIds,
|
||||
const SLboolean * pInterfaceRequired
|
||||
);
|
||||
|
||||
void SNDDMA_Activate( qboolean active )
|
||||
{
|
||||
if( !dma.initialized )
|
||||
return;
|
||||
|
||||
if( active )
|
||||
{
|
||||
memset( dma.buffer, 0, snddma_android_size * 2 );
|
||||
(*snddma_android_bufferQueue)->Enqueue( snddma_android_bufferQueue, dma.buffer, snddma_android_size );
|
||||
(*snddma_android_play)->SetPlayState( snddma_android_play, SL_PLAYSTATE_PLAYING );
|
||||
}
|
||||
else
|
||||
{
|
||||
(*snddma_android_play)->SetPlayState( snddma_android_play, SL_PLAYSTATE_STOPPED );
|
||||
(*snddma_android_bufferQueue)->Clear( snddma_android_bufferQueue );
|
||||
}
|
||||
}
|
||||
|
||||
static void SNDDMA_Android_Callback( SLBufferQueueItf bq, void *context )
|
||||
{
|
||||
uint8_t *buffer2;
|
||||
|
||||
pthread_mutex_lock( &snddma_android_mutex );
|
||||
|
||||
buffer2 = ( uint8_t * )dma.buffer + snddma_android_size;
|
||||
(*bq)->Enqueue( bq, buffer2, snddma_android_size );
|
||||
memcpy( buffer2, dma.buffer, snddma_android_size );
|
||||
memset( dma.buffer, 0, snddma_android_size );
|
||||
dma.samplepos += dma.samples;
|
||||
|
||||
pthread_mutex_unlock( &snddma_android_mutex );
|
||||
}
|
||||
|
||||
static const char *SNDDMA_Android_Init( void )
|
||||
{
|
||||
SLresult result;
|
||||
|
||||
SLEngineItf engine;
|
||||
|
||||
int freq;
|
||||
|
||||
SLDataLocator_BufferQueue sourceLocator;
|
||||
SLDataFormat_PCM sourceFormat;
|
||||
SLDataSource source;
|
||||
|
||||
SLDataLocator_OutputMix sinkLocator;
|
||||
SLDataSink sink;
|
||||
|
||||
SLInterfaceID interfaceID;
|
||||
SLboolean interfaceRequired;
|
||||
|
||||
int samples;
|
||||
void *handle = dlopen( "libOpenSLES.so", RTLD_LAZY );
|
||||
|
||||
if( !handle )
|
||||
return "dlopen for libOpenSLES.so";
|
||||
|
||||
pslCreateEngine = dlsym( handle, "slCreateEngine" );
|
||||
|
||||
if( !pslCreateEngine )
|
||||
return "resolve slCreateEngine";
|
||||
|
||||
pSL_IID_ENGINE = dlsym( handle, "SL_IID_ENGINE" );
|
||||
|
||||
if( !pSL_IID_ENGINE )
|
||||
return "resolve SL_IID_ENGINE";
|
||||
|
||||
pSL_IID_PLAY = dlsym( handle, "SL_IID_PLAY" );
|
||||
|
||||
if( !pSL_IID_PLAY )
|
||||
return "resolve SL_IID_PLAY";
|
||||
|
||||
pSL_IID_BUFFERQUEUE = dlsym( handle, "SL_IID_BUFFERQUEUE" );
|
||||
|
||||
if( !pSL_IID_BUFFERQUEUE )
|
||||
return "resolve SL_IID_BUFFERQUEUE";
|
||||
|
||||
|
||||
result = pslCreateEngine( &snddma_android_engine, 0, NULL, 0, NULL, NULL );
|
||||
if( result != SL_RESULT_SUCCESS ) return "slCreateEngine";
|
||||
result = (*snddma_android_engine)->Realize( snddma_android_engine, SL_BOOLEAN_FALSE );
|
||||
if( result != SL_RESULT_SUCCESS ) return "engine->Realize";
|
||||
result = (*snddma_android_engine)->GetInterface( snddma_android_engine, *pSL_IID_ENGINE, &engine );
|
||||
if( result != SL_RESULT_SUCCESS ) return "engine->GetInterface(ENGINE)";
|
||||
|
||||
result = (*engine)->CreateOutputMix( engine, &snddma_android_outputMix, 0, NULL, NULL );
|
||||
if( result != SL_RESULT_SUCCESS ) return "engine->CreateOutputMix";
|
||||
result = (*snddma_android_outputMix)->Realize( snddma_android_outputMix, SL_BOOLEAN_FALSE );
|
||||
if( result != SL_RESULT_SUCCESS ) return "outputMix->Realize";
|
||||
|
||||
freq = SOUND_DMA_SPEED;
|
||||
sourceLocator.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
|
||||
sourceLocator.numBuffers = 2;
|
||||
sourceFormat.formatType = SL_DATAFORMAT_PCM;
|
||||
sourceFormat.numChannels = 2; // always stereo, because engine supports only stereo
|
||||
sourceFormat.samplesPerSec = freq * 1000;
|
||||
sourceFormat.bitsPerSample = 16; // always 16 bit audio
|
||||
sourceFormat.containerSize = sourceFormat.bitsPerSample;
|
||||
sourceFormat.channelMask = SL_SPEAKER_FRONT_LEFT|SL_SPEAKER_FRONT_RIGHT;
|
||||
sourceFormat.endianness = SL_BYTEORDER_LITTLEENDIAN;
|
||||
source.pLocator = &sourceLocator;
|
||||
source.pFormat = &sourceFormat;
|
||||
|
||||
sinkLocator.locatorType = SL_DATALOCATOR_OUTPUTMIX;
|
||||
sinkLocator.outputMix = snddma_android_outputMix;
|
||||
sink.pLocator = &sinkLocator;
|
||||
sink.pFormat = NULL;
|
||||
|
||||
interfaceID = *pSL_IID_BUFFERQUEUE;
|
||||
interfaceRequired = SL_BOOLEAN_TRUE;
|
||||
|
||||
result = (*engine)->CreateAudioPlayer( engine, &snddma_android_player, &source, &sink, 1, &interfaceID, &interfaceRequired );
|
||||
if( result != SL_RESULT_SUCCESS ) return "engine->CreateAudioPlayer";
|
||||
result = (*snddma_android_player)->Realize( snddma_android_player, SL_BOOLEAN_FALSE );
|
||||
if( result != SL_RESULT_SUCCESS ) return "player->Realize";
|
||||
result = (*snddma_android_player)->GetInterface( snddma_android_player, *pSL_IID_BUFFERQUEUE, &snddma_android_bufferQueue );
|
||||
if( result != SL_RESULT_SUCCESS ) return "player->GetInterface(BUFFERQUEUE)";
|
||||
result = (*snddma_android_player)->GetInterface( snddma_android_player, *pSL_IID_PLAY, &snddma_android_play );
|
||||
if( result != SL_RESULT_SUCCESS ) return "player->GetInterface(PLAY)";
|
||||
result = (*snddma_android_bufferQueue)->RegisterCallback( snddma_android_bufferQueue, SNDDMA_Android_Callback, NULL );
|
||||
if( result != SL_RESULT_SUCCESS ) return "bufferQueue->RegisterCallback";
|
||||
|
||||
samples = s_samplecount.value;
|
||||
if( !samples )
|
||||
samples = 4096;
|
||||
|
||||
dma.format.channels = sourceFormat.numChannels;
|
||||
dma.samples = samples * sourceFormat.numChannels;
|
||||
dma.format.speed = freq;
|
||||
snddma_android_size = dma.samples * ( sourceFormat.bitsPerSample >> 3 );
|
||||
dma.buffer = Z_Malloc( snddma_android_size * 2 );
|
||||
dma.samplepos = 0;
|
||||
// dma.sampleframes = dma.samples / dma.format.channels;
|
||||
dma.format.width = 2;
|
||||
if( !dma.buffer ) return "malloc";
|
||||
|
||||
//snddma_android_mutex = trap_Mutex_Create();
|
||||
|
||||
dma.initialized = true;
|
||||
|
||||
SNDDMA_Activate( true );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qboolean SNDDMA_Init( void )
|
||||
{
|
||||
const char *initError;
|
||||
|
||||
Msg( "OpenSL ES audio device initializing...\n" );
|
||||
|
||||
initError = SNDDMA_Android_Init();
|
||||
if( initError )
|
||||
{
|
||||
Msg( S_ERROR "SNDDMA_Init: %s failed.\n", initError );
|
||||
SNDDMA_Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
Msg( "OpenSL ES audio initialized.\n" );
|
||||
dma.backendName = "OpenSL ES";
|
||||
return true;
|
||||
}
|
||||
|
||||
void SNDDMA_Shutdown( void )
|
||||
{
|
||||
Msg( "Closing OpenSL ES audio device...\n" );
|
||||
|
||||
if( snddma_android_player )
|
||||
{
|
||||
(*snddma_android_player)->Destroy( snddma_android_player );
|
||||
snddma_android_player = NULL;
|
||||
}
|
||||
if( snddma_android_outputMix )
|
||||
{
|
||||
(*snddma_android_outputMix)->Destroy( snddma_android_outputMix );
|
||||
snddma_android_outputMix = NULL;
|
||||
}
|
||||
if( snddma_android_engine )
|
||||
{
|
||||
(*snddma_android_engine)->Destroy( snddma_android_engine );
|
||||
snddma_android_engine = NULL;
|
||||
}
|
||||
|
||||
if( dma.buffer )
|
||||
{
|
||||
Z_Free( dma.buffer );
|
||||
dma.buffer = NULL;
|
||||
}
|
||||
|
||||
//if( snddma_android_mutex )
|
||||
//trap_Mutex_Destroy( &snddma_android_mutex );
|
||||
|
||||
Msg( "OpenSL ES audio device shut down.\n" );
|
||||
}
|
||||
|
||||
void SNDDMA_Submit( void )
|
||||
{
|
||||
pthread_mutex_unlock( &snddma_android_mutex );
|
||||
}
|
||||
|
||||
void SNDDMA_BeginPainting( void )
|
||||
{
|
||||
pthread_mutex_lock( &snddma_android_mutex );
|
||||
}
|
||||
|
||||
qboolean VoiceCapture_Init( void )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean VoiceCapture_Activate( qboolean activate )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
qboolean VoiceCapture_Lock( qboolean lock )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void VoiceCapture_Shutdown( void )
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
513
engine/platform/android/vid_android.c
Normal file
513
engine/platform/android/vid_android.c
Normal file
@@ -0,0 +1,513 @@
|
||||
#include "platform/platform.h"
|
||||
#if !XASH_SDL
|
||||
#include "input.h"
|
||||
#include "client.h"
|
||||
#include "filesystem.h"
|
||||
#include "platform/android/android_priv.h"
|
||||
#include "vid_common.h"
|
||||
#include <android/native_window.h>
|
||||
#include <android/native_window_jni.h>
|
||||
#include "eglutil.h"
|
||||
|
||||
|
||||
static struct vid_android_s
|
||||
{
|
||||
qboolean has_context;
|
||||
ANativeWindow* window;
|
||||
qboolean nativeegl;
|
||||
} vid_android;
|
||||
|
||||
static struct nw_s
|
||||
{
|
||||
void (*release)(ANativeWindow* window);
|
||||
int32_t (*getWidth)(ANativeWindow* window);
|
||||
int32_t (*getHeight)(ANativeWindow* window);
|
||||
int32_t (*getFormat)(ANativeWindow* window);
|
||||
int32_t (*setBuffersGeometry)(ANativeWindow* window, int32_t width, int32_t height, int32_t format);
|
||||
int32_t (*lock)(ANativeWindow* window, ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
|
||||
int32_t (*unlockAndPost)(ANativeWindow* window);
|
||||
ANativeWindow* (*fromSurface)(JNIEnv* env, jobject surface);
|
||||
} nw;
|
||||
|
||||
#define NW_FF(x) {"ANativeWindow_"#x, (void*)&nw.x}
|
||||
|
||||
|
||||
static dllfunc_t android_funcs[] =
|
||||
{
|
||||
NW_FF(release),
|
||||
NW_FF(getWidth),
|
||||
NW_FF(getHeight),
|
||||
NW_FF(getFormat),
|
||||
NW_FF(setBuffersGeometry),
|
||||
NW_FF(lock),
|
||||
NW_FF(unlockAndPost),
|
||||
NW_FF(fromSurface),
|
||||
{ NULL, NULL }
|
||||
};
|
||||
#undef NW_FF
|
||||
static dll_info_t android_info = { "libandroid.so", android_funcs, false };
|
||||
|
||||
/*
|
||||
========================
|
||||
Android_SwapInterval
|
||||
========================
|
||||
*/
|
||||
static void Android_SwapInterval( int interval )
|
||||
{
|
||||
if( vid_android.nativeegl && eglstate.valid )
|
||||
egl.SwapInterval( eglstate.dpy, interval );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
Android_SetTitle
|
||||
========================
|
||||
*/
|
||||
static void Android_SetTitle( const char *title )
|
||||
{
|
||||
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.setTitle, (*jni.env)->NewStringUTF( jni.env, title ) );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
Android_SetIcon
|
||||
========================
|
||||
*/
|
||||
static void Android_SetIcon( const char *path )
|
||||
{
|
||||
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.setIcon, (*jni.env)->NewStringUTF( jni.env, path ) );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
Android_GetScreenRes
|
||||
|
||||
Resolution got from last resize event
|
||||
========================
|
||||
*/
|
||||
static void Android_GetScreenRes( int *width, int *height )
|
||||
{
|
||||
*width = jni.width;
|
||||
*height = jni.height;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
Android_SwapBuffers
|
||||
|
||||
Update screen. Use native EGL if possible
|
||||
========================
|
||||
*/
|
||||
void GL_SwapBuffers( void )
|
||||
{
|
||||
if( vid_android.nativeegl && eglstate.valid )
|
||||
{
|
||||
egl.SwapBuffers( eglstate.dpy, eglstate.surface );
|
||||
}
|
||||
else
|
||||
{
|
||||
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.swapBuffers );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
Android_UpdateSurface
|
||||
|
||||
Check if we may use native EGL without jni calls
|
||||
========================
|
||||
*/
|
||||
void Android_UpdateSurface( surfacestate_t state )
|
||||
{
|
||||
qboolean active = state == surface_active;
|
||||
vid_android.nativeegl = false;
|
||||
|
||||
if( glw_state.software || ( eglstate.valid && !eglstate.imported ))
|
||||
{
|
||||
if( vid_android.window )
|
||||
{
|
||||
EGL_UpdateSurface( NULL, false );
|
||||
nw.release( vid_android.window );
|
||||
vid_android.window = NULL;
|
||||
}
|
||||
if( state == surface_dummy && glw_state.software )
|
||||
return;
|
||||
// first, ask EGL for surfaceless mode
|
||||
if( state == surface_dummy && EGL_UpdateSurface( NULL, true ))
|
||||
{
|
||||
vid_android.nativeegl = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if( state != surface_pause )
|
||||
{
|
||||
EGLint format = WINDOW_FORMAT_RGB_565;
|
||||
jobject surf;
|
||||
if( vid_android.window )
|
||||
nw.release( vid_android.window );
|
||||
surf = (*jni.env)->CallStaticObjectMethod( jni.env, jni.bindcls, jni.getSurface, state );
|
||||
Con_DPrintf("Surface handle %p\n", surf);
|
||||
if( surf )
|
||||
{
|
||||
vid_android.window = nw.fromSurface(jni.env, surf);
|
||||
Con_DPrintf("NativeWindow %p\n", vid_android.window);
|
||||
|
||||
if( eglstate.valid )
|
||||
egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_NATIVE_VISUAL_ID, &format );
|
||||
|
||||
nw.setBuffersGeometry(vid_android.window, 0, 0, format );
|
||||
|
||||
(*jni.env)->DeleteLocalRef( jni.env, surf );
|
||||
}
|
||||
}
|
||||
|
||||
if( eglstate.valid && !eglstate.imported )
|
||||
{
|
||||
EGL_UpdateSurface( vid_android.window, state == surface_dummy );
|
||||
vid_android.nativeegl = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if( !vid_android.has_context )
|
||||
return;
|
||||
|
||||
(*jni.env)->CallStaticVoidMethod( jni.env, jni.bindcls, jni.toggleEGL, (int)state );
|
||||
host.status = HOST_FRAME; // active ? HOST_FRAME : HOST_SLEEP;
|
||||
|
||||
// todo: check opengl context here and set HOST_SLEEP if not
|
||||
|
||||
if( !Sys_CheckParm("-nativeegl") || !active )
|
||||
return; // enabled by user
|
||||
|
||||
vid_android.nativeegl = EGL_ImportContext();
|
||||
if( vid_android.nativeegl )
|
||||
Con_DPrintf( "nativeEGL success\n");
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
Android_GetGLAttribute
|
||||
========================
|
||||
*/
|
||||
static int Android_GetGLAttribute( int eglAttr )
|
||||
{
|
||||
int ret = (*jni.env)->CallStaticIntMethod( jni.env, jni.bindcls, jni.getGLAttribute, eglAttr );
|
||||
// Con_Reportf( "Android_GetGLAttribute( %i ) => %i\n", eglAttr, ret );
|
||||
return ret;
|
||||
}
|
||||
|
||||
qboolean R_Init_Video( const int type )
|
||||
{
|
||||
qboolean retval;
|
||||
char buf[10]; // Sys_GetParmFromCmdLine
|
||||
|
||||
if( FS_FileExists( GI->iconpath, true ) )
|
||||
{
|
||||
// TODO: convert icon to some android-readable format and place
|
||||
Android_SetIcon( FS_GetDiskPath( GI->iconpath, false ));
|
||||
}
|
||||
|
||||
Android_SetTitle( GI->title );
|
||||
|
||||
VID_StartupGamma();
|
||||
|
||||
Sys_LoadLibrary( &android_info );
|
||||
|
||||
switch( type )
|
||||
{
|
||||
case REF_SOFTWARE:
|
||||
glw_state.software = true;
|
||||
break;
|
||||
case REF_GL:
|
||||
glw_state.software = false;
|
||||
EGL_LoadLibrary();
|
||||
|
||||
if( !glw_state.safe && Sys_GetParmFromCmdLine( "-safegl", buf ) )
|
||||
glw_state.safe = bound( SAFE_NO, Q_atoi( buf ), SAFE_DONTCARE );
|
||||
|
||||
break;
|
||||
default:
|
||||
Host_Error( "Can't initialize unknown context type %d!\n", type );
|
||||
break;
|
||||
}
|
||||
|
||||
if( glw_state.software )
|
||||
{
|
||||
uint arg;
|
||||
|
||||
if( !nw.release )
|
||||
{
|
||||
Con_Reportf( S_ERROR "Native software mode unavailiable\n" );
|
||||
return false;
|
||||
}
|
||||
Android_UpdateSurface( surface_active );
|
||||
if( !SW_CreateBuffer( jni.width, jni.height, &arg, &arg, &arg, &arg, &arg ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
while( !(retval = VID_SetMode()) )
|
||||
{
|
||||
glw_state.safe++;
|
||||
if( glw_state.safe > SAFE_LAST )
|
||||
return false;
|
||||
}
|
||||
|
||||
switch( type )
|
||||
{
|
||||
case REF_GL:
|
||||
// refdll also can check extensions
|
||||
ref.dllFuncs.GL_InitExtensions();
|
||||
break;
|
||||
case REF_SOFTWARE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
host.renderinfo_changed = false;
|
||||
|
||||
host.status = HOST_FRAME; // where it should we done? We have broken host.status on all non-SDL platforms!
|
||||
return true;
|
||||
}
|
||||
|
||||
void R_Free_Video( void )
|
||||
{
|
||||
// (*jni.env)->CallStaticBooleanMethod( jni.env, jni.bindcls, jni.deleteGLContext );
|
||||
|
||||
// VID_DestroyWindow ();
|
||||
|
||||
// R_FreeVideoModes();
|
||||
Sys_FreeLibrary( &android_info );
|
||||
vid_android.has_context = false;
|
||||
ref.dllFuncs.GL_ClearExtensions();
|
||||
}
|
||||
|
||||
void *Android_GetWindow( void )
|
||||
{
|
||||
EGLint format;
|
||||
|
||||
if( !vid_android.window )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( !egl.GetConfigAttrib( eglstate.dpy, eglstate.cfg, EGL_NATIVE_VISUAL_ID, &format) )
|
||||
{
|
||||
Con_Reportf( S_ERROR "eglGetConfigAttrib(VISUAL_ID) returned error: 0x%x\n", egl.GetError() );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( nw.setBuffersGeometry( vid_android.window, 0, 0, format ) )
|
||||
{
|
||||
Con_Reportf( S_ERROR "ANativeWindow_setBuffersGeometry returned error\n" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return vid_android.window;
|
||||
}
|
||||
|
||||
|
||||
qboolean VID_SetMode( void )
|
||||
{
|
||||
EGLint format;
|
||||
jintArray attribs, contextAttribs;
|
||||
static EGLint nAttribs[32+1], nContextAttribs[32+1];
|
||||
const size_t attribsSize = ARRAYSIZE( nAttribs );
|
||||
size_t s1, s2;
|
||||
|
||||
// create context on egl side by user request
|
||||
if( !vid_android.has_context && Sys_CheckParm("-egl") )
|
||||
{
|
||||
vid_android.has_context = vid_android.nativeegl = EGL_CreateContext();
|
||||
|
||||
if( vid_android.has_context )
|
||||
Android_UpdateSurface( surface_active );
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
if( vid_android.has_context || glw_state.software )
|
||||
{
|
||||
R_ChangeDisplaySettings( 0, 0, WINDOW_MODE_WINDOWED ); // width and height are ignored anyway
|
||||
return true;
|
||||
}
|
||||
|
||||
s1 = EGL_GenerateConfig(nAttribs, attribsSize);
|
||||
s2 = EGL_GenerateContextConfig(nContextAttribs, attribsSize);
|
||||
|
||||
attribs = (*jni.env)->NewIntArray( jni.env, s1 );
|
||||
contextAttribs = (*jni.env)->NewIntArray( jni.env, s2 );
|
||||
|
||||
(*jni.env)->SetIntArrayRegion( jni.env, attribs, 0, s1, nAttribs );
|
||||
(*jni.env)->SetIntArrayRegion( jni.env, contextAttribs, 0, s2, nContextAttribs );
|
||||
|
||||
R_ChangeDisplaySettings( 0, 0, WINDOW_MODE_WINDOWED ); // width and height are ignored anyway
|
||||
|
||||
|
||||
if( (*jni.env)->CallStaticBooleanMethod( jni.env, jni.bindcls, jni.createGLContext, attribs, contextAttribs ) )
|
||||
{
|
||||
vid_android.has_context = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
rserr_t R_ChangeDisplaySettings( int width, int height, window_mode_t window_mode )
|
||||
{
|
||||
int render_w, render_h;
|
||||
|
||||
Android_GetScreenRes(&width, &height);
|
||||
|
||||
render_w = width;
|
||||
render_h = height;
|
||||
|
||||
Con_Reportf( "R_ChangeDisplaySettings: forced resolution to %dx%d)\n", width, height);
|
||||
|
||||
VID_SetDisplayTransform( &render_w, &render_h );
|
||||
|
||||
R_SaveVideoMode( width, height, render_w, render_h, true );
|
||||
|
||||
refState.wideScreen = true; // V_AdjustFov will check for widescreen
|
||||
|
||||
return rserr_ok;
|
||||
}
|
||||
|
||||
int GL_SetAttribute( int attr, int val )
|
||||
{
|
||||
return EGL_SetAttribute( attr, val );
|
||||
}
|
||||
|
||||
int GL_GetAttribute( int attr, int *val )
|
||||
{
|
||||
EGLBoolean ret;
|
||||
|
||||
if( eglstate.valid )
|
||||
return EGL_GetAttribute( attr, val );
|
||||
|
||||
if( attr < 0 || attr >= REF_GL_ATTRIBUTES_COUNT )
|
||||
return -1;
|
||||
|
||||
if( !val )
|
||||
return -1;
|
||||
|
||||
switch( attr )
|
||||
{
|
||||
case REF_GL_RED_SIZE:
|
||||
*val = Android_GetGLAttribute( EGL_RED_SIZE );
|
||||
return 0;
|
||||
case REF_GL_GREEN_SIZE:
|
||||
*val = Android_GetGLAttribute( EGL_GREEN_SIZE );
|
||||
return 0;
|
||||
case REF_GL_BLUE_SIZE:
|
||||
*val = Android_GetGLAttribute( EGL_BLUE_SIZE );
|
||||
return 0;
|
||||
case REF_GL_ALPHA_SIZE:
|
||||
*val = Android_GetGLAttribute( EGL_ALPHA_SIZE );
|
||||
return 0;
|
||||
case REF_GL_DEPTH_SIZE:
|
||||
*val = Android_GetGLAttribute( EGL_DEPTH_SIZE );
|
||||
return 0;
|
||||
case REF_GL_STENCIL_SIZE:
|
||||
*val = Android_GetGLAttribute( EGL_STENCIL_SIZE );
|
||||
return 0;
|
||||
case REF_GL_MULTISAMPLESAMPLES:
|
||||
*val = Android_GetGLAttribute( EGL_SAMPLES );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int R_MaxVideoModes( void )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
vidmode_t* R_GetVideoMode( int num )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* GL_GetProcAddress( const char *name ) // RenderAPI requirement
|
||||
{
|
||||
return EGL_GetProcAddress( name );
|
||||
}
|
||||
|
||||
void GL_UpdateSwapInterval( void )
|
||||
{
|
||||
// disable VSync while level is loading
|
||||
if( cls.state < ca_active )
|
||||
{
|
||||
Android_SwapInterval( 0 );
|
||||
SetBits( gl_vsync.flags, FCVAR_CHANGED );
|
||||
}
|
||||
else if( FBitSet( gl_vsync.flags, FCVAR_CHANGED ))
|
||||
{
|
||||
ClearBits( gl_vsync.flags, FCVAR_CHANGED );
|
||||
Android_SwapInterval( gl_vsync.value );
|
||||
}
|
||||
}
|
||||
|
||||
void *SW_LockBuffer( void )
|
||||
{
|
||||
ANativeWindow_Buffer buffer;
|
||||
if( !nw.lock || !vid_android.window )
|
||||
return NULL;
|
||||
if( nw.lock( vid_android.window, &buffer, NULL ) )
|
||||
return NULL;
|
||||
if( buffer.width < refState.width || buffer.height < refState.height )
|
||||
return NULL;
|
||||
return buffer.bits;
|
||||
}
|
||||
|
||||
void SW_UnlockBuffer( void )
|
||||
{
|
||||
if( nw.unlockAndPost )
|
||||
nw.unlockAndPost( vid_android.window );
|
||||
}
|
||||
|
||||
qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *r, uint *g, uint *b )
|
||||
{
|
||||
ANativeWindow_Buffer buffer;
|
||||
int lock;
|
||||
if( !nw.lock || !vid_android.window )
|
||||
return false;
|
||||
nw.unlockAndPost( vid_android.window );
|
||||
|
||||
if( ( lock = nw.lock( vid_android.window, &buffer, NULL ) ) )
|
||||
{
|
||||
Con_Printf( "SW_CreateBuffer: lock %d\n", lock );
|
||||
return false;
|
||||
}
|
||||
nw.unlockAndPost( vid_android.window );
|
||||
Con_Printf( "SW_CreateBuffer: buffer %d %d %x %d %p\n", buffer.width, buffer.height, buffer.format, buffer.stride, buffer.bits );
|
||||
if( width > buffer.width || height > buffer.height )
|
||||
{
|
||||
// resize event missed? do not resize now, wait for REAL resize event or when java code will be fixed
|
||||
Con_Printf( S_ERROR "SW_CreateBuffer: buffer too small, need %dx%d, got %dx%d, java part probably sucks\n", width, height, buffer.width, buffer.height );
|
||||
#if 0
|
||||
if( jni.width < buffer.width )
|
||||
jni.width = buffer.width;
|
||||
if( jni.height < buffer.height )
|
||||
jni.width = buffer.height;
|
||||
VID_SetMode();
|
||||
Android_UpdateSurface( true );
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
if( buffer.format != WINDOW_FORMAT_RGB_565 )
|
||||
{
|
||||
Con_Printf( "SW_CreateBuffer: wrong format %d\n", buffer.format );
|
||||
return false;
|
||||
}
|
||||
Con_Printf( "SW_CreateBuffer: ok\n" );
|
||||
*stride = buffer.stride;
|
||||
|
||||
*bpp = 2;
|
||||
*r = (((1 << 5) - 1) << (5+6));
|
||||
*g = (((1 << 6) - 1) << (5));
|
||||
*b = (((1 << 5) - 1) << (0));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -654,7 +654,9 @@ static void SDLash_EventFilter( SDL_Event *event )
|
||||
SDLash_ActiveEvent( false );
|
||||
break;
|
||||
case SDL_WINDOWEVENT_RESIZED:
|
||||
#if !XASH_MOBILE_PLATFORM
|
||||
if( vid_fullscreen.value == WINDOW_MODE_WINDOWED )
|
||||
#endif
|
||||
{
|
||||
SDL_Window *wnd = SDL_GetWindowFromID( event->window.windowID );
|
||||
VID_SaveWindowSize( event->window.data1, event->window.data2,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -576,10 +576,8 @@ static qboolean VID_SetScreenResolution( int width, int height, window_mode_t wi
|
||||
SDL_DisplayMode got;
|
||||
Uint32 wndFlags = 0;
|
||||
|
||||
#if !XASH_APPLE
|
||||
if( vid_highdpi.value )
|
||||
SetBits( wndFlags, SDL_WINDOW_ALLOW_HIGHDPI );
|
||||
#endif
|
||||
|
||||
SDL_SetWindowBordered( host.hWnd, SDL_FALSE );
|
||||
|
||||
@@ -744,7 +742,6 @@ qboolean VID_CreateWindow( int width, int height, window_mode_t window_mode )
|
||||
if( !glw_state.software )
|
||||
SetBits( wndFlags, SDL_WINDOW_OPENGL );
|
||||
|
||||
#if !XASH_MOBILE_PLATFORM
|
||||
if( window_mode == WINDOW_MODE_WINDOWED )
|
||||
{
|
||||
SDL_Rect r;
|
||||
@@ -787,10 +784,6 @@ qboolean VID_CreateWindow( int width, int height, window_mode_t window_mode )
|
||||
SetBits( wndFlags, SDL_WINDOW_BORDERLESS );
|
||||
xpos = ypos = 0;
|
||||
}
|
||||
#else
|
||||
SetBits( wndFlags, SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_INPUT_GRABBED );
|
||||
xpos = ypos = SDL_WINDOWPOS_UNDEFINED;
|
||||
#endif
|
||||
|
||||
if( !VID_CreateWindowWithSafeGL( wndname, xpos, ypos, width, height, wndFlags ))
|
||||
return false;
|
||||
@@ -799,14 +792,12 @@ qboolean VID_CreateWindow( int width, int height, window_mode_t window_mode )
|
||||
if( FBitSet( SDL_GetWindowFlags( host.hWnd ), SDL_WINDOW_MAXIMIZED|SDL_WINDOW_FULLSCREEN_DESKTOP ) != 0 )
|
||||
SDL_GetWindowSize( host.hWnd, &width, &height );
|
||||
|
||||
#if !XASH_MOBILE_PLATFORM
|
||||
if( window_mode != WINDOW_MODE_WINDOWED )
|
||||
{
|
||||
if( !VID_SetScreenResolution( width, height, window_mode ))
|
||||
return false;
|
||||
}
|
||||
else VID_RestoreScreenResolution();
|
||||
#endif
|
||||
|
||||
VID_SetWindowIcon( host.hWnd );
|
||||
SDL_ShowWindow( host.hWnd );
|
||||
@@ -1175,6 +1166,14 @@ qboolean VID_SetMode( void )
|
||||
#endif // SDL_VERSION_ATLEAST( 2, 0, 0 )
|
||||
}
|
||||
|
||||
#if XASH_MOBILE_PLATFORM
|
||||
if( Q_strcmp( vid_fullscreen.string, DEFAULT_FULLSCREEN ))
|
||||
{
|
||||
Cvar_DirectSet( &vid_fullscreen, DEFAULT_FULLSCREEN );
|
||||
Con_Reportf( S_ERROR "VID_SetMode: windowed unavailable on this platform\n" );
|
||||
}
|
||||
#endif
|
||||
|
||||
if( !FBitSet( vid_fullscreen.flags, FCVAR_CHANGED ))
|
||||
Cvar_DirectSet( &vid_fullscreen, DEFAULT_FULLSCREEN );
|
||||
else
|
||||
|
||||
@@ -356,13 +356,13 @@ static void ListMissingModules( dll_user_t *hInst )
|
||||
byte *data;
|
||||
char buf[MAX_VA_STRING];
|
||||
|
||||
if ( !hInst ) return;
|
||||
|
||||
data = FS_LoadFile( hInst->dllName, NULL, false );
|
||||
if ( !data ) return;
|
||||
if( !hInst || !g_fsapi.LoadFile ) return;
|
||||
|
||||
data = g_fsapi.LoadFile( hInst->dllName, NULL, false );
|
||||
if( !data ) return;
|
||||
|
||||
importDesc = GetImportDescriptor( hInst->dllName, data, &peHeader );
|
||||
if ( !importDesc )
|
||||
if( !importDesc )
|
||||
{
|
||||
Mem_Free( data );
|
||||
return;
|
||||
|
||||
@@ -453,6 +453,11 @@ static void SV_ConnectClient( netadr_t from )
|
||||
|
||||
// parse some info from the info strings (this can override cl_updaterate)
|
||||
Q_strncpy( newcl->userinfo, userinfo, sizeof( newcl->userinfo ));
|
||||
newcl->fullupdate_next_calltime = 0;
|
||||
newcl->userinfo_next_changetime = 0;
|
||||
newcl->userinfo_penalty = 0;
|
||||
newcl->userinfo_change_attempts = 0;
|
||||
|
||||
SV_UserinfoChanged( newcl );
|
||||
SV_ClearResourceLists( newcl );
|
||||
#if 0
|
||||
@@ -794,7 +799,7 @@ sv_client_t *SV_ClientById( int id )
|
||||
|
||||
ASSERT( id >= 0 );
|
||||
|
||||
for( i = 0, cl = svs.clients; i < svgame.globals->maxClients; i++, cl++ )
|
||||
for( i = 0, cl = svs.clients; cl && i < svgame.globals->maxClients; i++, cl++ )
|
||||
{
|
||||
if( !cl->state )
|
||||
continue;
|
||||
@@ -814,7 +819,7 @@ sv_client_t *SV_ClientByName( const char *name )
|
||||
if( !COM_CheckString( name ))
|
||||
return NULL;
|
||||
|
||||
for( i = 0, cl = svs.clients; i < svgame.globals->maxClients; i++, cl++ )
|
||||
for( i = 0, cl = svs.clients; cl && i < svgame.globals->maxClients; i++, cl++ )
|
||||
{
|
||||
if( !cl->state )
|
||||
continue;
|
||||
@@ -3453,7 +3458,7 @@ static void SV_ParseVoiceData( sv_client_t *cl, sizebuf_t *msg )
|
||||
|
||||
MSG_ReadBytes( msg, received, size );
|
||||
|
||||
if( !sv_voiceenable.value )
|
||||
if( !sv_voiceenable.value || svs.maxclients <= 1 )
|
||||
return;
|
||||
|
||||
for( i = 0, cur = svs.clients; i < svs.maxclients; i++, cur++ )
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1209,7 +1209,7 @@ static edict_t* SV_AllocPrivateData( edict_t *ent, string_t className )
|
||||
|
||||
if( !SpawnEdict )
|
||||
{
|
||||
Con_Printf( S_ERROR "No spawn function for %s\n", STRING( className ));
|
||||
Con_Printf( S_ERROR "No spawn function for \"%s\"\n", pszClassName );
|
||||
|
||||
// free entity immediately
|
||||
SV_FreeEdict( ent );
|
||||
|
||||
@@ -469,7 +469,8 @@ static void SV_CreateBaseline( void )
|
||||
int delta_type;
|
||||
int entnum;
|
||||
|
||||
SV_WriteVoiceCodec( &sv.signon );
|
||||
if( svs.maxclients > 1 )
|
||||
SV_WriteVoiceCodec( &sv.signon );
|
||||
|
||||
if( FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
|
||||
playermodel = SV_ModelIndex( DEFAULT_PLAYER_PATH_QUAKE );
|
||||
@@ -672,14 +673,6 @@ void SV_ActivateServer( int runPhysics )
|
||||
|
||||
if( sv.ignored_world_decals )
|
||||
Con_Printf( S_WARN "%i static decals was rejected due buffer overflow\n", sv.ignored_world_decals );
|
||||
|
||||
if( svs.maxclients > 1 )
|
||||
{
|
||||
const char *cycle = Cvar_VariableString( "mapchangecfgfile" );
|
||||
|
||||
if( COM_CheckString( cycle ))
|
||||
Cbuf_AddTextf( "exec %s\n", cycle );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -692,6 +685,13 @@ deactivate server, free edicts, strings etc
|
||||
void SV_DeactivateServer( void )
|
||||
{
|
||||
int i;
|
||||
const char *cycle = Cvar_VariableString( "disconcfgfile" );
|
||||
|
||||
if( COM_CheckString( cycle ))
|
||||
Cbuf_AddTextf( "exec %s\n", cycle );
|
||||
|
||||
if( COM_CheckStringEmpty( sv.name ))
|
||||
Cbuf_AddTextf( "exec maps/%s_unload.cfg\n", sv.name );
|
||||
|
||||
if( !svs.initialized || sv.state == ss_dead )
|
||||
return;
|
||||
@@ -922,11 +922,11 @@ static void SV_GenerateTestPacket( void )
|
||||
// testpacket already generated once, exit
|
||||
// testpacket and lookup table takes ~300k of memory
|
||||
// disable for low memory mode
|
||||
if( svs.testpacket_buf || XASH_LOW_MEMORY >= 0 )
|
||||
if( svs.testpacket_buf || XASH_LOW_MEMORY > 0 )
|
||||
return;
|
||||
|
||||
// don't need in singleplayer with full client
|
||||
if( svs.maxclients <= 1 && !Host_IsDedicated( ))
|
||||
if( svs.maxclients <= 1 )
|
||||
return;
|
||||
|
||||
file = FS_Open( "gfx.wad", "rb", false );
|
||||
@@ -987,8 +987,9 @@ clients along with it.
|
||||
*/
|
||||
qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean background )
|
||||
{
|
||||
int i, current_skill;
|
||||
edict_t *ent;
|
||||
int i, current_skill;
|
||||
edict_t *ent;
|
||||
const char *cycle;
|
||||
|
||||
SV_SetupClients();
|
||||
|
||||
@@ -1006,6 +1007,13 @@ qboolean SV_SpawnServer( const char *mapname, const char *startspot, qboolean ba
|
||||
svs.timestart = Sys_DoubleTime();
|
||||
svs.spawncount++; // any partially connected client will be restarted
|
||||
|
||||
cycle = Cvar_VariableString( "mapchangecfgfile" );
|
||||
|
||||
if( COM_CheckString( cycle ))
|
||||
Cbuf_AddTextf( "exec %s\n", cycle );
|
||||
|
||||
Cbuf_AddTextf( "exec maps/%s_load.cfg\n", mapname );
|
||||
|
||||
// let's not have any servers with no name
|
||||
if( !COM_CheckString( hostname.string ))
|
||||
Cvar_Set( "hostname", svgame.dllFuncs.pfnGetGameDescription ? svgame.dllFuncs.pfnGetGameDescription() : FS_Title( ));
|
||||
|
||||
@@ -75,6 +75,8 @@ CVAR_DEFINE_AUTO( skill, "1", 0, "skill level in singleplayer game" );
|
||||
CVAR_DEFINE_AUTO( temp1, "0", 0, "temporary cvar that used by some mods" );
|
||||
CVAR_DEFINE_AUTO( listipcfgfile, "listip.cfg", 0, "name of listip.cfg file" );
|
||||
CVAR_DEFINE_AUTO( mapchangecfgfile, "", 0, "name of map change configuration file" );
|
||||
CVAR_DEFINE_AUTO( disconcfgfile, "", 0, "name of disconnect configuration file" );
|
||||
CVAR_DEFINE_AUTO( _sv_override_scientist_mdl, "", 0, "override default scientist model name (specially for HL25 Uplink maps)" );
|
||||
|
||||
// physic-related variables
|
||||
CVAR_DEFINE_AUTO( sv_gravity, "800", FCVAR_MOVEVARS, "world gravity value" );
|
||||
@@ -948,6 +950,8 @@ void SV_Init( void )
|
||||
Cvar_RegisterVariable( &bannedcfgfile );
|
||||
Cvar_RegisterVariable( &listipcfgfile );
|
||||
Cvar_RegisterVariable( &mapchangecfgfile );
|
||||
Cvar_RegisterVariable( &disconcfgfile );
|
||||
Cvar_RegisterVariable( &_sv_override_scientist_mdl );
|
||||
|
||||
Cvar_RegisterVariable( &sv_voiceenable );
|
||||
Cvar_RegisterVariable( &sv_voicequality );
|
||||
|
||||
@@ -150,21 +150,9 @@ void SV_WaterMove( edict_t *ent )
|
||||
if( flags & FL_INWATER )
|
||||
{
|
||||
// leave the water.
|
||||
switch( COM_RandomLong( 0, 3 ))
|
||||
{
|
||||
case 0:
|
||||
SV_StartSound( ent, CHAN_BODY, "player/pl_wade1.wav", 1.0f, ATTN_NORM, 0, 100 );
|
||||
break;
|
||||
case 1:
|
||||
SV_StartSound( ent, CHAN_BODY, "player/pl_wade2.wav", 1.0f, ATTN_NORM, 0, 100 );
|
||||
break;
|
||||
case 2:
|
||||
SV_StartSound( ent, CHAN_BODY, "player/pl_wade3.wav", 1.0f, ATTN_NORM, 0, 100 );
|
||||
break;
|
||||
case 3:
|
||||
SV_StartSound( ent, CHAN_BODY, "player/pl_wade4.wav", 1.0f, ATTN_NORM, 0, 100 );
|
||||
break;
|
||||
}
|
||||
const char *snd = SoundList_GetRandom( EntityWaterExit );
|
||||
if( snd )
|
||||
SV_StartSound( ent, CHAN_BODY, snd, 1.0f, ATTN_NORM, 0, 100 );
|
||||
|
||||
ent->v.flags = flags & ~FL_INWATER;
|
||||
}
|
||||
@@ -197,21 +185,9 @@ void SV_WaterMove( edict_t *ent )
|
||||
if( watertype == CONTENTS_WATER )
|
||||
{
|
||||
// entering the water
|
||||
switch( COM_RandomLong( 0, 3 ))
|
||||
{
|
||||
case 0:
|
||||
SV_StartSound( ent, CHAN_BODY, "player/pl_wade1.wav", 1.0f, ATTN_NORM, 0, 100 );
|
||||
break;
|
||||
case 1:
|
||||
SV_StartSound( ent, CHAN_BODY, "player/pl_wade2.wav", 1.0f, ATTN_NORM, 0, 100 );
|
||||
break;
|
||||
case 2:
|
||||
SV_StartSound( ent, CHAN_BODY, "player/pl_wade3.wav", 1.0f, ATTN_NORM, 0, 100 );
|
||||
break;
|
||||
case 3:
|
||||
SV_StartSound( ent, CHAN_BODY, "player/pl_wade4.wav", 1.0f, ATTN_NORM, 0, 100 );
|
||||
break;
|
||||
}
|
||||
const char *snd = SoundList_GetRandom( EntityWaterEnter );
|
||||
if( snd )
|
||||
SV_StartSound( ent, CHAN_BODY, snd, 1.0f, ATTN_NORM, 0, 100 );
|
||||
}
|
||||
|
||||
ent->v.flags = flags | FL_INWATER;
|
||||
|
||||
@@ -1384,7 +1384,9 @@ static void SV_CheckWaterTransition( edict_t *ent )
|
||||
if( ent->v.watertype == CONTENTS_EMPTY )
|
||||
{
|
||||
// just crossed into water
|
||||
SV_StartSound( ent, CHAN_AUTO, "player/pl_wade1.wav", 1.0f, ATTN_NORM, 0, 100 );
|
||||
const char *snd = SoundList_GetRandom( PlayerWaterEnter );
|
||||
if( snd )
|
||||
SV_StartSound( ent, CHAN_AUTO, snd, 1.0f, ATTN_NORM, 0, 100 );
|
||||
ent->v.velocity[2] *= 0.5f;
|
||||
}
|
||||
|
||||
@@ -1418,7 +1420,9 @@ static void SV_CheckWaterTransition( edict_t *ent )
|
||||
if( ent->v.watertype != CONTENTS_EMPTY )
|
||||
{
|
||||
// just crossed into water
|
||||
SV_StartSound( ent, CHAN_AUTO, "player/pl_wade2.wav", 1.0f, ATTN_NORM, 0, 100 );
|
||||
const char *snd = SoundList_GetRandom( PlayerWaterExit );
|
||||
if( snd )
|
||||
SV_StartSound( ent, CHAN_AUTO, snd, 1.0f, ATTN_NORM, 0, 100 );
|
||||
}
|
||||
ent->v.watertype = CONTENTS_EMPTY;
|
||||
ent->v.waterlevel = 0;
|
||||
@@ -2118,6 +2122,7 @@ static server_physics_api_t gPhysicsAPI =
|
||||
COM_SaveFile,
|
||||
pfnLoadImagePixels,
|
||||
pfnGetModelName,
|
||||
Sys_GetNativeObject
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -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:
|
||||
@@ -237,7 +242,8 @@ def build(bld):
|
||||
app_name = 'xash3d-fwgs'
|
||||
)
|
||||
else:
|
||||
if bld.env.DISABLE_LAUNCHER:
|
||||
# always build as shared library on Android
|
||||
if bld.env.DISABLE_LAUNCHER and bld.env.DEST_OS != "android":
|
||||
install_path = bld.env.BINDIR
|
||||
program = 'cxxprogram' if is_cxx_link else 'cprogram'
|
||||
if bld.env.STATIC:
|
||||
|
||||
@@ -15,7 +15,7 @@ GNU General Public License for more details.
|
||||
|
||||
#include "port.h"
|
||||
|
||||
#if XASH_ANDROID
|
||||
#if XASH_ANDROID_ASSETS
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -233,7 +233,7 @@ static file_t *FS_OpenFile_AndroidAssets( searchpath_t *search, const char *file
|
||||
return file;
|
||||
}
|
||||
|
||||
static byte *FS_LoadAndroidAssetsFile( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *filesize )
|
||||
static byte *FS_LoadAndroidAssetsFile( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *filesize, void *( *pfnAlloc )( size_t ), void ( *pfnFree )( void * ))
|
||||
{
|
||||
byte *buf;
|
||||
off_t size;
|
||||
@@ -247,18 +247,24 @@ static byte *FS_LoadAndroidAssetsFile( searchpath_t *search, const char *path, i
|
||||
|
||||
size = AAsset_getLength( asset );
|
||||
|
||||
buf = (byte *)Mem_Malloc( fs_mempool, size + 1 );
|
||||
buf = (byte *)pfnAlloc( size + 1 );
|
||||
if( unlikely( !buf ))
|
||||
{
|
||||
Con_Reportf( "%s: can't alloc %d bytes, no free memory\n", __func__, size + 1 );
|
||||
AAsset_close( asset );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf[size] = '\0';
|
||||
|
||||
if( AAsset_read( asset, buf, size ) < 0 )
|
||||
{
|
||||
Mem_Free( buf );
|
||||
pfnFree( buf );
|
||||
AAsset_close( asset );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AAsset_close( asset );
|
||||
|
||||
if( filesize ) *filesize = size;
|
||||
|
||||
return buf;
|
||||
@@ -322,4 +328,4 @@ void FS_InitAndroid( void )
|
||||
jni.getAssets = (*jni.env)->GetMethodID( jni.env, jni.activity_class, "getAssets", "(Z)Landroid/content/res/AssetManager;" );
|
||||
}
|
||||
|
||||
#endif // XASH_ANDROID
|
||||
#endif // XASH_ANDROID_ASSETS
|
||||
|
||||
@@ -72,7 +72,7 @@ const fs_archive_t g_archives[] =
|
||||
static const fs_archive_t g_directory_archive =
|
||||
{ NULL, SEARCHPATH_PLAIN, FS_AddDir_Fullpath, false };
|
||||
|
||||
#ifdef XASH_ANDROID
|
||||
#if XASH_ANDROID_ASSETS
|
||||
static const fs_archive_t g_android_archive =
|
||||
{ NULL, SEARCHPATH_ANDROID_ASSETS, FS_AddAndroidAssets_Fullpath, false };
|
||||
#endif
|
||||
@@ -406,7 +406,7 @@ void FS_AddGameDirectory( const char *dir, uint flags )
|
||||
|
||||
stringlistfreecontents( &list );
|
||||
|
||||
#ifdef XASH_ANDROID
|
||||
#if XASH_ANDROID_ASSETS
|
||||
FS_AddArchive_Fullpath( &g_android_archive, dir, flags );
|
||||
#endif
|
||||
|
||||
@@ -632,30 +632,23 @@ static void FS_InitGameInfo( gameinfo_t *GameInfo, const char *gamedir )
|
||||
memset( GameInfo, 0, sizeof( *GameInfo ));
|
||||
|
||||
// filesystem info
|
||||
Q_strncpy( GameInfo->gamefolder, gamedir, sizeof( GameInfo->gamefolder ));
|
||||
Q_strncpy( GameInfo->basedir, "valve", sizeof( GameInfo->basedir ));
|
||||
GameInfo->falldir[0] = 0;
|
||||
Q_strncpy( GameInfo->startmap, "c0a0", sizeof( GameInfo->startmap ));
|
||||
Q_strncpy( GameInfo->trainmap, "t0a0", sizeof( GameInfo->trainmap ));
|
||||
Q_strncpy( GameInfo->title, "New Game", sizeof( GameInfo->title ));
|
||||
GameInfo->version = 1.0f;
|
||||
|
||||
// .dll pathes
|
||||
Q_strncpy( GameInfo->gamefolder, gamedir, sizeof( GameInfo->gamefolder ));
|
||||
Q_strncpy( GameInfo->basedir, fs_basedir, sizeof( GameInfo->basedir ));
|
||||
Q_strncpy( GameInfo->sp_entity, "info_player_start", sizeof( GameInfo->sp_entity ));
|
||||
Q_strncpy( GameInfo->mp_entity, "info_player_deathmatch", sizeof( GameInfo->mp_entity ));
|
||||
Q_strncpy( GameInfo->startmap, "newmap", sizeof( GameInfo->startmap ));
|
||||
Q_strncpy( GameInfo->dll_path, "cl_dlls", sizeof( GameInfo->dll_path ));
|
||||
Q_strncpy( GameInfo->game_dll, "dlls/hl.dll", sizeof( GameInfo->game_dll ));
|
||||
Q_strncpy( GameInfo->game_dll_linux, "dlls/hl.so", sizeof( GameInfo->game_dll_linux ));
|
||||
Q_strncpy( GameInfo->game_dll_osx, "dlls/hl.dylib", sizeof( GameInfo->game_dll_osx ));
|
||||
|
||||
// .ico path
|
||||
Q_strncpy( GameInfo->iconpath, "game.ico", sizeof( GameInfo->iconpath ));
|
||||
|
||||
Q_strncpy( GameInfo->sp_entity, "info_player_start", sizeof( GameInfo->sp_entity ));
|
||||
Q_strncpy( GameInfo->mp_entity, "info_player_deathmatch", sizeof( GameInfo->mp_entity ));
|
||||
|
||||
GameInfo->max_edicts = DEFAULT_MAX_EDICTS; // default value if not specified
|
||||
GameInfo->max_tents = 500;
|
||||
GameInfo->max_beams = 128;
|
||||
GameInfo->max_particles = 4096;
|
||||
GameInfo->version = 1.0f;
|
||||
}
|
||||
|
||||
static void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qboolean isGameInfo )
|
||||
@@ -1468,7 +1461,7 @@ qboolean FS_InitStdio( qboolean unused_set_to_true, const char *rootdir, const c
|
||||
|
||||
FS_InitMemory();
|
||||
|
||||
#ifdef XASH_ANDROID
|
||||
#if XASH_ANDROID_ASSETS
|
||||
FS_InitAndroid();
|
||||
#endif
|
||||
|
||||
@@ -2419,6 +2412,16 @@ static void FS_Purge( file_t *file )
|
||||
file->ungetc = EOF;
|
||||
}
|
||||
|
||||
static void *FS_CustomAlloc( size_t size )
|
||||
{
|
||||
return Mem_Malloc( fs_mempool, size );
|
||||
}
|
||||
|
||||
static void FS_CustomFree( void *data )
|
||||
{
|
||||
return Mem_Free( data );
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
FS_LoadFile
|
||||
@@ -2427,12 +2430,16 @@ Filename are relative to the xash directory.
|
||||
Always appends a 0 byte.
|
||||
============
|
||||
*/
|
||||
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
|
||||
static byte *FS_LoadFile_( const char *path, fs_offset_t *filesizeptr, const qboolean gamedironly, const qboolean custom_alloc )
|
||||
{
|
||||
searchpath_t *search;
|
||||
fs_offset_t filesize;
|
||||
file_t *file;
|
||||
byte *buf;
|
||||
char netpath[MAX_SYSPATH];
|
||||
int pack_ind;
|
||||
void *( *pfnAlloc )( size_t ) = custom_alloc ? FS_CustomAlloc : malloc;
|
||||
void ( *pfnFree )( void * ) = custom_alloc ? FS_CustomFree : free;
|
||||
|
||||
// some mappers used leading '/' or '\' in path to models or sounds
|
||||
if( path[0] == '/' || path[0] == '\\' )
|
||||
@@ -2451,27 +2458,39 @@ byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamediro
|
||||
|
||||
// custom load file function for compressed files
|
||||
if( search->pfnLoadFile )
|
||||
return search->pfnLoadFile( search, netpath, pack_ind, filesizeptr );
|
||||
return search->pfnLoadFile( search, netpath, pack_ind, filesizeptr, pfnAlloc, pfnFree );
|
||||
|
||||
file = search->pfnOpenFile( search, netpath, "rb", pack_ind );
|
||||
|
||||
if( file )
|
||||
if( !file ) // TODO: indicate errors
|
||||
return NULL;
|
||||
|
||||
filesize = file->real_length;
|
||||
buf = (byte *)pfnAlloc( filesize + 1 );
|
||||
|
||||
if( unlikely( !buf )) // TODO: indicate errors
|
||||
{
|
||||
fs_offset_t filesize = file->real_length;
|
||||
byte *buf;
|
||||
|
||||
buf = (byte *)Mem_Malloc( fs_mempool, filesize + 1 );
|
||||
buf[filesize] = '\0';
|
||||
FS_Read( file, buf, filesize );
|
||||
Con_Reportf( "%s: can't alloc %d bytes, no free memory\n", __func__, filesize + 1 );
|
||||
FS_Close( file );
|
||||
|
||||
if( filesizeptr )
|
||||
*filesizeptr = filesize;
|
||||
|
||||
return buf;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
buf[filesize] = '\0';
|
||||
FS_Read( file, buf, filesize );
|
||||
FS_Close( file );
|
||||
if( filesizeptr ) *filesizeptr = filesize;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
byte *FS_LoadFileMalloc( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
|
||||
{
|
||||
return FS_LoadFile_( path, filesizeptr, gamedironly, false );
|
||||
}
|
||||
|
||||
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly )
|
||||
{
|
||||
return FS_LoadFile_( path, filesizeptr, gamedironly, g_engfuncs._Mem_Alloc != _Mem_Alloc );
|
||||
}
|
||||
|
||||
qboolean CRC32_File( dword *crcvalue, const char *filename )
|
||||
@@ -3020,6 +3039,7 @@ fs_api_t g_api =
|
||||
(void *)FS_MountArchive_Fullpath,
|
||||
|
||||
FS_GetFullDiskPath,
|
||||
FS_LoadFileMalloc,
|
||||
};
|
||||
|
||||
int EXPORT GetFSAPI( int version, fs_api_t *api, fs_globals_t **globals, fs_interface_t *engfuncs );
|
||||
|
||||
@@ -196,6 +196,9 @@ typedef struct fs_api_t
|
||||
void *(*MountArchive_Fullpath)( const char *path, int flags );
|
||||
|
||||
qboolean (*GetFullDiskPath)( char *buffer, size_t size, const char *name, qboolean gamedironly );
|
||||
|
||||
// like LoadFile but returns pointer that can be free'd using standard library function
|
||||
byte *(*LoadFileMalloc)( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
|
||||
} fs_api_t;
|
||||
|
||||
typedef struct fs_interface_t
|
||||
|
||||
@@ -103,7 +103,7 @@ typedef struct searchpath_s
|
||||
int (*pfnFileTime)( struct searchpath_s *search, const char *filename );
|
||||
int (*pfnFindFile)( struct searchpath_s *search, const char *path, char *fixedname, size_t len );
|
||||
void (*pfnSearch)( struct searchpath_s *search, stringlist_t *list, const char *pattern, int caseinsensitive );
|
||||
byte *(*pfnLoadFile)( struct searchpath_s *search, const char *path, int pack_ind, fs_offset_t *filesize );
|
||||
byte *(*pfnLoadFile)( struct searchpath_s *search, const char *path, int pack_ind, fs_offset_t *filesize, void *( *pfnAlloc )( size_t ), void ( *pfnFree )( void * ));
|
||||
} searchpath_t;
|
||||
|
||||
typedef searchpath_t *(*FS_ADDARCHIVE_FULLPATH)( const char *path, int flags );
|
||||
@@ -181,6 +181,7 @@ qboolean FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize );
|
||||
|
||||
// file buffer ops
|
||||
byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
|
||||
byte *FS_LoadFileMalloc( const char *path, fs_offset_t *filesizeptr, qboolean gamedironly );
|
||||
byte *FS_LoadDirectFile( const char *path, fs_offset_t *filesizeptr );
|
||||
qboolean FS_WriteFile( const char *filename, const void *data, fs_offset_t len );
|
||||
|
||||
|
||||
@@ -591,7 +591,7 @@ W_ReadLump
|
||||
reading lump into temp buffer
|
||||
===========
|
||||
*/
|
||||
static byte *W_ReadLump( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *lumpsizeptr )
|
||||
static byte *W_ReadLump( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *lumpsizeptr, void *( *pfnAlloc )( size_t ), void ( *pfnFree )( void * ))
|
||||
{
|
||||
const wfile_t *wad = search->wad;
|
||||
const dlumpinfo_t *lump = &wad->lumps[pack_ind];
|
||||
@@ -613,19 +613,25 @@ static byte *W_ReadLump( searchpath_t *search, const char *path, int pack_ind, f
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = (byte *)Mem_Malloc( wad->mempool, lump->disksize );
|
||||
buf = (byte *)pfnAlloc( lump->disksize );
|
||||
if( unlikely( !buf ))
|
||||
{
|
||||
Con_Reportf( S_ERROR "%s: can't alloc %d bytes, no free memory\n", __func__, lump->disksize );
|
||||
FS_Seek( wad->handle, oldpos, SEEK_SET );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = FS_Read( wad->handle, buf, lump->disksize );
|
||||
FS_Seek( wad->handle, oldpos, SEEK_SET );
|
||||
|
||||
if( size < lump->disksize )
|
||||
{
|
||||
Con_Reportf( S_WARN "W_ReadLump: %s is probably corrupted\n", lump->name );
|
||||
FS_Seek( wad->handle, oldpos, SEEK_SET );
|
||||
Mem_Free( buf );
|
||||
pfnFree( buf );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if( lumpsizeptr ) *lumpsizeptr = lump->disksize;
|
||||
FS_Seek( wad->handle, oldpos, SEEK_SET );
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -422,7 +422,7 @@ FS_LoadZIPFile
|
||||
|
||||
===========
|
||||
*/
|
||||
static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *sizeptr )
|
||||
static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_ind, fs_offset_t *sizeptr, void *( *pfnAlloc )( size_t ), void ( *pfnFree )( void * ))
|
||||
{
|
||||
zipfile_t *file;
|
||||
byte *compressed_buffer = NULL, *decompressed_buffer = NULL;
|
||||
@@ -451,11 +451,16 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
|
||||
return NULL;
|
||||
}*/
|
||||
|
||||
decompressed_buffer = pfnAlloc( file->size + 1 );
|
||||
if( unlikely( !decompressed_buffer ))
|
||||
{
|
||||
Con_Reportf( S_ERROR "%s: can't alloc %d bytes, no free memory\n", __func__, file->size + 1 );
|
||||
return NULL;
|
||||
}
|
||||
decompressed_buffer[file->size] = '\0';
|
||||
|
||||
if( file->flags == ZIP_COMPRESSION_NO_COMPRESSION )
|
||||
{
|
||||
decompressed_buffer = Mem_Malloc( fs_mempool, file->size + 1 );
|
||||
decompressed_buffer[file->size] = '\0';
|
||||
|
||||
c = read( search->zip->handle, decompressed_buffer, file->size );
|
||||
if( c != file->size )
|
||||
{
|
||||
@@ -472,7 +477,7 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
|
||||
if( final_crc != file->crc32 )
|
||||
{
|
||||
Con_Reportf( S_ERROR "Zip_LoadFile: %s file crc32 mismatch\n", file->name );
|
||||
Mem_Free( decompressed_buffer );
|
||||
pfnFree( decompressed_buffer );
|
||||
return NULL;
|
||||
}
|
||||
#endif // ENABLE_CRC_CHECK
|
||||
@@ -485,8 +490,6 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
|
||||
else if( file->flags == ZIP_COMPRESSION_DEFLATED )
|
||||
{
|
||||
compressed_buffer = Mem_Malloc( fs_mempool, file->compressed_size + 1 );
|
||||
decompressed_buffer = Mem_Malloc( fs_mempool, file->size + 1 );
|
||||
decompressed_buffer[file->size] = '\0';
|
||||
|
||||
c = read( search->zip->handle, compressed_buffer, file->compressed_size );
|
||||
if( c != file->compressed_size )
|
||||
@@ -529,7 +532,7 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
|
||||
if( final_crc != file->crc32 )
|
||||
{
|
||||
Con_Reportf( S_ERROR "Zip_LoadFile: %s file crc32 mismatch\n", file->name );
|
||||
Mem_Free( decompressed_buffer );
|
||||
pfnFree( decompressed_buffer );
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
@@ -542,7 +545,7 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
|
||||
{
|
||||
Con_Reportf( S_ERROR "Zip_LoadFile: %s : error while file decompressing. Zlib return code %d.\n", file->name, zlib_result );
|
||||
Mem_Free( compressed_buffer );
|
||||
Mem_Free( decompressed_buffer );
|
||||
pfnFree( decompressed_buffer );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -550,6 +553,7 @@ static byte *FS_LoadZIPFile( searchpath_t *search, const char *path, int pack_in
|
||||
else
|
||||
{
|
||||
Con_Reportf( S_ERROR "Zip_LoadFile: %s : file compressed with unknown algorithm.\n", file->name );
|
||||
pfnFree( decompressed_buffer );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -95,8 +95,6 @@ const char *Q_PlatformStringByID( const int platform )
|
||||
return "win32";
|
||||
case PLATFORM_ANDROID:
|
||||
return "android";
|
||||
case PLATFORM_LINUX_UNKNOWN:
|
||||
return "linuxunkabi";
|
||||
case PLATFORM_LINUX:
|
||||
return "linux";
|
||||
case PLATFORM_APPLE:
|
||||
|
||||
@@ -69,7 +69,6 @@ Then you can use another oneliner to query all variables:
|
||||
#undef XASH_IRIX
|
||||
#undef XASH_JS
|
||||
#undef XASH_LINUX
|
||||
#undef XASH_LINUX_UNKNOWN
|
||||
#undef XASH_LITTLE_ENDIAN
|
||||
#undef XASH_MIPS
|
||||
#undef XASH_MOBILE_PLATFORM
|
||||
@@ -103,13 +102,6 @@ Then you can use another oneliner to query all variables:
|
||||
#if defined __linux__
|
||||
#if defined __ANDROID__
|
||||
#define XASH_ANDROID 1
|
||||
#else
|
||||
#include <features.h>
|
||||
// if our system libc has features.h header
|
||||
// try to detect it to not confuse other libcs with built with glibc game libraries
|
||||
#if !defined __GLIBC__
|
||||
#define XASH_LINUX_UNKNOWN 1
|
||||
#endif
|
||||
#endif
|
||||
#define XASH_LINUX 1
|
||||
#elif defined __FreeBSD__
|
||||
|
||||
@@ -41,14 +41,11 @@ GNU General Public License for more details.
|
||||
#define PLATFORM_IRIX 12
|
||||
#define PLATFORM_NSWITCH 13
|
||||
#define PLATFORM_PSVITA 14
|
||||
#define PLATFORM_LINUX_UNKNOWN 15
|
||||
|
||||
#if XASH_WIN32
|
||||
#define XASH_PLATFORM PLATFORM_WIN32
|
||||
#elif XASH_ANDROID
|
||||
#define XASH_PLATFORM PLATFORM_ANDROID
|
||||
#elif XASH_LINUX_UNKNOWN
|
||||
#define XASH_PLATFORM PLATFORM_LINUX_UNKNOWN
|
||||
#elif XASH_LINUX
|
||||
#define XASH_PLATFORM PLATFORM_LINUX
|
||||
#elif XASH_APPLE
|
||||
|
||||
@@ -12,7 +12,6 @@ static struct
|
||||
{
|
||||
{ PLATFORM_WIN32, "win32" },
|
||||
{ PLATFORM_ANDROID, "android" },
|
||||
{ PLATFORM_LINUX_UNKNOWN, "linuxunkabi" },
|
||||
{ PLATFORM_LINUX, "linux" },
|
||||
{ PLATFORM_APPLE, "apple" },
|
||||
{ PLATFORM_FREEBSD, "freebsd" },
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
623
ref/null/r_context.c
Normal file
623
ref/null/r_context.c
Normal file
@@ -0,0 +1,623 @@
|
||||
/*
|
||||
r_context.c -- null renderer context
|
||||
Copyright (C) 2023-2024 a1batross
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This 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 <string.h>
|
||||
#include "xash3d_types.h"
|
||||
#include "const.h"
|
||||
#include "cvardef.h"
|
||||
#include "xash3d_mathlib.h"
|
||||
#include "ref_api.h"
|
||||
|
||||
/*
|
||||
* this initially was made to be able to run full client
|
||||
* in hazardous^Wheadless environments
|
||||
* but might be a starting point for new renderers as well
|
||||
*/
|
||||
|
||||
static ref_api_t gEngfuncs;
|
||||
static ref_globals_t *gpGlobals;
|
||||
|
||||
static void R_SimpleStub( void )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void R_SimpleStubInt( int )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void R_SimpleStubUInt( unsigned int )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void R_SimpleStubBool( qboolean )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static qboolean R_Init( void )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char *R_GetConfigName( void )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static qboolean R_SetDisplayTransform( ref_screen_rotation_t rotate, int x, int y, float scale_x, float scale_y )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void GL_SetupAttributes( int safegl )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static qboolean R_AddEntity( struct cl_entity_s *clent, int type )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void CL_AddCustomBeam( cl_entity_t *pEnvBeam )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void R_ProcessEntData( qboolean allocate, cl_entity_t *entities, unsigned int max_entities )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static const byte *R_GetTextureOriginalBuffer( unsigned int idx )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int GL_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void R_SetupSky( const char *skyname )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, const byte *data, qboolean dirty )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, int texnum )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void R_DrawTileClear( int texnum, int x, int y, int w, int h )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void FillRGBA( float x, float y, float w, float h, int r, int g, int b, int a )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static int WorldToScreen( const vec3_t world, vec3_t screen )
|
||||
{
|
||||
VectorClear( screen );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static qboolean VID_ScreenShot( const char *filename, int shot_type )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static qboolean VID_CubemapShot( const char *base, uint size, const float *vieworg, qboolean skyshot )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static colorVec R_LightPoint( const float *p )
|
||||
{
|
||||
colorVec c = { 0 };
|
||||
return c;
|
||||
}
|
||||
|
||||
static void R_DecalShoot( int textureIndex, int entityIndex, int modelIndex, vec3_t pos, int flags, float scale )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static int R_CreateDecalList( struct decallist_s *pList )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static float R_StudioEstimateFrame( cl_entity_t *e, mstudioseqdesc_t *pseqdesc, double time )
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
static void R_StudioLerpMovement( cl_entity_t *e, double time, vec3_t origin, vec3_t angles )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void R_InitSkyClouds( struct mip_s *mt, struct texture_s *tx, qboolean custom_palette )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void GL_SubdivideSurface( model_t *mod, msurface_t *fa )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void R_GetSpriteParms( int *frameWidth, int *frameHeight, int *numFrames, int currentFrame, const model_t *pSprite )
|
||||
{
|
||||
*frameWidth = *frameHeight = *numFrames = 0;
|
||||
}
|
||||
|
||||
static int R_GetSpriteTexture( const model_t *m_pSpriteModel, int frame )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void Mod_LoadMapSprite( struct model_s *mod, const void *buffer, size_t size, qboolean *loaded )
|
||||
{
|
||||
*loaded = false;
|
||||
return;
|
||||
}
|
||||
|
||||
static qboolean Mod_ProcessRenderData( model_t *mod, qboolean create, const byte *buffer )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Mod_StudioLoadTextures( model_t *mod, void *data )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void CL_DrawParticles( double frametime, particle_t *particles, float partsize )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void CL_DrawTracers( double frametime, particle_t *tracers )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void CL_DrawBeams( int fTrans, BEAM *beams )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static qboolean R_BeamCull( const vec3_t start, const vec3_t end, qboolean pvsOnly )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static int RefGetParm( int parm, int arg )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void GetDetailScaleForTexture( int texture, float *xScale, float *yScale )
|
||||
{
|
||||
*xScale = *yScale = 1.0f;
|
||||
}
|
||||
|
||||
static void GetExtraParmsForTexture( int texture, byte *red, byte *green, byte *blue, byte *alpha )
|
||||
{
|
||||
*red = *green = *blue = *alpha = 0;
|
||||
}
|
||||
|
||||
static float GetFrameTime( void )
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
static void R_SetCurrentEntity( struct cl_entity_s *ent )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void R_SetCurrentModel( struct model_s *mod )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static int GL_FindTexture( const char *name )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *GL_TextureName( unsigned int texnum )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const byte *GL_TextureData( unsigned int texnum )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int GL_LoadTexture( const char *name, const byte *buf, size_t size, int flags )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int GL_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int GL_LoadTextureArray( const char **names, int flags )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int GL_CreateTextureArray( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void DrawSingleDecal( struct decal_s *pDecal, struct msurface_s *fa )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static float *R_DecalSetupVerts( struct decal_s *pDecal, struct msurface_s *surf, int texture, int *outCount )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void R_EntityRemoveDecals( struct model_s *mod )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void AVI_UploadRawFrame( int texture, int cols, int rows, int width, int height, const byte *data )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void GL_Bind( int tmu, unsigned int texnum )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void GL_LoadTextureMatrix( const float *glmatrix )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void GL_TexGen( unsigned int coord, unsigned int mode )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void GL_UpdateTexSize( int texnum, int width, int height, int depth )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void GL_DrawParticles( const struct ref_viewpass_s *rvp, qboolean trans_pass, float frametime )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static colorVec LightVec( const float *start, const float *end, float *lightspot, float *lightvec )
|
||||
{
|
||||
colorVec c = { 0 };
|
||||
return c;
|
||||
}
|
||||
|
||||
static struct mstudiotex_s *StudioGetTexture( struct cl_entity_s *e )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void GL_RenderFrame( const struct ref_viewpass_s *rvp )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void GL_OrthoBounds( const float *mins, const float *maxs )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static qboolean R_SpeedsMessage( char *out, size_t size )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static byte *Mod_GetCurrentVis( void )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *R_GetProcAddress( const char *name )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void Color4f( float r, float g, float b, float a )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void Color4ub( unsigned char r, unsigned char g, unsigned char b, unsigned char a )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void TexCoord2f( float u, float v )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void Vertex3fv( const float *worldPnt )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void Vertex3f( float x, float y, float z )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void Fog( float flFogColor[3], float flStart, float flEnd, int bOn )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void ScreenToWorld( const float *screen, float *world )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void GetMatrix( const int pname, float *matrix )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void FogParams( float flDensity, int iFogSkybox )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void CullFace( TRICULLSTYLE mode )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void VGUI_SetupDrawing( int *pColor )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void VGUI_EnableTexture( qboolean enable )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void VGUI_CreateTexture( int id, int width, int height )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void VGUI_UploadTexture( int id, const char *buffer, int width, int height )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void VGUI_UploadTextureBlock( int id, int drawX, int drawY, const byte *rgba, int blockWidth, int blockHeight )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void VGUI_DrawQuad( const vpoint_t *ul, const vpoint_t *lr )
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
static void VGUI_GetTextureSizes( int *width, int *height )
|
||||
{
|
||||
*width = *height = 0;
|
||||
}
|
||||
|
||||
static int VGUI_GenerateTexture( void )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ref_interface_t gReffuncs =
|
||||
{
|
||||
.R_Init = R_Init,
|
||||
.R_Shutdown = R_SimpleStub,
|
||||
.R_GetConfigName = R_GetConfigName,
|
||||
.R_SetDisplayTransform = R_SetDisplayTransform,
|
||||
|
||||
.GL_SetupAttributes = GL_SetupAttributes,
|
||||
.GL_InitExtensions = R_SimpleStub,
|
||||
.GL_ClearExtensions = R_SimpleStub,
|
||||
|
||||
.R_GammaChanged = R_SimpleStubBool,
|
||||
.R_BeginFrame = R_SimpleStubBool,
|
||||
.R_RenderScene = R_SimpleStub,
|
||||
.R_EndFrame = R_SimpleStub,
|
||||
.R_PushScene = R_SimpleStub,
|
||||
.R_PopScene = R_SimpleStub,
|
||||
.GL_BackendStartFrame = R_SimpleStub,
|
||||
.GL_BackendEndFrame = R_SimpleStub,
|
||||
|
||||
.R_ClearScreen = R_SimpleStub,
|
||||
.R_AllowFog = R_SimpleStubBool,
|
||||
.GL_SetRenderMode = R_SimpleStubInt,
|
||||
|
||||
.R_AddEntity = R_AddEntity,
|
||||
.CL_AddCustomBeam = CL_AddCustomBeam,
|
||||
.R_ProcessEntData = R_ProcessEntData,
|
||||
.R_Flush = R_SimpleStubUInt,
|
||||
|
||||
.R_ShowTextures = R_SimpleStub,
|
||||
|
||||
.R_GetTextureOriginalBuffer = R_GetTextureOriginalBuffer,
|
||||
.GL_LoadTextureFromBuffer = GL_LoadTextureFromBuffer,
|
||||
.GL_ProcessTexture = GL_ProcessTexture,
|
||||
.R_SetupSky = R_SetupSky,
|
||||
|
||||
.R_Set2DMode = R_SimpleStubBool,
|
||||
.R_DrawStretchRaw = R_DrawStretchRaw,
|
||||
.R_DrawStretchPic = R_DrawStretchPic,
|
||||
.R_DrawTileClear = R_DrawTileClear,
|
||||
.FillRGBA = FillRGBA,
|
||||
.FillRGBABlend = FillRGBA,
|
||||
.WorldToScreen = WorldToScreen,
|
||||
|
||||
.VID_ScreenShot = VID_ScreenShot,
|
||||
.VID_CubemapShot = VID_CubemapShot,
|
||||
|
||||
.R_LightPoint = R_LightPoint,
|
||||
|
||||
.R_DecalShoot = R_DecalShoot,
|
||||
.R_DecalRemoveAll = R_SimpleStubInt,
|
||||
.R_CreateDecalList = R_CreateDecalList,
|
||||
.R_ClearAllDecals = R_SimpleStub,
|
||||
|
||||
.R_StudioEstimateFrame = R_StudioEstimateFrame,
|
||||
.R_StudioLerpMovement = R_StudioLerpMovement,
|
||||
.CL_InitStudioAPI = R_SimpleStub,
|
||||
|
||||
.R_InitSkyClouds = R_InitSkyClouds,
|
||||
.GL_SubdivideSurface = GL_SubdivideSurface,
|
||||
.CL_RunLightStyles = R_SimpleStub,
|
||||
|
||||
.R_GetSpriteParms = R_GetSpriteParms,
|
||||
.R_GetSpriteTexture = R_GetSpriteTexture,
|
||||
|
||||
.Mod_LoadMapSprite = Mod_LoadMapSprite,
|
||||
.Mod_ProcessRenderData = Mod_ProcessRenderData,
|
||||
.Mod_StudioLoadTextures = Mod_StudioLoadTextures,
|
||||
|
||||
.CL_DrawParticles = CL_DrawParticles,
|
||||
.CL_DrawTracers = CL_DrawTracers,
|
||||
.CL_DrawBeams = CL_DrawBeams,
|
||||
.R_BeamCull = R_BeamCull,
|
||||
|
||||
.RefGetParm = RefGetParm,
|
||||
.GetDetailScaleForTexture = GetDetailScaleForTexture,
|
||||
.GetExtraParmsForTexture = GetExtraParmsForTexture,
|
||||
.GetFrameTime = GetFrameTime,
|
||||
|
||||
.R_SetCurrentEntity = R_SetCurrentEntity,
|
||||
.R_SetCurrentModel = R_SetCurrentModel,
|
||||
|
||||
.GL_FindTexture = GL_FindTexture,
|
||||
.GL_TextureName = GL_TextureName,
|
||||
.GL_TextureData = GL_TextureData,
|
||||
.GL_LoadTexture = GL_LoadTexture,
|
||||
.GL_CreateTexture = GL_CreateTexture,
|
||||
.GL_LoadTextureArray = GL_LoadTextureArray,
|
||||
.GL_CreateTextureArray = GL_CreateTextureArray,
|
||||
.GL_FreeTexture = R_SimpleStubUInt,
|
||||
|
||||
.DrawSingleDecal = DrawSingleDecal,
|
||||
.R_DecalSetupVerts = R_DecalSetupVerts,
|
||||
.R_EntityRemoveDecals = R_EntityRemoveDecals,
|
||||
|
||||
.AVI_UploadRawFrame = AVI_UploadRawFrame,
|
||||
|
||||
.GL_Bind = GL_Bind,
|
||||
.GL_SelectTexture = R_SimpleStubInt,
|
||||
.GL_LoadTextureMatrix = GL_LoadTextureMatrix,
|
||||
.GL_TexMatrixIdentity = R_SimpleStub,
|
||||
.GL_CleanUpTextureUnits = R_SimpleStubInt,
|
||||
.GL_TexGen = GL_TexGen,
|
||||
.GL_TextureTarget = R_SimpleStubUInt,
|
||||
.GL_TexCoordArrayMode = R_SimpleStubUInt,
|
||||
.GL_UpdateTexSize = GL_UpdateTexSize,
|
||||
.GL_Reserved0 = NULL,
|
||||
.GL_Reserved1 = NULL,
|
||||
|
||||
.GL_DrawParticles = GL_DrawParticles,
|
||||
.LightVec = LightVec,
|
||||
.StudioGetTexture = StudioGetTexture,
|
||||
|
||||
.GL_RenderFrame = GL_RenderFrame,
|
||||
.GL_OrthoBounds = GL_OrthoBounds,
|
||||
.R_SpeedsMessage = R_SpeedsMessage,
|
||||
.Mod_GetCurrentVis = Mod_GetCurrentVis,
|
||||
.R_NewMap = R_SimpleStub,
|
||||
.R_ClearScene = R_SimpleStub,
|
||||
.R_GetProcAddress = R_GetProcAddress,
|
||||
|
||||
.TriRenderMode = R_SimpleStubInt,
|
||||
.Begin = R_SimpleStubInt,
|
||||
.End = R_SimpleStub,
|
||||
.Color4f = Color4f,
|
||||
.Color4ub = Color4ub,
|
||||
.TexCoord2f = TexCoord2f,
|
||||
.Vertex3fv = Vertex3fv,
|
||||
.Vertex3f = Vertex3f,
|
||||
.Fog = Fog,
|
||||
.ScreenToWorld = ScreenToWorld,
|
||||
.GetMatrix = GetMatrix,
|
||||
.FogParams = FogParams,
|
||||
.CullFace = CullFace,
|
||||
|
||||
.VGUI_DrawInit = R_SimpleStub,
|
||||
.VGUI_DrawShutdown = R_SimpleStub,
|
||||
.VGUI_SetupDrawingText = VGUI_SetupDrawing,
|
||||
.VGUI_SetupDrawingRect = VGUI_SetupDrawing,
|
||||
.VGUI_SetupDrawingImage = VGUI_SetupDrawing,
|
||||
.VGUI_BindTexture = R_SimpleStubInt,
|
||||
.VGUI_EnableTexture = VGUI_EnableTexture,
|
||||
.VGUI_CreateTexture = VGUI_CreateTexture,
|
||||
.VGUI_UploadTexture = VGUI_UploadTexture,
|
||||
.VGUI_UploadTextureBlock = VGUI_UploadTextureBlock,
|
||||
.VGUI_DrawQuad = VGUI_DrawQuad,
|
||||
.VGUI_GetTextureSizes = VGUI_GetTextureSizes,
|
||||
.VGUI_GenerateTexture = VGUI_GenerateTexture,
|
||||
};
|
||||
|
||||
int EXPORT GetRefAPI( int version, ref_interface_t *funcs, ref_api_t *engfuncs, ref_globals_t *globals );
|
||||
int EXPORT GetRefAPI( int version, ref_interface_t *funcs, ref_api_t *engfuncs, ref_globals_t *globals )
|
||||
{
|
||||
if( version != REF_API_VERSION )
|
||||
return 0;
|
||||
|
||||
// fill in our callbacks
|
||||
memcpy( funcs, &gReffuncs, sizeof( ref_interface_t ));
|
||||
memcpy( &gEngfuncs, engfuncs, sizeof( ref_api_t ));
|
||||
gpGlobals = globals;
|
||||
|
||||
return REF_API_VERSION;
|
||||
}
|
||||
20
ref/null/wscript
Normal file
20
ref/null/wscript
Normal file
@@ -0,0 +1,20 @@
|
||||
#! /usr/bin/env python
|
||||
# encoding: utf-8
|
||||
# mittorn, 2018
|
||||
|
||||
def options(opt):
|
||||
pass
|
||||
|
||||
def configure(conf):
|
||||
pass
|
||||
|
||||
def build(bld):
|
||||
bld.shlib(
|
||||
source = 'r_context.c',
|
||||
target = 'ref_null',
|
||||
features = 'c',
|
||||
defines = 'REF_DLL',
|
||||
use = 'engine_includes sdk_includes werror',
|
||||
install_path = bld.env.LIBDIR,
|
||||
subsystem = bld.env.MSVC_SUBSYSTEM
|
||||
)
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -7,16 +7,16 @@ export PATH=$PATH:$JAVA_HOME/bin:$ANDROID_HOME/tools:$ANDROID_HOME/tools/bin:$AN
|
||||
|
||||
pushd android
|
||||
|
||||
./gradlew assembleContinuous
|
||||
./gradlew assembleDebug
|
||||
|
||||
pushd app/build/outputs/apk/continuous
|
||||
pushd app/build/outputs/apk/debug
|
||||
|
||||
$ANDROID_HOME/build-tools/34.0.0/apksigner sign --ks $GITHUB_WORKSPACE/android/debug.keystore --ks-key-alias androiddebugkey \
|
||||
--ks-pass pass:android --key-pass pass:android --out app-continuous-signed.apk app-continuous-unsigned.apk
|
||||
--ks-pass pass:android --key-pass pass:android --out app-debug-signed.apk app-debug.apk
|
||||
|
||||
popd
|
||||
popd
|
||||
|
||||
mkdir -p artifacts/
|
||||
|
||||
mv android/app/build/outputs/apk/continuous/app-continuous-signed.apk artifacts/xash3d-fwgs-android.apk
|
||||
mv android/app/build/outputs/apk/debug/app-debug-signed.apk artifacts/xash3d-fwgs-android.apk
|
||||
|
||||
@@ -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
82
scripts/waifulib/psp.py
Normal 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])
|
||||
@@ -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()
|
||||
|
||||
@@ -16,7 +16,7 @@ class ziparchive(Task.Task):
|
||||
return 'Creating'
|
||||
|
||||
def run(self):
|
||||
outfile = self.outputs[0].path_from(self.outputs[0].ctx.launch_node())
|
||||
outfile = self.outputs[0].abspath()
|
||||
comp = zipfile.ZIP_STORED if self.compresslevel == 0 else zipfile.ZIP_DEFLATED
|
||||
|
||||
with zipfile.ZipFile(outfile, mode='w', compression=comp) as zf:
|
||||
@@ -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
|
||||
|
||||
52
wscript
52
wscript
@@ -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,12 +69,13 @@ 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),
|
||||
Subproject('ref/gl', lambda x: not x.env.DEDICATED and (x.env.GL or x.env.NANOGL or x.env.GLWES or x.env.GL4ES)),
|
||||
Subproject('ref/soft', lambda x: not x.env.DEDICATED and not x.env.SUPPORT_BSP2_FORMAT and x.env.SOFT),
|
||||
Subproject('ref/null', lambda x: not x.env.DEDICATED and x.env.NULL),
|
||||
Subproject('3rdparty/mainui', lambda x: not x.env.DEDICATED),
|
||||
Subproject('3rdparty/vgui_support', lambda x: not x.env.DEDICATED),
|
||||
Subproject('stub/client', lambda x: not x.env.DEDICATED),
|
||||
@@ -100,8 +101,45 @@ REFDLLS = [
|
||||
RefDll('gles2', False, 'GLWES'),
|
||||
RefDll('gl4es', False),
|
||||
RefDll('gles3compat', False),
|
||||
RefDll('null', False),
|
||||
]
|
||||
|
||||
def process_extra_projects_opts(ctx):
|
||||
options, commands, envvars = ctx.parse_cmd_args(allow_unknown = True)
|
||||
projs = options.EXTRA_PROJECTS
|
||||
if not projs:
|
||||
return
|
||||
for proj in projs.split(','):
|
||||
ctx.add_subproject(proj)
|
||||
def process_extra_projects_conf(ctx):
|
||||
projs = ctx.options.EXTRA_PROJECTS
|
||||
if not projs:
|
||||
return
|
||||
ctx.env.EXTRA_PROJECTS = projs
|
||||
|
||||
for proj in projs.split(','):
|
||||
tools_orig = ctx.tools.copy()
|
||||
ctx.add_subproject(proj)
|
||||
waifulib_path = os.path.join(proj, 'scripts', 'waifulib')
|
||||
if os.path.isdir(waifulib_path):
|
||||
for tool in ctx.tools:
|
||||
if not tool in tools_orig:
|
||||
if os.path.isfile(os.path.join(waifulib_path, tool['tool'] + '.py')):
|
||||
tool['tooldir'] = [waifulib_path]
|
||||
Logs.info('External tooldir set: ' + str(tool))
|
||||
|
||||
|
||||
def process_extra_projects_bld(ctx):
|
||||
projs = ctx.env.EXTRA_PROJECTS
|
||||
if not projs:
|
||||
return
|
||||
for proj in projs.split(','):
|
||||
ctx.add_subproject(proj)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def options(opt):
|
||||
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')
|
||||
|
||||
@@ -152,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')
|
||||
@@ -195,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
|
||||
@@ -491,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
|
||||
@@ -513,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)
|
||||
|
||||
Reference in New Issue
Block a user