lowmemory: merge

This commit is contained in:
Alibek Omarov 2019-11-05 01:15:31 +03:00
commit 79adaa11e0
33 changed files with 1379 additions and 107 deletions

View File

@ -126,6 +126,9 @@ GNU General Public License for more details.
#define XASH_ALLOW_SAVERESTORE_OFFSETS
#endif
#endif //WIN32
#ifndef XASH_LOW_MEMORY
#define XASH_LOW_MEMORY 0
#endif
#include <stdlib.h>
#include <string.h>

View File

@ -142,7 +142,13 @@ typedef void (*setpair_t)( const char *key, const void *value, void *buffer, voi
// config strings are a general means of communication from
// the server to all connected clients.
// each config string can be at most CS_SIZE characters.
#if XASH_LOW_MEMORY == 0
#define MAX_QPATH 64 // max length of a game pathname
#elif XASH_LOW_MEMORY == 2
#define MAX_QPATH 32 // should be enough for singleplayer
#elif XASH_LOW_MEMORY == 1
#define MAX_QPATH 48
#endif
#define MAX_OSPATH 260 // max length of a filesystem pathname
#define CS_SIZE 64 // size of one config string
#define CS_TIME 16 // size of time string

View File

@ -1123,8 +1123,9 @@ void CL_InitEdicts( void )
Assert( clgame.entities == NULL );
if( !clgame.mempool ) return; // Host_Error without client
CL_UPDATE_BACKUP = ( cl.maxclients == 1 ) ? SINGLEPLAYER_BACKUP : MULTIPLAYER_BACKUP;
#if XASH_LOW_MEMORY != 2
CL_UPDATE_BACKUP = ( cl.maxclients <= 1 ) ? SINGLEPLAYER_BACKUP : MULTIPLAYER_BACKUP;
#endif
cls.num_client_entities = CL_UPDATE_BACKUP * NUM_PACKET_ENTITIES;
cls.packet_entities = Mem_Realloc( clgame.mempool, cls.packet_entities, sizeof( entity_state_t ) * cls.num_client_entities );
clgame.entities = Mem_Calloc( clgame.mempool, sizeof( cl_entity_t ) * clgame.maxEntities );

View File

@ -21,9 +21,9 @@ GNU General Public License for more details.
#include "shake.h"
#include "hltv.h"
#include "input.h"
#if XASH_LOW_MEMORY != 2
int CL_UPDATE_BACKUP = SINGLEPLAYER_BACKUP;
#endif
/*
===============
CL_UserMsgStub
@ -92,7 +92,7 @@ void CL_ParseSoundPacket( sizebuf_t *msg )
char sentenceName[32];
if( FBitSet( flags, SND_SEQUENCE ))
Q_snprintf( sentenceName, sizeof( sentenceName ), "!#%i", sound + MAX_SOUNDS );
Q_snprintf( sentenceName, sizeof( sentenceName ), "!#%i", sound + MAX_SOUNDS_NONSENTENCE );
else Q_snprintf( sentenceName, sizeof( sentenceName ), "!%i", sound );
handle = S_RegisterSound( sentenceName );
@ -156,7 +156,7 @@ void CL_ParseRestoreSoundPacket( sizebuf_t *msg )
char sentenceName[32];
if( flags & SND_SEQUENCE )
Q_snprintf( sentenceName, sizeof( sentenceName ), "!%i", sound + MAX_SOUNDS );
Q_snprintf( sentenceName, sizeof( sentenceName ), "!%i", sound + MAX_SOUNDS_NONSENTENCE );
else Q_snprintf( sentenceName, sizeof( sentenceName ), "!%i", sound );
handle = S_RegisterSound( sentenceName );
@ -881,7 +881,7 @@ void CL_ParseServerData( sizebuf_t *msg )
cl.playernum = MSG_ReadByte( msg );
cl.maxclients = MSG_ReadByte( msg );
clgame.maxEntities = MSG_ReadWord( msg );
clgame.maxEntities = bound( 600, clgame.maxEntities, MAX_EDICTS );
clgame.maxEntities = bound( MIN_EDICTS, clgame.maxEntities, MAX_EDICTS );
clgame.maxModels = MSG_ReadWord( msg );
Q_strncpy( clgame.mapname, MSG_ReadString( msg ), MAX_STRING );
Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), MAX_STRING );
@ -1411,6 +1411,36 @@ void CL_ParseResource( sizebuf_t *msg )
if( MSG_ReadOneBit( msg ))
MSG_ReadBytes( msg, pResource->rguc_reserved, sizeof( pResource->rguc_reserved ));
if( pResource->type == t_sound && pResource->nIndex > MAX_SOUNDS )
{
Mem_Free( pResource );
Host_Error( "bad sound index\n" );
}
if( pResource->type == t_model && pResource->nIndex > MAX_MODELS )
{
Mem_Free( pResource );
Host_Error( "bad model index\n" );
}
if( pResource->type == t_eventscript && pResource->nIndex > MAX_EVENTS )
{
Mem_Free( pResource );
Host_Error( "bad event index\n" );
}
if( pResource->type == t_generic && pResource->nIndex > MAX_CUSTOM )
{
Mem_Free( pResource );
Host_Error( "bad file index\n" );
}
if( pResource->type == t_decal && pResource->nIndex > MAX_DECALS )
{
Mem_Free( pResource );
Host_Error( "bad decal index\n" );
}
CL_AddToResourceList( pResource, &cl.resourcesneeded );
}
@ -2394,7 +2424,7 @@ void CL_ParseLegacyServerData( sizebuf_t *msg )
cl.playernum = MSG_ReadByte( msg );
cl.maxclients = MSG_ReadByte( msg );
clgame.maxEntities = MSG_ReadWord( msg );
clgame.maxEntities = bound( 600, clgame.maxEntities, 4096 );
clgame.maxEntities = bound( 30, clgame.maxEntities, 4096 );
clgame.maxModels = 512;
Q_strncpy( clgame.mapname, MSG_ReadString( msg ), MAX_STRING );
Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), MAX_STRING );
@ -2724,7 +2754,13 @@ void CL_LegacyUpdateUserinfo( sizebuf_t *msg )
}
else memset( player, 0, sizeof( *player ));
}
#if XASH_LOW_MEMORY == 0
#define MAX_LEGACY_RESOURCES 2048
#elif XASH_LOW_MEMORY == 2
#define MAX_LEGACY_RESOURCES 1
#elif XASH_LOW_MEMORY == 1
#define MAX_LEGACY_RESOURCES 512
#endif
/*
==============
CL_ParseResourceList
@ -2738,17 +2774,20 @@ void CL_LegacyParseResourceList( sizebuf_t *msg )
static struct
{
int rescount;
int restype[MAX_RESOURCES];
char resnames[MAX_RESOURCES][CS_SIZE];
int restype[MAX_LEGACY_RESOURCES];
char resnames[MAX_LEGACY_RESOURCES][MAX_QPATH];
} reslist;
memset( &reslist, 0, sizeof( reslist ));
reslist.rescount = MSG_ReadWord( msg ) - 1;
if( reslist.rescount > MAX_LEGACY_RESOURCES )
Host_Error("MAX_RESOURCES reached\n");
for( i = 0; i < reslist.rescount; i++ )
{
reslist.restype[i] = MSG_ReadWord( msg );
Q_strncpy( reslist.resnames[i], MSG_ReadString( msg ), CS_SIZE );
Q_strncpy( reslist.resnames[i], MSG_ReadString( msg ), MAX_QPATH );
}
if( CL_IsPlaybackDemo() )

View File

@ -486,6 +486,7 @@ void V_PostRender( void )
Con_DrawVersion();
Con_DrawDebug(); // must be last
Touch_Draw();
OSK_Draw();
S_ExtraUpdate();
}

View File

@ -96,7 +96,11 @@ typedef struct
#define ANGLE_MASK (ANGLE_BACKUP - 1)
#define CL_UPDATE_MASK (CL_UPDATE_BACKUP - 1)
#if XASH_LOW_MEMORY == 2
#define CL_UPDATE_BACKUP SINGLEPLAYER_BACKUP
#else
extern int CL_UPDATE_BACKUP;
#endif
#define SIGNONS 2 // signon messages to receive before connected
#define INVALID_HANDLE 0xFFFF // for XashXT cache system
@ -1115,6 +1119,26 @@ void SCR_RunCinematic( void );
void SCR_StopCinematic( void );
void CL_PlayVideo_f( void );
//
// keys.c
//
int Key_IsDown( int keynum );
const char *Key_IsBind( int keynum );
void Key_Event( int key, int down );
void Key_Init( void );
void Key_WriteBindings( file_t *f );
const char *Key_GetBinding( int keynum );
void Key_SetBinding( int keynum, const char *binding );
void Key_ClearStates( void );
const char *Key_KeynumToString( int keynum );
int Key_StringToKeynum( const char *str );
int Key_GetKey( const char *binding );
void Key_EnumCmds_f( void );
void Key_SetKeyDest( int key_dest );
void Key_EnableTextInput( qboolean enable, qboolean force );
void OSK_Draw( void );
extern rgba_t g_color_table[8];
#endif//CLIENT_H

View File

@ -37,15 +37,19 @@ static qboolean g_utf8 = false;
#define COLOR_DEFAULT '7'
#define CON_HISTORY 64
#define MAX_DBG_NOTIFY 128
#if XASH_LOW_MEMORY
#define CON_NUMFONTS 1 // do not load different font textures
#define CON_TEXTSIZE 32768 // max scrollback buffer characters in console (32 kb)
#define CON_MAXLINES 2048 // max scrollback buffer lines in console
#else
#define CON_NUMFONTS 3 // maxfonts
#define CON_TEXTSIZE 1048576 // max scrollback buffer characters in console (1 Mb)
#define CON_MAXLINES 16384 // max scrollback buffer lines in console
#endif
#define CON_LINES( i ) (con.lines[(con.lines_first + (i)) % con.maxlines])
#define CON_LINES_COUNT con.lines_count
#define CON_LINES_LAST() CON_LINES( CON_LINES_COUNT - 1 )
#define CON_TEXTSIZE 1048576 // max scrollback buffer characters in console (1 Mb)
#define CON_MAXLINES 16384 // max scrollback buffer lines in console
// console color typeing
rgba_t g_color_table[8] =
{
@ -663,7 +667,7 @@ static void Con_LoadConchars( void )
int i, fontSize;
// load all the console fonts
for( i = 0; i < 3; i++ )
for( i = 0; i < CON_NUMFONTS; i++ )
Con_LoadConsoleFont( i, con.chars + i );
// select properly fontsize
@ -673,6 +677,9 @@ static void Con_LoadConchars( void )
fontSize = 2;
else fontSize = 1;
if( fontSize > CON_NUMFONTS - 1 )
fontSize = CON_NUMFONTS - 1;
// sets the current font
con.lastUsedFont = con.curFont = &con.chars[fontSize];
}
@ -929,7 +936,7 @@ choose font size
*/
void Con_SetFont( int fontNum )
{
fontNum = bound( 0, fontNum, 2 );
fontNum = bound( 0, fontNum, CON_NUMFONTS - 1 );
con.curFont = &con.chars[fontNum];
}
@ -1880,8 +1887,8 @@ void Con_DrawInput( int lines )
return;
y = lines - ( con.curFont->charHeight * 2 );
Con_DrawCharacter( 8, y, ']', g_color_table[7] );
Field_DrawInputLine( 16, y, &con.input );
Con_DrawCharacter( con.curFont->charWidths[' '], y, ']', g_color_table[7] );
Field_DrawInputLine( con.curFont->charWidths[' ']*2, y, &con.input );
}
/*
@ -2079,6 +2086,8 @@ void Con_DrawSolidConsole( int lines )
// draw the background
ref.dllFuncs.GL_SetRenderMode( kRenderNormal );
ref.dllFuncs.Color4ub( 255, 255, 255, 255 ); // to prevent grab color from screenfade
if( refState.width * 3 / 4 < refState.height && lines >= refState.height )
ref.dllFuncs.R_DrawStretchPic( 0, lines - refState.height, refState.width, refState.height - refState.width * 3 / 4, 0, 0, 1, 1, R_GetBuiltinTexture( REF_BLACK_TEXTURE) );
ref.dllFuncs.R_DrawStretchPic( 0, lines - refState.width * 3 / 4, refState.width, refState.width * 3 / 4, 0, 0, 1, 1, con.background );
if( !con.curFont || !host.allow_console )
@ -2132,7 +2141,7 @@ void Con_DrawSolidConsole( int lines )
y -= Con_DrawConsoleLine( y, x );
// top of console buffer or console window
if( x == 0 || y < con.curFont->charHeight )
if( x == 0 || y < con.curFont->charHeight )
break;
x--;
}
@ -2356,10 +2365,11 @@ INTERNAL RESOURCE
*/
void Con_VidInit( void )
{
Con_CheckResize();
Con_LoadConchars();
Con_CheckResize();
#if XASH_LOW_MEMORY
con.background = R_GetBuiltinTexture( REF_BLACK_TEXTURE );
#else
// loading console image
if( host.allow_console )
{
@ -2434,6 +2444,7 @@ void Con_VidInit( void )
// missed console image will be replaced as gray background like X-Ray or Crysis
if( con.background == R_GetBuiltinTexture( REF_DEFAULT_TEXTURE ) || con.background == 0 )
con.background = R_GetBuiltinTexture( REF_GRAY_TEXTURE );
#endif
}
/*

View File

@ -140,6 +140,11 @@ keyname_t keynames[] =
{NULL, 0, NULL },
};
static void OSK_EnableTextInput( qboolean enable, qboolean force );
static qboolean OSK_KeyEvent( int key, int down );
static convar_t *osk_enable;
static convar_t *key_rotate;
/*
===================
Key_IsDown
@ -514,6 +519,10 @@ void Key_Init( void )
// setup default binding. "unbindall" from config.cfg will be reset it
for( kn = keynames; kn->name; kn++ ) Key_SetBinding( kn->keynum, kn->binding );
osk_enable = Cvar_Get( "osk_enable", "0", FCVAR_ARCHIVE, "enable built-in on-screen keyboard" );
key_rotate = Cvar_Get( "key_rotate", "0", FCVAR_ARCHIVE, "rotate arrow keys (0-3)" );
}
/*
@ -586,6 +595,48 @@ static qboolean Key_IsAllowedAutoRepeat( int key )
}
}
static int Key_Rotate( int key )
{
if( key_rotate->value == 1.0f ) // CW
{
if( key == K_UPARROW )
key = K_LEFTARROW;
else if( key == K_LEFTARROW )
key = K_DOWNARROW;
else if( key == K_RIGHTARROW )
key = K_UPARROW;
else if( key == K_DOWNARROW )
key = K_RIGHTARROW;
}
else if( key_rotate->value == 3.0f ) // CCW
{
if( key == K_UPARROW )
key = K_RIGHTARROW;
else if( key == K_LEFTARROW )
key = K_UPARROW;
else if( key == K_RIGHTARROW )
key = K_DOWNARROW;
else if( key == K_DOWNARROW )
key = K_LEFTARROW;
}
else if( key_rotate->value == 2.0f )
{
if( key == K_UPARROW )
key = K_DOWNARROW;
else if( key == K_LEFTARROW )
key = K_RIGHTARROW;
else if( key == K_RIGHTARROW )
key = K_LEFTARROW;
else if( key == K_DOWNARROW )
key = K_UPARROW;
}
return key;
}
/*
===================
Key_Event
@ -597,6 +648,11 @@ void Key_Event( int key, int down )
{
const char *kb;
key = Key_Rotate( key );
if( OSK_KeyEvent( key, down ) )
return;
// key was pressed before engine was run
if( !keys[key].down && !down )
return;
@ -749,6 +805,11 @@ Key_EnableTextInput
*/
void Key_EnableTextInput( qboolean enable, qboolean force )
{
if( CVAR_TO_BOOL( osk_enable ) )
{
OSK_EnableTextInput( enable, force );
return;
}
if( enable && ( !host.textmode || force ) )
Platform_EnableTextInput( true );
else if( !enable )
@ -845,3 +906,286 @@ void CL_CharEvent( int key )
UI_CharEvent( key );
}
}
/* On-screen keyboard:
*
* 4 lines with 13 buttons each
* Left trigger == backspace
* Right trigger == space
* Any button press is button press on keyboard
*
* Our layout:
* 0 1 2 3 4 5 6 7 8 9 10 11 12
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
* |` |1 |2 |3 |4 |5 |6 |7 |8 |9 |0 |- |= | 0
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
* |q |w |e |r |t |y |u |i |o |p |[ |] |\ | 1
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
* |CL|a |s |d |f |g |h |j |k |l |; |' |BS| 2
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
* |SH|z |x |c |v |b |n |m |, |. |/ |SP|EN| 3
* +--+--+--+--+--+--+--+--+--+--+--+--+--+
*/
#define MAX_OSK_ROWS 13
#define MAX_OSK_LINES 4
enum
{
OSK_DEFAULT = 0,
OSK_UPPER, // on caps, shift
/*
OSK_RUSSIAN,
OSK_RUSSIAN_UPPER,
*/
OSK_LAST
};
enum
{
OSK_TAB = 16,
OSK_SHIFT,
OSK_BACKSPACE,
OSK_ENTER,
OSK_SPECKEY_LAST
};
static const char *osk_keylayout[][4] =
{
{
"`1234567890-=", // 13
"qwertyuiop[]\\", // 13
"\x10" "asdfghjkl;'" "\x12", // 11 + caps on a left, enter on a right
"\x11" "zxcvbnm,./ " "\x13" // 10 + esc on left + shift on a left/right
},
{
"~!@#$%^&*()_+",
"QWERTYUIOP{}|",
"\x10" "ASDFGHJKL:\"" "\x12",
"\x11" "ZXCVBNM<>? " "\x13"
}
};
struct osk_s
{
qboolean enable;
int curlayout;
qboolean shift;
qboolean sending;
struct {
signed char x;
signed char y;
char val;
} curbutton;
} osk;
static qboolean OSK_KeyEvent( int key, int down )
{
if( !osk.enable || !CVAR_TO_BOOL( osk_enable ) )
return false;
if( osk.sending )
{
osk.sending = false;
return false;
}
if( osk.curbutton.val == 0 )
{
if( key == K_ENTER )
{
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
return true;
}
return false;
}
switch ( key )
{
case K_ENTER:
switch( osk.curbutton.val )
{
case OSK_ENTER:
osk.sending = true;
Key_Event( K_ENTER, down );
//osk_enable = false; // TODO: handle multiline
break;
case OSK_SHIFT:
if( !down )
break;
if( osk.curlayout & 1 )
osk.curlayout--;
else
osk.curlayout++;
osk.shift = osk.curbutton.val == OSK_SHIFT;
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
break;
case OSK_BACKSPACE:
Key_Event( K_BACKSPACE, down ); break;
case OSK_TAB:
Key_Event( K_TAB, down ); break;
default:
{
int ch;
if( !down )
{
if( osk.shift && osk.curlayout & 1 )
osk.curlayout--;
osk.shift = false;
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
break;
}
if( !Q_stricmp( cl_charset->string, "utf-8" ) )
ch = (unsigned char)osk.curbutton.val;
else
ch = Con_UtfProcessCharForce( (unsigned char)osk.curbutton.val );
if( !ch )
break;
Con_CharEvent( ch );
if( cls.key_dest == key_menu )
UI_CharEvent ( ch );
break;
}
}
break;
case K_UPARROW:
if( down && --osk.curbutton.y < 0 )
{
osk.curbutton.y = MAX_OSK_LINES - 1;
osk.curbutton.val = 0;
return true;
}
break;
case K_DOWNARROW:
if( down && ++osk.curbutton.y >= MAX_OSK_LINES )
{
osk.curbutton.y = 0;
osk.curbutton.val = 0;
return true;
}
break;
case K_LEFTARROW:
if( down && --osk.curbutton.x < 0 )
osk.curbutton.x = MAX_OSK_ROWS - 1;
break;
case K_RIGHTARROW:
if( down && ++osk.curbutton.x >= MAX_OSK_ROWS )
osk.curbutton.x = 0;
break;
default:
return false;
}
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
return true;
}
/*
=============
Joy_EnableTextInput
Enables built-in IME
=============
*/
static void OSK_EnableTextInput( qboolean enable, qboolean force )
{
qboolean old = osk.enable;
osk.enable = enable;
if( osk.enable && (!old || force) )
{
osk.curlayout = 0;
osk.curbutton.val = osk_keylayout[osk.curlayout][osk.curbutton.y][osk.curbutton.x];
}
}
#define X_START 0.1347475f
#define Y_START 0.567f
#define X_STEP 0.05625
#define Y_STEP 0.0825
/*
============
Joy_DrawSymbolButton
Draw button with symbol on it
============
*/
static void OSK_DrawSymbolButton( int symb, float x, float y, float width, float height )
{
char str[] = {symb & 255, 0};
byte color[] = { 255, 255, 255, 255 };
int x1 = x * refState.width,
y1 = y * refState.height,
w = width * refState.width,
h = height * refState.height;
if( symb == osk.curbutton.val )
{
ref.dllFuncs.FillRGBABlend( x1, y1, w, h, 255, 160, 0, 100 );
}
if( !symb || symb == ' ' || (symb >= OSK_TAB && symb < OSK_SPECKEY_LAST ) )
return;
Con_DrawCharacter( x1 + 1, y1, symb, color );
}
/*
=============
Joy_DrawSpecialButton
Draw special button, like shift, enter or esc
=============
*/
static void OSK_DrawSpecialButton( const char *name, float x, float y, float width, float height )
{
byte color[] = { 0, 255, 0, 255 };
Con_DrawString( x * refState.width, y * refState.height, name, color );
}
/*
=============
Joy_DrawOnScreenKeyboard
Draw on screen keyboard, if enabled
=============
*/
void OSK_Draw( void )
{
const char **curlayout = osk_keylayout[osk.curlayout]; // shortcut :)
float x, y;
int i, j;
if( !osk.enable || !CVAR_TO_BOOL(osk_enable) || !osk.curbutton.val )
return;
// draw keyboard
ref.dllFuncs.FillRGBABlend( X_START * refState.width, Y_START * refState.height,
X_STEP * MAX_OSK_ROWS * refState.width,
Y_STEP * MAX_OSK_LINES * refState.height, 100, 100, 100, 100 );
OSK_DrawSpecialButton( "-]", X_START, Y_START + Y_STEP * 2, X_STEP, Y_STEP );
OSK_DrawSpecialButton( "<-", X_START + X_STEP * 12, Y_START + Y_STEP * 2, X_STEP, Y_STEP );
OSK_DrawSpecialButton( "sh", X_START, Y_START + Y_STEP * 3, X_STEP, Y_STEP );
OSK_DrawSpecialButton( "en", X_START + X_STEP * 12, Y_START + Y_STEP * 3, X_STEP, Y_STEP );
for( y = Y_START, j = 0; j < MAX_OSK_LINES; j++, y += Y_STEP )
for( x = X_START, i = 0; i < MAX_OSK_ROWS; i++, x += X_STEP )
OSK_DrawSymbolButton( curlayout[j][i], x, y, X_STEP, Y_STEP );
}

