Merge branch 'master' into netsplit
This commit is contained in:
commit
2b1ed2b20a
30 changed files with 3048 additions and 255 deletions
|
@ -70,6 +70,13 @@ qboolean CL_CheckFile( sizebuf_t *msg, resource_t *pResource )
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( cl.downloadUrl[0] )
|
||||||
|
{
|
||||||
|
HTTP_AddDownload( filepath, pResource->nDownloadSize, true );
|
||||||
|
host.downloadcount++;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
MSG_BeginClientCmd( msg, clc_stringcmd );
|
MSG_BeginClientCmd( msg, clc_stringcmd );
|
||||||
MSG_WriteString( msg, va( "dlfile %s", filepath ));
|
MSG_WriteString( msg, va( "dlfile %s", filepath ));
|
||||||
host.downloadcount++;
|
host.downloadcount++;
|
||||||
|
@ -140,4 +147,4 @@ void CL_ClearResourceLists( void )
|
||||||
{
|
{
|
||||||
CL_ClearResourceList( &cl.resourcesneeded );
|
CL_ClearResourceList( &cl.resourcesneeded );
|
||||||
CL_ClearResourceList( &cl.resourcesonhand );
|
CL_ClearResourceList( &cl.resourcesonhand );
|
||||||
}
|
}
|
||||||
|
|
|
@ -1049,6 +1049,15 @@ void CL_DrawHUD( int state )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void CL_ClearUserMessage( char *pszName, int svc_num )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for( i = 0; i < MAX_USER_MESSAGES && clgame.msg[i].name[0]; i++ )
|
||||||
|
if( ( clgame.msg[i].number == svc_num ) && Q_strcmp( clgame.msg[i].name, pszName ) )
|
||||||
|
clgame.msg[i].number = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void CL_LinkUserMessage( char *pszName, const int svc_num, int iSize )
|
void CL_LinkUserMessage( char *pszName, const int svc_num, int iSize )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -1067,6 +1076,7 @@ void CL_LinkUserMessage( char *pszName, const int svc_num, int iSize )
|
||||||
{
|
{
|
||||||
clgame.msg[i].number = svc_num;
|
clgame.msg[i].number = svc_num;
|
||||||
clgame.msg[i].size = iSize;
|
clgame.msg[i].size = iSize;
|
||||||
|
CL_ClearUserMessage( pszName, svc_num );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1081,6 +1091,7 @@ void CL_LinkUserMessage( char *pszName, const int svc_num, int iSize )
|
||||||
Q_strncpy( clgame.msg[i].name, pszName, sizeof( clgame.msg[i].name ));
|
Q_strncpy( clgame.msg[i].name, pszName, sizeof( clgame.msg[i].name ));
|
||||||
clgame.msg[i].number = svc_num;
|
clgame.msg[i].number = svc_num;
|
||||||
clgame.msg[i].size = iSize;
|
clgame.msg[i].size = iSize;
|
||||||
|
CL_ClearUserMessage( pszName, svc_num );
|
||||||
}
|
}
|
||||||
|
|
||||||
void CL_FreeEntity( cl_entity_t *pEdict )
|
void CL_FreeEntity( cl_entity_t *pEdict )
|
||||||
|
@ -1215,7 +1226,7 @@ static qboolean CL_LoadHudSprite( const char *szSpriteName, model_t *m_pSprite,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Con_Reportf( S_ERROR "%s couldn't load\n", szSpriteName );
|
Con_Reportf( S_ERROR "Could not load HUD sprite %s\n", szSpriteName );
|
||||||
Mod_UnloadSpriteModel( m_pSprite );
|
Mod_UnloadSpriteModel( m_pSprite );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2341,7 +2352,7 @@ int CL_FindModelIndex( const char *m )
|
||||||
if( lasttimewarn < host.realtime )
|
if( lasttimewarn < host.realtime )
|
||||||
{
|
{
|
||||||
// tell user about problem (but don't spam console)
|
// tell user about problem (but don't spam console)
|
||||||
Con_Printf( S_ERROR "%s not precached\n", filepath );
|
Con_Printf( S_ERROR "Could not find index for model %s: not precached\n", filepath );
|
||||||
lasttimewarn = host.realtime + 1.0f;
|
lasttimewarn = host.realtime + 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -382,7 +382,7 @@ static HIMAGE pfnPIC_Load( const char *szPicName, const byte *image_buf, int ima
|
||||||
|
|
||||||
if( !szPicName || !*szPicName )
|
if( !szPicName || !*szPicName )
|
||||||
{
|
{
|
||||||
Con_Reportf( S_ERROR "CL_LoadImage: bad name!\n" );
|
Con_Reportf( S_ERROR "CL_LoadImage: refusing to load image with empty name\n" );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1351,6 +1351,7 @@ void CL_ClearState( void )
|
||||||
Cvar_SetValue( "scr_download", -1.0f );
|
Cvar_SetValue( "scr_download", -1.0f );
|
||||||
Cvar_SetValue( "scr_loading", 0.0f );
|
Cvar_SetValue( "scr_loading", 0.0f );
|
||||||
host.allow_console = host.allow_console_init;
|
host.allow_console = host.allow_console_init;
|
||||||
|
HTTP_ClearCustomServers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1534,6 +1535,7 @@ void CL_LocalServers_f( void )
|
||||||
|
|
||||||
Con_Printf( "Scanning for servers on the local network area...\n" );
|
Con_Printf( "Scanning for servers on the local network area...\n" );
|
||||||
NET_Config( true ); // allow remote
|
NET_Config( true ); // allow remote
|
||||||
|
cls.legacyservercount = 0;
|
||||||
|
|
||||||
// send a broadcast packet
|
// send a broadcast packet
|
||||||
adr.type = NA_BROADCAST;
|
adr.type = NA_BROADCAST;
|
||||||
|
@ -1561,6 +1563,7 @@ void CL_InternetServers_f( void )
|
||||||
Info_SetValueForKey( info, "gamedir", GI->gamefolder, remaining );
|
Info_SetValueForKey( info, "gamedir", GI->gamefolder, remaining );
|
||||||
Info_SetValueForKey( info, "clver", XASH_VERSION, remaining ); // let master know about client version
|
Info_SetValueForKey( info, "clver", XASH_VERSION, remaining ); // let master know about client version
|
||||||
// Info_SetValueForKey( info, "nat", cl_nat->string, remaining );
|
// Info_SetValueForKey( info, "nat", cl_nat->string, remaining );
|
||||||
|
cls.legacyservercount = 0;
|
||||||
|
|
||||||
cls.internetservers_wait = NET_SendToMasters( NS_CLIENT, sizeof( MS_SCAN_REQUEST ) + Q_strlen( info ), fullquery );
|
cls.internetservers_wait = NET_SendToMasters( NS_CLIENT, sizeof( MS_SCAN_REQUEST ) + Q_strlen( info ), fullquery );
|
||||||
cls.internetservers_pending = true;
|
cls.internetservers_pending = true;
|
||||||
|
@ -1683,6 +1686,7 @@ void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg )
|
||||||
{
|
{
|
||||||
static char infostring[MAX_INFO_STRING+8];
|
static char infostring[MAX_INFO_STRING+8];
|
||||||
char *s = MSG_ReadString( msg );
|
char *s = MSG_ReadString( msg );
|
||||||
|
int i;
|
||||||
|
|
||||||
CL_FixupColorStringsForInfoString( s, infostring );
|
CL_FixupColorStringsForInfoString( s, infostring );
|
||||||
|
|
||||||
|
@ -1690,6 +1694,8 @@ void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg )
|
||||||
{
|
{
|
||||||
Netchan_OutOfBandPrint( NS_CLIENT, from, "info %i", PROTOCOL_LEGACY_VERSION );
|
Netchan_OutOfBandPrint( NS_CLIENT, from, "info %i", PROTOCOL_LEGACY_VERSION );
|
||||||
Con_Printf( "^1Server^7: %s, Info: %s\n", NET_AdrToString( from ), infostring );
|
Con_Printf( "^1Server^7: %s, Info: %s\n", NET_AdrToString( from ), infostring );
|
||||||
|
if( cls.legacyservercount < MAX_LEGACY_SERVERS )
|
||||||
|
cls.legacyservers[cls.legacyservercount++] = from;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1699,6 +1705,16 @@ void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg )
|
||||||
return; // unsupported proto
|
return; // unsupported proto
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for( i = 0; i < cls.legacyservercount; i++ )
|
||||||
|
{
|
||||||
|
if( NET_CompareAdr( cls.legacyservers[i], from ) )
|
||||||
|
{
|
||||||
|
Info_SetValueForKey( infostring, "legacy", "1", sizeof( infostring ) );
|
||||||
|
Con_Print("Legacy: ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// more info about servers
|
// more info about servers
|
||||||
Con_Printf( "^2Server^7: %s, Game: %s\n", NET_AdrToString( from ), Info_ValueForKey( infostring, "gamedir" ));
|
Con_Printf( "^2Server^7: %s, Game: %s\n", NET_AdrToString( from ), Info_ValueForKey( infostring, "gamedir" ));
|
||||||
|
|
||||||
|
@ -2309,6 +2325,17 @@ void CL_ProcessFile( qboolean successfully_received, const char *filename )
|
||||||
{
|
{
|
||||||
Con_Printf( S_ERROR "server failed to transmit file '%s'\n", CL_CleanFileName( filename ));
|
Con_Printf( S_ERROR "server failed to transmit file '%s'\n", CL_CleanFileName( filename ));
|
||||||
}
|
}
|
||||||
|
if( cls.legacymode )
|
||||||
|
{
|
||||||
|
if( host.downloadcount > 0 )
|
||||||
|
host.downloadcount--;
|
||||||
|
if( !host.downloadcount )
|
||||||
|
{
|
||||||
|
MSG_WriteByte( &cls.netchan.message, clc_stringcmd );
|
||||||
|
MSG_WriteString( &cls.netchan.message, "continueloading" );
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
pfilename = filename;
|
pfilename = filename;
|
||||||
|
|
||||||
|
@ -2358,7 +2385,7 @@ void CL_ProcessFile( qboolean successfully_received, const char *filename )
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Con_Printf( "Downloaded %i bytes for purported %i byte file, ignoring download\n",
|
Con_Printf( "Downloaded %i bytes for purported %i byte file, ignoring download\n",
|
||||||
cls.netchan.tempbuffersize, p->nDownloadSize );
|
cls.netchan.tempbuffersize, p->nDownloadSize );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2553,7 +2580,7 @@ qboolean CL_PrecacheResources( void )
|
||||||
{
|
{
|
||||||
if( FBitSet( pRes->ucFlags, RES_WASMISSING ))
|
if( FBitSet( pRes->ucFlags, RES_WASMISSING ))
|
||||||
{
|
{
|
||||||
Con_Printf( S_ERROR "%s%s couldn't load\n", DEFAULT_SOUNDPATH, pRes->szFileName );
|
Con_Printf( S_ERROR "Could not load sound %s%s\n", DEFAULT_SOUNDPATH, pRes->szFileName );
|
||||||
cl.sound_precache[pRes->nIndex][0] = 0;
|
cl.sound_precache[pRes->nIndex][0] = 0;
|
||||||
cl.sound_index[pRes->nIndex] = 0;
|
cl.sound_index[pRes->nIndex] = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -534,7 +534,11 @@ void CL_BatchResourceRequest( qboolean initialize )
|
||||||
|
|
||||||
if( cls.state != ca_disconnected )
|
if( cls.state != ca_disconnected )
|
||||||
{
|
{
|
||||||
if( !MSG_GetNumBytesWritten( &msg ) && CL_PrecacheResources( ))
|
if( !cl.downloadUrl[0] && !MSG_GetNumBytesWritten( &msg ) && CL_PrecacheResources( ))
|
||||||
|
{
|
||||||
|
CL_RegisterResources( &msg );
|
||||||
|
}
|
||||||
|
if( cl.downloadUrl[0] && host.downloadcount == 0 && CL_PrecacheResources( ) )
|
||||||
{
|
{
|
||||||
CL_RegisterResources( &msg );
|
CL_RegisterResources( &msg );
|
||||||
}
|
}
|
||||||
|
@ -1702,16 +1706,23 @@ CL_ParseResLocation
|
||||||
*/
|
*/
|
||||||
void CL_ParseResLocation( sizebuf_t *msg )
|
void CL_ParseResLocation( sizebuf_t *msg )
|
||||||
{
|
{
|
||||||
const char *url = MSG_ReadString( msg );
|
const char *data = MSG_ReadString( msg );
|
||||||
|
char token[256];
|
||||||
|
|
||||||
if( url && ( !Q_strnicmp( "http://", url, 7 ) || !Q_strnicmp( "https://", url, 8 )))
|
if( Q_strlen( data ) > 256 )
|
||||||
{
|
{
|
||||||
const char *lastSlash = Q_strrchr( url, '/' );
|
Con_Printf( S_ERROR "Resource location too long!\n" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if( lastSlash && lastSlash[1] == '\0' )
|
while( ( data = COM_ParseFile( data, token ) ) )
|
||||||
Q_strncpy( cl.downloadUrl, url, sizeof( cl.downloadUrl ));
|
{
|
||||||
else Q_snprintf( cl.downloadUrl, sizeof( cl.downloadUrl ), "%s/", url );
|
Con_Reportf( "Adding %s as download location\n", token );
|
||||||
Con_Reportf( "Using %s as primary download location\n", cl.downloadUrl );
|
|
||||||
|
if( !cl.downloadUrl[0] )
|
||||||
|
Q_strncpy( cl.downloadUrl, token, sizeof( token ) );
|
||||||
|
|
||||||
|
HTTP_AddCustomServer( token );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2716,6 +2727,61 @@ void CL_LegacyUpdateUserinfo( sizebuf_t *msg )
|
||||||
else memset( player, 0, sizeof( *player ));
|
else memset( player, 0, sizeof( *player ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==============
|
||||||
|
CL_ParseResourceList
|
||||||
|
|
||||||
|
==============
|
||||||
|
*/
|
||||||
|
void CL_LegacyParseResourceList( sizebuf_t *msg )
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
int rescount;
|
||||||
|
int restype[MAX_RESOURCES];
|
||||||
|
char resnames[MAX_RESOURCES][CS_SIZE];
|
||||||
|
} reslist;
|
||||||
|
memset( &reslist, 0, sizeof( reslist ));
|
||||||
|
|
||||||
|
reslist.rescount = MSG_ReadWord( msg ) - 1;
|
||||||
|
|
||||||
|
for( i = 0; i < reslist.rescount; i++ )
|
||||||
|
{
|
||||||
|
reslist.restype[i] = MSG_ReadWord( msg );
|
||||||
|
Q_strncpy( reslist.resnames[i], MSG_ReadString( msg ), CS_SIZE );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( CL_IsPlaybackDemo() )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
host.downloadcount = 0;
|
||||||
|
|
||||||
|
for( i = 0; i < reslist.rescount; i++ )
|
||||||
|
{
|
||||||
|
const char *path;
|
||||||
|
|
||||||
|
if( reslist.restype[i] == t_sound )
|
||||||
|
path = va( "sound/%s", reslist.resnames[i] );
|
||||||
|
else path = reslist.resnames[i];
|
||||||
|
|
||||||
|
if( FS_FileExists( path, false ))
|
||||||
|
continue; // already exists
|
||||||
|
|
||||||
|
host.downloadcount++;
|
||||||
|
HTTP_AddDownload( path, -1, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !host.downloadcount )
|
||||||
|
{
|
||||||
|
MSG_WriteByte( &cls.netchan.message, clc_stringcmd );
|
||||||
|
MSG_WriteString( &cls.netchan.message, "continueloading" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
=====================
|
=====================
|
||||||
CL_ParseLegacyServerMessage
|
CL_ParseLegacyServerMessage
|
||||||
|
@ -2845,13 +2911,9 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message )
|
||||||
if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS )
|
if( !Q_strnicmp( s, "disconnect", 10 ) && cls.signon != SIGNONS )
|
||||||
break; // too early
|
break; // too early
|
||||||
#endif
|
#endif
|
||||||
if( !Q_strcmp(s, "cmd getresourcelist\n") )
|
|
||||||
Cbuf_AddText("cmd continueloading\n");
|
Con_Reportf( "Stufftext: %s", s );
|
||||||
else
|
Cbuf_AddText( s );
|
||||||
{
|
|
||||||
Con_Reportf( "Stufftext: %s", s );
|
|
||||||
Cbuf_AddText( s );
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case svc_setangle:
|
case svc_setangle:
|
||||||
CL_ParseSetAngle( msg );
|
CL_ParseSetAngle( msg );
|
||||||
|
@ -2981,7 +3043,7 @@ void CL_ParseLegacyServerMessage( sizebuf_t *msg, qboolean normal_message )
|
||||||
//cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].receivedtime = -2.0;
|
//cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].receivedtime = -2.0;
|
||||||
break;
|
break;
|
||||||
case svc_resourcelist:
|
case svc_resourcelist:
|
||||||
CL_ParseResourceList( msg );
|
CL_LegacyParseResourceList( msg );
|
||||||
break;
|
break;
|
||||||
case svc_deltamovevars:
|
case svc_deltamovevars:
|
||||||
CL_ParseMovevars( msg );
|
CL_ParseMovevars( msg );
|
||||||
|
|
|
@ -663,6 +663,8 @@ typedef struct
|
||||||
qboolean internetservers_pending; // internetservers is waiting for dns request
|
qboolean internetservers_pending; // internetservers is waiting for dns request
|
||||||
qboolean legacymode; // one-way 48 protocol compatibility
|
qboolean legacymode; // one-way 48 protocol compatibility
|
||||||
netadr_t legacyserver;
|
netadr_t legacyserver;
|
||||||
|
netadr_t legacyservers[MAX_LEGACY_SERVERS];
|
||||||
|
int legacyservercount;
|
||||||
int extensions;
|
int extensions;
|
||||||
} client_static_t;
|
} client_static_t;
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ typedef struct
|
||||||
static float g_DecalClipVerts[MAX_DECALCLIPVERT][VERTEXSIZE];
|
static float g_DecalClipVerts[MAX_DECALCLIPVERT][VERTEXSIZE];
|
||||||
static float g_DecalClipVerts2[MAX_DECALCLIPVERT][VERTEXSIZE];
|
static float g_DecalClipVerts2[MAX_DECALCLIPVERT][VERTEXSIZE];
|
||||||
|
|
||||||
static decal_t gDecalPool[MAX_RENDER_DECALS];
|
decal_t gDecalPool[MAX_RENDER_DECALS];
|
||||||
static int gDecalCount;
|
static int gDecalCount;
|
||||||
|
|
||||||
void R_ClearDecals( void )
|
void R_ClearDecals( void )
|
||||||
|
@ -570,6 +570,7 @@ static void R_AddDecalToSurface( decal_t *pdecal, msurface_t *surf, decalinfo_t
|
||||||
|
|
||||||
// alloc clipped poly for decal
|
// alloc clipped poly for decal
|
||||||
R_DecalCreatePoly( decalinfo, pdecal, surf );
|
R_DecalCreatePoly( decalinfo, pdecal, surf );
|
||||||
|
R_AddDecalVBO( pdecal, surf );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void R_DecalCreate( decalinfo_t *decalinfo, msurface_t *surf, float x, float y )
|
static void R_DecalCreate( decalinfo_t *decalinfo, msurface_t *surf, float x, float y )
|
||||||
|
@ -1282,4 +1283,4 @@ void R_ClearAllDecals( void )
|
||||||
{
|
{
|
||||||
clgame.drawFuncs.R_ClearStudioDecals();
|
clgame.drawFuncs.R_ClearStudioDecals();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -408,6 +408,9 @@ void GL_RebuildLightmaps( void );
|
||||||
void GL_InitRandomTable( void );
|
void GL_InitRandomTable( void );
|
||||||
void GL_BuildLightmaps( void );
|
void GL_BuildLightmaps( void );
|
||||||
void GL_ResetFogColor( void );
|
void GL_ResetFogColor( void );
|
||||||
|
void R_GenerateVBO();
|
||||||
|
void R_ClearVBO();
|
||||||
|
void R_AddDecalVBO( decal_t *pdecal, msurface_t *surf );
|
||||||
|
|
||||||
//
|
//
|
||||||
// gl_sprite.c
|
// gl_sprite.c
|
||||||
|
@ -523,6 +526,7 @@ enum
|
||||||
GL_EXT_GPU_SHADER4, // shaders only
|
GL_EXT_GPU_SHADER4, // shaders only
|
||||||
GL_DEPTH_TEXTURE,
|
GL_DEPTH_TEXTURE,
|
||||||
GL_DEBUG_OUTPUT,
|
GL_DEBUG_OUTPUT,
|
||||||
|
GL_ARB_VERTEX_BUFFER_OBJECT_EXT,
|
||||||
GL_EXTCOUNT, // must be last
|
GL_EXTCOUNT, // must be last
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -678,6 +682,8 @@ extern convar_t *r_lockfrustum;
|
||||||
extern convar_t *r_traceglow;
|
extern convar_t *r_traceglow;
|
||||||
extern convar_t *r_dynamic;
|
extern convar_t *r_dynamic;
|
||||||
extern convar_t *r_lightmap;
|
extern convar_t *r_lightmap;
|
||||||
|
extern convar_t *r_vbo;
|
||||||
|
extern convar_t *r_vbo_dlightmode;
|
||||||
|
|
||||||
extern convar_t *vid_displayfrequency;
|
extern convar_t *vid_displayfrequency;
|
||||||
extern convar_t *vid_fullscreen;
|
extern convar_t *vid_fullscreen;
|
||||||
|
|
|
@ -199,4 +199,5 @@ void R_NewMap( void )
|
||||||
R_SetupSky( clgame.movevars.skyName );
|
R_SetupSky( clgame.movevars.skyName );
|
||||||
|
|
||||||
GL_BuildLightmaps ();
|
GL_BuildLightmaps ();
|
||||||
}
|
R_GenerateVBO();
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -102,13 +102,22 @@ typedef struct
|
||||||
vec4_t lightpos[MAXSTUDIOVERTS][MAX_LOCALLIGHTS];
|
vec4_t lightpos[MAXSTUDIOVERTS][MAX_LOCALLIGHTS];
|
||||||
vec3_t lightbonepos[MAXSTUDIOBONES][MAX_LOCALLIGHTS];
|
vec3_t lightbonepos[MAXSTUDIOBONES][MAX_LOCALLIGHTS];
|
||||||
float locallightR2[MAX_LOCALLIGHTS];
|
float locallightR2[MAX_LOCALLIGHTS];
|
||||||
|
|
||||||
|
// drawelements renderer
|
||||||
|
vec3_t arrayverts[MAXSTUDIOVERTS];
|
||||||
|
vec2_t arraycoord[MAXSTUDIOVERTS];
|
||||||
|
unsigned short arrayelems[MAXSTUDIOVERTS*6];
|
||||||
|
GLubyte arraycolor[MAXSTUDIOVERTS][4];
|
||||||
|
uint numverts;
|
||||||
|
uint numelems;
|
||||||
} studio_draw_state_t;
|
} studio_draw_state_t;
|
||||||
|
|
||||||
// studio-related cvars
|
// studio-related cvars
|
||||||
convar_t *r_studio_sort_textures;
|
static convar_t *r_studio_sort_textures;
|
||||||
convar_t *r_drawviewmodel;
|
static convar_t *r_drawviewmodel;
|
||||||
convar_t *cl_righthand = NULL;
|
convar_t *cl_righthand = NULL;
|
||||||
convar_t *cl_himodels;
|
static convar_t *cl_himodels;
|
||||||
|
static convar_t *r_studio_drawelements;
|
||||||
|
|
||||||
static r_studio_interface_t *pStudioDraw;
|
static r_studio_interface_t *pStudioDraw;
|
||||||
static studio_draw_state_t g_studio; // global studio state
|
static studio_draw_state_t g_studio; // global studio state
|
||||||
|
@ -135,6 +144,7 @@ void R_StudioInit( void )
|
||||||
cl_himodels = Cvar_Get( "cl_himodels", "1", FCVAR_ARCHIVE, "draw high-resolution player models in multiplayer" );
|
cl_himodels = Cvar_Get( "cl_himodels", "1", FCVAR_ARCHIVE, "draw high-resolution player models in multiplayer" );
|
||||||
r_studio_sort_textures = Cvar_Get( "r_studio_sort_textures", "0", FCVAR_ARCHIVE, "change draw order for additive meshes" );
|
r_studio_sort_textures = Cvar_Get( "r_studio_sort_textures", "0", FCVAR_ARCHIVE, "change draw order for additive meshes" );
|
||||||
r_drawviewmodel = Cvar_Get( "r_drawviewmodel", "1", 0, "draw firstperson weapon model" );
|
r_drawviewmodel = Cvar_Get( "r_drawviewmodel", "1", 0, "draw firstperson weapon model" );
|
||||||
|
r_studio_drawelements = Cvar_Get( "r_studio_drawelements", "1", FCVAR_ARCHIVE, "use glDrawElements for studiomodels" );
|
||||||
|
|
||||||
Matrix3x4_LoadIdentity( g_studio.rotationmatrix );
|
Matrix3x4_LoadIdentity( g_studio.rotationmatrix );
|
||||||
Cvar_RegisterVariable( &r_glowshellfreq );
|
Cvar_RegisterVariable( &r_glowshellfreq );
|
||||||
|
@ -1723,7 +1733,7 @@ R_LightLambert
|
||||||
|
|
||||||
====================
|
====================
|
||||||
*/
|
*/
|
||||||
void R_LightLambert( vec4_t light[MAX_LOCALLIGHTS], vec3_t normal, vec3_t color )
|
void R_LightLambert( vec4_t light[MAX_LOCALLIGHTS], vec3_t normal, vec3_t color, byte *out )
|
||||||
{
|
{
|
||||||
vec3_t finalLight;
|
vec3_t finalLight;
|
||||||
vec3_t localLight;
|
vec3_t localLight;
|
||||||
|
@ -1761,7 +1771,53 @@ void R_LightLambert( vec4_t light[MAX_LOCALLIGHTS], vec3_t normal, vec3_t color
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pglColor4f( finalLight[0], finalLight[1], finalLight[2], tr.blend );
|
out[0] = finalLight[0] * 255;
|
||||||
|
out[1] = finalLight[1] * 255;
|
||||||
|
out[2] = finalLight[2] * 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void R_StudioSetColorBegin(short *ptricmds, vec3_t *pstudionorms )
|
||||||
|
{
|
||||||
|
float *lv = (float *)g_studio.lightvalues[ptricmds[1]];
|
||||||
|
rgba_t color;
|
||||||
|
|
||||||
|
if( g_studio.numlocallights )
|
||||||
|
{
|
||||||
|
color[3] = tr.blend * 255;
|
||||||
|
R_LightLambert( g_studio.lightpos[ptricmds[0]], pstudionorms[ptricmds[1]], lv, color );
|
||||||
|
pglColor4ubv( color );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( RI.currententity->curstate.rendermode == kRenderTransColor )
|
||||||
|
{
|
||||||
|
color[3] = tr.blend * 255;
|
||||||
|
VectorCopy( (byte*)&RI.currententity->curstate.rendercolor, color );
|
||||||
|
pglColor4ubv( color );
|
||||||
|
}
|
||||||
|
else pglColor4f( lv[0], lv[1], lv[2], tr.blend );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void R_StudioSetColorArray(short *ptricmds, vec3_t *pstudionorms, byte *color )
|
||||||
|
{
|
||||||
|
float *lv = (float *)g_studio.lightvalues[ptricmds[1]];
|
||||||
|
|
||||||
|
color[3] = tr.blend * 255;
|
||||||
|
|
||||||
|
if( g_studio.numlocallights )
|
||||||
|
R_LightLambert( g_studio.lightpos[ptricmds[0]], pstudionorms[ptricmds[1]], lv, color );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( RI.currententity->curstate.rendermode == kRenderTransColor )
|
||||||
|
VectorCopy( (byte*)&RI.currententity->curstate.rendercolor, color );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
color[0] = lv[0] * 255;
|
||||||
|
color[1] = lv[1] * 255;
|
||||||
|
color[2] = lv[2] * 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1934,11 +1990,8 @@ _inline void R_StudioDrawNormalMesh( short *ptricmds, vec3_t *pstudionorms, floa
|
||||||
|
|
||||||
for( ; i > 0; i--, ptricmds += 4 )
|
for( ; i > 0; i--, ptricmds += 4 )
|
||||||
{
|
{
|
||||||
lv = (float *)g_studio.lightvalues[ptricmds[1]];
|
R_StudioSetColorBegin( ptricmds, pstudionorms );
|
||||||
|
|
||||||
if( g_studio.numlocallights )
|
|
||||||
R_LightLambert( g_studio.lightpos[ptricmds[0]], pstudionorms[ptricmds[1]], lv );
|
|
||||||
else pglColor4f( lv[0], lv[1], lv[2], tr.blend );
|
|
||||||
pglTexCoord2f( ptricmds[2] * s, ptricmds[3] * t );
|
pglTexCoord2f( ptricmds[2] * s, ptricmds[3] * t );
|
||||||
pglVertex3fv( g_studio.verts[ptricmds[0]] );
|
pglVertex3fv( g_studio.verts[ptricmds[0]] );
|
||||||
}
|
}
|
||||||
|
@ -1970,10 +2023,7 @@ _inline void R_StudioDrawFloatMesh( short *ptricmds, vec3_t *pstudionorms )
|
||||||
|
|
||||||
for( ; i > 0; i--, ptricmds += 4 )
|
for( ; i > 0; i--, ptricmds += 4 )
|
||||||
{
|
{
|
||||||
lv = (float *)g_studio.lightvalues[ptricmds[1]];
|
R_StudioSetColorBegin( ptricmds, pstudionorms );
|
||||||
if( g_studio.numlocallights )
|
|
||||||
R_LightLambert( g_studio.lightpos[ptricmds[0]], pstudionorms[ptricmds[1]], lv );
|
|
||||||
else pglColor4f( lv[0], lv[1], lv[2], tr.blend );
|
|
||||||
pglTexCoord2f( HalfToFloat( ptricmds[2] ), HalfToFloat( ptricmds[3] ));
|
pglTexCoord2f( HalfToFloat( ptricmds[2] ), HalfToFloat( ptricmds[3] ));
|
||||||
pglVertex3fv( g_studio.verts[ptricmds[0]] );
|
pglVertex3fv( g_studio.verts[ptricmds[0]] );
|
||||||
}
|
}
|
||||||
|
@ -2009,10 +2059,13 @@ _inline void R_StudioDrawChromeMesh( short *ptricmds, vec3_t *pstudionorms, floa
|
||||||
{
|
{
|
||||||
if( glowShell )
|
if( glowShell )
|
||||||
{
|
{
|
||||||
|
color24 *clr = &RI.currententity->curstate.rendercolor;
|
||||||
|
|
||||||
idx = g_studio.normaltable[ptricmds[0]];
|
idx = g_studio.normaltable[ptricmds[0]];
|
||||||
av = g_studio.verts[ptricmds[0]];
|
av = g_studio.verts[ptricmds[0]];
|
||||||
lv = g_studio.norms[ptricmds[0]];
|
lv = g_studio.norms[ptricmds[0]];
|
||||||
VectorMA( av, scale, lv, vert );
|
VectorMA( av, scale, lv, vert );
|
||||||
|
pglColor4ub( clr->r, clr->g, clr->b, 255 );
|
||||||
pglTexCoord2f( g_studio.chrome[idx][0] * s, g_studio.chrome[idx][1] * t );
|
pglTexCoord2f( g_studio.chrome[idx][0] * s, g_studio.chrome[idx][1] * t );
|
||||||
pglVertex3fv( vert );
|
pglVertex3fv( vert );
|
||||||
}
|
}
|
||||||
|
@ -2020,9 +2073,7 @@ _inline void R_StudioDrawChromeMesh( short *ptricmds, vec3_t *pstudionorms, floa
|
||||||
{
|
{
|
||||||
idx = ptricmds[1];
|
idx = ptricmds[1];
|
||||||
lv = (float *)g_studio.lightvalues[ptricmds[1]];
|
lv = (float *)g_studio.lightvalues[ptricmds[1]];
|
||||||
if( g_studio.numlocallights )
|
R_StudioSetColorBegin( ptricmds, pstudionorms );
|
||||||
R_LightLambert( g_studio.lightpos[ptricmds[0]], pstudionorms[ptricmds[1]], lv );
|
|
||||||
else pglColor4f( lv[0], lv[1], lv[2], tr.blend );
|
|
||||||
pglTexCoord2f( g_studio.chrome[idx][0] * s, g_studio.chrome[idx][1] * t );
|
pglTexCoord2f( g_studio.chrome[idx][0] * s, g_studio.chrome[idx][1] * t );
|
||||||
pglVertex3fv( g_studio.verts[ptricmds[0]] );
|
pglVertex3fv( g_studio.verts[ptricmds[0]] );
|
||||||
}
|
}
|
||||||
|
@ -2032,6 +2083,220 @@ _inline void R_StudioDrawChromeMesh( short *ptricmds, vec3_t *pstudionorms, floa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_inline int R_StudioBuildIndices( qboolean tri_strip, int vertexState )
|
||||||
|
{
|
||||||
|
// build in indices
|
||||||
|
if( vertexState++ < 3 )
|
||||||
|
{
|
||||||
|
g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts;
|
||||||
|
}
|
||||||
|
else if( tri_strip )
|
||||||
|
{
|
||||||
|
// flip triangles between clockwise and counter clockwise
|
||||||
|
if( vertexState & 1 )
|
||||||
|
{
|
||||||
|
// draw triangle [n-2 n-1 n]
|
||||||
|
g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - 2;
|
||||||
|
g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - 1;
|
||||||
|
g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// draw triangle [n-1 n-2 n]
|
||||||
|
g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - 1;
|
||||||
|
g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - 2;
|
||||||
|
g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// draw triangle fan [0 n-1 n]
|
||||||
|
g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - ( vertexState - 1 );
|
||||||
|
g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts - 1;
|
||||||
|
g_studio.arrayelems[g_studio.numelems++] = g_studio.numverts;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vertexState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
R_StudioDrawNormalMesh
|
||||||
|
|
||||||
|
generic path
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
_inline void R_StudioBuildArrayNormalMesh( short *ptricmds, vec3_t *pstudionorms, float s, float t )
|
||||||
|
{
|
||||||
|
float *lv;
|
||||||
|
int i;
|
||||||
|
float alpha = tr.blend;
|
||||||
|
|
||||||
|
while( i = *( ptricmds++ ))
|
||||||
|
{
|
||||||
|
int vertexState = 0;
|
||||||
|
qboolean tri_strip = true;
|
||||||
|
|
||||||
|
if( i < 0 )
|
||||||
|
{
|
||||||
|
tri_strip = false;
|
||||||
|
i = -i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( ; i > 0; i--, ptricmds += 4 )
|
||||||
|
{
|
||||||
|
GLubyte *cl;
|
||||||
|
cl = g_studio.arraycolor[g_studio.numverts];
|
||||||
|
lv = (float *)g_studio.lightvalues[ptricmds[1]];
|
||||||
|
|
||||||
|
vertexState = R_StudioBuildIndices( tri_strip, vertexState );
|
||||||
|
|
||||||
|
R_StudioSetColorArray( ptricmds, pstudionorms, cl );
|
||||||
|
|
||||||
|
g_studio.arraycoord[g_studio.numverts][0] = ptricmds[2] * s;
|
||||||
|
g_studio.arraycoord[g_studio.numverts][1] = ptricmds[3] * t;
|
||||||
|
|
||||||
|
VectorCopy( g_studio.verts[ptricmds[0]], g_studio.arrayverts[g_studio.numverts] );
|
||||||
|
g_studio.numverts++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
R_StudioDrawNormalMesh
|
||||||
|
|
||||||
|
generic path
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
_inline void R_StudioBuildArrayFloatMesh( short *ptricmds, vec3_t *pstudionorms )
|
||||||
|
{
|
||||||
|
float *lv;
|
||||||
|
int i;
|
||||||
|
float alpha = tr.blend;
|
||||||
|
|
||||||
|
while( i = *( ptricmds++ ))
|
||||||
|
{
|
||||||
|
int vertexState = 0;
|
||||||
|
qboolean tri_strip = true;
|
||||||
|
|
||||||
|
if( i < 0 )
|
||||||
|
{
|
||||||
|
tri_strip = false;
|
||||||
|
i = -i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( ; i > 0; i--, ptricmds += 4 )
|
||||||
|
{
|
||||||
|
GLubyte *cl;
|
||||||
|
cl = g_studio.arraycolor[g_studio.numverts];
|
||||||
|
lv = (float *)g_studio.lightvalues[ptricmds[1]];
|
||||||
|
|
||||||
|
vertexState = R_StudioBuildIndices( tri_strip, vertexState );
|
||||||
|
|
||||||
|
R_StudioSetColorArray( ptricmds, pstudionorms, cl );
|
||||||
|
|
||||||
|
g_studio.arraycoord[g_studio.numverts][0] = HalfToFloat( ptricmds[2] );
|
||||||
|
g_studio.arraycoord[g_studio.numverts][1] = HalfToFloat( ptricmds[3] );
|
||||||
|
|
||||||
|
VectorCopy( g_studio.verts[ptricmds[0]], g_studio.arrayverts[g_studio.numverts] );
|
||||||
|
g_studio.numverts++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
R_StudioDrawNormalMesh
|
||||||
|
|
||||||
|
generic path
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
_inline void R_StudioBuildArrayChromeMesh( short *ptricmds, vec3_t *pstudionorms, float s, float t, float scale )
|
||||||
|
{
|
||||||
|
float *lv, *av;
|
||||||
|
int i, idx;
|
||||||
|
qboolean glowShell = (scale > 0.0f) ? true : false;
|
||||||
|
vec3_t vert;
|
||||||
|
float alpha = tr.blend;
|
||||||
|
|
||||||
|
while( i = *( ptricmds++ ))
|
||||||
|
{
|
||||||
|
int vertexState = 0;
|
||||||
|
qboolean tri_strip = true;
|
||||||
|
|
||||||
|
if( i < 0 )
|
||||||
|
{
|
||||||
|
tri_strip = false;
|
||||||
|
i = -i;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( ; i > 0; i--, ptricmds += 4 )
|
||||||
|
{
|
||||||
|
GLubyte *cl;
|
||||||
|
cl = g_studio.arraycolor[g_studio.numverts];
|
||||||
|
lv = (float *)g_studio.lightvalues[ptricmds[1]];
|
||||||
|
|
||||||
|
vertexState = R_StudioBuildIndices( tri_strip, vertexState );
|
||||||
|
|
||||||
|
if( glowShell )
|
||||||
|
{
|
||||||
|
idx = g_studio.normaltable[ptricmds[0]];
|
||||||
|
av = g_studio.verts[ptricmds[0]];
|
||||||
|
lv = g_studio.norms[ptricmds[0]];
|
||||||
|
|
||||||
|
cl[0] = RI.currententity->curstate.rendercolor.r;
|
||||||
|
cl[1] = RI.currententity->curstate.rendercolor.g;
|
||||||
|
cl[2] = RI.currententity->curstate.rendercolor.b;
|
||||||
|
cl[3] = 255;
|
||||||
|
|
||||||
|
VectorMA( av, scale, lv, vert );
|
||||||
|
VectorCopy( vert, g_studio.arrayverts[g_studio.numverts] );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
idx = ptricmds[1];
|
||||||
|
R_StudioSetColorArray( ptricmds, pstudionorms, cl );
|
||||||
|
|
||||||
|
VectorCopy( g_studio.verts[ptricmds[0]], g_studio.arrayverts[g_studio.numverts] );
|
||||||
|
}
|
||||||
|
|
||||||
|
g_studio.arraycoord[g_studio.numverts][0] = g_studio.chrome[idx][0] * s;
|
||||||
|
g_studio.arraycoord[g_studio.numverts][1] = g_studio.chrome[idx][1] * t;
|
||||||
|
|
||||||
|
g_studio.numverts++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_inline void R_StudioDrawArrays( uint startverts, uint startelems )
|
||||||
|
{
|
||||||
|
pglEnableClientState( GL_VERTEX_ARRAY );
|
||||||
|
pglVertexPointer( 3, GL_FLOAT, 12, g_studio.arrayverts );
|
||||||
|
|
||||||
|
pglEnableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||||
|
pglTexCoordPointer( 2, GL_FLOAT, 0, g_studio.arraycoord );
|
||||||
|
|
||||||
|
if( !( g_nForceFaceFlags & STUDIO_NF_CHROME ) )
|
||||||
|
{
|
||||||
|
pglEnableClientState( GL_COLOR_ARRAY );
|
||||||
|
pglColorPointer( 4, GL_UNSIGNED_BYTE, 0, g_studio.arraycolor );
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !defined XASH_NANOGL || defined XASH_WES && defined __EMSCRIPTEN__ // WebGL need to know array sizes
|
||||||
|
if( pglDrawRangeElements )
|
||||||
|
pglDrawRangeElements( GL_TRIANGLES, startverts, g_studio.numverts,
|
||||||
|
g_studio.numelems - startelems, GL_UNSIGNED_SHORT, &g_studio.arrayelems[startelems] );
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
pglDrawElements( GL_TRIANGLES, g_studio.numelems - startelems, GL_UNSIGNED_SHORT, &g_studio.arrayelems[startelems] );
|
||||||
|
pglDisableClientState( GL_VERTEX_ARRAY );
|
||||||
|
pglDisableClientState( GL_TEXTURE_COORD_ARRAY );
|
||||||
|
if( !( g_nForceFaceFlags & STUDIO_NF_CHROME ) )
|
||||||
|
pglDisableClientState( GL_COLOR_ARRAY );
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============
|
===============
|
||||||
R_StudioDrawPoints
|
R_StudioDrawPoints
|
||||||
|
@ -2054,6 +2319,9 @@ static void R_StudioDrawPoints( void )
|
||||||
|
|
||||||
if( !m_pStudioHeader ) return;
|
if( !m_pStudioHeader ) return;
|
||||||
|
|
||||||
|
|
||||||
|
g_studio.numverts = g_studio.numelems = 0;
|
||||||
|
|
||||||
// safety bounding the skinnum
|
// safety bounding the skinnum
|
||||||
m_skinnum = bound( 0, RI.currententity->curstate.skin, ( m_pStudioHeader->numskinfamilies - 1 ));
|
m_skinnum = bound( 0, RI.currententity->curstate.skin, ( m_pStudioHeader->numskinfamilies - 1 ));
|
||||||
ptexture = (mstudiotexture_t *)((byte *)m_pStudioHeader + m_pStudioHeader->textureindex);
|
ptexture = (mstudiotexture_t *)((byte *)m_pStudioHeader + m_pStudioHeader->textureindex);
|
||||||
|
@ -2151,6 +2419,8 @@ static void R_StudioDrawPoints( void )
|
||||||
for( j = 0; j < m_pSubModel->nummesh; j++ )
|
for( j = 0; j < m_pSubModel->nummesh; j++ )
|
||||||
{
|
{
|
||||||
float oldblend = tr.blend;
|
float oldblend = tr.blend;
|
||||||
|
uint startArrayVerts = g_studio.numverts;
|
||||||
|
uint startArrayElems = g_studio.numelems;
|
||||||
short *ptricmds;
|
short *ptricmds;
|
||||||
float s, t;
|
float s, t;
|
||||||
|
|
||||||
|
@ -2184,11 +2454,24 @@ static void R_StudioDrawPoints( void )
|
||||||
|
|
||||||
R_StudioSetupSkin( m_pStudioHeader, pskinref[pmesh->skinref] );
|
R_StudioSetupSkin( m_pStudioHeader, pskinref[pmesh->skinref] );
|
||||||
|
|
||||||
if( FBitSet( g_nFaceFlags, STUDIO_NF_CHROME ))
|
if( CVAR_TO_BOOL(r_studio_drawelements) )
|
||||||
R_StudioDrawChromeMesh( ptricmds, pstudionorms, s, t, shellscale );
|
{
|
||||||
else if( FBitSet( g_nFaceFlags, STUDIO_NF_UV_COORDS ))
|
if( FBitSet( g_nFaceFlags, STUDIO_NF_CHROME ))
|
||||||
R_StudioDrawFloatMesh( ptricmds, pstudionorms );
|
R_StudioBuildArrayChromeMesh( ptricmds, pstudionorms, s, t, shellscale );
|
||||||
else R_StudioDrawNormalMesh( ptricmds, pstudionorms, s, t );
|
else if( FBitSet( g_nFaceFlags, STUDIO_NF_UV_COORDS ))
|
||||||
|
R_StudioBuildArrayFloatMesh( ptricmds, pstudionorms );
|
||||||
|
else R_StudioBuildArrayNormalMesh( ptricmds, pstudionorms, s, t );
|
||||||
|
|
||||||
|
R_StudioDrawArrays( startArrayVerts, startArrayElems );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( FBitSet( g_nFaceFlags, STUDIO_NF_CHROME ))
|
||||||
|
R_StudioDrawChromeMesh( ptricmds, pstudionorms, s, t, shellscale );
|
||||||
|
else if( FBitSet( g_nFaceFlags, STUDIO_NF_UV_COORDS ))
|
||||||
|
R_StudioDrawFloatMesh( ptricmds, pstudionorms );
|
||||||
|
else R_StudioDrawNormalMesh( ptricmds, pstudionorms, s, t );
|
||||||
|
}
|
||||||
|
|
||||||
if( FBitSet( g_nFaceFlags, STUDIO_NF_MASKED ))
|
if( FBitSet( g_nFaceFlags, STUDIO_NF_MASKED ))
|
||||||
{
|
{
|
||||||
|
|
|
@ -527,8 +527,11 @@ Key_IsAllowedAutoRepeat
|
||||||
List of keys that allows auto-repeat
|
List of keys that allows auto-repeat
|
||||||
===================
|
===================
|
||||||
*/
|
*/
|
||||||
qboolean Key_IsAllowedAutoRepeat( int key )
|
static qboolean Key_IsAllowedAutoRepeat( int key )
|
||||||
{
|
{
|
||||||
|
if( cls.key_dest != key_game )
|
||||||
|
return true;
|
||||||
|
|
||||||
switch( key )
|
switch( key )
|
||||||
{
|
{
|
||||||
case K_BACKSPACE:
|
case K_BACKSPACE:
|
||||||
|
|
|
@ -545,7 +545,7 @@ void VOX_ParseLineCommands( char *pSentenceData, int sentenceIndex )
|
||||||
length = pNext - pSentenceData;
|
length = pNext - pSentenceData;
|
||||||
if( tempBufferPos + length > sizeof( tempBuffer ))
|
if( tempBufferPos + length > sizeof( tempBuffer ))
|
||||||
{
|
{
|
||||||
Con_Printf( S_ERROR "sentence too long!\n" );
|
Con_Printf( S_ERROR "Sentence too long (max length %d characters)\n", sizeof(tempBuffer) - 1 );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -619,7 +619,7 @@ void VOX_ReadSentenceFile( const char *psentenceFileName )
|
||||||
{
|
{
|
||||||
if( g_numSentences >= MAX_SENTENCES )
|
if( g_numSentences >= MAX_SENTENCES )
|
||||||
{
|
{
|
||||||
Con_Printf( S_ERROR "VOX_Init: too many sentences specified\n" );
|
Con_Printf( S_ERROR "VOX_Init: too many sentences specified, max is %d\n", MAX_SENTENCES );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,8 @@ convar_t *r_traceglow;
|
||||||
convar_t *r_dynamic;
|
convar_t *r_dynamic;
|
||||||
convar_t *r_lightmap;
|
convar_t *r_lightmap;
|
||||||
convar_t *gl_round_down;
|
convar_t *gl_round_down;
|
||||||
|
convar_t *r_vbo;
|
||||||
|
convar_t *r_vbo_dlightmode;
|
||||||
|
|
||||||
convar_t *vid_displayfrequency;
|
convar_t *vid_displayfrequency;
|
||||||
convar_t *vid_fullscreen;
|
convar_t *vid_fullscreen;
|
||||||
|
@ -546,6 +548,51 @@ static void SetFullscreenModeFromCommandLine( )
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
R_CheckVBO
|
||||||
|
|
||||||
|
register VBO cvars and get default value
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
static void R_CheckVBO( void )
|
||||||
|
{
|
||||||
|
const char *def = "1";
|
||||||
|
const char *dlightmode = "1";
|
||||||
|
int flags = FCVAR_ARCHIVE;
|
||||||
|
qboolean disable = false;
|
||||||
|
|
||||||
|
// some bad GLES1 implementations breaks dlights completely
|
||||||
|
if( glConfig.max_texture_units < 3 )
|
||||||
|
disable = true;
|
||||||
|
|
||||||
|
#ifdef XASH_MOBILE_PLATFORM
|
||||||
|
// VideoCore4 drivers have a problem with mixing VBO and client arrays
|
||||||
|
// Disable it, as there is no suitable workaround here
|
||||||
|
if( Q_stristr( glConfig.renderer_string, "VideoCore IV" ) || Q_stristr( glConfig.renderer_string, "vc4" ) )
|
||||||
|
disable = true;
|
||||||
|
|
||||||
|
// dlightmode 1 is not too much tested on android
|
||||||
|
// so better to left it off
|
||||||
|
dlightmode = "0";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( disable )
|
||||||
|
{
|
||||||
|
// do not keep in config unless dev > 3 and enabled
|
||||||
|
flags = 0;
|
||||||
|
def = "0";
|
||||||
|
}
|
||||||
|
|
||||||
|
r_vbo = Cvar_Get( "r_vbo", def, flags, "draw world using VBO" );
|
||||||
|
r_vbo_dlightmode = Cvar_Get( "r_vbo_dlightmode", dlightmode, FCVAR_ARCHIVE, "vbo dlight rendering mode(0-1)" );
|
||||||
|
|
||||||
|
// check if enabled manually
|
||||||
|
if( CVAR_TO_BOOL(r_vbo) )
|
||||||
|
r_vbo->flags |= FCVAR_ARCHIVE;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
===============
|
===============
|
||||||
R_Init
|
R_Init
|
||||||
|
@ -580,6 +627,7 @@ qboolean R_Init( void )
|
||||||
r_temppool = Mem_AllocPool( "Render Zone" );
|
r_temppool = Mem_AllocPool( "Render Zone" );
|
||||||
|
|
||||||
GL_SetDefaults();
|
GL_SetDefaults();
|
||||||
|
R_CheckVBO();
|
||||||
R_InitImages();
|
R_InitImages();
|
||||||
R_SpriteInit();
|
R_SpriteInit();
|
||||||
R_StudioInit();
|
R_StudioInit();
|
||||||
|
|
|
@ -20,18 +20,18 @@ GNU General Public License for more details.
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "library.h"
|
#include "library.h"
|
||||||
|
|
||||||
const char *file_exts[10] =
|
static const char *file_exts[] =
|
||||||
{
|
{
|
||||||
".cfg",
|
"cfg",
|
||||||
".lst",
|
"lst",
|
||||||
".exe",
|
"exe",
|
||||||
".vbs",
|
"vbs",
|
||||||
".com",
|
"com",
|
||||||
".bat",
|
"bat",
|
||||||
".dll",
|
"dll",
|
||||||
".ini",
|
"ini",
|
||||||
".log",
|
"log",
|
||||||
".sys",
|
"sys",
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
|
|
|
@ -1053,6 +1053,7 @@ qboolean CL_IsBackgroundDemo( void );
|
||||||
qboolean CL_IsBackgroundMap( void );
|
qboolean CL_IsBackgroundMap( void );
|
||||||
qboolean SV_Initialized( void );
|
qboolean SV_Initialized( void );
|
||||||
qboolean CL_LoadProgs( const char *name );
|
qboolean CL_LoadProgs( const char *name );
|
||||||
|
void CL_ProcessFile( qboolean successfully_received, const char *filename );
|
||||||
int SV_GetSaveComment( const char *savename, char *comment );
|
int SV_GetSaveComment( const char *savename, char *comment );
|
||||||
qboolean SV_NewGame( const char *mapName, qboolean loadGame );
|
qboolean SV_NewGame( const char *mapName, qboolean loadGame );
|
||||||
void SV_ClipPMoveToEntity( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr );
|
void SV_ClipPMoveToEntity( struct physent_s *pe, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end, struct pmtrace_s *tr );
|
||||||
|
|
|
@ -84,6 +84,11 @@ const char *svc_strings[256] =
|
||||||
"svc_unused63",
|
"svc_unused63",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void CL_ProcessFile( qboolean successfully_received, const char *filename )
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
int CL_Active( void )
|
int CL_Active( void )
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -542,6 +542,7 @@ void Host_Frame( float time )
|
||||||
Host_GetCommands (); // dedicated in
|
Host_GetCommands (); // dedicated in
|
||||||
Host_ServerFrame (); // server frame
|
Host_ServerFrame (); // server frame
|
||||||
Host_ClientFrame (); // client frame
|
Host_ClientFrame (); // client frame
|
||||||
|
HTTP_Run(); // both server and client
|
||||||
|
|
||||||
host.framecount++;
|
host.framecount++;
|
||||||
}
|
}
|
||||||
|
@ -978,6 +979,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||||
SV_Init();
|
SV_Init();
|
||||||
CL_Init();
|
CL_Init();
|
||||||
|
|
||||||
|
HTTP_Init();
|
||||||
ID_Init();
|
ID_Init();
|
||||||
|
|
||||||
if( Host_IsDedicated() )
|
if( Host_IsDedicated() )
|
||||||
|
@ -1060,6 +1062,7 @@ void EXPORT Host_Shutdown( void )
|
||||||
|
|
||||||
Mod_Shutdown();
|
Mod_Shutdown();
|
||||||
NET_Shutdown();
|
NET_Shutdown();
|
||||||
|
HTTP_Shutdown();
|
||||||
Host_FreeCommon();
|
Host_FreeCommon();
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
Wcon_DestroyConsole();
|
Wcon_DestroyConsole();
|
||||||
|
|
|
@ -309,7 +309,7 @@ static void Mod_LoadLump( const byte *in, mlumpinfo_t *info, mlumpstat_t *stat,
|
||||||
if( l->filelen % real_entrysize )
|
if( l->filelen % real_entrysize )
|
||||||
{
|
{
|
||||||
if( !FBitSet( flags, LUMP_SILENT ))
|
if( !FBitSet( flags, LUMP_SILENT ))
|
||||||
Con_DPrintf( S_ERROR "Mod_Load%s: funny lump size\n", msg2 );
|
Con_DPrintf( S_ERROR "Mod_Load%s: Lump size %d was not a multiple of %u bytes\n", msg2, l->filelen, real_entrysize );
|
||||||
loadstat.numerrors++;
|
loadstat.numerrors++;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -288,8 +288,8 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
||||||
{
|
{
|
||||||
memset( mod, 0, sizeof( model_t ));
|
memset( mod, 0, sizeof( model_t ));
|
||||||
|
|
||||||
if( crash ) Host_Error( "%s couldn't load\n", tempname );
|
if( crash ) Host_Error( "Could not load model %s from disk\n", tempname );
|
||||||
else Con_Printf( S_ERROR "%s couldn't load\n", tempname );
|
else Con_Printf( S_ERROR "Could not load model %s from disk\n", tempname );
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -331,8 +331,8 @@ model_t *Mod_LoadModel( model_t *mod, qboolean crash )
|
||||||
Mod_FreeModel( mod );
|
Mod_FreeModel( mod );
|
||||||
Mem_Free( buf );
|
Mem_Free( buf );
|
||||||
|
|
||||||
if( crash ) Host_Error( "%s couldn't load\n", tempname );
|
if( crash ) Host_Error( "Could not load model %s\n", tempname );
|
||||||
else Con_Printf( S_ERROR "%s couldn't load\n", tempname );
|
else Con_Printf( S_ERROR "Could not load model %s\n", tempname );
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1877,3 +1877,827 @@ void NET_Shutdown( void )
|
||||||
#endif
|
#endif
|
||||||
net.initialized = false;
|
net.initialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
=================================================
|
||||||
|
|
||||||
|
HTTP downloader
|
||||||
|
|
||||||
|
=================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct httpserver_s
|
||||||
|
{
|
||||||
|
char host[256];
|
||||||
|
int port;
|
||||||
|
char path[PATH_MAX];
|
||||||
|
qboolean needfree;
|
||||||
|
struct httpserver_s *next;
|
||||||
|
|
||||||
|
} httpserver_t;
|
||||||
|
|
||||||
|
enum connectionstate
|
||||||
|
{
|
||||||
|
HTTP_QUEUE = 0,
|
||||||
|
HTTP_OPENED,
|
||||||
|
HTTP_SOCKET,
|
||||||
|
HTTP_NS_RESOLVED,
|
||||||
|
HTTP_CONNECTED,
|
||||||
|
HTTP_REQUEST,
|
||||||
|
HTTP_REQUEST_SENT,
|
||||||
|
HTTP_RESPONSE_RECEIVED,
|
||||||
|
HTTP_FREE
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct httpfile_s
|
||||||
|
{
|
||||||
|
struct httpfile_s *next;
|
||||||
|
httpserver_t *server;
|
||||||
|
char path[PATH_MAX];
|
||||||
|
file_t *file;
|
||||||
|
int socket;
|
||||||
|
int size;
|
||||||
|
int downloaded;
|
||||||
|
int lastchecksize;
|
||||||
|
float checktime;
|
||||||
|
float blocktime;
|
||||||
|
int id;
|
||||||
|
enum connectionstate state;
|
||||||
|
qboolean process;
|
||||||
|
|
||||||
|
// query or response
|
||||||
|
char buf[BUFSIZ];
|
||||||
|
int header_size, query_length, bytes_sent;
|
||||||
|
} httpfile_t;
|
||||||
|
|
||||||
|
static struct http_static_s
|
||||||
|
{
|
||||||
|
// file and server lists
|
||||||
|
httpfile_t *first_file, *last_file;
|
||||||
|
httpserver_t *first_server, *last_server;
|
||||||
|
} http;
|
||||||
|
|
||||||
|
|
||||||
|
static convar_t *http_useragent;
|
||||||
|
static convar_t *http_autoremove;
|
||||||
|
static convar_t *http_timeout;
|
||||||
|
static convar_t *http_maxconnections;
|
||||||
|
|
||||||
|
/*
|
||||||
|
========================
|
||||||
|
HTTP_ClearCustomServers
|
||||||
|
========================
|
||||||
|
*/
|
||||||
|
void HTTP_ClearCustomServers( void )
|
||||||
|
{
|
||||||
|
if( http.first_file )
|
||||||
|
return; // may be referenced
|
||||||
|
|
||||||
|
while( http.first_server && http.first_server->needfree )
|
||||||
|
{
|
||||||
|
httpserver_t *tmp = http.first_server;
|
||||||
|
|
||||||
|
http.first_server = http.first_server->next;
|
||||||
|
Mem_Free( tmp );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==============
|
||||||
|
HTTP_FreeFile
|
||||||
|
|
||||||
|
Skip to next server/file
|
||||||
|
==============
|
||||||
|
*/
|
||||||
|
static void HTTP_FreeFile( httpfile_t *file, qboolean error )
|
||||||
|
{
|
||||||
|
char incname[256];
|
||||||
|
|
||||||
|
// Allways close file and socket
|
||||||
|
if( file->file )
|
||||||
|
FS_Close( file->file );
|
||||||
|
|
||||||
|
file->file = NULL;
|
||||||
|
|
||||||
|
if( file->socket != -1 )
|
||||||
|
pCloseSocket( file->socket );
|
||||||
|
|
||||||
|
file->socket = -1;
|
||||||
|
|
||||||
|
Q_snprintf( incname, 256, "%s.incomplete", file->path );
|
||||||
|
if( error )
|
||||||
|
{
|
||||||
|
// Switch to next fastdl server if present
|
||||||
|
if( file->server && ( file->state > HTTP_QUEUE ) && (file->state != HTTP_FREE ) )
|
||||||
|
{
|
||||||
|
file->server = file->server->next;
|
||||||
|
file->state = HTTP_QUEUE; // Reset download state, HTTP_Run() will open file again
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called because there was no servers to download, free file now
|
||||||
|
if( http_autoremove->value == 1 ) // remove broken file
|
||||||
|
FS_Delete( incname );
|
||||||
|
else // autoremove disabled, keep file
|
||||||
|
Con_Printf( "cannot download %s from any server. "
|
||||||
|
"You may remove %s now\n", file->path, incname ); // Warn about trash file
|
||||||
|
|
||||||
|
if( file->process )
|
||||||
|
CL_ProcessFile( false, file->path ); // Process file, increase counter
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Success, rename and process file
|
||||||
|
char name[256];
|
||||||
|
|
||||||
|
Q_snprintf( name, 256, "%s", file->path );
|
||||||
|
FS_Rename( incname, name );
|
||||||
|
|
||||||
|
if( file->process )
|
||||||
|
CL_ProcessFile( true, name );
|
||||||
|
else
|
||||||
|
Con_Printf( "successfully downloaded %s, processing disabled!\n", name );
|
||||||
|
}
|
||||||
|
|
||||||
|
file->state = HTTP_FREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===================
|
||||||
|
HTTP_AutoClean
|
||||||
|
|
||||||
|
remove files with HTTP_FREE state from list
|
||||||
|
===================
|
||||||
|
*/
|
||||||
|
static void HTTP_AutoClean( void )
|
||||||
|
{
|
||||||
|
httpfile_t *curfile, *prevfile = 0;
|
||||||
|
|
||||||
|
// clean all files marked to free
|
||||||
|
for( curfile = http.first_file; curfile; curfile = curfile->next )
|
||||||
|
{
|
||||||
|
if( curfile->state != HTTP_FREE )
|
||||||
|
{
|
||||||
|
prevfile = curfile;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( curfile == http.first_file )
|
||||||
|
{
|
||||||
|
http.first_file = http.first_file->next;
|
||||||
|
Mem_Free( curfile );
|
||||||
|
curfile = http.first_file;
|
||||||
|
if( !curfile )
|
||||||
|
break;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( prevfile )
|
||||||
|
prevfile->next = curfile->next;
|
||||||
|
Mem_Free( curfile );
|
||||||
|
curfile = prevfile;
|
||||||
|
if( !curfile )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
http.last_file = prevfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===================
|
||||||
|
HTTP_ProcessStream
|
||||||
|
|
||||||
|
process incoming data
|
||||||
|
===================
|
||||||
|
*/
|
||||||
|
static qboolean HTTP_ProcessStream( httpfile_t *curfile )
|
||||||
|
{
|
||||||
|
char buf[BUFSIZ+1];
|
||||||
|
char *begin = 0;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
while( ( res = pRecv( curfile->socket, buf, BUFSIZ, 0 ) ) > 0) // if we got there, we are receiving data
|
||||||
|
{
|
||||||
|
curfile->blocktime = 0;
|
||||||
|
|
||||||
|
if( curfile->state < HTTP_RESPONSE_RECEIVED ) // Response still not received
|
||||||
|
{
|
||||||
|
buf[res] = 0; // string break to search \r\n\r\n
|
||||||
|
memcpy( curfile->buf + curfile->header_size, buf, res );
|
||||||
|
begin = Q_strstr( curfile->buf, "\r\n\r\n" );
|
||||||
|
|
||||||
|
if( begin ) // Got full header
|
||||||
|
{
|
||||||
|
int cutheadersize = begin - curfile->buf + 4; // after that begin of data
|
||||||
|
char *length;
|
||||||
|
|
||||||
|
Con_Reportf( "HTTP: Got response!\n" );
|
||||||
|
|
||||||
|
if( !Q_strstr( curfile->buf, "200 OK" ) )
|
||||||
|
{
|
||||||
|
*begin = 0; // cut string to print out response
|
||||||
|
begin = Q_strchr( curfile->buf, '\r' );
|
||||||
|
|
||||||
|
if( !begin ) begin = Q_strchr( curfile->buf, '\n' );
|
||||||
|
if( begin )
|
||||||
|
*begin = 0;
|
||||||
|
|
||||||
|
Con_Printf( S_ERROR "bad response: %s\n", curfile->buf );
|
||||||
|
HTTP_FreeFile( curfile, true );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// print size
|
||||||
|
length = Q_stristr( curfile->buf, "Content-Length: " );
|
||||||
|
if( length )
|
||||||
|
{
|
||||||
|
int size = Q_atoi( length += 16 );
|
||||||
|
|
||||||
|
Con_Reportf( "HTTP: File size is %d\n", size );
|
||||||
|
|
||||||
|
if( ( curfile->size != -1 ) && ( curfile->size != size ) ) // check size if specified, not used
|
||||||
|
Con_Reportf( S_WARN "Server reports wrong file size!\n" );
|
||||||
|
|
||||||
|
curfile->size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( curfile->size == -1 )
|
||||||
|
{
|
||||||
|
// Usually fastdl's reports file size if link is correct
|
||||||
|
Con_Printf( S_ERROR "file size is unknown, refusing download!\n" );
|
||||||
|
HTTP_FreeFile( curfile, true );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
curfile->state = HTTP_RESPONSE_RECEIVED; // got response, let's start download
|
||||||
|
begin += 4;
|
||||||
|
|
||||||
|
// Write remaining message part
|
||||||
|
if( res - cutheadersize - curfile->header_size > 0 )
|
||||||
|
{
|
||||||
|
int ret = FS_Write( curfile->file, begin, res - cutheadersize - curfile->header_size );
|
||||||
|
|
||||||
|
if( ret != res - cutheadersize - curfile->header_size ) // could not write file
|
||||||
|
{
|
||||||
|
// close it and go to next
|
||||||
|
Con_Printf( S_ERROR "write failed for %s!\n", curfile->path );
|
||||||
|
HTTP_FreeFile( curfile, true );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
curfile->downloaded += ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curfile->header_size += res;
|
||||||
|
}
|
||||||
|
else if( res > 0 )
|
||||||
|
{
|
||||||
|
// data download
|
||||||
|
int ret = FS_Write( curfile->file, buf, res );
|
||||||
|
|
||||||
|
if ( ret != res )
|
||||||
|
{
|
||||||
|
// close it and go to next
|
||||||
|
Con_Printf( S_ERROR "write failed for %s!\n", curfile->path );
|
||||||
|
curfile->state = HTTP_FREE;
|
||||||
|
HTTP_FreeFile( curfile, true );
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
curfile->downloaded += ret;
|
||||||
|
curfile->lastchecksize += ret;
|
||||||
|
|
||||||
|
// as after it will run in same frame
|
||||||
|
if( curfile->checktime > 5 )
|
||||||
|
{
|
||||||
|
curfile->checktime = 0;
|
||||||
|
Con_Reportf( "download speed %f KB/s\n", (float)curfile->lastchecksize / ( 5.0 * 1024 ) );
|
||||||
|
curfile->lastchecksize = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curfile->checktime += host.frametime;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==============
|
||||||
|
HTTP_Run
|
||||||
|
|
||||||
|
Download next file block of each active file
|
||||||
|
Call every frame
|
||||||
|
==============
|
||||||
|
*/
|
||||||
|
void HTTP_Run( void )
|
||||||
|
{
|
||||||
|
httpfile_t *curfile;
|
||||||
|
int iActiveCount = 0;
|
||||||
|
int iProgressCount = 0;
|
||||||
|
float flProgress = 0;
|
||||||
|
qboolean fResolving = false;
|
||||||
|
|
||||||
|
for( curfile = http.first_file; curfile; curfile = curfile->next )
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
struct sockaddr addr;
|
||||||
|
|
||||||
|
if( curfile->state == HTTP_FREE )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( curfile->state == HTTP_QUEUE )
|
||||||
|
{
|
||||||
|
char name[PATH_MAX];
|
||||||
|
|
||||||
|
if( iActiveCount > http_maxconnections->value )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( !curfile->server )
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "no servers to download %s!\n", curfile->path );
|
||||||
|
HTTP_FreeFile( curfile, true );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Con_Reportf( "HTTP: Starting download %s from %s\n", curfile->path, curfile->server->host );
|
||||||
|
Q_snprintf( name, PATH_MAX, "%s.incomplete", curfile->path );
|
||||||
|
|
||||||
|
curfile->file = FS_Open( name, "wb", true );
|
||||||
|
|
||||||
|
if( !curfile->file )
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "cannot open %s!\n", name );
|
||||||
|
HTTP_FreeFile( curfile, true );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
curfile->state = HTTP_OPENED;
|
||||||
|
curfile->blocktime = 0;
|
||||||
|
curfile->downloaded = 0;
|
||||||
|
curfile->lastchecksize = 0;
|
||||||
|
curfile->checktime = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
iActiveCount++;
|
||||||
|
|
||||||
|
if( curfile->state < HTTP_SOCKET ) // Socket is not created
|
||||||
|
{
|
||||||
|
dword mode;
|
||||||
|
|
||||||
|
curfile->socket = pSocket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
|
||||||
|
|
||||||
|
// Now set non-blocking mode
|
||||||
|
// You may skip this if not supported by system,
|
||||||
|
// but download will lock engine, maybe you will need to add manual returns
|
||||||
|
mode = 1;
|
||||||
|
pIoctlSocket( curfile->socket, FIONBIO, &mode );
|
||||||
|
#ifdef __linux__
|
||||||
|
// SOCK_NONBLOCK is not portable, so use fcntl
|
||||||
|
fcntl( curfile->socket, F_SETFL, fcntl( curfile->socket, F_GETFL, 0 ) | O_NONBLOCK );
|
||||||
|
#endif
|
||||||
|
curfile->state = HTTP_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( curfile->state < HTTP_NS_RESOLVED )
|
||||||
|
{
|
||||||
|
if( fResolving )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
res = NET_StringToSockaddr( va( "%s:%d", curfile->server->host, curfile->server->port ), &addr, true );
|
||||||
|
|
||||||
|
if( res == 2 )
|
||||||
|
{
|
||||||
|
fResolving = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !res )
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "failed to resolve server address for %s!\n", curfile->server->host );
|
||||||
|
HTTP_FreeFile( curfile, true ); // Cannot connect
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
curfile->state = HTTP_NS_RESOLVED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( curfile->state < HTTP_CONNECTED ) // Connection not enstabilished
|
||||||
|
{
|
||||||
|
res = pConnect( curfile->socket, &addr, sizeof( struct sockaddr ) );
|
||||||
|
|
||||||
|
if( res )
|
||||||
|
{
|
||||||
|
if( pWSAGetLastError() == WSAEINPROGRESS || pWSAGetLastError() == WSAEWOULDBLOCK ) // Should give EWOOLDBLOCK if try recv too soon
|
||||||
|
curfile->state = HTTP_CONNECTED;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "cannot connect to server: %s\n", NET_ErrorString( ) );
|
||||||
|
HTTP_FreeFile( curfile, true ); // Cannot connect
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
continue; // skip to next file
|
||||||
|
}
|
||||||
|
curfile->state = HTTP_CONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( curfile->state < HTTP_REQUEST ) // Request not formatted
|
||||||
|
{
|
||||||
|
curfile->query_length = Q_snprintf( curfile->buf, sizeof( curfile->buf ),
|
||||||
|
"GET %s%s HTTP/1.0\r\n"
|
||||||
|
"Host: %s\r\n"
|
||||||
|
"User-Agent: %s\r\n\r\n", curfile->server->path,
|
||||||
|
curfile->path, curfile->server->host, http_useragent->string );
|
||||||
|
curfile->header_size = 0;
|
||||||
|
curfile->bytes_sent = 0;
|
||||||
|
curfile->state = HTTP_REQUEST;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( curfile->state < HTTP_REQUEST_SENT ) // Request not sent
|
||||||
|
{
|
||||||
|
qboolean wait = false;
|
||||||
|
|
||||||
|
while( curfile->bytes_sent < curfile->query_length )
|
||||||
|
{
|
||||||
|
res = pSend( curfile->socket, curfile->buf + curfile->bytes_sent, curfile->query_length - curfile->bytes_sent, 0 );
|
||||||
|
|
||||||
|
|
||||||
|
if( res < 0 )
|
||||||
|
{
|
||||||
|
if( pWSAGetLastError() != WSAEWOULDBLOCK && pWSAGetLastError() != WSAENOTCONN )
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "failed to send request: %s\n", NET_ErrorString() );
|
||||||
|
HTTP_FreeFile( curfile, true );
|
||||||
|
wait = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// blocking while waiting connection
|
||||||
|
// increase counter when blocking
|
||||||
|
curfile->blocktime += host.frametime;
|
||||||
|
wait = true;
|
||||||
|
|
||||||
|
if( curfile->blocktime > http_timeout->value )
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "timeout on request send:\n%s\n", curfile->buf );
|
||||||
|
HTTP_FreeFile( curfile, true );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curfile->bytes_sent += res;
|
||||||
|
curfile->blocktime = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( wait )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Con_Reportf( "HTTP: Request sent!\n");
|
||||||
|
memset( curfile->buf, 0, sizeof( curfile->buf ) );
|
||||||
|
curfile->state = HTTP_REQUEST_SENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !HTTP_ProcessStream( curfile ) )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( curfile->size > 0 )
|
||||||
|
{
|
||||||
|
flProgress += (float)curfile->downloaded / curfile->size;
|
||||||
|
iProgressCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( curfile->size > 0 && curfile->downloaded >= curfile->size )
|
||||||
|
{
|
||||||
|
HTTP_FreeFile( curfile, false ); // success
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if( pWSAGetLastError() != WSAEWOULDBLOCK )
|
||||||
|
Con_Reportf( "problem downloading %s:\n%s\n", curfile->path, NET_ErrorString() );
|
||||||
|
else
|
||||||
|
curfile->blocktime += host.frametime;
|
||||||
|
|
||||||
|
if( curfile->blocktime > http_timeout->value )
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "timeout on receiving data!\n");
|
||||||
|
HTTP_FreeFile( curfile, true );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// update progress
|
||||||
|
Cvar_SetValue( "scr_download", flProgress/iProgressCount * 100 );
|
||||||
|
|
||||||
|
HTTP_AutoClean();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===================
|
||||||
|
HTTP_AddDownload
|
||||||
|
|
||||||
|
Add new download to end of queue
|
||||||
|
===================
|
||||||
|
*/
|
||||||
|
void HTTP_AddDownload( const char *path, int size, qboolean process )
|
||||||
|
{
|
||||||
|
httpfile_t *httpfile = Z_Calloc( sizeof( httpfile_t ) );
|
||||||
|
|
||||||
|
Con_Reportf( "File %s queued to download\n", path );
|
||||||
|
|
||||||
|
httpfile->size = size;
|
||||||
|
httpfile->downloaded = 0;
|
||||||
|
httpfile->socket = -1;
|
||||||
|
Q_strncpy ( httpfile->path, path, sizeof( httpfile->path ) );
|
||||||
|
|
||||||
|
if( http.last_file )
|
||||||
|
{
|
||||||
|
// Add next to last download
|
||||||
|
httpfile->id = http.last_file->id + 1;
|
||||||
|
http.last_file->next= httpfile;
|
||||||
|
http.last_file = httpfile;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// It will be the only download
|
||||||
|
httpfile->id = 0;
|
||||||
|
http.last_file = http.first_file = httpfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
httpfile->file = NULL;
|
||||||
|
httpfile->next = NULL;
|
||||||
|
httpfile->state = HTTP_QUEUE;
|
||||||
|
httpfile->server = http.first_server;
|
||||||
|
httpfile->process = process;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
HTTP_Download_f
|
||||||
|
|
||||||
|
Console wrapper
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
static void HTTP_Download_f( void )
|
||||||
|
{
|
||||||
|
if( Cmd_Argc() < 2 )
|
||||||
|
{
|
||||||
|
Con_Printf( S_USAGE "download <gamedir_path>\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HTTP_AddDownload( Cmd_Argv( 1 ), -1, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==============
|
||||||
|
HTTP_ParseURL
|
||||||
|
==============
|
||||||
|
*/
|
||||||
|
static httpserver_t *HTTP_ParseURL( const char *url )
|
||||||
|
{
|
||||||
|
httpserver_t *server;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
url = Q_strstr( url, "http://" );
|
||||||
|
|
||||||
|
if( !url )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
url += 7;
|
||||||
|
server = Z_Calloc( sizeof( httpserver_t ) );
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
while( *url && ( *url != ':' ) && ( *url != '/' ) && ( *url != '\r' ) && ( *url != '\n' ) )
|
||||||
|
{
|
||||||
|
if( i > sizeof( server->host ) )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
server->host[i++] = *url++;
|
||||||
|
}
|
||||||
|
|
||||||
|
server->host[i] = 0;
|
||||||
|
|
||||||
|
if( *url == ':' )
|
||||||
|
{
|
||||||
|
server->port = Q_atoi( ++url );
|
||||||
|
|
||||||
|
while( *url && ( *url != '/' ) && ( *url != '\r' ) && ( *url != '\n' ) )
|
||||||
|
url++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
server->port = 80;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
while( *url && ( *url != '\r' ) && ( *url != '\n' ) )
|
||||||
|
{
|
||||||
|
if( i > sizeof( server->path ) )
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
server->path[i++] = *url++;
|
||||||
|
}
|
||||||
|
|
||||||
|
server->path[i] = 0;
|
||||||
|
server->next = NULL;
|
||||||
|
server->needfree = false;
|
||||||
|
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=======================
|
||||||
|
HTTP_AddCustomServer
|
||||||
|
=======================
|
||||||
|
*/
|
||||||
|
void HTTP_AddCustomServer( const char *url )
|
||||||
|
{
|
||||||
|
httpserver_t *server = HTTP_ParseURL( url );
|
||||||
|
|
||||||
|
if( !server )
|
||||||
|
{
|
||||||
|
Con_Printf( S_ERROR "\"%s\" is not valid url!\n", url );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
server->needfree = true;
|
||||||
|
server->next = http.first_server;
|
||||||
|
http.first_server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=======================
|
||||||
|
HTTP_AddCustomServer_f
|
||||||
|
=======================
|
||||||
|
*/
|
||||||
|
static void HTTP_AddCustomServer_f( void )
|
||||||
|
{
|
||||||
|
if( Cmd_Argc() == 2 )
|
||||||
|
{
|
||||||
|
HTTP_AddCustomServer( Cmd_Argv( 1 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
============
|
||||||
|
HTTP_Clear_f
|
||||||
|
|
||||||
|
Clear all queue
|
||||||
|
============
|
||||||
|
*/
|
||||||
|
static void HTTP_Clear_f( void )
|
||||||
|
{
|
||||||
|
http.last_file = NULL;
|
||||||
|
|
||||||
|
while( http.first_file )
|
||||||
|
{
|
||||||
|
httpfile_t *file = http.first_file;
|
||||||
|
|
||||||
|
http.first_file = http.first_file->next;
|
||||||
|
|
||||||
|
if( file->file )
|
||||||
|
FS_Close( file->file );
|
||||||
|
|
||||||
|
if( file->socket != -1 )
|
||||||
|
pCloseSocket ( file->socket );
|
||||||
|
|
||||||
|
Mem_Free( file );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
==============
|
||||||
|
HTTP_Cancel_f
|
||||||
|
|
||||||
|
Stop current download, skip to next file
|
||||||
|
==============
|
||||||
|
*/
|
||||||
|
static void HTTP_Cancel_f( void )
|
||||||
|
{
|
||||||
|
if( !http.first_file )
|
||||||
|
return;
|
||||||
|
|
||||||
|
http.first_file->state = HTTP_FREE;
|
||||||
|
HTTP_FreeFile( http.first_file, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
HTTP_Skip_f
|
||||||
|
|
||||||
|
Stop current download, skip to next server
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
static void HTTP_Skip_f( void )
|
||||||
|
{
|
||||||
|
if( http.first_file )
|
||||||
|
HTTP_FreeFile( http.first_file, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
HTTP_List_f
|
||||||
|
|
||||||
|
Print all pending downloads to console
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
static void HTTP_List_f( void )
|
||||||
|
{
|
||||||
|
httpfile_t *file = http.first_file;
|
||||||
|
|
||||||
|
while( file )
|
||||||
|
{
|
||||||
|
if ( file->server )
|
||||||
|
Con_Printf ( "\t%d %d http://%s:%d/%s%s %d\n", file->id, file->state,
|
||||||
|
file->server->host, file->server->port, file->server->path,
|
||||||
|
file->path, file->downloaded );
|
||||||
|
else
|
||||||
|
Con_Printf ( "\t%d %d (no server) %s\n", file->id, file->state, file->path );
|
||||||
|
|
||||||
|
file = file->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
================
|
||||||
|
HTTP_ResetProcessState
|
||||||
|
|
||||||
|
When connected to new server, all old files should not increase counter
|
||||||
|
================
|
||||||
|
*/
|
||||||
|
void HTTP_ResetProcessState( void )
|
||||||
|
{
|
||||||
|
httpfile_t *file = http.first_file;
|
||||||
|
|
||||||
|
while( file )
|
||||||
|
{
|
||||||
|
file->process = false;
|
||||||
|
file = file->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
=============
|
||||||
|
HTTP_Init
|
||||||
|
=============
|
||||||
|
*/
|
||||||
|
void HTTP_Init( void )
|
||||||
|
{
|
||||||
|
char *serverfile, *line, token[1024];
|
||||||
|
|
||||||
|
http.last_server = NULL;
|
||||||
|
|
||||||
|
http.first_file = http.last_file = NULL;
|
||||||
|
|
||||||
|
Cmd_AddCommand("http_download", &HTTP_Download_f, "add file to download queue");
|
||||||
|
Cmd_AddCommand("http_skip", &HTTP_Skip_f, "skip current download server");
|
||||||
|
Cmd_AddCommand("http_cancel", &HTTP_Cancel_f, "cancel current download");
|
||||||
|
Cmd_AddCommand("http_clear", &HTTP_Clear_f, "cancel all downloads");
|
||||||
|
Cmd_AddCommand("http_list", &HTTP_List_f, "list all queued downloads");
|
||||||
|
Cmd_AddCommand("http_addcustomserver", &HTTP_AddCustomServer_f, "add custom fastdl server");
|
||||||
|
http_useragent = Cvar_Get( "http_useragent", "xash3d", FCVAR_ARCHIVE, "User-Agent string" );
|
||||||
|
http_autoremove = Cvar_Get( "http_autoremove", "1", FCVAR_ARCHIVE, "remove broken files" );
|
||||||
|
http_timeout = Cvar_Get( "http_timeout", "45", FCVAR_ARCHIVE, "timeout for http downloader" );
|
||||||
|
http_maxconnections = Cvar_Get( "http_maxconnections", "4", FCVAR_ARCHIVE, "maximum http connection number" );
|
||||||
|
|
||||||
|
// Read servers from fastdl.txt
|
||||||
|
line = serverfile = (char *)FS_LoadFile( "fastdl.txt", 0, false );
|
||||||
|
|
||||||
|
if( serverfile )
|
||||||
|
{
|
||||||
|
while( ( line = COM_ParseFile( line, token ) ) )
|
||||||
|
{
|
||||||
|
httpserver_t *server = HTTP_ParseURL( token );
|
||||||
|
|
||||||
|
if( !server )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if( !http.last_server )
|
||||||
|
http.last_server = http.first_server = server;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
http.last_server->next = server;
|
||||||
|
http.last_server = server;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Mem_Free( serverfile );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
====================
|
||||||
|
HTTP_Shutdown
|
||||||
|
====================
|
||||||
|
*/
|
||||||
|
void HTTP_Shutdown( void )
|
||||||
|
{
|
||||||
|
HTTP_Clear_f();
|
||||||
|
|
||||||
|
while( http.first_server )
|
||||||
|
{
|
||||||
|
httpserver_t *tmp = http.first_server;
|
||||||
|
|
||||||
|
http.first_server = http.first_server->next;
|
||||||
|
Mem_Free( tmp );
|
||||||
|
}
|
||||||
|
|
||||||
|
http.last_server = 0;
|
||||||
|
}
|
||||||
|
|
|
@ -69,4 +69,11 @@ qboolean CL_LegacyMode( void );
|
||||||
int CL_GetSplitSize( void );
|
int CL_GetSplitSize( void );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void HTTP_AddCustomServer( const char *url );
|
||||||
|
void HTTP_AddDownload( const char *path, int size, qboolean process );
|
||||||
|
void HTTP_ClearCustomServers( void );
|
||||||
|
void HTTP_Shutdown( void );
|
||||||
|
void HTTP_Init( void );
|
||||||
|
void HTTP_Run( void );
|
||||||
|
|
||||||
#endif//NET_WS_H
|
#endif//NET_WS_H
|
||||||
|
|
|
@ -262,4 +262,6 @@ extern const char *clc_strings[clc_lastmsg+1];
|
||||||
#define MAX_LEGACY_ENTITY_BITS 12
|
#define MAX_LEGACY_ENTITY_BITS 12
|
||||||
#define MAX_LEGACY_WEAPON_BITS 5
|
#define MAX_LEGACY_WEAPON_BITS 5
|
||||||
#define MAX_LEGACY_MODEL_BITS 11
|
#define MAX_LEGACY_MODEL_BITS 11
|
||||||
|
#define MAX_LEGACY_SERVERS 32
|
||||||
|
|
||||||
#endif//NET_PROTOCOL_H
|
#endif//NET_PROTOCOL_H
|
||||||
|
|
|
@ -25,176 +25,189 @@ GNU General Public License for more details.
|
||||||
static vidmode_t *vidmodes = NULL;
|
static vidmode_t *vidmodes = NULL;
|
||||||
static int num_vidmodes = 0;
|
static int num_vidmodes = 0;
|
||||||
static int context_flags = 0;
|
static int context_flags = 0;
|
||||||
|
#define GL_CALL( x ) #x, (void**)&p##x
|
||||||
static dllfunc_t opengl_110funcs[] =
|
static dllfunc_t opengl_110funcs[] =
|
||||||
{
|
{
|
||||||
{ "glClearColor" , (void **)&pglClearColor },
|
{ GL_CALL( glClearColor ) },
|
||||||
{ "glClear" , (void **)&pglClear },
|
{ GL_CALL( glClear ) },
|
||||||
{ "glAlphaFunc" , (void **)&pglAlphaFunc },
|
{ GL_CALL( glAlphaFunc ) },
|
||||||
{ "glBlendFunc" , (void **)&pglBlendFunc },
|
{ GL_CALL( glBlendFunc ) },
|
||||||
{ "glCullFace" , (void **)&pglCullFace },
|
{ GL_CALL( glCullFace ) },
|
||||||
{ "glDrawBuffer" , (void **)&pglDrawBuffer },
|
{ GL_CALL( glDrawBuffer ) },
|
||||||
{ "glReadBuffer" , (void **)&pglReadBuffer },
|
{ GL_CALL( glReadBuffer ) },
|
||||||
{ "glAccum" , (void **)&pglAccum },
|
{ GL_CALL( glAccum ) },
|
||||||
{ "glEnable" , (void **)&pglEnable },
|
{ GL_CALL( glEnable ) },
|
||||||
{ "glDisable" , (void **)&pglDisable },
|
{ GL_CALL( glDisable ) },
|
||||||
{ "glEnableClientState" , (void **)&pglEnableClientState },
|
{ GL_CALL( glEnableClientState ) },
|
||||||
{ "glDisableClientState" , (void **)&pglDisableClientState },
|
{ GL_CALL( glDisableClientState ) },
|
||||||
{ "glGetBooleanv" , (void **)&pglGetBooleanv },
|
{ GL_CALL( glGetBooleanv ) },
|
||||||
{ "glGetDoublev" , (void **)&pglGetDoublev },
|
{ GL_CALL( glGetDoublev ) },
|
||||||
{ "glGetFloatv" , (void **)&pglGetFloatv },
|
{ GL_CALL( glGetFloatv ) },
|
||||||
{ "glGetIntegerv" , (void **)&pglGetIntegerv },
|
{ GL_CALL( glGetIntegerv ) },
|
||||||
{ "glGetError" , (void **)&pglGetError },
|
{ GL_CALL( glGetError ) },
|
||||||
{ "glGetString" , (void **)&pglGetString },
|
{ GL_CALL( glGetString ) },
|
||||||
{ "glFinish" , (void **)&pglFinish },
|
{ GL_CALL( glFinish ) },
|
||||||
{ "glFlush" , (void **)&pglFlush },
|
{ GL_CALL( glFlush ) },
|
||||||
{ "glClearDepth" , (void **)&pglClearDepth },
|
{ GL_CALL( glClearDepth ) },
|
||||||
{ "glDepthFunc" , (void **)&pglDepthFunc },
|
{ GL_CALL( glDepthFunc ) },
|
||||||
{ "glDepthMask" , (void **)&pglDepthMask },
|
{ GL_CALL( glDepthMask ) },
|
||||||
{ "glDepthRange" , (void **)&pglDepthRange },
|
{ GL_CALL( glDepthRange ) },
|
||||||
{ "glFrontFace" , (void **)&pglFrontFace },
|
{ GL_CALL( glFrontFace ) },
|
||||||
{ "glDrawElements" , (void **)&pglDrawElements },
|
{ GL_CALL( glDrawElements ) },
|
||||||
{ "glDrawArrays" , (void **)&pglDrawArrays },
|
{ GL_CALL( glDrawArrays ) },
|
||||||
{ "glColorMask" , (void **)&pglColorMask },
|
{ GL_CALL( glColorMask ) },
|
||||||
{ "glIndexPointer" , (void **)&pglIndexPointer },
|
{ GL_CALL( glIndexPointer ) },
|
||||||
{ "glVertexPointer" , (void **)&pglVertexPointer },
|
{ GL_CALL( glVertexPointer ) },
|
||||||
{ "glNormalPointer" , (void **)&pglNormalPointer },
|
{ GL_CALL( glNormalPointer ) },
|
||||||
{ "glColorPointer" , (void **)&pglColorPointer },
|
{ GL_CALL( glColorPointer ) },
|
||||||
{ "glTexCoordPointer" , (void **)&pglTexCoordPointer },
|
{ GL_CALL( glTexCoordPointer ) },
|
||||||
{ "glArrayElement" , (void **)&pglArrayElement },
|
{ GL_CALL( glArrayElement ) },
|
||||||
{ "glColor3f" , (void **)&pglColor3f },
|
{ GL_CALL( glColor3f ) },
|
||||||
{ "glColor3fv" , (void **)&pglColor3fv },
|
{ GL_CALL( glColor3fv ) },
|
||||||
{ "glColor4f" , (void **)&pglColor4f },
|
{ GL_CALL( glColor4f ) },
|
||||||
{ "glColor4fv" , (void **)&pglColor4fv },
|
{ GL_CALL( glColor4fv ) },
|
||||||
{ "glColor3ub" , (void **)&pglColor3ub },
|
{ GL_CALL( glColor3ub ) },
|
||||||
{ "glColor4ub" , (void **)&pglColor4ub },
|
{ GL_CALL( glColor4ub ) },
|
||||||
{ "glColor4ubv" , (void **)&pglColor4ubv },
|
{ GL_CALL( glColor4ubv ) },
|
||||||
{ "glTexCoord1f" , (void **)&pglTexCoord1f },
|
{ GL_CALL( glTexCoord1f ) },
|
||||||
{ "glTexCoord2f" , (void **)&pglTexCoord2f },
|
{ GL_CALL( glTexCoord2f ) },
|
||||||
{ "glTexCoord3f" , (void **)&pglTexCoord3f },
|
{ GL_CALL( glTexCoord3f ) },
|
||||||
{ "glTexCoord4f" , (void **)&pglTexCoord4f },
|
{ GL_CALL( glTexCoord4f ) },
|
||||||
{ "glTexCoord1fv" , (void **)&pglTexCoord1fv },
|
{ GL_CALL( glTexCoord1fv ) },
|
||||||
{ "glTexCoord2fv" , (void **)&pglTexCoord2fv },
|
{ GL_CALL( glTexCoord2fv ) },
|
||||||
{ "glTexCoord3fv" , (void **)&pglTexCoord3fv },
|
{ GL_CALL( glTexCoord3fv ) },
|
||||||
{ "glTexCoord4fv" , (void **)&pglTexCoord4fv },
|
{ GL_CALL( glTexCoord4fv ) },
|
||||||
{ "glTexGenf" , (void **)&pglTexGenf },
|
{ GL_CALL( glTexGenf ) },
|
||||||
{ "glTexGenfv" , (void **)&pglTexGenfv },
|
{ GL_CALL( glTexGenfv ) },
|
||||||
{ "glTexGeni" , (void **)&pglTexGeni },
|
{ GL_CALL( glTexGeni ) },
|
||||||
{ "glVertex2f" , (void **)&pglVertex2f },
|
{ GL_CALL( glVertex2f ) },
|
||||||
{ "glVertex3f" , (void **)&pglVertex3f },
|
{ GL_CALL( glVertex3f ) },
|
||||||
{ "glVertex3fv" , (void **)&pglVertex3fv },
|
{ GL_CALL( glVertex3fv ) },
|
||||||
{ "glNormal3f" , (void **)&pglNormal3f },
|
{ GL_CALL( glNormal3f ) },
|
||||||
{ "glNormal3fv" , (void **)&pglNormal3fv },
|
{ GL_CALL( glNormal3fv ) },
|
||||||
{ "glBegin" , (void **)&pglBegin },
|
{ GL_CALL( glBegin ) },
|
||||||
{ "glEnd" , (void **)&pglEnd },
|
{ GL_CALL( glEnd ) },
|
||||||
{ "glLineWidth" , (void**)&pglLineWidth },
|
{ GL_CALL( glLineWidth ) },
|
||||||
{ "glPointSize" , (void**)&pglPointSize },
|
{ GL_CALL( glPointSize ) },
|
||||||
{ "glMatrixMode" , (void **)&pglMatrixMode },
|
{ GL_CALL( glMatrixMode ) },
|
||||||
{ "glOrtho" , (void **)&pglOrtho },
|
{ GL_CALL( glOrtho ) },
|
||||||
{ "glRasterPos2f" , (void **) &pglRasterPos2f },
|
{ GL_CALL( glRasterPos2f ) },
|
||||||
{ "glFrustum" , (void **)&pglFrustum },
|
{ GL_CALL( glFrustum ) },
|
||||||
{ "glViewport" , (void **)&pglViewport },
|
{ GL_CALL( glViewport ) },
|
||||||
{ "glPushMatrix" , (void **)&pglPushMatrix },
|
{ GL_CALL( glPushMatrix ) },
|
||||||
{ "glPopMatrix" , (void **)&pglPopMatrix },
|
{ GL_CALL( glPopMatrix ) },
|
||||||
{ "glPushAttrib" , (void **)&pglPushAttrib },
|
{ GL_CALL( glPushAttrib ) },
|
||||||
{ "glPopAttrib" , (void **)&pglPopAttrib },
|
{ GL_CALL( glPopAttrib ) },
|
||||||
{ "glLoadIdentity" , (void **)&pglLoadIdentity },
|
{ GL_CALL( glLoadIdentity ) },
|
||||||
{ "glLoadMatrixd" , (void **)&pglLoadMatrixd },
|
{ GL_CALL( glLoadMatrixd ) },
|
||||||
{ "glLoadMatrixf" , (void **)&pglLoadMatrixf },
|
{ GL_CALL( glLoadMatrixf ) },
|
||||||
{ "glMultMatrixd" , (void **)&pglMultMatrixd },
|
{ GL_CALL( glMultMatrixd ) },
|
||||||
{ "glMultMatrixf" , (void **)&pglMultMatrixf },
|
{ GL_CALL( glMultMatrixf ) },
|
||||||
{ "glRotated" , (void **)&pglRotated },
|
{ GL_CALL( glRotated ) },
|
||||||
{ "glRotatef" , (void **)&pglRotatef },
|
{ GL_CALL( glRotatef ) },
|
||||||
{ "glScaled" , (void **)&pglScaled },
|
{ GL_CALL( glScaled ) },
|
||||||
{ "glScalef" , (void **)&pglScalef },
|
{ GL_CALL( glScalef ) },
|
||||||
{ "glTranslated" , (void **)&pglTranslated },
|
{ GL_CALL( glTranslated ) },
|
||||||
{ "glTranslatef" , (void **)&pglTranslatef },
|
{ GL_CALL( glTranslatef ) },
|
||||||
{ "glReadPixels" , (void **)&pglReadPixels },
|
{ GL_CALL( glReadPixels ) },
|
||||||
{ "glDrawPixels" , (void **)&pglDrawPixels },
|
{ GL_CALL( glDrawPixels ) },
|
||||||
{ "glStencilFunc" , (void **)&pglStencilFunc },
|
{ GL_CALL( glStencilFunc ) },
|
||||||
{ "glStencilMask" , (void **)&pglStencilMask },
|
{ GL_CALL( glStencilMask ) },
|
||||||
{ "glStencilOp" , (void **)&pglStencilOp },
|
{ GL_CALL( glStencilOp ) },
|
||||||
{ "glClearStencil" , (void **)&pglClearStencil },
|
{ GL_CALL( glClearStencil ) },
|
||||||
{ "glIsEnabled" , (void **)&pglIsEnabled },
|
{ GL_CALL( glIsEnabled ) },
|
||||||
{ "glIsList" , (void **)&pglIsList },
|
{ GL_CALL( glIsList ) },
|
||||||
{ "glIsTexture" , (void **)&pglIsTexture },
|
{ GL_CALL( glIsTexture ) },
|
||||||
{ "glTexEnvf" , (void **)&pglTexEnvf },
|
{ GL_CALL( glTexEnvf ) },
|
||||||
{ "glTexEnvfv" , (void **)&pglTexEnvfv },
|
{ GL_CALL( glTexEnvfv ) },
|
||||||
{ "glTexEnvi" , (void **)&pglTexEnvi },
|
{ GL_CALL( glTexEnvi ) },
|
||||||
{ "glTexParameterf" , (void **)&pglTexParameterf },
|
{ GL_CALL( glTexParameterf ) },
|
||||||
{ "glTexParameterfv" , (void **)&pglTexParameterfv },
|
{ GL_CALL( glTexParameterfv ) },
|
||||||
{ "glTexParameteri" , (void **)&pglTexParameteri },
|
{ GL_CALL( glTexParameteri ) },
|
||||||
{ "glHint" , (void **)&pglHint },
|
{ GL_CALL( glHint ) },
|
||||||
{ "glPixelStoref" , (void **)&pglPixelStoref },
|
{ GL_CALL( glPixelStoref ) },
|
||||||
{ "glPixelStorei" , (void **)&pglPixelStorei },
|
{ GL_CALL( glPixelStorei ) },
|
||||||
{ "glGenTextures" , (void **)&pglGenTextures },
|
{ GL_CALL( glGenTextures ) },
|
||||||
{ "glDeleteTextures" , (void **)&pglDeleteTextures },
|
{ GL_CALL( glDeleteTextures ) },
|
||||||
{ "glBindTexture" , (void **)&pglBindTexture },
|
{ GL_CALL( glBindTexture ) },
|
||||||
{ "glTexImage1D" , (void **)&pglTexImage1D },
|
{ GL_CALL( glTexImage1D ) },
|
||||||
{ "glTexImage2D" , (void **)&pglTexImage2D },
|
{ GL_CALL( glTexImage2D ) },
|
||||||
{ "glTexSubImage1D" , (void **)&pglTexSubImage1D },
|
{ GL_CALL( glTexSubImage1D ) },
|
||||||
{ "glTexSubImage2D" , (void **)&pglTexSubImage2D },
|
{ GL_CALL( glTexSubImage2D ) },
|
||||||
{ "glCopyTexImage1D" , (void **)&pglCopyTexImage1D },
|
{ GL_CALL( glCopyTexImage1D ) },
|
||||||
{ "glCopyTexImage2D" , (void **)&pglCopyTexImage2D },
|
{ GL_CALL( glCopyTexImage2D ) },
|
||||||
{ "glCopyTexSubImage1D" , (void **)&pglCopyTexSubImage1D },
|
{ GL_CALL( glCopyTexSubImage1D ) },
|
||||||
{ "glCopyTexSubImage2D" , (void **)&pglCopyTexSubImage2D },
|
{ GL_CALL( glCopyTexSubImage2D ) },
|
||||||
{ "glScissor" , (void **)&pglScissor },
|
{ GL_CALL( glScissor ) },
|
||||||
{ "glGetTexImage" , (void **)&pglGetTexImage },
|
{ GL_CALL( glGetTexImage ) },
|
||||||
{ "glGetTexEnviv" , (void **)&pglGetTexEnviv },
|
{ GL_CALL( glGetTexEnviv ) },
|
||||||
{ "glPolygonOffset" , (void **)&pglPolygonOffset },
|
{ GL_CALL( glPolygonOffset ) },
|
||||||
{ "glPolygonMode" , (void **)&pglPolygonMode },
|
{ GL_CALL( glPolygonMode ) },
|
||||||
{ "glPolygonStipple" , (void **)&pglPolygonStipple },
|
{ GL_CALL( glPolygonStipple ) },
|
||||||
{ "glClipPlane" , (void **)&pglClipPlane },
|
{ GL_CALL( glClipPlane ) },
|
||||||
{ "glGetClipPlane" , (void **)&pglGetClipPlane },
|
{ GL_CALL( glGetClipPlane ) },
|
||||||
{ "glShadeModel" , (void **)&pglShadeModel },
|
{ GL_CALL( glShadeModel ) },
|
||||||
{ "glGetTexLevelParameteriv" , (void **)&pglGetTexLevelParameteriv },
|
{ GL_CALL( glGetTexLevelParameteriv ) },
|
||||||
{ "glGetTexLevelParameterfv" , (void **)&pglGetTexLevelParameterfv },
|
{ GL_CALL( glGetTexLevelParameterfv ) },
|
||||||
{ "glFogfv" , (void **)&pglFogfv },
|
{ GL_CALL( glFogfv ) },
|
||||||
{ "glFogf" , (void **)&pglFogf },
|
{ GL_CALL( glFogf ) },
|
||||||
{ "glFogi" , (void **)&pglFogi },
|
{ GL_CALL( glFogi ) },
|
||||||
{ NULL , NULL }
|
{ NULL , NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static dllfunc_t debugoutputfuncs[] =
|
static dllfunc_t debugoutputfuncs[] =
|
||||||
{
|
{
|
||||||
{ "glDebugMessageControlARB" , (void **)&pglDebugMessageControlARB },
|
{ GL_CALL( glDebugMessageControlARB ) },
|
||||||
{ "glDebugMessageInsertARB" , (void **)&pglDebugMessageInsertARB },
|
{ GL_CALL( glDebugMessageInsertARB ) },
|
||||||
{ "glDebugMessageCallbackARB" , (void **)&pglDebugMessageCallbackARB },
|
{ GL_CALL( glDebugMessageCallbackARB ) },
|
||||||
{ "glGetDebugMessageLogARB" , (void **)&pglGetDebugMessageLogARB },
|
{ GL_CALL( glGetDebugMessageLogARB ) },
|
||||||
{ NULL , NULL }
|
{ NULL , NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static dllfunc_t multitexturefuncs[] =
|
static dllfunc_t multitexturefuncs[] =
|
||||||
{
|
{
|
||||||
{ "glMultiTexCoord1fARB" , (void **)&pglMultiTexCoord1f },
|
{ GL_CALL( glMultiTexCoord1f ) },
|
||||||
{ "glMultiTexCoord2fARB" , (void **)&pglMultiTexCoord2f },
|
{ GL_CALL( glMultiTexCoord2f ) },
|
||||||
{ "glMultiTexCoord3fARB" , (void **)&pglMultiTexCoord3f },
|
{ GL_CALL( glMultiTexCoord3f ) },
|
||||||
{ "glMultiTexCoord4fARB" , (void **)&pglMultiTexCoord4f },
|
{ GL_CALL( glMultiTexCoord4f ) },
|
||||||
{ "glActiveTextureARB" , (void **)&pglActiveTexture },
|
{ GL_CALL( glActiveTexture ) },
|
||||||
{ "glActiveTextureARB" , (void **)&pglActiveTextureARB },
|
{ GL_CALL( glActiveTextureARB ) },
|
||||||
{ "glClientActiveTextureARB" , (void **)&pglClientActiveTexture },
|
{ GL_CALL( glClientActiveTexture ) },
|
||||||
{ "glClientActiveTextureARB" , (void **)&pglClientActiveTextureARB },
|
{ GL_CALL( glClientActiveTextureARB ) },
|
||||||
{ NULL , NULL }
|
{ NULL , NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static dllfunc_t texture3dextfuncs[] =
|
static dllfunc_t texture3dextfuncs[] =
|
||||||
{
|
{
|
||||||
{ "glTexImage3DEXT" , (void **)&pglTexImage3D },
|
{ GL_CALL( glTexImage3D ) },
|
||||||
{ "glTexSubImage3DEXT" , (void **)&pglTexSubImage3D },
|
{ GL_CALL( glTexSubImage3D ) },
|
||||||
{ "glCopyTexSubImage3DEXT" , (void **)&pglCopyTexSubImage3D },
|
{ GL_CALL( glCopyTexSubImage3D ) },
|
||||||
{ NULL , NULL }
|
{ NULL , NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static dllfunc_t texturecompressionfuncs[] =
|
static dllfunc_t texturecompressionfuncs[] =
|
||||||
{
|
{
|
||||||
{ "glCompressedTexImage3DARB" , (void **)&pglCompressedTexImage3DARB },
|
{ GL_CALL( glCompressedTexImage3DARB ) },
|
||||||
{ "glCompressedTexImage2DARB" , (void **)&pglCompressedTexImage2DARB },
|
{ GL_CALL( glCompressedTexImage2DARB ) },
|
||||||
{ "glCompressedTexImage1DARB" , (void **)&pglCompressedTexImage1DARB },
|
{ GL_CALL( glCompressedTexImage1DARB ) },
|
||||||
{ "glCompressedTexSubImage3DARB" , (void **)&pglCompressedTexSubImage3DARB },
|
{ GL_CALL( glCompressedTexSubImage3DARB ) },
|
||||||
{ "glCompressedTexSubImage2DARB" , (void **)&pglCompressedTexSubImage2DARB },
|
{ GL_CALL( glCompressedTexSubImage2DARB ) },
|
||||||
{ "glCompressedTexSubImage1DARB" , (void **)&pglCompressedTexSubImage1DARB },
|
{ GL_CALL( glCompressedTexSubImage1DARB ) },
|
||||||
{ "glGetCompressedTexImageARB" , (void **)&pglGetCompressedTexImage },
|
{ GL_CALL( glGetCompressedTexImage ) },
|
||||||
{ NULL , NULL }
|
{ NULL , NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static dllfunc_t vbofuncs[] =
|
||||||
|
{
|
||||||
|
{ GL_CALL( glBindBufferARB ) },
|
||||||
|
{ GL_CALL( glDeleteBuffersARB ) },
|
||||||
|
{ GL_CALL( glGenBuffersARB ) },
|
||||||
|
{ GL_CALL( glIsBufferARB ) },
|
||||||
|
{ GL_CALL( glMapBufferARB ) },
|
||||||
|
{ GL_CALL( glUnmapBufferARB ) }, // ,
|
||||||
|
{ GL_CALL( glBufferDataARB ) },
|
||||||
|
{ GL_CALL( glBufferSubDataARB ) },
|
||||||
|
{ NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void GL_SetupAttributes( void );
|
static void GL_SetupAttributes( void );
|
||||||
|
@ -884,7 +897,6 @@ qboolean R_Init_Video( void )
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef XASH_GLES
|
#ifdef XASH_GLES
|
||||||
void GL_InitExtensionsGLES( void )
|
void GL_InitExtensionsGLES( void )
|
||||||
{
|
{
|
||||||
|
@ -1039,6 +1051,8 @@ void GL_InitExtensionsBigGL()
|
||||||
GL_CheckExtension( "GL_ARB_depth_buffer_float", NULL, "gl_arb_depth_float", GL_ARB_DEPTH_FLOAT_EXT );
|
GL_CheckExtension( "GL_ARB_depth_buffer_float", NULL, "gl_arb_depth_float", GL_ARB_DEPTH_FLOAT_EXT );
|
||||||
GL_CheckExtension( "GL_EXT_gpu_shader4", NULL, NULL, GL_EXT_GPU_SHADER4 ); // don't confuse users
|
GL_CheckExtension( "GL_EXT_gpu_shader4", NULL, NULL, GL_EXT_GPU_SHADER4 ); // don't confuse users
|
||||||
GL_CheckExtension( "GL_ARB_shading_language_100", NULL, "gl_glslprogram", GL_SHADER_GLSL100_EXT );
|
GL_CheckExtension( "GL_ARB_shading_language_100", NULL, "gl_glslprogram", GL_SHADER_GLSL100_EXT );
|
||||||
|
GL_CheckExtension( "GL_ARB_vertex_buffer_object", vbofuncs, "gl_vertex_buffer_object", GL_ARB_VERTEX_BUFFER_OBJECT_EXT );
|
||||||
|
|
||||||
// rectangle textures support
|
// rectangle textures support
|
||||||
GL_CheckExtension( "GL_ARB_texture_rectangle", NULL, "gl_texture_rectangle", GL_TEXTURE_2D_RECT_EXT );
|
GL_CheckExtension( "GL_ARB_texture_rectangle", NULL, "gl_texture_rectangle", GL_TEXTURE_2D_RECT_EXT );
|
||||||
|
|
||||||
|
|
|
@ -375,6 +375,7 @@ void SV_ConnectClient( netadr_t from )
|
||||||
sv.current_client = newcl;
|
sv.current_client = newcl;
|
||||||
newcl->edict = EDICT_NUM( (newcl - svs.clients) + 1 );
|
newcl->edict = EDICT_NUM( (newcl - svs.clients) + 1 );
|
||||||
newcl->challenge = challenge; // save challenge for checksumming
|
newcl->challenge = challenge; // save challenge for checksumming
|
||||||
|
if( newcl->frames ) Mem_Free( newcl->frames );
|
||||||
newcl->frames = (client_frame_t *)Z_Calloc( sizeof( client_frame_t ) * SV_UPDATE_BACKUP );
|
newcl->frames = (client_frame_t *)Z_Calloc( sizeof( client_frame_t ) * SV_UPDATE_BACKUP );
|
||||||
newcl->userid = g_userid++; // create unique userid
|
newcl->userid = g_userid++; // create unique userid
|
||||||
newcl->state = cs_connected;
|
newcl->state = cs_connected;
|
||||||
|
@ -1875,6 +1876,26 @@ static qboolean SV_DownloadFile_f( sv_client_t *cl )
|
||||||
{
|
{
|
||||||
if( sv_send_resources.value )
|
if( sv_send_resources.value )
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
// security: allow download only precached resources
|
||||||
|
for( i = 0; i < sv.num_resources; i++ )
|
||||||
|
{
|
||||||
|
const char *cmpname = name;
|
||||||
|
|
||||||
|
if( sv.resources[i].type == t_sound )
|
||||||
|
cmpname += sizeof( DEFAULT_SOUNDPATH ) - 1; // cut "sound/" off
|
||||||
|
|
||||||
|
if( !Q_strncmp( sv.resources[i].szFileName, cmpname, 64 ) )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( i == sv.num_resources )
|
||||||
|
{
|
||||||
|
SV_FailDownload( cl, name );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// also check the model textures
|
// also check the model textures
|
||||||
if( !Q_stricmp( COM_FileExtension( name ), "mdl" ))
|
if( !Q_stricmp( COM_FileExtension( name ), "mdl" ))
|
||||||
{
|
{
|
||||||
|
|
|
@ -998,9 +998,15 @@ void SV_InactivateClients( void )
|
||||||
if( !cl->state || !cl->edict )
|
if( !cl->state || !cl->edict )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( !cl->edict || FBitSet( cl->edict->v.flags, FL_FAKECLIENT ))
|
if( !cl->edict )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if( FBitSet( cl->edict->v.flags, FL_FAKECLIENT ))
|
||||||
|
{
|
||||||
|
SV_DropClient( cl, false );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if( cl->state > cs_connected )
|
if( cl->state > cs_connected )
|
||||||
cl->state = cs_connected;
|
cl->state = cs_connected;
|
||||||
|
|
||||||
|
@ -1015,4 +1021,4 @@ void SV_InactivateClients( void )
|
||||||
MSG_Clear( &cl->netchan.message );
|
MSG_Clear( &cl->netchan.message );
|
||||||
MSG_Clear( &cl->datagram );
|
MSG_Clear( &cl->datagram );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1294,16 +1294,21 @@ void pfnSetModel( edict_t *e, const char *m )
|
||||||
|
|
||||||
if( COM_CheckString( name ))
|
if( COM_CheckString( name ))
|
||||||
{
|
{
|
||||||
|
qboolean notfound = true;
|
||||||
|
|
||||||
// check to see if model was properly precached
|
// check to see if model was properly precached
|
||||||
for( i = 1; i < MAX_MODELS && sv.model_precache[i][0]; i++ )
|
for( i = 1; i < MAX_MODELS && sv.model_precache[i][0]; i++ )
|
||||||
{
|
{
|
||||||
if( !Q_stricmp( sv.model_precache[i], name ))
|
if( !Q_stricmp( sv.model_precache[i], name ))
|
||||||
|
{
|
||||||
|
notfound = false;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( i == MAX_MODELS )
|
if( notfound )
|
||||||
{
|
{
|
||||||
Con_Printf( S_ERROR "no precache: %s\n", name );
|
Con_Printf( S_ERROR "Failed to set model %s: was not precached\n", name );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1311,7 +1316,7 @@ void pfnSetModel( edict_t *e, const char *m )
|
||||||
if( e == svgame.edicts )
|
if( e == svgame.edicts )
|
||||||
{
|
{
|
||||||
if( sv.state == ss_active )
|
if( sv.state == ss_active )
|
||||||
Con_Printf( S_ERROR "world model can't be changed\n" );
|
Con_Printf( S_ERROR "Failed to set model %s: world model cannot be changed\n", name );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1358,8 +1363,8 @@ int pfnModelIndex( const char *m )
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
Con_Printf( S_ERROR "no precache: %s\n", name );
|
Con_Printf( S_ERROR "Cannot get index for model %s: not precached\n", name );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4410,7 +4415,7 @@ void pfnForceUnmodified( FORCE_TYPE type, float *mins, float *maxs, const char *
|
||||||
if( !Q_strcmp( filename, pc->filename ))
|
if( !Q_strcmp( filename, pc->filename ))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Con_Printf( S_ERROR "no precache: %s\n", filename );
|
Con_Printf( S_ERROR "Failed to enforce consistency for %s: was not precached\n", filename );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -274,15 +274,11 @@ model_t *SV_ModelHandle( int modelindex )
|
||||||
return sv.models[modelindex];
|
return sv.models[modelindex];
|
||||||
}
|
}
|
||||||
|
|
||||||
void SV_CreateGenericResources( void )
|
void SV_ReadResourceList( const char *filename )
|
||||||
{
|
{
|
||||||
string filename, token;
|
string token;
|
||||||
char *afile, *pfile;
|
char *afile, *pfile;
|
||||||
|
|
||||||
Q_strncpy( filename, sv.model_precache[1], sizeof( filename ));
|
|
||||||
COM_ReplaceExtension( filename, ".res" );
|
|
||||||
COM_FixSlashes( filename );
|
|
||||||
|
|
||||||
afile = FS_LoadFile( filename, NULL, false );
|
afile = FS_LoadFile( filename, NULL, false );
|
||||||
if( !afile ) return;
|
if( !afile ) return;
|
||||||
|
|
||||||
|
@ -304,6 +300,18 @@ void SV_CreateGenericResources( void )
|
||||||
Mem_Free( afile );
|
Mem_Free( afile );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SV_CreateGenericResources( void )
|
||||||
|
{
|
||||||
|
string filename;
|
||||||
|
|
||||||
|
Q_strncpy( filename, sv.model_precache[1], sizeof( filename ));
|
||||||
|
COM_ReplaceExtension( filename, ".res" );
|
||||||
|
COM_FixSlashes( filename );
|
||||||
|
|
||||||
|
SV_ReadResourceList( filename );
|
||||||
|
SV_ReadResourceList( "reslist.txt" );
|
||||||
|
}
|
||||||
|
|
||||||
void SV_CreateResourceList( void )
|
void SV_CreateResourceList( void )
|
||||||
{
|
{
|
||||||
qboolean ffirstsent = false;
|
qboolean ffirstsent = false;
|
||||||
|
|
|
@ -842,7 +842,7 @@ static SAVERESTOREDATA *LoadSaveData( const char *level )
|
||||||
|
|
||||||
if(( pFile = FS_Open( name, "rb", true )) == NULL )
|
if(( pFile = FS_Open( name, "rb", true )) == NULL )
|
||||||
{
|
{
|
||||||
Con_Printf( S_ERROR "couldn't open.\n" );
|
Con_Printf( S_ERROR "Couldn't open save data file %s.\n", name );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
mainui
2
mainui
|
@ -1 +1 @@
|
||||||
Subproject commit 995ed39b9a88a20c650df624c309f7cee3ecfdee
|
Subproject commit 33e6e585e875d91ae44b22d5425f1c38f2413741
|
Loading…
Add table
Reference in a new issue