View File

@ -558,7 +558,7 @@ static void SetWidthAndHeightFromCommandLine( void )
return;
}
R_SaveVideoMode( width, height );
R_SaveVideoMode( width, height, width, height );
}
static void SetFullscreenModeFromCommandLine( void )

View File

@ -31,6 +31,10 @@ glwstate_t glw_state;
convar_t *window_xpos;
convar_t *window_ypos;
convar_t *vid_rotate;
convar_t *vid_scale;
/*
=================
VID_StartupGamma
@ -62,19 +66,21 @@ void VID_InitDefaultResolution( void )
R_SaveVideoMode
=================
*/
void R_SaveVideoMode( int w, int h )
void R_SaveVideoMode( int w, int h , int render_w, int render_h )
{
refState.width = w;
refState.height = h;
host.window_center_x = w / 2;
host.window_center_y = h / 2;
Cvar_SetValue( "width", w );
Cvar_SetValue( "height", h );
refState.width = render_w;
refState.height = render_h;
host.renderinfo_changed = false;
// check for 4:3 or 5:4
if( w * 3 != h * 4 && w * 4 != h * 5 )
if( render_w * 3 != render_h * 4 && render_w * 4 != render_h * 5 )
refState.wideScreen = true;
else refState.wideScreen = false;
}
@ -175,6 +181,8 @@ void VID_Init( void )
vid_displayfrequency = Cvar_Get ( "vid_displayfrequency", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "fullscreen refresh rate" );
vid_fullscreen = Cvar_Get( "fullscreen", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "enable fullscreen mode" );
vid_highdpi = Cvar_Get( "vid_highdpi", "1", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "enable High-DPI mode" );
vid_rotate = Cvar_Get( "vid_rotate", "0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "screen rotation (0-3)" );
vid_scale = Cvar_Get( "vid_scale", "1.0", FCVAR_RENDERINFO|FCVAR_VIDRESTART, "pixel scale" );
// a1ba: planned to be named vid_mode for compability
// but supported mode list is filled by backends, so numbers are not portable any more

View File

@ -34,8 +34,11 @@ extern glwstate_t glw_state;
extern convar_t *vid_fullscreen;
extern convar_t *vid_displayfrequency;
extern convar_t *vid_highdpi;
extern convar_t *vid_rotate;
extern convar_t *vid_scale;
extern convar_t *gl_wgl_msaa_samples;
void R_SaveVideoMode( int w, int h );
void R_SaveVideoMode( int w, int h, int render_w, int render_h );
void VID_CheckChanges( void );
const char *VID_GetModeString( int vid_mode );
void VID_StartupGamma( void );

View File

@ -137,10 +137,18 @@ typedef enum
#define CIN_MAIN 0
#define CIN_LOGO 1
#if XASH_LOW_MEMORY == 0
#define MAX_DECALS 512 // touching TE_DECAL messages, etc
#define MAX_STATIC_ENTITIES 3096 // static entities that moved on the client when level is spawn
#elif XASH_LOW_MEMORY == 2
#define MAX_DECALS 256 // touching TE_DECAL messages, etc
#define MAX_STATIC_ENTITIES 32 // static entities that moved on the client when level is spawn
#elif XASH_LOW_MEMORY == 1
#define MAX_DECALS 512 // touching TE_DECAL messages, etc
#define MAX_STATIC_ENTITIES 128 // static entities that moved on the client when level is spawn
#endif
// filesystem flags
#define FS_STATIC_PATH ( 1U << 0 ) // FS_ClearSearchPath will be ignore this path
#define FS_NOWRITE_PATH ( 1U << 1 ) // default behavior - last added gamedir set as writedir. This flag disables it
@ -811,24 +819,6 @@ void HPAK_CheckIntegrity( const char *filename );
void HPAK_CheckSize( const char *filename );
void HPAK_FlushHostQueue( void );
//
// keys.c
//
int Key_IsDown( int keynum );
const char *Key_IsBind( int keynum );
void Key_Event( int key, int down );
void Key_Init( void );
void Key_WriteBindings( file_t *f );
const char *Key_GetBinding( int keynum );
void Key_SetBinding( int keynum, const char *binding );
void Key_ClearStates( void );
const char *Key_KeynumToString( int keynum );
int Key_StringToKeynum( const char *str );
int Key_GetKey( const char *binding );
void Key_EnumCmds_f( void );
void Key_SetKeyDest( int key_dest );
void Key_EnableTextInput( qboolean enable, qboolean force );
#include "avi/avi.h"
//

View File

@ -1588,7 +1588,7 @@ void FS_ParseGenericGameInfo( gameinfo_t *GameInfo, const char *buf, const qbool
else if( !Q_stricmp( token, isGameInfo ? "max_edicts" : "edicts" ))
{
pfile = COM_ParseFile( pfile, token );
GameInfo->max_edicts = bound( 600, Q_atoi( token ), MAX_EDICTS );
GameInfo->max_edicts = bound( MIN_EDICTS, Q_atoi( token ), MAX_EDICTS );
}
// only for gameinfo
else if( isGameInfo )

View File

@ -29,8 +29,12 @@ typedef enum
// Max length of a multicast message
#define MAX_MULTICAST 8192 // some mods spamming for rain effect
#define MAX_INIT_MSG 0x20000 // max length of possible message
#if !XASH_LOW_MEMORY
#define MAX_INIT_MSG 0x20000 // max length of possible message
#else
#define MAX_INIT_MSG 0x8000
#endif
// net packets type
#define NET_HEADER_OUTOFBANDPACKET -1
#define NET_HEADER_SPLITPACKET -2

View File

@ -78,17 +78,38 @@ GNU General Public License for more details.
#define PORT_SERVER 27015
#define MULTIPLAYER_BACKUP 64 // how many data slots to use when in multiplayer (must be power of 2)
#define SINGLEPLAYER_BACKUP 16 // same for single player
#define SINGLEPLAYER_BACKUP 16 // same for single player
#define CMD_BACKUP 64 // allow a lot of command backups for very fast systems
#define CMD_MASK (CMD_BACKUP - 1)
#define NUM_PACKET_ENTITIES 256 // 170 Mb for multiplayer with 32 players
#define MAX_CUSTOM_BASELINES 64
#define NET_LEGACY_EXT_SPLIT (1U<<1)
#define NETSPLIT_BACKUP 8
#define NETSPLIT_BACKUP_MASK (NETSPLIT_BACKUP - 1)
#define NETSPLIT_HEADER_SIZE 18
#if XASH_LOW_MEMORY == 2
#undef MULTIPLAYER_BACKUP
#undef SINGLEPLAYER_BACKUP
#undef NUM_PACKET_ENTITIES
#undef MAX_CUSTOM_BASELINES
#undef NET_MAX_FRAGMENT
#define MULTIPLAYER_BACKUP 4 // breaks protocol in legacy mode, new protocol status unknown
#define SINGLEPLAYER_BACKUP 4
#define NUM_PACKET_ENTITIES 32
#define MAX_CUSTOM_BASELINES 8
#define NET_MAX_FRAGMENT 32768
#elif XASH_LOW_MEMORY == 1
#undef SINGLEPLAYER_BACKUP
#undef NUM_PACKET_ENTITIES
#undef MAX_CUSTOM_BASELINES
#undef NET_MAX_FRAGMENT
#define SINGLEPLAYER_BACKUP 4
#define NUM_PACKET_ENTITIES 64
#define MAX_CUSTOM_BASELINES 8
#define NET_MAX_FRAGMENT 32768
#endif
typedef struct netsplit_chain_packet_s
{
// bool vector

View File

@ -119,12 +119,15 @@ GNU General Public License for more details.
#define MAX_SOUND_BITS 11
#define MAX_SOUNDS (1<<MAX_SOUND_BITS) // 11 bits == 2048 sounds
#define MAX_SOUNDS_NONSENTENCE MAX_SOUNDS
#define MAX_ENTITY_BITS 13 // 13 bits = 8192 edicts
#define MAX_EDICTS (1<<MAX_ENTITY_BITS)
#define MAX_EDICTS_BYTES ((MAX_EDICTS + 7) / 8)
#define LAST_EDICT (MAX_EDICTS - 1)
#define MIN_EDICTS 64
#define MAX_CUSTOM_BITS 10
#define MAX_CUSTOM (1<<MAX_CUSTOM_BITS)// 10 bits == 1024 generic file
#define MAX_USER_MESSAGES 197 // another 58 messages reserved for engine routines
@ -179,6 +182,59 @@ GNU General Public License for more details.
#define FRAGMENT_MAX_SIZE 64000 // maximal fragment size
#define FRAGMENT_LOCAL_SIZE FRAGMENT_MAX_SIZE // local connection
#if XASH_LOW_MEMORY == 2
#undef MAX_VISIBLE_PACKET
#undef MAX_VISIBLE_PACKET_VIS_BYTES
#undef MAX_EVENTS
#undef MAX_SUPPORTED_MODELS
#undef MAX_MODELS
#undef MAX_SOUNDS
#undef MAX_CUSTOM
#undef MAX_DLIGHTS
#undef MAX_ELIGHTS
#undef MAX_RENDER_DECALS
#undef MAX_RESOURCES
// memory reduced protocol, not for use in multiplayer (but still compatible)
#define MAX_VISIBLE_PACKET 128
#define MAX_VISIBLE_PACKET_VIS_BYTES ((MAX_VISIBLE_PACKET + 7) / 8)
#define MAX_EVENTS 128
#define MAX_SUPPORTED_MODELS 512
#define MAX_MODELS 512
#define MAX_SOUNDS 512
#define MAX_CUSTOM 32
#define MAX_DLIGHTS 16 // dynamic lights (rendered per one frame)
#define MAX_ELIGHTS 32 // entity only point lights
#define MAX_RENDER_DECALS 64 // max rendering decals per a level
#define MAX_RESOURCES 1024
#elif XASH_LOW_MEMORY == 1
#undef MAX_VISIBLE_PACKET
#undef MAX_VISIBLE_PACKET_VIS_BYTES
#undef MAX_EVENTS
#undef MAX_SUPPORTED_MODELS
#undef MAX_MODELS
#undef MAX_CUSTOM
#undef MAX_RENDER_DECALS
#undef MAX_RESOURCES
#define MAX_VISIBLE_PACKET 256
#define MAX_VISIBLE_PACKET_VIS_BYTES ((MAX_VISIBLE_PACKET + 7) / 8)
#define MAX_EVENTS 128
#define MAX_SUPPORTED_MODELS 1024
#define MAX_MODELS 1024
#define MAX_CUSTOM 512
#define MAX_RENDER_DECALS 128
#define MAX_RESOURCES 1024
#endif
// Quake1 Protocol
#define PROTOCOL_VERSION_QUAKE 15

View File

@ -18,6 +18,15 @@ GNU General Public License for more details.
#define MEMHEADER_SENTINEL1 0xDEADF00D
#define MEMHEADER_SENTINEL2 0xDF
#ifdef XASH_CUSTOM_SWAP
#include "platform/swap/swap.h"
#define Q_malloc SWAP_Malloc
#define Q_free SWAP_Free
#else
#define Q_malloc malloc
#define Q_free free
#endif
typedef struct memheader_s
{
struct memheader_s *next; // next and previous memheaders in chain belonging to pool
@ -58,7 +67,7 @@ void *_Mem_Alloc( byte *poolptr, size_t size, qboolean clear, const char *filena
// big allocations are not clumped
pool->realsize += sizeof( memheader_t ) + size + sizeof( int );
mem = (memheader_t *)malloc( sizeof( memheader_t ) + size + sizeof( int ));
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( int ));
if( mem == NULL ) Sys_Error( "Mem_Alloc: out of memory (alloc at %s:%i)\n", filename, fileline );
mem->filename = filename;
@ -74,7 +83,8 @@ void *_Mem_Alloc( byte *poolptr, size_t size, qboolean clear, const char *filena
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 );
if( clear )
memset((void *)((byte *)mem + sizeof( memheader_t )), 0, mem->size );
return (void *)((byte *)mem + sizeof( memheader_t ));
}
@ -128,7 +138,7 @@ static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline
pool->totalsize -= mem->size;
pool->realsize -= sizeof( memheader_t ) + mem->size + sizeof( int );
free( mem );
Q_free( mem );
}
void _Mem_Free( void *data, const char *filename, int fileline )
@ -166,7 +176,7 @@ byte *_Mem_AllocPool( const char *name, const char *filename, int fileline )
{
mempool_t *pool;
pool = (mempool_t *)malloc( sizeof( mempool_t ));
pool = (mempool_t *)Q_malloc( sizeof( mempool_t ));
if( pool == NULL ) Sys_Error( "Mem_AllocPool: out of memory (allocpool at %s:%i)\n", filename, fileline );
memset( pool, 0, sizeof( mempool_t ));
@ -203,7 +213,7 @@ void _Mem_FreePool( byte **poolptr, const char *filename, int fileline )
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
// free the pool itself
memset( pool, 0xBF, sizeof( mempool_t ));
free( pool );
Q_free( pool );
*poolptr = NULL;
}
}

View File

@ -327,14 +327,35 @@ qboolean VID_SetMode( void )
rserr_t R_ChangeDisplaySettings( int width, int height, qboolean fullscreen )
{
int render_w, render_h;
uint rotate = vid_rotate->value;
Android_GetScreenRes(&width, &height);
render_w = width;
render_h = height;
Con_Reportf( "R_ChangeDisplaySettings: forced resolution to %dx%d)\n", width, height);
R_SaveVideoMode( width, height );
if( ref.dllFuncs.R_SetDisplayTransform( rotate, 0, 0, vid_scale->value, vid_scale->value ) )
{
if( rotate & 1 )
{
int swap = render_w;
host.window_center_x = width / 2;
host.window_center_y = height / 2;
render_w = render_h;
render_h = swap;
}
render_h /= vid_scale->value;
render_w /= vid_scale->value;
}
else
{
Con_Printf( S_WARN "failed to setup screen transform\n" );
}
R_SaveVideoMode( width, height, render_w, render_h );
refState.wideScreen = true; // V_AdjustFov will check for widescreen

View File

@ -37,6 +37,8 @@ struct evdev_s
qboolean shift;
} evdev;
static convar_t *evdev_keydebug;
static int KeycodeFromEvdev(int keycode, int value)
{
switch (keycode) {
@ -119,6 +121,10 @@ static int KeycodeFromEvdev(int keycode, int value)
case BTN_LEFT: return K_MOUSE1;
case BTN_RIGHT: return K_MOUSE2;
case BTN_MIDDLE: return K_MOUSE3;
case KEY_POWER: return K_ESCAPE;
case KEY_VOLUMEDOWN: return K_PGDN;
case KEY_VOLUMEUP: return K_PGUP;
case KEY_PLAYPAUSE: return K_ENTER;
default:
break;
}
@ -216,7 +222,7 @@ void Evdev_Autodetect_f( void )
open:
Q_strncpy( evdev.paths[evdev.devices], path, MAX_STRING );
evdev.fds[evdev.devices++] = fd;
Msg( "Opened device %s\n", path );
Con_Printf( "Opened device %s\n", path );
#if XASH_INPUT == INPUT_EVDEV
if( Sys_CheckParm( "-grab" ) )
ioctl( evdev.fds[i], EVIOCGRAB, (void*) 1 );
@ -244,7 +250,7 @@ void Evdev_OpenDevice ( const char *path )
if ( evdev.devices >= MAX_EVDEV_DEVICES )
{
Msg( "Only %d devices supported!\n", MAX_EVDEV_DEVICES );
Con_Printf( "Only %d devices supported!\n", MAX_EVDEV_DEVICES );
return;
}
@ -256,7 +262,7 @@ void Evdev_OpenDevice ( const char *path )
{
if( !Q_strncmp( evdev.paths[i], path, MAX_STRING ) )
{
Msg( "device %s already open!\n", path );
Con_Printf( "device %s already open!\n", path );
return;
}
}
@ -267,7 +273,7 @@ void Evdev_OpenDevice ( const char *path )
Con_Reportf( S_ERROR "Could not open input device %s: %s\n", path, strerror( errno ) );
return;
}
Msg( "Input device #%d: %s opened sucessfully\n", evdev.devices, path );
Con_Printf( "Input device #%d: %s opened sucessfully\n", evdev.devices, path );
evdev.fds[evdev.devices] = ret;
Q_strncpy( evdev.paths[evdev.devices++], path, MAX_STRING );
@ -280,7 +286,7 @@ void Evdev_OpenDevice ( const char *path )
void Evdev_OpenDevice_f( void )
{
if( Cmd_Argc() < 2 )
Msg( S_USAGE "evdev_opendevice <path>\n" );
Con_Printf( S_USAGE "evdev_opendevice <path>\n" );
Evdev_OpenDevice( Cmd_Argv( 1 ) );
}
@ -308,13 +314,13 @@ void Evdev_CloseDevice_f ( void )
if( i >= evdev.devices )
{
Msg( "Device %s is not open\n", arg );
Con_Printf( "Device %s is not open\n", arg );
return;
}
close( evdev.fds[i] );
evdev.devices--;
Msg( "Device %s closed successfully\n", evdev.paths[i] );
Con_Printf( "Device %s closed successfully\n", evdev.paths[i] );
for( ; i < evdev.devices; i++ )
{
@ -360,7 +366,11 @@ void IN_EvdevFrame ( void )
else if ( ( ev.type == EV_KEY ) && (cls.key_dest == key_game || XASH_INPUT == INPUT_EVDEV ) )
{
int key = KeycodeFromEvdev( ev.code, ev.value );
Key_Event ( key , ev.value );
if( CVAR_TO_BOOL(evdev_keydebug) )
Con_Printf( "key %d %d %d\n", ev.code, key, ev.value );
Key_Event( key , ev.value );
if( evdev.chars && ev.value )
{
@ -452,6 +462,7 @@ void Evdev_Shutdown( void )
Cmd_RemoveCommand( "evdev_open" );
Cmd_RemoveCommand( "evdev_close" );
Cmd_RemoveCommand( "evdev_autodetect" );
evdev_keydebug = Cvar_Get( "evdev_keydebug", "0", 0, "print key events to console" );
for( i = 0; i < evdev.devices; i++ )
{

View File

@ -39,7 +39,7 @@ void GL_SwapBuffers( void )
{
}
void FB_GetScreenRes(int *x, int *y)
void FB_GetScreenRes( int *x, int *y )
{
*x = fb.vinfo.xres;
*y = fb.vinfo.yres;
@ -121,16 +121,34 @@ qboolean VID_SetMode( void )
rserr_t R_ChangeDisplaySettings( int width, int height, qboolean fullscreen )
{
int render_w, render_h;
uint rotate = vid_rotate->value;
FB_GetScreenRes( &width, &height );
Con_Reportf( "R_ChangeDisplaySettings: forced resolution to %dx%d)\n", width, height);
render_w = width;
render_h = height;
R_SaveVideoMode( width, height );
Con_Reportf( "R_ChangeDisplaySettings: forced resolution to %dx%d)\n", width, height );
host.window_center_x = width / 2;
host.window_center_y = height / 2;
if( ref.dllFuncs.R_SetDisplayTransform( rotate, 0, 0, vid_scale->value, vid_scale->value ) )
{
if( rotate & 1 )
{
int swap = render_w;
refState.wideScreen = true; // V_AdjustFov will check for widescreen
render_w = render_h;
render_h = swap;
}
render_h /= vid_scale->value;
render_w /= vid_scale->value;
}
else
{
Con_Printf( S_WARN "failed to setup screen transform\n" );
}
R_SaveVideoMode( width, height, render_w, render_h );
return rserr_ok;
}
@ -204,6 +222,13 @@ void SW_UnlockBuffer( void )
qboolean SW_CreateBuffer( int width, int height, uint *stride, uint *bpp, uint *r, uint *g, uint *b )
{
if( width > fb.vinfo.xres_virtual || height > fb.vinfo.yres_virtual )
{
Con_Printf( S_ERROR "requested size %dx%d not fit to framebuffer size %dx%d\n",
width, height, fb.vinfo.xres_virtual, fb.vinfo.yres_virtual );
return false;
}
*bpp = fb.vinfo.bits_per_pixel >> 3;
*stride = fb.vinfo.xres_virtual;
*r = FB_BF_TO_MASK(fb.vinfo.red);

View File

@ -423,14 +423,11 @@ static void SDLash_EventFilter( SDL_Event *event )
VID_RestoreScreenResolution();
break;
case SDL_WINDOWEVENT_RESIZED:
case SDL_WINDOWEVENT_MAXIMIZED:
{
int w = VID_MIN_WIDTH, h = VID_MIN_HEIGHT;
if( vid_fullscreen->value )
break;
SDL_GL_GetDrawableSize( host.hWnd, &w, &h );
R_SaveVideoMode( w, h );
VID_SaveWindowSize( event->window.data1, event->window.data2 );
SCR_VidInit(); // tell the client.dll what vid_mode has changed
break;
}

View File

@ -28,7 +28,7 @@ void GL_InitExtensions( void );
qboolean GL_CreateContext( void );
qboolean GL_UpdateContext( void );
qboolean GL_DeleteContext( void );
void VID_SaveWindowSize( int width, int height );
#endif // XASH_SDL
#endif // KEYWRAPPER_H

View File

@ -449,7 +449,38 @@ qboolean GL_UpdateContext( void )
return true;
}
qboolean VID_SetScreenResolution( int width, int height )
void VID_SaveWindowSize( int width, int height )
{
int render_w = width, render_h = height;
uint rotate = vid_rotate->value;
if( !glw_state.software )
SDL_GL_GetDrawableSize( host.hWnd, &render_w, &render_h );
else
SDL_RenderSetLogicalSize( sw.renderer, width, height );
if( ref.dllFuncs.R_SetDisplayTransform( rotate, 0, 0, vid_scale->value, vid_scale->value ) )
{
if( rotate & 1 )
{
int swap = render_w;
render_w = render_h;
render_h = swap;
}
render_h /= vid_scale->value;
render_w /= vid_scale->value;
}
else
{
Con_Printf( S_WARN "failed to setup screen transform\n" );
}
R_SaveVideoMode( width, height, render_w, render_h );
}
static qboolean VID_SetScreenResolution( int width, int height )
{
SDL_DisplayMode want, got;
Uint32 wndFlags = 0;
@ -479,9 +510,8 @@ qboolean VID_SetScreenResolution( int width, int height )
SDL_SetWindowGrab( host.hWnd, SDL_TRUE );
SDL_SetWindowSize( host.hWnd, got.w, got.h );
SDL_GL_GetDrawableSize( host.hWnd, &got.w, &got.h );
VID_SaveWindowSize( got.w, got.h );
R_SaveVideoMode( got.w, got.h );
return true;
}
@ -672,9 +702,9 @@ qboolean VID_CreateWindow( int width, int height, qboolean fullscreen )
if( !GL_UpdateContext( ))
return false;
SDL_GL_GetDrawableSize( host.hWnd, &width, &height );
}
R_SaveVideoMode( width, height );
VID_SaveWindowSize( width, height );
return true;
}
@ -906,11 +936,7 @@ rserr_t R_ChangeDisplaySettings( int width, int height, qboolean fullscreen )
#endif
SDL_SetWindowBordered( host.hWnd, SDL_TRUE );
SDL_SetWindowSize( host.hWnd, width, height );
if( !glw_state.software )
SDL_GL_GetDrawableSize( host.hWnd, &width, &height );
else
SDL_RenderSetLogicalSize(sw.renderer, width, height);
R_SaveVideoMode( width, height );
VID_SaveWindowSize( width, height );
}
return rserr_ok;

View File

@ -0,0 +1,488 @@
/* $NetBSD: malloc.c,v 1.8 1997/04/07 03:12:14 christos Exp $ */
/*
* Copyright (c) 1983 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char *sccsid = "from: @(#)malloc.c 5.11 (Berkeley) 2/23/91";
#else
static char *rcsid = "$NetBSD: malloc.c,v 1.8 1997/04/07 03:12:14 christos Exp $";
#endif
#endif /* LIBC_SCCS and not lint */
/*
* malloc.c (Caltech) 2/21/82
* Chris Kingsley, kingsley@cit-20.
*
* This is a very fast storage allocator. It allocates blocks of a small
* number of different sizes, and keeps free lists of each size. Blocks that
* don't exactly fit are passed up to the next larger size. In this
* implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long.
* This is designed for use in a virtual memory environment.
*/
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include "platform/swap/swap.h"
/* #define MSTATS 1 */
#ifndef _WIN32
#include <unistd.h>
#define NULL 0
#else
#define u_char unsigned char
#define u_long unsigned long
#define getpagesize() 4096
#define caddr_t size_t
#define bcopy(a,b,c) memcpy(b,a,c)
#endif
static void morecore(int);
/*
* The overhead on a block is at least 4 bytes. When free, this space
* contains a pointer to the next free block, and the bottom two bits must
* be zero. When in use, the first byte is set to MAGIC, and the second
* byte is the size index. The remaining bytes are for alignment.
* If range checking is enabled then a second word holds the size of the
* requested block, less 1, rounded up to a multiple of sizeof(RMAGIC).
* The order of elements is critical: ov_magic must overlay the low order
* bits of ov_next, and ov_magic can not be a valid ov_next bit pattern.
*/
union overhead {
union overhead *ov_next; /* when free */
struct {
u_char ovu_magic; /* magic number */
u_char ovu_index; /* bucket # */
#ifdef RCHECK
u_short ovu_rmagic; /* range magic number */
u_long ovu_size; /* actual block size */
#endif
} ovu;
#define ov_magic ovu.ovu_magic
#define ov_index ovu.ovu_index
#define ov_rmagic ovu.ovu_rmagic
#define ov_size ovu.ovu_size
};
static int findbucket( union overhead *freep,
int srchlen);
#define MAGIC 0xef /* magic # on accounting info */
#define RMAGIC 0x5555 /* magic # on range info */
#ifdef RCHECK
#define RSLOP sizeof (u_short)
#else
#define RSLOP 0
#endif
/*
* nextf[i] is the pointer to the next free block of size 2^(i+3). The
* smallest allocatable block is 8 bytes. The overhead information
* precedes the data area returned to the user.
*/
#define NBUCKETS 30
static union overhead *nextf[NBUCKETS];
/* extern char *sbrk(); */
static int pagesz; /* page size */
static int pagebucket; /* page size bucket */
#ifdef MSTATS
/*
* nmalloc[i] is the difference between the number of mallocs and frees
* for a given block size.
*/
static unsigned int nmalloc[NBUCKETS];
#include <stdio.h>
#endif
#if defined(DEBUG) || defined(RCHECK)
#define ASSERT(p) if (!(p)) botch(__STRING(p))
#include /* <stdio.h> */
static
botch(s)
char *s;
{
fprintf(stderr, "\r\nassertion botched: %s\r\n", s);
(void) fflush(stderr); /* just in case user buffered it */
abort();
}
#else
#define ASSERT(p)
#endif
#include <stdio.h>
/* */
/* malloc */
/* malloc */
void * SWAP_Malloc( size_t nbytes )
{
register union overhead *op;
register int bucket;
register long n;
register unsigned amt;
/*
* First time malloc is called, setup page size and
* align break pointer so all data will be page aligned.
*/
if (pagesz == 0) {
pagesz = n = getpagesize();
op = (union overhead *)SWAP_Sbrk( 0 );
n = n - sizeof (*op) - ((long)op & (n - 1));
if (n < 0)
n += pagesz;
if (n) {
if (SWAP_Sbrk(n) == (char *)-1) {
return (NULL);
}
}
bucket = 0;
amt = 8;
while (pagesz > amt) {
amt <<= 1;
bucket++;
}
pagebucket = bucket;
}
/*
* Convert amount of memory requested into closest block size
* stored in hash buckets which satisfies request.
* Account for space used per block for accounting.
*/
if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) {
#ifndef RCHECK
amt = 8; /* size of first bucket */
bucket = 0;
#else
amt = 16; /* size of first bucket */
bucket = 1;
#endif
n = -((long)sizeof (*op) + RSLOP);
} else {
amt = pagesz;
bucket = pagebucket;
}
while (nbytes > amt + n) {
amt <<= 1;
if (amt == 0) {
return (NULL);
}
bucket++;
}
/*
* If nothing in hash bucket right now,
* request more memory from the system.
*/
if ((op = nextf[bucket]) == NULL) {
morecore(bucket);
if ((op = nextf[bucket]) == NULL) {
return (NULL);
}
}
/* remove from linked list */
nextf[bucket] = op->ov_next;
op->ov_magic = MAGIC;
op->ov_index = bucket;
#ifdef MSTATS
nmalloc[bucket]++;
#endif
#ifdef RCHECK
/*
* Record allocated size of block and
* bound space with magic numbers.
*/
op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
op->ov_rmagic = RMAGIC;
*(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
#endif
return ((char *)(op + 1));
}
void * SWAP_Calloc(size_t nelem, size_t elsize) {
void * ptr = SWAP_Malloc (nelem * elsize);
// Zero out the malloc'd block.
memset (ptr, 0, nelem * elsize);
return ptr;
}
/*
* Allocate more memory to the indicated bucket.
*/
static void
morecore(int bucket)
{
register union overhead *op;
register long sz; /* size of desired block */
long amt; /* amount to allocate */
int nblks; /* how many blocks we get */
/*
* sbrk_size <= 0 only for big, FLUFFY, requests (about
* 2^30 bytes on a VAX, I think) or for a negative arg.
*/
sz = 1 << (bucket + 3);
#ifdef DEBUG
ASSERT(sz > 0);
#else
if (sz <= 0)
return;
#endif
if (sz < pagesz) {
amt = pagesz;
nblks = amt / sz;
} else {
amt = sz + pagesz;
nblks = 1;
}
op = (union overhead *)SWAP_Sbrk(amt);
/* no more room! */
if ((long)op == -1)
return;
/*
* Add new memory allocated to that on
* free list for this hash bucket.
*/
nextf[bucket] = op;
while (--nblks > 0) {
op->ov_next = (union overhead *)((caddr_t)op + sz);
op = (union overhead *)((caddr_t)op + sz);
}
}
/* */
/* free */
/* free */
void SWAP_Free( void *cp)
{
register long size;
register union overhead *op;
if (cp == NULL)
return;
op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
#ifdef DEBUG
ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */
#else
if (op->ov_magic != MAGIC)
return; /* sanity */
#endif
#ifdef RCHECK
ASSERT(op->ov_rmagic == RMAGIC);
ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
#endif
size = op->ov_index;
ASSERT(size < NBUCKETS);
op->ov_next = nextf[size]; /* also clobbers ov_magic */
nextf[size] = op;
#ifdef MSTATS
nmalloc[size]--;
#endif
}
/* EDB: added size lookup */
size_t SWAP_MallocUsableSize(void * cp)
{
register long size;
register union overhead *op;
if (cp == NULL)
return 0;
op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
#ifdef DEBUG
ASSERT(op->ov_magic == MAGIC); /* make sure it was in use */
#else
if (op->ov_magic != MAGIC)
return 0; /* sanity */
#endif
#ifdef RCHECK
ASSERT(op->ov_rmagic == RMAGIC);
ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
#endif
return op->ov_index;
}
/* End EDB */
/*
* When a program attempts "storage compaction" as mentioned in the
* old malloc man page, it realloc's an already freed block. Usually
* this is the last block it freed; occasionally it might be farther
* back. We have to search all the free lists for the block in order
* to determine its bucket: 1st we make one pass thru the lists
* checking only the first block in each; if that fails we search
* ``realloc_srchlen'' blocks in each list for a match (the variable
* is extern so the caller can modify it). If that fails we just copy
* however many bytes was given to realloc() and hope it's not huge.
*/
int realloc_srchlen = 4; /* 4 should be plenty, -1 =>'s whole list */
/* */
/* realloc */
/* realloc */
void *
SWAP_Realloc( void *cp,
size_t nbytes)
{
register u_long onb;
register long i;
union overhead *op;
char *res;
int was_alloced = 0;
if (cp == NULL)
return (SWAP_Malloc(nbytes));
if (nbytes == 0) {
SWAP_Free (cp);
return NULL;
}
op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
if (op->ov_magic == MAGIC) {
was_alloced++;
i = op->ov_index;
} else {
/*
* Already free, doing "compaction".
*
* Search for the old block of memory on the
* free list. First, check the most common
* case (last element free'd), then (this failing)
* the last ``realloc_srchlen'' items free'd.
* If all lookups fail, then assume the size of
* the memory block being realloc'd is the
* largest possible (so that all "nbytes" of new
* memory are copied into). Note that this could cause
* a memory fault if the old area was tiny, and the moon
* is gibbous. However, that is very unlikely.
*/
if ((i = findbucket(op, 1)) < 0 &&
(i = findbucket(op, realloc_srchlen)) < 0)
i = NBUCKETS;
}
onb = 1 << (i + 3);
if (onb < pagesz)
onb -= sizeof (*op) + RSLOP;
else
onb += pagesz - sizeof (*op) - RSLOP;
/* avoid the copy if same size block */
if (was_alloced) {
if (i) {
i = 1 << (i + 2);
if (i < pagesz)
i -= sizeof (*op) + RSLOP;
else
i += pagesz - sizeof (*op) - RSLOP;
}
if (nbytes <= onb && nbytes > i) {
#ifdef RCHECK
op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
*(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
#endif
return(cp);
} else
SWAP_Free(cp);
}
if ((res = SWAP_Malloc(nbytes)) == NULL)
return (NULL);
if (cp != res) /* common optimization if "compacting" */
bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
return (res);
}
/*
* Search ``srchlen'' elements of each free list for a block whose
* header starts at ``freep''. If srchlen is -1 search the whole list.
* Return bucket number, or -1 if not found.
*/
static int
findbucket( union overhead *freep,
int srchlen)
{
register union overhead *p;
register int i, j;
for (i = 0; i < NBUCKETS; i++) {
j = 0;
for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
if (p == freep)
return (i);
j++;
}
}
return (-1);
}
#ifdef MSTATS
/*
* mstats - print out statistics about malloc
*
* Prints two lines of numbers, one showing the length of the free list
* for each size category, the second showing the number of mallocs -
* frees for each size category.
*/
/* */
mstats(void)
{
register int i, j;
register union overhead *p;
int totfree = 0,
totused = 0;
fprintf(stderr, "Memory allocation statistics\nfree:\t");
for (i = 0; i < NBUCKETS; i++) {
for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
;
fprintf(stderr, " %d", j);
totfree += j * (1 << (i + 3));
}
fprintf(stderr, "\nused:\t");
for (i = 0; i < NBUCKETS; i++) {
fprintf(stderr, " %d", nmalloc[i]);
totused += nmalloc[i] * (1 << (i + 3));
}
fprintf(stderr, "\n\tTotal in use: %d, total free: %d, total allocated: %d\n",
totused, totfree, totused + totfree);
}
#endif

108
engine/platform/swap/sbrk.c Normal file
View File

@ -0,0 +1,108 @@
/*
sbrk.c - swap memory allocation
Copyright (C) 2019 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.
*/
#define _GNU_SOURCE
#include <dlfcn.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#define _GNU_SOURCE
#include <dlfcn.h>
#include "platform/swap/swap.h"
#include "string.h"
#ifndef XASH_DEFAULT_SWAP_PATH
#define XASH_DEFAULT_SWAP_PATH "/tmp/xash3d-swap"
#endif
#define PAGE_SIZE 4096
static struct sbrk_state_s
{
void *top;
int fd;
size_t size;
size_t prealloc;
pid_t pid;
} s;
static void SWAP_Initialize(void)
{
char *path;
char *prealloc = getenv("SWAP_SIZE");
int fd;
if( s.top )
return;
path = getenv("SWAP_PATH");
if( !path )
path = XASH_DEFAULT_SWAP_PATH;
fd = open( path, O_CREAT|O_RDWR, 0600 );
if( prealloc ) s.prealloc = atoi(prealloc);
else s.prealloc = 128*1024*1024;
s.prealloc &= ~(PAGE_SIZE - 1);
s.fd = fd;
ftruncate( fd, s.prealloc );
s.top = mmap( 0, s.prealloc, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0 );
// space will be freed on exit
//unlink(path);
}
void *SWAP_Sbrk(size_t size)
{
char buf[64];
SWAP_Initialize();
if( size == 0 )
return s.top;
else if( size > 0 )
{
void *res;
//write(1, buf, snprintf(buf, 32, "allocating %d\n", size) );
res = s.top;
s.size += size;
s.top = res + size;
if( s.size + size > s.prealloc )
return (void*)-1;
memset( res, 0, size );
return res;
}
else
{
void *res = s.top;
if( -size > s.size )
res = (void*)-1;
else
{
s.top += size;
s.size += size;
//write(1, buf, snprintf(buf, 32, "freed %d\n", -size) );
}
return res;
}
}

View File

@ -0,0 +1,21 @@
/*
sbrk_swap.h - swap memory allocation
Copyright (C) 2019 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 <stdint.h>
void *SWAP_Sbrk( size_t size );
void *SWAP_Malloc( size_t size );
void *SWAP_Calloc( size_t nelem, size_t size );
void SWAP_Free( void *cp );
void *SWAP_Realloc( void *cp, size_t size );
size_t SWAP_MallocUsableSize( void * cp );

View File

@ -88,6 +88,7 @@ typedef struct ref_globals_s
// viewport width and height
int width;
int height;
qboolean fullScreen;
qboolean wideScreen;
@ -211,6 +212,14 @@ enum
REF_GL_CONTEXT_RESET_ISOLATION_FLAG = 0x0008
};
typedef enum ref_screen_rotation_e
{
REF_ROTATE_NONE = 0,
REF_ROTATE_CW = 1,
REF_ROTATE_UD = 2,
REF_ROTATE_CCW = 3,
} ref_screen_rotation_t;
typedef struct remap_info_s
{
unsigned short textures[MAX_SKINS];// alias textures
@ -435,6 +444,7 @@ typedef struct ref_interface_s
// const char *(*R_GetInitError)( void );
void (*R_Shutdown)( void );
const char *(*R_GetConfigName)( void ); // returns config name without extension
qboolean (*R_SetDisplayTransform)( ref_screen_rotation_t rotate, int x, int y, float scale_x, float scale_y );
// only called for GL contexts
void (*GL_SetupAttributes)( int safegl );

View File

@ -32,7 +32,11 @@ GNU General Public License for more details.
//=============================================================================
#define SV_UPDATE_MASK (SV_UPDATE_BACKUP - 1)
#if XASH_LOW_MEMORY == 2
#define SV_UPDATE_BACKUP SINGLEPLAYER_BACKUP
#else
extern int SV_UPDATE_BACKUP;
#endif
// hostflags
#define SVF_SKIPLOCALHOST BIT( 0 )

View File

@ -2042,10 +2042,10 @@ int SV_BuildSoundMsg( sizebuf_t *msg, edict_t *ent, int chan, const char *sample
{
sound_idx = Q_atoi( sample + 1 );
if( sound_idx >= MAX_SOUNDS )
if( sound_idx >= MAX_SOUNDS_NONSENTENCE )
{
SetBits( flags, SND_SENTENCE|SND_SEQUENCE );
sound_idx -= MAX_SOUNDS;
sound_idx -= MAX_SOUNDS_NONSENTENCE;
}
else SetBits( flags, SND_SENTENCE );
}

View File

@ -17,9 +17,9 @@ GNU General Public License for more details.
#include "server.h"
#include "net_encode.h"
#include "library.h"
#if XASH_LOW_MEMORY != 2
int SV_UPDATE_BACKUP = SINGLEPLAYER_BACKUP;
#endif
server_t sv; // local server
server_static_t svs; // persistant server info
svgame_static_t svgame; // persistant game info
@ -752,7 +752,9 @@ void SV_SetupClients( void )
// feedback for cvar
Cvar_FullSet( "maxplayers", va( "%d", svs.maxclients ), FCVAR_LATCH );
#if XASH_LOW_MEMORY != 2
SV_UPDATE_BACKUP = ( svs.maxclients == 1 ) ? SINGLEPLAYER_BACKUP : MULTIPLAYER_BACKUP;
#endif
svs.clients = Z_Realloc( svs.clients, sizeof( sv_client_t ) * svs.maxclients );
svs.num_client_entities = svs.maxclients * SV_UPDATE_BACKUP * NUM_PACKET_ENTITIES;

View File

@ -14,6 +14,10 @@ def options(opt):
help = 'enable console input from stdin (always enabled for dedicated) [default: %default]')
grp.add_option('--fbdev', action = 'store_true', dest = 'FBDEV_SW', default = False,
help = 'build fbdev-only software-only engine')
grp.add_option('--disable-async-resolve', action = 'store_true', dest = 'NO_ASYNC_RESOLVE', default = False,
help = 'disable asynchronous name resolution')
grp.add_option('--enable-custom-swap', action = 'store_true', dest = 'CUSTOM_SWAP', default = False,
help = 'enable custom swap allocator. For devices with no swap support')
opt.load('sdl2')
@ -28,7 +32,8 @@ def configure(conf):
conf.check_cc(lib = i)
elif conf.options.FBDEV_SW:
conf.define('XASH_FBDEV', 1)
conf.check_cc(lib = 'asound')
conf.check_cc( lib = 'asound' )
conf.check_cc( lib = 'rt' )
else:
conf.load('sdl2')
if not conf.env.HAVE_SDL2:
@ -38,8 +43,15 @@ def configure(conf):
if conf.options.USE_SELECT == None:
conf.options.USE_SELECT = conf.options.DEDICATED
conf.define_cond('SINGLE_BINARY', conf.env.SINGLE_BINARY)
if not conf.env.DEST_OS in ['win32', 'android'] and not conf.options.NO_ASYNC_RESOLVE:
conf.check_cc( lib='pthread' )
if conf.options.CUSTOM_SWAP:
conf.define('XASH_CUSTOM_SWAP',1)
conf.env.CUSTOM_SWAP = True
conf.define_cond('SINGLE_BINARY', conf.env.SINGLE_BINARY)
conf.define_cond('XASH_NO_ASYNC_NS_RESOLVE', conf.options.NO_ASYNC_RESOLVE)
conf.define_cond('XASH_USE_SELECT', conf.options.USE_SELECT or conf.options.DEDICATED)
conf.define_cond('SUPPORT_BSP2_FORMAT', conf.options.SUPPORT_BSP2_FORMAT)
conf.define_cond('XASH_64BIT', conf.env.DEST_SIZEOF_VOID_P != 4)
@ -57,8 +69,9 @@ def build(bld):
# basic build: dedicated only, no dependencies
if bld.env.DEST_OS != 'win32':
libs += [ 'DL' , 'M' , 'RT', 'PTHREAD']
libs += [ 'DL' , 'M' , 'RT', 'PTHREAD', 'ASOUND']
source += bld.path.ant_glob(['platform/posix/*.c'])
else:
libs += ['USER32', 'SHELL32', 'GDI32', 'ADVAPI32', 'DBGHELP', 'PSAPI', 'WS2_32' ]
source += bld.path.ant_glob(['platform/win32/*.c'])
@ -66,7 +79,8 @@ def build(bld):
if bld.env.DEST_OS == 'linux':
source += bld.path.ant_glob(['platform/linux/*.c'])
source += bld.path.ant_glob(['platform/stub/*.c'])
if bld.env.CUSTOM_SWAP:
source += bld.path.ant_glob(['platform/swap/*.c'])
if bld.env.HAVE_SDL2:
libs.append('SDL2')
@ -83,12 +97,6 @@ def build(bld):
'client/vgui/*.c',
'client/avi/*.c'])
if bld.env.DEST_OS == 'linux' and not bld.env.HAVE_SDL2:
libs.append('RT')
if not bld.env.DEDICATED:
libs.append('ASOUND')
# HACK: public headers must be put before common, so we don't get wrong mathlib included
includes = ['common', 'server', 'client', 'client/vgui', '.', '../public', '../common', '../pm_shared' ]

View File

@ -308,6 +308,30 @@ void R_ProcessEntData( qboolean allocate )
gEngfuncs.drawFuncs->R_ProcessEntData( allocate );
}
qboolean R_SetDisplayTransform( ref_screen_rotation_t rotate, int offset_x, int offset_y, float scale_x, float scale_y )
{
qboolean ret = true;
if( rotate > 0 )
{
gEngfuncs.Con_Printf("rotation transform not supported\n");
ret = false;
}
if( offset_x || offset_y )
{
gEngfuncs.Con_Printf("offset transform not supported\n");
ret = false;
}
if( scale_x != 1.0f || scale_y != 1.0f )
{
gEngfuncs.Con_Printf("scale transform not supported\n");
ret = false;
}
return ret;
}
static const char *R_GetConfigName( void )
{
return "opengl";
@ -318,6 +342,7 @@ ref_interface_t gReffuncs =
R_Init,
R_Shutdown,
R_GetConfigName,
R_SetDisplayTransform,
GL_SetupAttributes,
GL_InitExtensions,

View File

@ -76,6 +76,9 @@ 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('--low-memory-mode', action = 'store', dest = 'LOW_MEMORY', default = 0,
help = 'enable low memory mode (only for devices have <128 ram)')
opt.load('subproject')
opt.add_subproject(subdirs())
@ -108,7 +111,7 @@ def configure(conf):
conf.env.MSVC_TARGETS = ['x86'] # explicitly request x86 target for MSVC
if sys.platform == 'win32':
conf.load('msvc msvc_pdb msdev msvs')
conf.load('subproject xcompile compiler_c compiler_cxx gitversion clang_compilation_database strip_on_install waf_unit_test pthreads')
conf.load('subproject xcompile compiler_c compiler_cxx gitversion clang_compilation_database strip_on_install waf_unit_test')
# Every static library must have fPIC
if conf.env.DEST_OS != 'win32' and '-fPIC' in conf.env.CFLAGS_cshlib:
@ -262,7 +265,6 @@ def configure(conf):
conf.env.SINGLE_BINARY = conf.options.SINGLE_BINARY or conf.env.DEDICATED
if conf.env.DEST_OS != 'win32':
conf.check_pthread_flag()
conf.check_cc(lib='dl', mandatory=False)
if not conf.env.LIB_M: # HACK: already added in xcompile!
@ -301,6 +303,9 @@ def configure(conf):
conf.define('XASH_BUILD_COMMIT', conf.env.GIT_VERSION if conf.env.GIT_VERSION else 'notset')
if conf.options.LOW_MEMORY:
conf.define('XASH_LOW_MEMORY', int(conf.options.LOW_MEMORY))
for i in SUBDIRS:
if not i.is_enabled(conf):
continue