From 91b1f6c0828c056f868927ab5fb21850793c41af Mon Sep 17 00:00:00 2001 From: g-cont Date: Sun, 20 Nov 2016 00:00:00 +0300 Subject: [PATCH] 20 Nov 2016 --- common/wadfile.h | 4 +- engine/client/cl_demo.c | 2 +- engine/client/cl_main.c | 38 +- engine/client/cl_scrn.c | 15 +- engine/client/client.h | 5 +- engine/client/gl_local.h | 2 + engine/client/gl_rmath.c | 34 ++ engine/client/gl_vidnt.c | 18 +- engine/client/gl_warp.c | 4 +- engine/common/common.c | 50 ++ engine/common/common.h | 11 +- engine/common/console.c | 641 +++++++++++++++---------- engine/common/crtlib.c | 23 + engine/common/crtlib.h | 1 + engine/common/cvar.c | 9 +- engine/common/filesystem.c | 782 +++++++++++++++++++------------ engine/common/filesystem.h | 7 +- engine/common/gamma.c | 22 +- engine/common/host.c | 12 +- engine/common/imagelib/img_wad.c | 24 +- engine/common/input.c | 40 +- engine/common/keys.c | 2 - engine/common/library.c | 42 +- engine/common/sys_win.c | 8 +- mainui/basemenu.cpp | 13 +- mainui/basemenu.h | 2 +- mainui/menu_creategame.cpp | 2 +- mainui/menu_internetgames.cpp | 28 +- mainui/menu_langame.cpp | 28 +- mainui/utils.cpp | 24 + mainui/utils.h | 1 + 31 files changed, 1161 insertions(+), 733 deletions(-) diff --git a/common/wadfile.h b/common/wadfile.h index f5d47ef5..503349ab 100644 --- a/common/wadfile.h +++ b/common/wadfile.h @@ -20,7 +20,7 @@ ======================================================================== .WAD archive format (WhereAllData - WAD) -List of compressed files, that can be identify only by TYPE_* +List of compressed files, that can be identify only by TYP_* header: dwadinfo_t[dwadinfo_t] @@ -33,7 +33,7 @@ infotable dlumpinfo_t[dwadinfo_t->numlumps] ======================================================================== */ -#define IDWAD3HEADER (('3'<<24)+('D'<<16)+('A'<<8)+'W') +#define IDWAD3HEADER (('3'<<24)+('D'<<16)+('A'<<8)+'W') // little-endian "WAD3" half-life wads // dlumpinfo_t->attribs #define ATTR_NONE 0 // allow to read-write diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index 3c5c234b..754b551e 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -1224,7 +1224,7 @@ void CL_PlayDemo_f( void ) CL_Disconnect(); Host_ShutdownServer(); - Con_Close(); + Con_FastClose(); UI_SetActiveMenu( false ); } diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index ca00aae3..bdf13aae 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -1153,22 +1153,6 @@ void CL_Reconnect_f( void ) } } -/* -================= -CL_ParseStatusMessage - -Handle a reply from a info -================= -*/ -void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg ) -{ - char *s = MSG_ReadString( msg ); - - // more info about servers - MsgDev( D_INFO, "Server: %s, Game: %s\n", NET_AdrToString( from ), Info_ValueForKey( s, "gamedir" )); - UI_AddServerToList( from, s ); -} - /* ================= CL_FixupColorStringsForInfoString @@ -1233,6 +1217,26 @@ void CL_FixupColorStringsForInfoString( const char *in, char *out ) *out = '\0'; } +/* +================= +CL_ParseStatusMessage + +Handle a reply from a info +================= +*/ +void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg ) +{ + static char infostring[MAX_INFO_STRING+8]; + char *s = MSG_ReadString( msg ); + + CL_FixupColorStringsForInfoString( s, infostring ); + + // more info about servers + MsgDev( D_INFO, "Server: %s, Game: %s\n", NET_AdrToString( from ), Info_ValueForKey( infostring, "gamedir" )); + + UI_AddServerToList( from, infostring ); +} + /* ================= CL_ParseNETInfoMessage @@ -2153,4 +2157,6 @@ void CL_Shutdown( void ) SCR_FreeCinematic (); // release AVI's *after* client.dll because custom renderer may use them S_Shutdown (); R_Shutdown (); + + Con_Shutdown (); } \ No newline at end of file diff --git a/engine/client/cl_scrn.c b/engine/client/cl_scrn.c index bb813b56..efed8004 100644 --- a/engine/client/cl_scrn.c +++ b/engine/client/cl_scrn.c @@ -603,7 +603,7 @@ void SCR_Init( void ) Cmd_AddCommand( "sizeup", SCR_SizeUp_f, "screen size up to 10 points" ); Cmd_AddCommand( "sizedown", SCR_SizeDown_f, "screen size down to 10 points" ); - if( host.state != HOST_RESTART && !UI_LoadProgs( )) + if( !UI_LoadProgs( )) { Msg( "^1Error: ^7can't initialize gameui.dll\n" ); // there is non fatal for us if( !host.developer ) host.developer = 1; // we need console, because menu is missing @@ -616,12 +616,9 @@ void SCR_Init( void ) CL_InitNetgraph(); SCR_VidInit(); - if( host.state != HOST_RESTART ) - { - if( host.developer && Sys_CheckParm( "-toconsole" )) - Cbuf_AddText( "toggleconsole\n" ); - else UI_SetActiveMenu( true ); - } + if( host.developer && Sys_CheckParm( "-toconsole" )) + Cbuf_AddText( "toggleconsole\n" ); + else UI_SetActiveMenu( true ); scr_init = true; } @@ -635,9 +632,7 @@ void SCR_Shutdown( void ) Cmd_RemoveCommand( "skyname" ); Cmd_RemoveCommand( "viewpos" ); UI_SetActiveMenu( false ); - - if( host.state != HOST_RESTART ) - UI_UnloadProgs(); + UI_UnloadProgs(); scr_init = false; } \ No newline at end of file diff --git a/engine/client/client.h b/engine/client/client.h index b17f5492..3d405a92 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -37,7 +37,7 @@ GNU General Public License for more details. #define MAX_CDTRACKS 32 #define MAX_IMAGES 256 // SpriteTextures #define MAX_EFRAGS 4096 -#define MAX_REQUESTS 128 +#define MAX_REQUESTS 64 // screenshot types #define VID_SCREENSHOT 0 @@ -831,6 +831,7 @@ extern convar_t *con_fontsize; qboolean Con_Visible( void ); void Con_Init( void ); void Con_VidInit( void ); +void Con_Shutdown( void ); void Con_ToggleConsole_f( void ); void Con_ClearNotify( void ); void Con_DrawDebug( void ); @@ -848,7 +849,7 @@ void Con_CharEvent( int key ); void Con_RestoreFont( void ); void Key_Console( int key ); void Key_Message( int key ); -void Con_Close( void ); +void Con_FastClose( void ); // // s_main.c diff --git a/engine/client/gl_local.h b/engine/client/gl_local.h index e733e06b..6b4625d5 100644 --- a/engine/client/gl_local.h +++ b/engine/client/gl_local.h @@ -379,6 +379,8 @@ void Matrix4x4_CreateScale3( matrix4x4 out, float x, float y, float z ); void Matrix4x4_CreateProjection(matrix4x4 out, float xMax, float xMin, float yMax, float yMin, float zNear, float zFar); void Matrix4x4_CreateOrtho(matrix4x4 m, float xLeft, float xRight, float yBottom, float yTop, float zNear, float zFar); void Matrix4x4_CreateModelview( matrix4x4 out ); +void R_InitLookupTables( void ); +float R_FastSin( float t ); // // gl_rmisc. diff --git a/engine/client/gl_rmath.c b/engine/client/gl_rmath.c index 83baf098..4f4f9cc3 100644 --- a/engine/client/gl_rmath.c +++ b/engine/client/gl_rmath.c @@ -18,6 +18,40 @@ GNU General Public License for more details. #include "mathlib.h" #include "client.h" +#define FTABLE_SIZE 1024 +#define FTABLE_CLAMP( x ) (((uint)(( x ) * FTABLE_SIZE ) & ( FTABLE_SIZE - 1 ))) +#define FTABLE_EVALUATE( table, x ) (( table )[FTABLE_CLAMP( x )] ) + +static float r_sintable[FTABLE_SIZE]; + +/* +============== +R_InitLookupTables + +============== +*/ +void R_InitLookupTables( void ) +{ + float t; + int i; + + for( i = 0; i < FTABLE_SIZE; i++ ) + { + t = (float)i / (float)FTABLE_SIZE; + r_sintable[i] = sin( t * M_PI2 ); + } +} + +/* +============== +R_FastSin +============== +*/ +float R_FastSin( float t ) +{ + return sin( t );// FIXME FTABLE_EVALUATE( r_sintable, t ); +} + /* ==================== V_CalcFov diff --git a/engine/client/gl_vidnt.c b/engine/client/gl_vidnt.c index 8a1fa5f3..2261e413 100644 --- a/engine/client/gl_vidnt.c +++ b/engine/client/gl_vidnt.c @@ -1562,7 +1562,7 @@ void VID_CheckChanges( void ) if( renderinfo->modified ) { - if( !VID_SetMode()) + if( !VID_SetMode( )) { Msg( "Error: can't initialize video subsystem\n" ); Host_NewInstance( va("#%s", GI->gamefolder ), "stopped" ); @@ -1620,8 +1620,6 @@ GL_SetDefaults */ static void GL_SetDefaults( void ) { - int i; - pglFinish(); pglClearColor( 0.5f, 0.5f, 0.5f, 1.0f ); @@ -1645,19 +1643,8 @@ static void GL_SetDefaults( void ) pglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); pglPolygonOffset( -1.0f, -2.0f ); - // properly disable multitexturing at startup - for( i = (MAX_TEXTURE_UNITS - 1); i > 0; i-- ) - { - if( i >= GL_MaxTextureUnits( )) - continue; + GL_CleanupAllTextureUnits(); - GL_SelectTexture( i ); - pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); - pglDisable( GL_BLEND ); - pglDisable( GL_TEXTURE_2D ); - } - - GL_SelectTexture( 0 ); pglDisable( GL_BLEND ); pglDisable( GL_ALPHA_TEST ); pglDisable( GL_POLYGON_OFFSET_FILL ); @@ -2035,6 +2022,7 @@ qboolean R_Init( void ) GL_InitCommands(); GL_SetDefaultState(); + R_InitLookupTables(); // create the window and set up the context if( !R_Init_OpenGL( )) diff --git a/engine/client/gl_warp.c b/engine/client/gl_warp.c index 59293fd2..d89f44eb 100644 --- a/engine/client/gl_warp.c +++ b/engine/client/gl_warp.c @@ -22,6 +22,7 @@ GNU General Public License for more details. #define SKYCLOUDS_QUALITY 12 #define MAX_CLIP_VERTS 128 // skybox clip vertices #define TURBSCALE ( 256.0f / ( M_PI2 )) +#define R_TurbSin( x ) ( R_FastSin( x * 0.02f + cl.time )) static const char* r_skyBoxSuffix[6] = { "rt", "bk", "lf", "ft", "up", "dn" }; static const int r_skyTexOrder[6] = { 0, 2, 1, 3, 4, 5 }; @@ -800,8 +801,7 @@ void EmitWaterPolys( glpoly_t *polys, qboolean noCull ) { if( waveHeight ) { - nv = v[2] + waveHeight + ( waveHeight * sin(v[0] * 0.02f + cl.time) - * sin(v[1] * 0.02 + cl.time) * sin(v[2] * 0.02f + cl.time)); + nv = v[2] + waveHeight + ( waveHeight * R_TurbSin( v[0] ) * R_TurbSin( v[1] ) * R_TurbSin( v[2] )); nv -= waveHeight; } else nv = v[2]; diff --git a/engine/common/common.c b/engine/common/common.c index f9371b29..4af629c8 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -132,6 +132,56 @@ skipwhite: return data; } +/* +================ +COM_ParseVector + +================ +*/ +qboolean COM_ParseVector( char **pfile, float *v, size_t size ) +{ + string token; + qboolean bracket = false; + char *saved; + uint i; + + if( v == NULL || size == 0 ) + return false; + + memset( v, 0, sizeof( *v ) * size ); + + if( size == 1 ) + { + *pfile = COM_ParseFile( *pfile, token ); + v[0] = Q_atof( token ); + return true; + } + + saved = *pfile; + + if(( *pfile = COM_ParseFile( *pfile, token )) == NULL ) + return false; + + if( token[0] == '(' ) + bracket = true; + else *pfile = saved; // restore token to right get it again + + for( i = 0; i < size; i++ ) + { + *pfile = COM_ParseFile( *pfile, token ); + v[i] = Q_atof( token ); + } + + if( !bracket ) return true; // done + + if(( *pfile = COM_ParseFile( *pfile, token )) == NULL ) + return false; + + if( token[0] == ')' ) + return true; + return false; +} + /* ============= COM_FileSize diff --git a/engine/common/common.h b/engine/common/common.h index a946729d..32e27f36 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -36,6 +36,7 @@ extern "C" { #define MAX_STRING 256 // generic string #define MAX_INFO_STRING 256 // infostrings are transmitted across network #define MAX_SYSPATH 1024 // system filepath +#define MAX_PRINT_MSG 8192 // how many symbols can handle single call of Msg or MsgDev #define MAX_MODS 512 // environment games that engine can keep visible #define EXPORT __declspec( dllexport ) #define BIT( n ) (1<<( n )) @@ -225,7 +226,6 @@ typedef enum HOST_ERR_FATAL, // sys error HOST_SLEEP, // sleeped by different reason, e.g. minimize window HOST_NOFOCUS, // same as HOST_FRAME, but disable mouse - HOST_RESTART, // during the changes video mode HOST_CRASHED // an exception handler called } host_state; @@ -370,15 +370,16 @@ void FS_LoadGameInfo( const char *rootfolder ); void FS_FileBase( const char *in, char *out ); const char *FS_FileExtension( const char *in ); void FS_DefaultExtension( char *path, const char *extension ); -void FS_ExtractFilePath( const char* const path, char* dest ); +void FS_ExtractFilePath( const char *path, char *dest ); const char *FS_GetDiskPath( const char *name, qboolean gamedironly ); const char *FS_FileWithoutPath( const char *in ); -wfile_t *W_Open( const char *filename, const char *mode ); +wfile_t *W_Open( const char *filename, const char *mode, int *errorcode ); byte *W_LoadLump( wfile_t *wad, const char *lumpname, size_t *lumpsizeptr, const char type ); void W_Close( wfile_t *wad ); file_t *FS_OpenFile( const char *path, long *filesizeptr, qboolean gamedironly ); byte *FS_LoadFile( const char *path, long *filesizeptr, qboolean gamedironly ); qboolean FS_WriteFile( const char *filename, const void *data, long len ); +qboolean COM_ParseVector( char **pfile, float *v, size_t size ); int COM_FileSize( const char *filename ); void COM_FixSlashes( char *pname ); void COM_FreeFile( void *buffer ); @@ -396,7 +397,7 @@ long FS_FileTime( const char *filename, qboolean gamedironly ); int FS_Print( file_t *file, const char *msg ); qboolean FS_Rename( const char *oldname, const char *newname ); qboolean FS_FileExists( const char *filename, qboolean gamedironly ); -void FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize ); +qboolean FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize ); qboolean FS_Delete( const char *path ); int FS_UnGetc( file_t *file, byte c ); void FS_StripExtension( char *path ); @@ -913,8 +914,6 @@ void S_StopAllSounds( void ); void BuildGammaTable( float gamma, float texGamma ); byte TextureToTexGamma( byte b ); byte TextureToGamma( byte b ); -float TextureToLinear( int c ); -int LinearToTexture( float f ); #ifdef __cplusplus } diff --git a/engine/common/console.c b/engine/common/console.c index 014368f3..b2e5b376 100644 --- a/engine/common/console.c +++ b/engine/common/console.c @@ -25,14 +25,19 @@ convar_t *con_notifytime; convar_t *scr_conspeed; convar_t *con_fontsize; -#define CON_TIMES 5 // need for 4 lines +#define CON_TIMES 4 // notify lines #define COLOR_DEFAULT '7' #define CON_HISTORY 64 #define MAX_DBG_NOTIFY 128 #define CON_MAXCMDS 4096 // auto-complete intermediate list #define CON_NUMFONTS 3 // maxfonts -#define CON_TEXTSIZE 131072 // 128 kb buffer +#define CON_LINES( i ) (con.lines[(con.lines_first + (i)) % con.maxlines]) +#define CON_LINES_COUNT con.lines_count +#define CON_LINES_LAST() CON_LINES( CON_LINES_COUNT - 1 ) + +#define CON_TEXTSIZE 1048576 // max scrollback buffer characters in console (1 Mb) +#define CON_MAXLINES 16384 // max scrollback buffer lines in console // console color typeing rgba_t g_color_table[8] = @@ -63,29 +68,38 @@ typedef struct int key_dest; } notify_t; +typedef struct con_lineinfo_s +{ + char *start; + size_t length; + double addtime; // notify stuff +} con_lineinfo_t; + typedef struct { qboolean initialized; - short text[CON_TEXTSIZE]; - int current; // line where next message will be printed - int display; // bottom of console displays this line - int x; // offset in current line for next print + // conbuffer + char *buffer; // common buffer for all console lines + int bufsize; // CON_TEXSIZE + con_lineinfo_t *lines; // console lines + int maxlines; // CON_MAXLINES + int lines_first; // cyclic buffer + int lines_count; + + // console scroll + int backscroll; // lines up from bottom to display int linewidth; // characters across screen - int totallines; // total lines in console scrollback - - float displayFrac; // aproaches finalFrac at scr_conspeed - float finalFrac; // 0.0 to 1.0 lines of console to display + // console animation + int showlines; // how many lines we should display int vislines; // in scanlines - double times[CON_TIMES]; // host.realtime the line was generated for transparent notify lines - rgba_t color; // console images int background; // console background - // conchars + // console fonts cl_font_t chars[CON_NUMFONTS];// fonts.wad/font1.fnt cl_font_t *curFont, *lastUsedFont; @@ -124,11 +138,8 @@ Con_Clear_f */ void Con_Clear_f( void ) { - int i; - - for( i = 0; i < CON_TEXTSIZE; i++ ) - con.text[i] = ( ColorIndex( COLOR_DEFAULT ) << 8 ) | ' '; - con.display = con.current; // go to end + con.lines_count = 0; + con.backscroll = 0; // go to end } /* @@ -169,8 +180,8 @@ void Con_ClearNotify( void ) { int i; - for( i = 0; i < CON_TIMES; i++ ) - con.times[i] = 0; + for( i = 0; i < CON_LINES_COUNT; i++ ) + CON_LINES( i ).addtime = 0.0; } /* @@ -296,6 +307,135 @@ void Con_ToggleConsole_f( void ) } } +/* +================ +Con_FixTimes + +Notifies the console code about the current time +(and shifts back times of other entries when the time +went backwards) +================ +*/ +void Con_FixTimes( void ) +{ + double diff; + int i; + + if( con.lines_count <= 0 ) return; + + diff = cl.time - CON_LINES_LAST().addtime; + if( diff >= 0.0 ) return; // nothing to fix + + for( i = 0; i < con.lines_count; i++ ) + CON_LINES( i ).addtime += diff; +} + +/* +================ +Con_DeleteLine + +Deletes the first line from the console history. +================ +*/ +void Con_DeleteLine( void ) +{ + if( con.lines_count == 0 ) + return; + con.lines_count--; + con.lines_first = (con.lines_first + 1) % con.maxlines; +} + +/* +================ +Con_DeleteLastLine + +Deletes the last line from the console history. +================ +*/ +void Con_DeleteLastLine( void ) +{ + if( con.lines_count == 0 ) + return; + con.lines_count--; +} + +/* +================ +Con_BytesLeft + +Checks if there is space for a line of the given length, and if yes, returns a +pointer to the start of such a space, and NULL otherwise. +================ +*/ +static char *Con_BytesLeft( int length ) +{ + if( length > con.bufsize ) + return NULL; + + if( con.lines_count == 0 ) + { + return con.buffer; + } + else + { + char *firstline_start = con.lines[con.lines_first].start; + char *lastline_onepastend = CON_LINES_LAST().start + CON_LINES_LAST().length; + + // the buffer is cyclic, so we first have two cases... + if( firstline_start < lastline_onepastend ) // buffer is contiguous + { + // put at end? + if( length <= con.buffer + con.bufsize - lastline_onepastend ) + return lastline_onepastend; + // put at beginning? + else if( length <= firstline_start - con.buffer ) + return con.buffer; + + return NULL; + } + else + { + // buffer has a contiguous hole + if( length <= firstline_start - lastline_onepastend ) + return lastline_onepastend; + + return NULL; + } + } +} + +/* +================ +Con_AddLine + +Appends a given string as a new line to the console. +================ +*/ +void Con_AddLine( const char *line, int length ) +{ + byte *putpos; + con_lineinfo_t *p; + + if( !con.initialized ) return; + + Con_FixTimes(); + length++; // reserve space for term + + ASSERT( length < CON_TEXTSIZE ); + + while( !( putpos = Con_BytesLeft( length )) || con.lines_count >= con.maxlines ) + Con_DeleteLine(); + + memcpy( putpos, line, length ); + putpos[length - 1] = '\0'; + con.lines_count++; + + p = &CON_LINES_LAST(); + p->start = putpos; + p->length = length; + p->addtime = cl.time; +} + /* ================ Con_CheckResize @@ -305,63 +445,21 @@ If the line width has changed, reformat the buffer. */ void Con_CheckResize( void ) { - int i, j, width, numlines, numchars; - int oldwidth, oldtotallines; - short tbuf[CON_TEXTSIZE]; int charWidth = 8; + int i, width; if( con.curFont && con.curFont->hFontTexture ) - charWidth = con.curFont->charWidths[' '] - 1; + charWidth = con.curFont->charWidths['M'] - 1; - width = ( scr_width->integer / charWidth ); - con.vislines = 0; // FIXME: sometimes here get unthinkable values + width = ( scr_width->integer / charWidth ) - 2; + if( !glw_state.initialized ) width = 78; if( width == con.linewidth ) return; - if( !glw_state.initialized ) - { - // video hasn't been initialized yet - con.linewidth = width; - con.totallines = CON_TEXTSIZE / con.linewidth; - - for( i = 0; i < CON_TEXTSIZE; i++ ) - con.text[i] = ( ColorIndex( COLOR_DEFAULT ) << 8 ) | ' '; - } - else - { - oldwidth = con.linewidth; - con.linewidth = width; - oldtotallines = con.totallines; - con.totallines = CON_TEXTSIZE / con.linewidth; - numlines = oldtotallines; - - if( con.totallines < numlines ) - numlines = con.totallines; - - numchars = oldwidth; - - if( con.linewidth < numchars ) - numchars = con.linewidth; - - memcpy( tbuf, con.text, CON_TEXTSIZE * sizeof( short )); - - for( i = 0; i < CON_TEXTSIZE; i++ ) - con.text[i] = ( ColorIndex( COLOR_DEFAULT ) << 8 ) | ' '; - - for( i = 0; i < numlines; i++ ) - { - for( j = 0; j < numchars; j++ ) - { - con.text[(con.totallines - 1 - i) * con.linewidth + j] = - tbuf[((con.current - i + oldtotallines) % oldtotallines) * oldwidth + j + con.x]; - } - } - Con_ClearNotify (); - } - - con.current = con.totallines - 1; - con.display = con.current; + Con_ClearNotify(); + con.linewidth = width; + con.backscroll = 0; con.input.widthInChars = con.linewidth; @@ -376,10 +474,7 @@ Con_PageUp */ void Con_PageUp( int lines ) { - con.display -= abs( lines ); - - if( con.current - con.display >= con.totallines ) - con.display = con.current - con.totallines + 1; + con.backscroll += abs( lines ); } /* @@ -389,10 +484,7 @@ Con_PageDown */ void Con_PageDown( int lines ) { - con.display += abs( lines ); - - if( con.display > con.current ) - con.display = con.current; + con.backscroll -= abs( lines ); } /* @@ -402,10 +494,7 @@ Con_Top */ void Con_Top( void ) { - con.display = con.totallines; - - if( con.current - con.display >= con.totallines ) - con.display = con.current - con.totallines + 1; + con.backscroll = CON_MAXLINES; } /* @@ -415,7 +504,7 @@ Con_Bottom */ void Con_Bottom( void ) { - con.display = con.current; + con.backscroll = 0; } /* @@ -442,7 +531,7 @@ static void Con_LoadConsoleFont( int fontNumber, cl_font_t *font ) if( font->valid ) return; // already loaded // loading conchars - font->hFontTexture = GL_LoadTexture( va( "fonts.wad/font%i", fontNumber ), NULL, 0, TF_FONT, NULL ); + font->hFontTexture = GL_LoadTexture( va( "fonts.wad/font%i", fontNumber ), NULL, 0, TF_FONT|TF_NEAREST, NULL ); R_GetTextureParms( &fontWidth, NULL, font->hFontTexture ); // setup creditsfont @@ -504,7 +593,7 @@ static void Con_LoadConchars( void ) /* ==================== -TextAdjustSize +Con_TextAdjustSize draw charcters routine ==================== @@ -513,7 +602,6 @@ static void Con_TextAdjustSize( int *x, int *y, int *w, int *h ) { float xscale, yscale; - if( !clgame.ds.adjust_size ) return; if( !x && !y && !w && !h ) return; // scale for screen sizes @@ -561,7 +649,8 @@ static int Con_DrawGenericChar( int x, int y, int number, rgba_t color ) width = rc->right - rc->left; height = rc->bottom - rc->top; - Con_TextAdjustSize( &x, &y, &width, &height ); + if( clgame.ds.adjust_size ) + Con_TextAdjustSize( &x, &y, &width, &height ); R_DrawStretchPic( x, y, width, height, s1, t1, s2, t2, con.curFont->hFontTexture ); pglColor4ub( 255, 255, 255, 255 ); // don't forget reset color @@ -681,10 +770,10 @@ int Con_DrawGenericString( int x, int y, const char *string, rgba_t setColor, qb if( !con.curFont ) return 0; // no font set // draw the colored text - s = string; *(uint *)color = *(uint *)setColor; + s = string; - while ( *s ) + while( *s ) { if( *s == '\n' ) { @@ -748,6 +837,13 @@ void Con_Init( void ) con_notifytime = Cvar_Get( "con_notifytime", "3", CVAR_ARCHIVE, "notify time to live" ); con_fontsize = Cvar_Get( "con_fontsize", "1", CVAR_ARCHIVE, "console font number (0, 1 or 2)" ); + // init the console buffer + con.bufsize = CON_TEXTSIZE; + con.buffer = (char *)Z_Malloc( con.bufsize ); + con.maxlines = CON_MAXLINES; + con.lines = (con_lineinfo_t *)Z_Malloc( con.maxlines * sizeof( *con.lines )); + con.lines_first = con.lines_count = 0; + Con_CheckResize(); Con_ClearField( &con.input ); @@ -773,26 +869,22 @@ void Con_Init( void ) } /* -=============== -Con_Linefeed -=============== +================ +Con_Shutdown +================ */ -void Con_Linefeed( void ) +void Con_Shutdown( void ) { - int i; + con.initialized = false; - // mark time for transparent overlay - if( con.current >= 0 ) - con.times[con.current % CON_TIMES] = host.realtime; + if( con.buffer ) + Mem_Free( con.buffer ); - con.x = 0; - if( con.display == con.current ) - con.display++; + if( con.lines ) + Mem_Free( con.lines ); - con.current++; - - for( i = 0; i < con.linewidth; i++ ) - con.text[(con.current % con.totallines) * con.linewidth+i] = ( ColorIndex( COLOR_DEFAULT ) << 8 ) | ' '; + con.buffer = NULL; + con.lines = NULL; } /* @@ -800,54 +892,52 @@ void Con_Linefeed( void ) Con_Print Handles cursor positioning, line wrapping, etc -All console printing must go through this in order to be logged to disk -If no console is visible, the text will appear at the top of the game window +All console printing must go through this in order to be displayed +If no console is visible, the notify window will pop up. ================ */ void Con_Print( const char *txt ) { - int y, c, l, color; + static int cr_pending = 0; + static char buf[MAX_PRINT_MSG]; + static int bufpos = 0; // client not running - if( !con.initialized || host.type == HOST_DEDICATED ) + if( !con.initialized || !con.buffer || host.type == HOST_DEDICATED ) return; - color = ColorIndex( COLOR_DEFAULT ); - - while(( c = *txt ) != 0 ) + for( ; *txt; txt++ ) { - if( IsColorString( txt )) + if( cr_pending ) { - color = ColorIndex( *( txt + 1 )); - txt += 2; - continue; + Con_DeleteLastLine(); + cr_pending = 0; } - // count word length - for( l = 0; l < con.linewidth; l++ ) - if( txt[l] <= ' ' ) break; - txt++; - - switch( c ) + switch( *txt ) { - case '\n': - Con_Linefeed(); + case '\0': break; case '\r': - con.x = 0; + Con_AddLine( buf, bufpos ); + cr_pending = 1; + bufpos = 0; break; - default: // display character and advance - y = con.current % con.totallines; - con.text[y*con.linewidth+con.x] = (color << 8) | c; - con.x++; - if( con.x >= con.linewidth ) + case '\n': + Con_AddLine( buf, bufpos ); + bufpos = 0; + break; + default: + buf[bufpos++] = *txt; + if(( bufpos >= sizeof( buf ) - 1 ) || bufpos >= ( con.linewidth - 1 )) { - Con_Linefeed(); - con.x = 0; + Con_AddLine( buf, bufpos ); + bufpos = 0; } break; } } + } /* @@ -1448,7 +1538,7 @@ void Key_Console( int key ) } // enter finishes the line - if ( key == K_ENTER || key == K_KP_ENTER ) + if( key == K_ENTER || key == K_KP_ENTER ) { // if not in the game explicitly prepent a slash if needed if( cls.state != ca_active && con.input.buffer[0] != '\\' && con.input.buffer[0] != '/' ) @@ -1471,8 +1561,7 @@ void Key_Console( int key ) // copy line to history buffer con.historyLines[con.nextHistoryLine % CON_HISTORY] = con.input; - con.nextHistoryLine++; - con.historyLine = con.nextHistoryLine; + con.historyLine = con.nextHistoryLine++; Con_ClearField( &con.input ); con.input.widthInChars = con.linewidth; @@ -1496,9 +1585,7 @@ void Key_Console( int key ) if(( key == K_MWHEELUP && Key_IsDown( K_SHIFT )) || ( key == K_UPARROW ) || (( Q_tolower(key) == 'p' ) && Key_IsDown( K_CTRL ))) { if( con.nextHistoryLine - con.historyLine < CON_HISTORY && con.historyLine > 0 ) - { con.historyLine--; - } con.input = con.historyLines[con.historyLine % CON_HISTORY]; return; } @@ -1514,13 +1601,13 @@ void Key_Console( int key ) // console scrolling if( key == K_PGUP ) { - Con_PageUp( 2 ); + Con_PageUp( 1 ); return; } if( key == K_PGDN ) { - Con_PageDown( 2 ); + Con_PageDown( 1 ); return; } @@ -1606,21 +1693,17 @@ Con_DrawInput The input line scrolls horizontally if typing goes beyond the right edge ================ */ -void Con_DrawInput( void ) +void Con_DrawInput( int lines ) { - byte *colorDefault; - int x, y; + int y; // don't draw anything (always draw if not active) - if( cls.key_dest != key_console ) return; - if( !con.curFont ) return; + if( cls.key_dest != key_console || !con.curFont ) + return; - x = QCHAR_WIDTH; // room for ']' - y = con.vislines - ( con.curFont->charHeight * 2 ); - colorDefault = g_color_table[ColorIndex( COLOR_DEFAULT )]; - - Con_DrawCharacter( QCHAR_WIDTH >> 1, y, ']', colorDefault ); - Field_DrawInputLine( x, y, &con.input ); + y = lines - ( con.curFont->charHeight * 2 ); + Con_DrawCharacter( 8, y, ']', g_color_table[7] ); + Field_DrawInputLine( 16, y, &con.input ); } /* @@ -1633,8 +1716,8 @@ Custom debug messages int Con_DrawDebugLines( void ) { int i, count = 0; - int y = 20; int defaultX; + int y = 20; defaultX = glState.width / 4; @@ -1689,38 +1772,24 @@ Draws the last few lines of output transparently over the game top */ void Con_DrawNotify( void ) { - int i, x, v = 0; - int start, currentColor; - short *text; - float time; + double time = cl.time; + int i, x, y = 0; if( !con.curFont ) return; + x = con.curFont->charWidths[' ']; // offset one space at left screen side + if( host.developer && ( !Cvar_VariableInteger( "cl_background" ) && !Cvar_VariableInteger( "sv_background" ))) { - currentColor = 7; - pglColor4ubv( g_color_table[currentColor] ); - - for( i = con.current - CON_TIMES + 1; i <= con.current; i++ ) + for( i = CON_LINES_COUNT - CON_TIMES; i < CON_LINES_COUNT; i++ ) { - if( i < 0 ) continue; - time = con.times[i % CON_TIMES]; - if( time == 0 ) continue; - time = host.realtime - time; + con_lineinfo_t *l = &CON_LINES( i ); - if( time > con_notifytime->value ) - continue; // expired + if( l->addtime < ( time - con_notifytime->value )) + continue; - text = con.text + (i % con.totallines) * con.linewidth; - start = con.curFont->charWidths[' ']; // offset one space at left screen side - - for( x = 0; x < con.linewidth; x++ ) - { - if((( text[x] >> 8 ) & 7 ) != currentColor ) - currentColor = ( text[x] >> 8 ) & 7; - start += Con_DrawCharacter( start, v, text[x] & 0xFF, g_color_table[currentColor] ); - } - v += con.curFont->charHeight; + Con_DrawString( x, y, l->start, g_color_table[7] ); + y += con.curFont->charHeight; } } @@ -1729,26 +1798,71 @@ void Con_DrawNotify( void ) string buf; int len; - currentColor = 7; - pglColor4ubv( g_color_table[currentColor] ); - - start = con.curFont->charWidths[' ']; // offset one space at left screen side - // update chatline position from client.dll if( clgame.dllFuncs.pfnChatInputPosition ) - clgame.dllFuncs.pfnChatInputPosition( &start, &v ); + clgame.dllFuncs.pfnChatInputPosition( &x, &y ); Q_snprintf( buf, sizeof( buf ), "%s: ", con.chat_cmd ); Con_DrawStringLen( buf, &len, NULL ); - Con_DrawString( start, v, buf, g_color_table[7] ); + Con_DrawString( x, y, buf, g_color_table[7] ); - Field_DrawInputLine( start + len, v, &con.chat ); + Field_DrawInputLine( x + len, y, &con.chat ); } pglColor4ub( 255, 255, 255, 255 ); } +/* +================ +Con_DrawConsoleLine + +Draws a line of the console; returns its height in lines. +If alpha is 0, the line is not drawn, but still wrapped and its height +returned. +================ +*/ +int Con_DrawConsoleLine( int y, int lineno ) +{ + con_lineinfo_t *li = &CON_LINES( lineno ); + + if( y >= con.curFont->charHeight ) + Con_DrawGenericString( con.curFont->charWidths[' '], y, li->start, g_color_table[7], false, -1 ); + + return con.curFont->charHeight; +} + +/* +================ +Con_LastVisibleLine + +Calculates the last visible line index and how much to show +of it based on con.backscroll. +================ +*/ +static void Con_LastVisibleLine( int *lastline ) +{ + int i, lines_seen = 0; + + con.backscroll = Q_max( 0, con.backscroll ); + *lastline = 0; + + // now count until we saw con_backscroll actual lines + for( i = CON_LINES_COUNT - 1; i >= 0; i-- ) + { + // line is the last visible line? + *lastline = i; + + if( lines_seen + 1 > con.backscroll && lines_seen <= con.backscroll ) + return; + + lines_seen += 1; + } + + // if we get here, no line was on screen - scroll so that one line is visible then. + con.backscroll = lines_seen - 1; +} + /* ================ Con_DrawConsole @@ -1756,37 +1870,27 @@ Con_DrawConsole Draws the console with the solid background ================ */ -void Con_DrawSolidConsole( float frac ) +void Con_DrawSolidConsole( int lines ) { int i, x, y; - int rows; - short *text; - int row, start; - int currentColor; - string curbuild; + float fraction; + int start; - con.vislines = scr_height->integer * frac; - if( con.vislines <= 0 ) return; - if( con.vislines > scr_height->integer ) - con.vislines = scr_height->integer; + if( lines <= 0 ) return; // draw the background - y = frac * scr_height->integer; + GL_SetRenderMode( kRenderNormal ); + pglColor4ub( 255, 255, 255, 255 ); // to prevent grab color from screenfade + R_DrawStretchPic( 0, lines - scr_height->integer, scr_width->integer, scr_height->integer, 0, 0, 1, 1, con.background ); - if( y >= 1 ) - { - GL_SetRenderMode( kRenderNormal ); - pglColor4ub( 255, 255, 255, 255 ); // to prevent grab color from screenfade - R_DrawStretchPic( 0, y - scr_height->integer, scr_width->integer, scr_height->integer, 0, 0, 1, 1, con.background ); - } - else y = 0; + if( !con.curFont || host.developer <= 0 ) + return; // nothing to draw - if( !con.curFont ) return; // nothing to draw - - if( host.developer ) + if( host.developer > 0 ) { // draw current version int stringLen, width = 0, charH; + string curbuild; byte color[4]; memcpy( color, g_color_table[7], sizeof( color )); @@ -1796,58 +1900,48 @@ void Con_DrawSolidConsole( float frac ) start = scr_width->integer - stringLen; stringLen = Con_StringLength( curbuild ); - color[3] = min( con.displayFrac * 2.0f, 1.0f ) * 255; // fadeout version number + fraction = lines / (float)scr_height->integer; + color[3] = Q_min( fraction * 2.0f, 1.0f ) * 255; // fadeout version number for( i = 0; i < stringLen; i++ ) width += Con_DrawCharacter( start + width, 0, curbuild[i], color ); } // draw the text - rows = ( con.vislines - QCHAR_WIDTH ) / QCHAR_WIDTH; // rows of text to draw - y = con.vislines - ( con.curFont->charHeight * 3 ); - - // draw from the bottom up - if( con.display != con.current ) + if( CON_LINES_COUNT > 0 ) { - start = con.curFont->charWidths[' ']; // offset one space at left screen side + int ymax = lines - (con.curFont->charHeight * 2.0f); + int lastline; - // draw red arrows to show the buffer is backscrolled - for( x = 0; x < con.linewidth; x += 4 ) - Con_DrawCharacter(( x + 1 ) * start, y, '^', g_color_table[1] ); - y -= con.curFont->charHeight; - rows--; - } - - row = con.display; - if( con.x == 0 ) row--; + Con_LastVisibleLine( &lastline ); + y = ymax - con.curFont->charHeight; - currentColor = 7; - pglColor4ubv( g_color_table[currentColor] ); - - for( i = 0; i < rows; i++, y -= con.curFont->charHeight, row-- ) - { - if( row < 0 ) break; - if( con.current - row >= con.totallines ) + if( con.backscroll ) { - // past scrollback wrap point - continue; + start = con.curFont->charWidths[' ']; // offset one space at left screen side + + // draw red arrows to show the buffer is backscrolled + for( x = 0; x < con.linewidth; x += 4 ) + Con_DrawCharacter(( x + 1 ) * start, y, '^', g_color_table[1] ); + y -= con.curFont->charHeight; } + x = lastline; - text = con.text + ( row % con.totallines ) * con.linewidth; - start = con.curFont->charWidths[' ']; // offset one space at left screen side - - for( x = 0; x < con.linewidth; x++ ) + while( 1 ) { - if((( text[x] >> 8 ) & 7 ) != currentColor ) - currentColor = ( text[x] >> 8 ) & 7; - start += Con_DrawCharacter( start, y, text[x] & 0xFF, g_color_table[currentColor] ); + y -= Con_DrawConsoleLine( y, x ); + + // top of console buffer or console window + if( x == 0 || y < con.curFont->charHeight ) + break; + x--; } } // draw the input prompt, user text, and cursor if desired - Con_DrawInput(); + Con_DrawInput( lines ); - y = con.vislines - ( con.curFont->charHeight * 1.2f ); + y = lines - ( con.curFont->charHeight * 1.2f ); SCR_DrawFPS( max( y, 4 )); // to avoid to hide fps counter pglColor4ub( 255, 255, 255, 255 ); @@ -1872,18 +1966,18 @@ void Con_DrawConsole( void ) if( !cl_allow_levelshots->integer ) { if(( Cvar_VariableInteger( "cl_background" ) || Cvar_VariableInteger( "sv_background" )) && cls.key_dest != key_console ) - con.displayFrac = con.finalFrac = 0.0f; - else con.displayFrac = con.finalFrac = 1.0f; + con.vislines = con.showlines = 0; + else con.vislines = con.showlines = scr_height->integer; } else { if( host.developer >= 4 ) { - con.displayFrac = 0.5f; // keep console open + con.vislines = (scr_height->integer >> 1); // keep console open } else { - con.finalFrac = 0.0f; + con.showlines = 0; Con_RunConsole(); if( host.developer >= 2 ) @@ -1900,26 +1994,30 @@ void Con_DrawConsole( void ) case ca_disconnected: if( cls.key_dest != key_menu && host.developer ) { - Con_DrawSolidConsole( 1.0f ); + Con_DrawSolidConsole( scr_height->integer ); Key_SetKeyDest( key_console ); } break; case ca_connected: case ca_connecting: // force to show console always for -dev 3 and higher - if( con.displayFrac ) Con_DrawSolidConsole( con.displayFrac ); + if( con.vislines ) + { + GL_CleanupAllTextureUnits(); // ugly hack to remove blinking voiceicon.spr during loading + Con_DrawSolidConsole( con.vislines ); + } break; case ca_active: case ca_cinematic: if( Cvar_VariableInteger( "cl_background" ) || Cvar_VariableInteger( "sv_background" )) { if( cls.key_dest == key_console ) - Con_DrawSolidConsole( 1.0f ); + Con_DrawSolidConsole( scr_height->integer ); } else { - if( con.displayFrac ) - Con_DrawSolidConsole( con.displayFrac ); + if( con.vislines ) + Con_DrawSolidConsole( con.vislines ); else if( cls.state == ca_active && ( cls.key_dest == key_game || cls.key_dest == key_message )) Con_DrawNotify(); // draw notify lines } @@ -1980,14 +2078,16 @@ Scroll it up or down */ void Con_RunConsole( void ) { + int lines_per_frame; + // decide on the destination height of the console if( host.developer && cls.key_dest == key_console ) { if( cls.state == ca_disconnected ) - con.finalFrac = 1.0f;// full screen - else con.finalFrac = 0.5f; // half screen + con.showlines = scr_height->integer; // full screen + else con.showlines = (scr_height->integer >> 1); // half screen } - else con.finalFrac = 0; // none visible + else con.showlines = 0; // none visible // when level is loading frametime may be is wrong if( cls.state == ca_connecting || cls.state == ca_connected ) @@ -1997,17 +2097,19 @@ void Con_RunConsole( void ) else host.realframetime = HOST_FRAMETIME; } - if( con.finalFrac < con.displayFrac ) + lines_per_frame = bound( 1, fabs( scr_conspeed->value ) * host.realframetime, scr_height->integer ); + + if( con.showlines < con.vislines ) { - con.displayFrac -= fabs( scr_conspeed->value ) * 0.002f * host.realframetime; - if( con.finalFrac > con.displayFrac ) - con.displayFrac = con.finalFrac; + con.vislines -= lines_per_frame; + if( con.showlines > con.vislines ) + con.vislines = con.showlines; } - else if( con.finalFrac > con.displayFrac ) + else if( con.showlines > con.vislines ) { - con.displayFrac += fabs( scr_conspeed->value ) * 0.002f * host.realframetime; - if( con.finalFrac < con.displayFrac ) - con.displayFrac = con.finalFrac; + con.vislines += lines_per_frame; + if( con.showlines < con.vislines ) + con.vislines = con.showlines; } } @@ -2038,6 +2140,14 @@ void Con_CharEvent( int key ) } } +/* +========= +Con_VidInit + +reload background +resize console +========= +*/ void Con_VidInit( void ) { Con_CheckResize(); @@ -2095,6 +2205,12 @@ void Con_VidInit( void ) Con_LoadConchars(); } +/* +========= +Con_InvalidateFonts + +========= +*/ void Con_InvalidateFonts( void ) { memset( con.chars, 0, sizeof( con.chars )); @@ -2127,12 +2243,19 @@ void Cmd_AutoComplete( char *complete_string ) else Q_strncpy( complete_string, input.buffer, sizeof( input.buffer )); } -void Con_Close( void ) +/* +========= +Con_FastClose + +immediately close the console +========= +*/ +void Con_FastClose( void ) { Con_ClearField( &con.input ); Con_ClearNotify(); - con.finalFrac = 0.0f; // none visible - con.displayFrac = 0.0f; + con.showlines = 0; + con.vislines = 0; } /* diff --git a/engine/common/crtlib.c b/engine/common/crtlib.c index 14a4ac34..352d6799 100644 --- a/engine/common/crtlib.c +++ b/engine/common/crtlib.c @@ -71,6 +71,29 @@ int Q_strlen( const char *string ) return len; } +int Q_colorstr( const char *string ) +{ + int len; + const char *p; + + if( !string ) return 0; + + len = 0; + p = string; + while( *p ) + { + if( IsColorString( p )) + { + len += 2; + p += 2; + continue; + } + p++; + } + + return len; +} + char Q_toupper( const char in ) { char out; diff --git a/engine/common/crtlib.h b/engine/common/crtlib.h index 0f35e0d0..4d5bafad 100644 --- a/engine/common/crtlib.h +++ b/engine/common/crtlib.h @@ -138,6 +138,7 @@ void Q_strnupr( const char *in, char *out, size_t size_out ); #define Q_strlwr( int, out ) Q_strnlwr( in, out, 99999 ) void Q_strnlwr( const char *in, char *out, size_t size_out ); int Q_strlen( const char *string ); +int Q_colorstr( const char *string ); char Q_toupper( const char in ); char Q_tolower( const char in ); #define Q_strcat( dst, src ) Q_strncat( dst, src, 99999 ) diff --git a/engine/common/cvar.c b/engine/common/cvar.c index 6875cd02..6d7453dd 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -969,6 +969,7 @@ void Cvar_List_f( void ) { convar_t *var; char *match = NULL; + char *value; int i = 0; if( Cmd_Argc() > 1 ) @@ -982,9 +983,13 @@ void Cvar_List_f( void ) if( match && !Q_stricmpext( match, var->name )) continue; + if( Q_colorstr( var->string )) + value = va( "\"%s\"", var->string ); + else value = va( "\"^2%s^7\"", var->string ); + if( FBitSet( var->flags, CVAR_SERVERDLL )) - Msg( " %-*s \"^2%s^7\" ^3%s^7\n", 32, var->name, var->string, "server cvar" ); - else Msg( " %-*s \"^2%s^7\" ^3%s^7\n", 32, var->name, var->string, var->description ); + Msg( " %-*s %s ^3%s^7\n", 32, var->name, value, "server cvar" ); + else Msg( " %-*s %s ^3%s^7\n", 32, var->name, value, var->description ); i++; } diff --git a/engine/common/filesystem.c b/engine/common/filesystem.c index 08c790ea..df1d4fda 100644 --- a/engine/common/filesystem.c +++ b/engine/common/filesystem.c @@ -24,14 +24,26 @@ GNU General Public License for more details. #include "library.h" #include "mathlib.h" -#define FILE_BUFF_SIZE 2048 +#define FILE_COPY_SIZE (1024 * 1024) +#define FILE_BUFF_SIZE (65535) + +// PAK errors #define PAK_LOAD_OK 0 #define PAK_LOAD_COULDNT_OPEN 1 #define PAK_LOAD_BAD_HEADER 2 #define PAK_LOAD_BAD_FOLDERS 3 #define PAK_LOAD_TOO_MANY_FILES 4 #define PAK_LOAD_NO_FILES 5 -#define PAK_LOAD_CORRUPTED 6 +#define PAK_LOAD_CORRUPTED 6 + +// WAD errors +#define WAD_LOAD_OK 0 +#define WAD_LOAD_COULDNT_OPEN 1 +#define WAD_LOAD_BAD_HEADER 2 +#define WAD_LOAD_BAD_FOLDERS 3 +#define WAD_LOAD_TOO_MANY_FILES 4 +#define WAD_LOAD_NO_FILES 5 +#define WAD_LOAD_CORRUPTED 6 typedef struct stringlist_s { @@ -55,14 +67,14 @@ typedef struct file_s long offset; // offset into the package (0 if external file) int ungetc; // single stored character from ungetc, cleared to EOF when read time_t filetime; // pak, wad or real filetime - // Contents buffer + // contents buffer long buff_ind, buff_len; // buffer current index and length byte buff[FILE_BUFF_SIZE]; // intermediate buffer }; typedef struct wfile_s { - char filename[MAX_SYSPATH]; + string filename; int infotableofs; byte *mempool; // W_ReadLump temp buffers int numlumps; @@ -72,46 +84,40 @@ typedef struct wfile_s time_t filetime; }; -typedef struct packfile_s -{ - char name[56]; - long offset; - long realsize; // real file size (uncompressed) -} packfile_t; - typedef struct pack_s { - char filename[MAX_SYSPATH]; + string filename; int handle; int numfiles; time_t filetime; // common for all packed files - packfile_t *files; + dpackfile_t *files; } pack_t; typedef struct searchpath_s { - char filename[MAX_SYSPATH]; + string filename; pack_t *pack; wfile_t *wad; int flags; struct searchpath_s *next; } searchpath_t; -byte *fs_mempool; -searchpath_t *fs_searchpaths = NULL; -searchpath_t fs_directpath; // static direct path -char fs_rootdir[MAX_SYSPATH]; // engine root directory -char fs_basedir[MAX_SYSPATH]; // base directory of game -char fs_falldir[MAX_SYSPATH]; // game falling directory -char fs_gamedir[MAX_SYSPATH]; // game current directory -char gs_basedir[MAX_SYSPATH]; // initial dir before loading gameinfo.txt (used for compilers too) -qboolean fs_ext_path = false; // attempt to read\write from ./ or ../ pathes +byte *fs_mempool; +searchpath_t *fs_searchpaths = NULL; // chain +searchpath_t fs_directpath; // static direct path +char fs_rootdir[MAX_SYSPATH]; // engine root directory +char fs_basedir[MAX_SYSPATH]; // base directory of game +char fs_falldir[MAX_SYSPATH]; // game falling directory +char fs_gamedir[MAX_SYSPATH]; // game current directory +char gs_basedir[MAX_SYSPATH]; // initial dir before loading gameinfo.txt (used for compilers too) +qboolean fs_ext_path = false; // attempt to read\write from ./ or ../ pathes +static const wadtype_t wad_hints[10]; static void FS_InitMemory( void ); const char *FS_FileExtension( const char *in ); static searchpath_t *FS_FindFile( const char *name, int *index, qboolean gamedironly ); static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const char matchtype ); -static packfile_t* FS_AddFileToPack( const char* name, pack_t *pack, long offset, long size ); +static dpackfile_t* FS_AddFileToPack( const char* name, pack_t *pack, long offset, long size ); static byte *W_LoadFile( const char *path, long *filesizeptr, qboolean gamedironly ); static qboolean FS_SysFileExists( const char *path ); static qboolean FS_SysFolderExists( const char *path ); @@ -126,56 +132,53 @@ FILEMATCH COMMON SYSTEM ============================================================================= */ -int matchpattern( const char *in, const char *pattern, qboolean caseinsensitive ) +int matchpattern( const char *str, const char *cmp, qboolean caseinsensitive ) { int c1, c2; - while( *pattern ) + while( *cmp ) { - switch( *pattern ) + switch( *cmp ) { case 0: return 1; // end of pattern case '?': // match any single character - if( *in == 0 || *in == '/' || *in == '\\' || *in == ':' ) + if( *str == 0 || *str == '/' || *str == '\\' || *str == ':' ) return 0; // no match - in++; - pattern++; + str++; + cmp++; break; case '*': // match anything until following string - if( !*in ) return 1; // match - pattern++; - while( *in ) + if( !*str ) return 1; // match + cmp++; + while( *str ) { - if( *in == '/' || *in == '\\' || *in == ':' ) + if( *str == '/' || *str == '\\' || *str == ':' ) break; // see if pattern matches at this offset - if( matchpattern( in, pattern, caseinsensitive )) + if( matchpattern( str, cmp, caseinsensitive )) return 1; // nope, advance to next offset - in++; + str++; } break; default: - if( *in != *pattern ) + if( *str != *cmp ) { if( !caseinsensitive ) return 0; // no match - c1 = *in; - if( c1 >= 'A' && c1 <= 'Z' ) - c1 += 'a' - 'A'; - c2 = *pattern; - if( c2 >= 'A' && c2 <= 'Z' ) - c2 += 'a' - 'A'; - if( c1 != c2) return 0; // no match + c1 = Q_tolower( *str ); + c2 = Q_tolower( *cmp ); + if( c1 != c2 ) return 0; // no match } - in++; - pattern++; + + str++; + cmp++; break; } } - if( *in ) return 0; // reached end of pattern but not end of input - return 1; // success + // reached end of pattern but not end of input? + return (*str) ? 0 : 1; } void stringlistinit( stringlist_t *list ) @@ -194,23 +197,25 @@ void stringlistfreecontents( stringlist_t *list ) list->strings[i] = NULL; } + if( list->strings ) + Mem_Free( list->strings ); + list->numstrings = 0; list->maxstrings = 0; - if( list->strings ) Mem_Free( list->strings ); + list->strings = NULL; } void stringlistappend( stringlist_t *list, char *text ) { size_t textlen; - char **oldstrings; + + if( !Q_stricmp( text, "." ) || !Q_stricmp( text, ".." )) + return; // ignore the virtual directories if( list->numstrings >= list->maxstrings ) { - oldstrings = list->strings; list->maxstrings += 4096; - list->strings = Mem_Alloc( fs_mempool, list->maxstrings * sizeof( *list->strings )); - if( list->numstrings ) memcpy( list->strings, oldstrings, list->numstrings * sizeof( *list->strings )); - if( oldstrings ) Mem_Free( oldstrings ); + list->strings = Mem_Realloc( fs_mempool, list->strings, list->maxstrings * sizeof( *list->strings )); } textlen = Q_strlen( text ) + 1; @@ -221,8 +226,8 @@ void stringlistappend( stringlist_t *list, char *text ) void stringlistsort( stringlist_t *list ) { - int i, j; char *temp; + int i, j; // this is a selection sort (finds the best entry for each slot) for( i = 0; i < list->numstrings - 1; i++ ) @@ -241,10 +246,11 @@ void stringlistsort( stringlist_t *list ) void listdirectory( stringlist_t *list, const char *path ) { - int i; - char pattern[4096], *c; + char pattern[4096]; struct _finddata_t n_file; long hFile; + char *c; + int i; Q_strncpy( pattern, path, sizeof( pattern )); Q_strncat( pattern, "*", sizeof( pattern )); @@ -264,10 +270,7 @@ void listdirectory( stringlist_t *list, const char *path ) for( i = 0; i < list->numstrings; i++ ) { for( c = list->strings[i]; *c; c++ ) - { - if( *c >= 'A' && *c <= 'Z' ) - *c += 'a' - 'A'; - } + *c = Q_tolower( *c ); } } @@ -285,10 +288,10 @@ FS_AddFileToPack Add a file to the list of files contained into a package ==================== */ -static packfile_t* FS_AddFileToPack( const char* name, pack_t* pack, long offset, long size ) +static dpackfile_t* FS_AddFileToPack( const char* name, pack_t* pack, long offset, long size ) { int left, right, middle; - packfile_t *pfile; + dpackfile_t *pfile; // look for the slot we should put that file into (binary search) left = 0; @@ -301,7 +304,7 @@ static packfile_t* FS_AddFileToPack( const char* name, pack_t* pack, long offset diff = Q_stricmp( pack->files[middle].name, name ); // If we found the file, there's a problem - if( !diff ) MsgDev( D_NOTE, "Package %s contains the file %s several times\n", pack->filename, name ); + if( !diff ) MsgDev( D_WARN, "Package %s contains the file %s several times\n", pack->filename, name ); // If we're too far in the list if( diff > 0 ) right = middle - 1; @@ -314,8 +317,8 @@ static packfile_t* FS_AddFileToPack( const char* name, pack_t* pack, long offset pack->numfiles++; Q_strncpy( pfile->name, name, sizeof( pfile->name )); - pfile->offset = offset; - pfile->realsize = size; + pfile->filepos = offset; + pfile->filelen = size; return pfile; } @@ -363,7 +366,8 @@ void FS_Path_f( void ) else if( s->wad ) Msg( "%s (%i files)", s->wad->filename, s->wad->numlumps ); else Msg( "%s", s->filename ); - if( s->flags & FS_GAMEDIR_PATH ) Msg( " ^2gamedir^7\n" ); + if( FBitSet( s->flags, FS_GAMEDIR_PATH )) + Msg( " ^2gamedir^7\n" ); else Msg( "\n" ); } } @@ -436,8 +440,8 @@ of the list so they override previous pack files. pack_t *FS_LoadPackPAK( const char *packfile, int *error ) { dpackheader_t header; - int i, numpackfiles; int packhandle; + int i, numpackfiles; pack_t *pack; dpackfile_t *info; @@ -500,16 +504,14 @@ pack_t *FS_LoadPackPAK( const char *packfile, int *error ) pack = (pack_t *)Mem_Alloc( fs_mempool, sizeof( pack_t )); Q_strncpy( pack->filename, packfile, sizeof( pack->filename )); + pack->files = (dpackfile_t *)Mem_Alloc( fs_mempool, numpackfiles * sizeof( dpackfile_t )); + pack->filetime = FS_SysFileTime( packfile ); pack->handle = packhandle; pack->numfiles = 0; - pack->files = (packfile_t *)Mem_Alloc( fs_mempool, numpackfiles * sizeof( packfile_t )); - pack->filetime = FS_SysFileTime( packfile ); // parse the directory for( i = 0; i < numpackfiles; i++ ) - { FS_AddFileToPack( info[i].name, pack, info[i].filepos, info[i].filelen ); - } MsgDev( D_NOTE, "Adding packfile: %s (%i files)\n", packfile, numpackfiles ); if( error ) *error = PAK_LOAD_OK; @@ -520,7 +522,7 @@ pack_t *FS_LoadPackPAK( const char *packfile, int *error ) /* ================ -FS_AddPack_Fullpath +FS_AddPak_Fullpath Adds the given pack to the search path. The pack type is autodetected by the file extension. @@ -532,7 +534,7 @@ If keep_plain_dirs is set, the pack will be added AFTER the first sequence of plain directories. ================ */ -static qboolean FS_AddPack_Fullpath( const char *pakfile, qboolean *already_loaded, qboolean keep_plain_dirs, int flags ) +static qboolean FS_AddPak_Fullpath( const char *pakfile, qboolean *already_loaded, qboolean keep_plain_dirs, int flags ) { searchpath_t *search; pack_t *pak = NULL; @@ -558,7 +560,7 @@ static qboolean FS_AddPack_Fullpath( const char *pakfile, qboolean *already_load if( keep_plain_dirs ) { // find the first item whose next one is a pack or NULL - searchpath_t *insertion_point = 0; + searchpath_t *insertion_point = NULL; if( fs_searchpaths && !fs_searchpaths->pack ) { insertion_point = fs_searchpaths; @@ -603,7 +605,7 @@ static qboolean FS_AddPack_Fullpath( const char *pakfile, qboolean *already_load else { if( errorcode != PAK_LOAD_NO_FILES ) - MsgDev( D_ERROR, "FS_AddPack_Fullpath: unable to load pak \"%s\"\n", pakfile ); + MsgDev( D_ERROR, "FS_AddPak_Fullpath: unable to load pak \"%s\"\n", pakfile ); return false; } } @@ -613,11 +615,12 @@ static qboolean FS_AddPack_Fullpath( const char *pakfile, qboolean *already_load FS_AddWad_Fullpath ==================== */ -static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loaded, qboolean keep_plain_dirs ) +static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loaded, qboolean keep_plain_dirs, int flags ) { searchpath_t *search; wfile_t *wad = NULL; const char *ext = FS_FileExtension( wadfile ); + int errorcode = WAD_LOAD_COULDNT_OPEN; for( search = fs_searchpaths; search; search = search->next ) { @@ -629,7 +632,7 @@ static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loade } if( already_loaded ) *already_loaded = false; - if( !Q_stricmp( ext, "wad" )) wad = W_Open( wadfile, "rb" ); + if( !Q_stricmp( ext, "wad" )) wad = W_Open( wadfile, "rb", &errorcode ); else MsgDev( D_ERROR, "\"%s\" doesn't have a wad extension\n", wadfile ); if( wad ) @@ -656,6 +659,7 @@ static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loade search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t )); search->wad = wad; search->next = fs_searchpaths; + search->flags |= flags; fs_searchpaths = search; } else // otherwise we want to append directly after insertion_point. @@ -663,6 +667,7 @@ static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loade search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t )); search->wad = wad; search->next = insertion_point->next; + search->flags |= flags; insertion_point->next = search; } } @@ -671,6 +676,7 @@ static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loade search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t )); search->wad = wad; search->next = fs_searchpaths; + search->flags |= flags; fs_searchpaths = search; } @@ -679,7 +685,8 @@ static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loade } else { - MsgDev( D_ERROR, "FS_AddWad_Fullpath: unable to load wad \"%s\"\n", wadfile ); + if( errorcode != WAD_LOAD_NO_FILES ) + MsgDev( D_ERROR, "FS_AddWad_Fullpath: unable to load wad \"%s\"\n", wadfile ); return false; } } @@ -699,7 +706,7 @@ void FS_AddGameDirectory( const char *dir, int flags ) string fullpath; int i; - if(!( flags & FS_NOWRITE_PATH )) + if( !FBitSet( flags, FS_NOWRITE_PATH )) Q_strncpy( fs_gamedir, dir, sizeof( fs_gamedir )); stringlistinit( &list ); @@ -712,7 +719,7 @@ void FS_AddGameDirectory( const char *dir, int flags ) if( !Q_stricmp( FS_FileExtension( list.strings[i] ), "pak" )) { Q_sprintf( fullpath, "%s%s", dir, list.strings[i] ); - FS_AddPack_Fullpath( fullpath, NULL, false, flags ); + FS_AddPak_Fullpath( fullpath, NULL, false, flags ); } } @@ -722,7 +729,7 @@ void FS_AddGameDirectory( const char *dir, int flags ) if( !Q_stricmp( FS_FileExtension( list.strings[i] ), "wad" )) { Q_sprintf( fullpath, "%s%s", dir, list.strings[i] ); - FS_AddWad_Fullpath( fullpath, NULL, false ); + FS_AddWad_Fullpath( fullpath, NULL, false, flags ); } } @@ -761,13 +768,20 @@ const char *FS_FileExtension( const char *in ) separator = Q_strrchr( in, '/' ); backslash = Q_strrchr( in, '\\' ); - if( !separator || separator < backslash ) separator = backslash; + + if( !separator || separator < backslash ) + separator = backslash; + colon = Q_strrchr( in, ':' ); - if( !separator || separator < colon ) separator = colon; + + if( !separator || separator < colon ) + separator = colon; dot = Q_strrchr( in, '.' ); + if( dot == NULL || ( separator && ( dot < separator ))) return ""; + return dot + 1; } @@ -782,9 +796,15 @@ const char *FS_FileWithoutPath( const char *in ) separator = Q_strrchr( in, '/' ); backslash = Q_strrchr( in, '\\' ); - if( !separator || separator < backslash ) separator = backslash; + + if( !separator || separator < backslash ) + separator = backslash; + colon = Q_strrchr( in, ':' ); - if( !separator || separator < colon ) separator = colon; + + if( !separator || separator < colon ) + separator = colon; + return separator ? separator + 1 : in; } @@ -793,10 +813,9 @@ const char *FS_FileWithoutPath( const char *in ) FS_ExtractFilePath ============ */ -void FS_ExtractFilePath( const char* const path, char* dest ) +void FS_ExtractFilePath( const char *path, char *dest ) { - const char *src; - src = path + Q_strlen( path ) - 1; + const char *src = path + Q_strlen( path ) - 1; // back up until a \ or the start while( src != path && !(*(src - 1) == '\\' || *(src - 1) == '/' )) @@ -821,7 +840,9 @@ void FS_ClearSearchPath( void ) { searchpath_t *search = fs_searchpaths; - if( search->flags & FS_STATIC_PATH ) + if( !search ) break; + + if( FBitSet( search->flags, FS_STATIC_PATH )) { // skip read-only pathes if( search->next ) @@ -841,7 +862,7 @@ void FS_ClearSearchPath( void ) W_Close( search->wad ); } - if( search ) Mem_Free( search ); + Mem_Free( search ); } } @@ -874,15 +895,7 @@ int FS_CheckNastyPath( const char *path, qboolean isgamedir ) // Windows and UNIXes: don't allow absolute paths if( path[0] == '/' && !fs_ext_path ) return 2; // attempt to go outside the game directory -#if 0 - // all: don't allow . characters before the last slash (it should only be used in filenames, not path elements), - // this catches all imaginable cases of ./, ../, .../, etc - if( Q_strchr( path, '.' ) && !fs_ext_path ) - { - if( isgamedir ) return 2; // gamedir is entirely path elements, so simply forbid . entirely - if( Q_strchr( path, '.' ) < Q_strrchr( path, '/' )) return 2; // possible attempt to go outside the game directory - } -#endif + // all: forbid trailing slash on gamedir if( isgamedir && !fs_ext_path && path[Q_strlen( path )-1] == '/' ) return 2; @@ -912,55 +925,16 @@ void FS_Rescan( void ) FS_AddGameHierarchy( GI->gamedir, FS_GAMEDIR_PATH ); } +/* +================ +FS_Rescan_f +================ +*/ void FS_Rescan_f( void ) { FS_Rescan(); } -static qboolean FS_ParseVector( char **pfile, float *v, size_t size ) -{ - string token; - qboolean bracket = false; - char *saved; - uint i; - - if( v == NULL || size == 0 ) - return false; - - memset( v, 0, sizeof( *v ) * size ); - - if( size == 1 ) - { - *pfile = COM_ParseFile( *pfile, token ); - v[0] = Q_atof( token ); - return true; - } - - saved = *pfile; - - if(( *pfile = COM_ParseFile( *pfile, token )) == NULL ) - return false; - - if( token[0] == '(' ) - bracket = true; - else *pfile = saved; // restore token to right get it again - - for( i = 0; i < size; i++ ) - { - *pfile = COM_ParseFile( *pfile, token ); - v[i] = Q_atof( token ); - } - - if( !bracket ) return true; // done - - if(( *pfile = COM_ParseFile( *pfile, token )) == NULL ) - return false; - - if( token[0] == ')' ) - return true; - return false; -} - /* ================ FS_WriteGameInfo @@ -1113,6 +1087,11 @@ void FS_CreateDefaultGameInfo( const char *filename ) FS_WriteGameInfo( filename, &defGI ); } +/* +================ +FS_ParseLiblistGam +================ +*/ static qboolean FS_ParseLiblistGam( const char *filename, const char *gamedir, gameinfo_t *GameInfo ) { char *afile, *pfile; @@ -1461,8 +1440,8 @@ static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo ) } else { - FS_ParseVector( &pfile, GameInfo->client_mins[hullNum], 3 ); - FS_ParseVector( &pfile, GameInfo->client_maxs[hullNum], 3 ); + COM_ParseVector( &pfile, GameInfo->client_mins[hullNum], 3 ); + COM_ParseVector( &pfile, GameInfo->client_maxs[hullNum], 3 ); } } else if( !Q_strnicmp( token, "ambient", 7 )) @@ -1657,18 +1636,22 @@ static file_t* FS_SysOpen( const char* filepath, const char* mode ) // Parse the mode string switch( mode[0] ) { - case 'r': + case 'r': // read mod = O_RDONLY; opt = 0; break; - case 'w': + case 'w': // write mod = O_WRONLY; opt = O_CREAT | O_TRUNC; break; - case 'a': + case 'a': // append mod = O_WRONLY; opt = O_CREAT | O_APPEND; break; + case 'e': // edit + mod = O_WRONLY; + opt = O_CREAT; + break; default: MsgDev( D_ERROR, "FS_SysOpen(%s, %s): invalid mode\n", filepath, mode ); return NULL; @@ -1720,13 +1703,13 @@ Open a packed file using its package file descriptor */ file_t *FS_OpenPackedFile( pack_t *pack, int pack_ind ) { - packfile_t *pfile; + dpackfile_t *pfile; int dup_handle; file_t *file; pfile = &pack->files[pack_ind]; - if( lseek( pack->handle, pfile->offset, SEEK_SET ) == -1 ) + if( lseek( pack->handle, pfile->filepos, SEEK_SET ) == -1 ) return NULL; dup_handle = dup( pack->handle ); @@ -1735,10 +1718,9 @@ file_t *FS_OpenPackedFile( pack_t *pack, int pack_ind ) return NULL; file = (file_t *)Mem_Alloc( fs_mempool, sizeof( *file )); - memset( file, 0, sizeof( *file )); file->handle = dup_handle; - file->real_length = pfile->realsize; - file->offset = pfile->offset; + file->real_length = pfile->filelen; + file->offset = pfile->filepos; file->position = 0; file->ungetc = EOF; @@ -1755,10 +1737,10 @@ Look for a file in the filesystem only qboolean FS_SysFileExists( const char *path ) { int desc; - - desc = open( path, O_RDONLY|O_BINARY ); - if( desc < 0 ) return false; + if(( desc = open( path, O_RDONLY|O_BINARY )) < 0 ) + return false; + close( desc ); return true; } @@ -1774,7 +1756,7 @@ qboolean FS_SysFolderExists( const char *path ) { DWORD dwFlags = GetFileAttributes( path ); - return ( dwFlags != -1 ) && ( dwFlags & FILE_ATTRIBUTE_DIRECTORY ); + return ( dwFlags != -1 ) && FBitSet( dwFlags, FILE_ATTRIBUTE_DIRECTORY ); } /* @@ -1796,7 +1778,7 @@ static searchpath_t *FS_FindFile( const char *name, int* index, qboolean gamedir // search through the path, one element at a time for( search = fs_searchpaths; search; search = search->next ) { - if( gamedironly & !( search->flags & FS_GAMEDIR_PATH )) + if( gamedironly & !FBitSet( search->flags, FS_GAMEDIR_PATH )) continue; // is the element a pak file? @@ -1987,7 +1969,7 @@ file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly ) return NULL; // if the file is opened in "write", "append", or "read/write" mode - if( mode[0] == 'w' || mode[0] == 'a' || Q_strchr( mode, '+' )) + if( mode[0] == 'w' || mode[0] == 'a'|| mode[0] == 'e' || Q_strchr( mode, '+' )) { char real_path[MAX_SYSPATH]; @@ -2104,7 +2086,7 @@ long FS_Read( file_t *file, void *buffer, size_t buffersize ) { done += nb; file->position += nb; - // Purge cached data + // purge cached data FS_Purge( file ); } } @@ -2181,7 +2163,10 @@ int FS_VPrintf( file_t *file, const char* format, va_list ap ) { tempbuff = (char *)Mem_Alloc( fs_mempool, buff_size ); len = Q_vsprintf( tempbuff, format, ap ); - if( len >= 0 && len < buff_size ) break; + + if( len >= 0 && len < buff_size ) + break; + Mem_Free( tempbuff ); buff_size *= 2; } @@ -2251,7 +2236,8 @@ int FS_Gets( file_t *file, byte *string, size_t bufsize ) if( c == '\r' ) { c = FS_Getc( file ); - if( c != '\n' ) FS_UnGetc( file, (byte)c ); + if( c != '\n' ) + FS_UnGetc( file, (byte)c ); } return c; @@ -2281,7 +2267,7 @@ int FS_Seek( file_t *file, long offset, int whence ) return -1; } - if( offset < 0 || offset > (long)file->real_length ) + if( offset < 0 || offset > file->real_length ) return -1; // if we have the data in our read buffer, we don't need to actually seek @@ -2493,18 +2479,16 @@ const char *FS_GetDiskPath( const char *name, qboolean gamedironly ) { int index; searchpath_t *search; - + search = FS_FindFile( name, &index, gamedironly ); if( search ) { - if( index != -1 ) - { - // file in pack or wad + if( index != -1 ) // file in pack or wad return NULL; - } return va( "%s%s", search->filename, name ); } + return NULL; } @@ -2725,22 +2709,32 @@ FS_FileCopy ================== */ -void FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize ) +qboolean FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize ) { - char buf[MAX_SYSPATH]; // A small buffer for the copy - int size; + char *buf = Mem_Alloc( fs_mempool, FILE_COPY_SIZE ); + int size, readSize; + qboolean done = true; while( fileSize > 0 ) { - if( fileSize > MAX_SYSPATH ) - size = MAX_SYSPATH; + if( fileSize > FILE_COPY_SIZE ) + size = FILE_COPY_SIZE; else size = fileSize; - FS_Read( pInput, buf, size ); - FS_Write( pOutput, buf, size ); - + if(( readSize = FS_Read( pInput, buf, size )) < size ) + { + MsgDev( D_ERROR, "FS_FileCopy: unexpected end of input file\n" ); + fileSize = 0; + done = false; + break; + } + + FS_Write( pOutput, buf, readSize ); fileSize -= size; } + + Mem_Free( buf ); + return done; } /* @@ -2787,7 +2781,7 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly ) // search through the path, one element at a time for( searchpath = fs_searchpaths; searchpath; searchpath = searchpath->next ) { - if( gamedironly && !( searchpath->flags & FS_GAMEDIR_PATH )) + if( gamedironly && !FBitSet( searchpath->flags, FS_GAMEDIR_PATH )) continue; // is the element a pak file? @@ -2809,9 +2803,7 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly ) } if( resultlistindex == resultlist.numstrings ) - { stringlistappend( &resultlist, temp ); - } } // strip off one path element at a time until empty // this way directories are added to the listing if they match the pattern @@ -2866,7 +2858,9 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly ) if( type != TYP_ANY && wad->lumps[i].type != type ) continue; - Q_strncpy( temp, wad->lumps[i].name, sizeof( temp )); + // build the lumpname with image suffix (if present) + Q_snprintf( temp, sizeof( temp ), "%s%s", wad->lumps[i].name, wad_hints[wad->lumps[i].img_type].ext ); + while( temp[0] ) { if( matchpattern( temp, wadpattern, true )) @@ -2920,11 +2914,10 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly ) } if( resultlistindex == resultlist.numstrings ) - { stringlistappend( &resultlist, temp ); - } } } + stringlistfreecontents( &dirlist ); } } @@ -3006,6 +2999,13 @@ static const wadtype_t wad_hints[10] = { NULL, 0 } // terminator }; +/* +=========== +W_TypeFromExt + +Extracts file type from extension +=========== +*/ static char W_TypeFromExt( const char *lumpname ) { const char *ext = FS_FileExtension( lumpname ); @@ -3080,6 +3080,13 @@ char W_HintFromSuf( const char *lumpname ) return IMG_DIFFUSE; } +/* +=========== +W_FindLump + +Serach for already existed lump +=========== +*/ static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const char matchtype ) { char img_type = IMG_DIFFUSE; @@ -3147,9 +3154,10 @@ static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const char match /* ==================== -FS_AddFileToWad +W_AddFileToWad Add a file to the list of files contained into a package +and sort LAT in alpha-bethical order ==================== */ static dlumpinfo_t *W_AddFileToWad( const char *name, wfile_t *wad, dlumpinfo_t *newlump ) @@ -3157,14 +3165,6 @@ static dlumpinfo_t *W_AddFileToWad( const char *name, wfile_t *wad, dlumpinfo_t int left, right; dlumpinfo_t *plump; - // convert all qmip types to miptex - if( newlump->type == TYP_RAWDATA ) - newlump->type = TYP_MIPTEX; - - // check for Quake 'conchars' issues (only lmp loader supposed to read this lame pic) - if( !Q_stricmp( newlump->name, "conchars" ) && newlump->type == TYP_RAWDATA ) - newlump->type = TYP_GFXPIC; - // look for the slot we should put that file into (binary search) left = 0; right = wad->numlumps - 1; @@ -3184,7 +3184,7 @@ static dlumpinfo_t *W_AddFileToWad( const char *name, wfile_t *wad, dlumpinfo_t diff = 1; else if( wad->lumps[middle].type > newlump->type ) diff = -1; - else MsgDev( D_NOTE, "Wad %s contains the file %s several times\n", wad->filename, name ); + else MsgDev( D_WARN, "Wad %s contains the file %s several times\n", wad->filename, name ); } // If we're too far in the list @@ -3203,53 +3203,17 @@ static dlumpinfo_t *W_AddFileToWad( const char *name, wfile_t *wad, dlumpinfo_t return plump; } -static qboolean W_ReadLumpTable( wfile_t *wad ) -{ - size_t lat_size; - dlumpinfo_t *srclumps; - int i, k, numlumps; - - // nothing to convert ? - if( !wad || !wad->numlumps ) - return false; - - lat_size = wad->numlumps * sizeof( dlumpinfo_t ); - srclumps = (dlumpinfo_t *)Mem_Alloc( wad->mempool, lat_size ); - numlumps = wad->numlumps; - wad->numlumps = 0; // reset it - - if( read( wad->handle, srclumps, lat_size ) != lat_size ) - { - MsgDev( D_ERROR, "W_ReadLumpTable: %s has corrupted lump allocation table\n", wad->filename ); - W_Close( wad ); - return false; - } - - // swap everything - for( i = 0; i < numlumps; i++ ) - { - char name[16]; - - // cleanup lumpname - Q_strnlwr( srclumps[i].name, name, sizeof( srclumps[i].name )); - - // check for '*' symbol issues - k = Q_strlen( Q_strrchr( name, '*' )); - if( k ) name[Q_strlen( name ) - k] = '!'; // quake1 issues (can't save images that contain '*' symbol) - - W_AddFileToWad( name, wad, &srclumps[i] ); - } - - // release source lumps - Mem_Free( srclumps ); - - return true; -} - -byte *W_ReadLump( wfile_t *wad, dlumpinfo_t *lump, size_t *lumpsizeptr ) +/* +=========== +W_ReadLump + +reading lump into temp buffer +=========== +*/ +byte *W_ReadLump( wfile_t *wad, dlumpinfo_t *lump, long *lumpsizeptr ) { + size_t oldpos, size = 0; byte *buf; - size_t size = 0; // assume error if( lumpsizeptr ) *lumpsizeptr = 0; @@ -3257,9 +3221,12 @@ byte *W_ReadLump( wfile_t *wad, dlumpinfo_t *lump, size_t *lumpsizeptr ) // no wads loaded if( !wad || !lump ) return NULL; + oldpos = tell( wad->handle ); // don't forget restore original position + if( lseek( wad->handle, lump->filepos, SEEK_SET ) == -1 ) { MsgDev( D_ERROR, "W_ReadLump: %s is corrupted\n", lump->name ); + lseek( wad->handle, oldpos, SEEK_SET ); return NULL; } @@ -3268,14 +3235,48 @@ byte *W_ReadLump( wfile_t *wad, dlumpinfo_t *lump, size_t *lumpsizeptr ) if( size < lump->disksize ) { MsgDev( D_WARN, "W_ReadLump: %s is probably corrupted\n", lump->name ); + lseek( wad->handle, oldpos, SEEK_SET ); Mem_Free( buf ); return NULL; } + if( lumpsizeptr ) *lumpsizeptr = lump->size; + lseek( wad->handle, oldpos, SEEK_SET ); + return buf; } +/* +=========== +W_WriteLump + +compress and write lump +=========== +*/ +qboolean W_WriteLump( wfile_t *wad, dlumpinfo_t *lump, const void *data, size_t datasize ) +{ + if( !wad || !lump ) return false; + + if( !data || !datasize ) + { + MsgDev( D_WARN, "W_WriteLump: ignore blank lump %s - nothing to save\n", lump->name ); + return false; + } + + if( wad->mode == O_RDONLY ) + { + MsgDev( D_ERROR, "W_WriteLump: %s opened in readonly mode\n", wad->filename ); + return false; + } + + lump->size = lump->disksize = datasize; + + if( write( wad->handle, data, datasize ) == datasize ) + return true; + return false; +} + /* ============================================================================= @@ -3283,32 +3284,80 @@ WADSYSTEM PUBLIC BASE FUNCTIONS ============================================================================= */ -wfile_t *W_Open( const char *filename, const char *mode ) +/* +=========== +W_Open + +open the wad for reading & writing +=========== +*/ +wfile_t *W_Open( const char *filename, const char *mode, int *error ) { dwadinfo_t header; wfile_t *wad = (wfile_t *)Mem_Alloc( fs_mempool, sizeof( wfile_t )); - const char *comment = "Generated by Xash WadLib. "; + const char *comment = "Created by Xash3D Engine.\0"; + int i, ind, mod, opt, lumpcount; + size_t wadsize, lat_size; + dlumpinfo_t *srclumps; - if( mode[0] == 'a' ) wad->handle = open( filename, O_RDWR|O_BINARY, 0x666 ); - else if( mode[0] == 'w' ) wad->handle = open( filename, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0x666 ); - else if( mode[0] == 'r' ) wad->handle = open( filename, O_RDONLY|O_BINARY, 0x666 ); + // parse the mode string + switch( mode[0] ) + { + case 'r': + mod = O_RDONLY; + opt = 0; + break; + case 'w': + mod = O_WRONLY; + opt = O_CREAT|O_TRUNC; + break; + case 'a': + mod = O_WRONLY; + opt = O_CREAT; + break; + default: + MsgDev( D_ERROR, "W_Open(%s, %s): invalid mode\n", filename, mode ); + return NULL; + } + + for( ind = 1; mode[ind] != '\0'; ind++ ) + { + switch( mode[ind] ) + { + case '+': + mod = O_RDWR; + break; + case 'b': + opt |= O_BINARY; + break; + default: + MsgDev( D_ERROR, "W_Open: %s: unknown char in mode (%c)\n", filename, mode, mode[ind] ); + break; + } + } + + wad->handle = open( filename, mod|opt, 0666 ); if( wad->handle < 0 ) { - W_Close( wad ); MsgDev( D_ERROR, "W_Open: couldn't open %s\n", filename ); + if( error ) *error = WAD_LOAD_COULDNT_OPEN; + W_Close( wad ); return NULL; } // copy wad name Q_strncpy( wad->filename, filename, sizeof( wad->filename )); - wad->mempool = Mem_AllocPool( filename ); wad->filetime = FS_SysFileTime( filename ); + wad->mempool = Mem_AllocPool( filename ); + + wadsize = lseek( wad->handle, 0, SEEK_END ); + lseek( wad->handle, 0, SEEK_SET ); // if the file is opened in "write", "append", or "read/write" mode - if( mode[0] == 'w' ) + if( mod == O_WRONLY || !wadsize ) { - dwadinfo_t hdr; + dwadinfo_t hdr; wad->numlumps = 0; // blank wad wad->lumps = NULL; // @@ -3322,95 +3371,122 @@ wfile_t *W_Open( const char *filename, const char *mode ) write( wad->handle, comment, Q_strlen( comment ) + 1 ); wad->infotableofs = tell( wad->handle ); } - else if( mode[0] == 'r' || mode[0] == 'a' ) + else if( mod == O_RDWR || mod == O_RDONLY ) { - if( mode[0] == 'a' ) - { - lseek( wad->handle, 0, SEEK_SET ); + if( mod == O_RDWR ) wad->mode = O_APPEND; - } + else wad->mode = O_RDONLY; if( read( wad->handle, &header, sizeof( dwadinfo_t )) != sizeof( dwadinfo_t )) { MsgDev( D_ERROR, "W_Open: %s can't read header\n", filename ); + if( error ) *error = WAD_LOAD_BAD_HEADER; W_Close( wad ); return NULL; } - switch( header.ident ) + if( header.ident != IDWAD3HEADER ) { - case IDWAD2HEADER: - case IDWAD3HEADER: - break; // WAD2, WAD3 allow r\w mode - default: - MsgDev( D_ERROR, "W_Open: %s unknown wadtype\n", filename ); + MsgDev( D_ERROR, "W_Open: %s is not a WAD3 file\n", filename ); + if( error ) *error = WAD_LOAD_BAD_HEADER; W_Close( wad ); return NULL; } - wad->numlumps = header.numlumps; - if( wad->numlumps >= MAX_FILES_IN_WAD && wad->mode == O_APPEND ) + lumpcount = header.numlumps; + + if( lumpcount >= MAX_FILES_IN_WAD && wad->mode == O_APPEND ) { - MsgDev( D_WARN, "W_Open: %s is full (%i lumps)\n", wad->numlumps ); + MsgDev( D_WARN, "W_Open: %s is full (%i lumps)\n", filename, lumpcount ); + if( error ) *error = WAD_LOAD_TOO_MANY_FILES; wad->mode = O_RDONLY; // set read-only mode } + else if( lumpcount <= 0 && wad->mode == O_RDONLY ) + { + MsgDev( D_ERROR, "W_Open: %s has no lumps\n", filename ); + if( error ) *error = WAD_LOAD_NO_FILES; + W_Close( wad ); + return NULL; + } + else if( error ) *error = WAD_LOAD_OK; + wad->infotableofs = header.infotableofs; // save infotableofs position + if( lseek( wad->handle, wad->infotableofs, SEEK_SET ) == -1 ) { MsgDev( D_ERROR, "W_Open: %s can't find lump allocation table\n", filename ); + if( error ) *error = WAD_LOAD_BAD_FOLDERS; W_Close( wad ); return NULL; } + lat_size = lumpcount * sizeof( dlumpinfo_t ); + // NOTE: lumps table can be reallocated for O_APPEND mode - wad->lumps = Mem_Alloc( wad->mempool, wad->numlumps * sizeof( dlumpinfo_t )); + srclumps = (dlumpinfo_t *)Mem_Alloc( wad->mempool, lat_size ); - if( wad->mode == O_APPEND ) - { - size_t lat_size = wad->numlumps * sizeof( dlumpinfo_t ); - - if( read( wad->handle, wad->lumps, lat_size ) != lat_size ) - { - MsgDev( D_ERROR, "W_ReadLumpTable: %s has corrupted lump allocation table\n", wad->filename ); - W_Close( wad ); - return NULL; - } - - // if we are in append mode - we need started from infotableofs poisition - // overwrite lumptable as well, we have her copy in wad->lumps - lseek( wad->handle, wad->infotableofs, SEEK_SET ); - } - else + if( read( wad->handle, srclumps, lat_size ) != lat_size ) { - // setup lump allocation table - switch( header.ident ) - { - case IDWAD2HEADER: - case IDWAD3HEADER: - if(!W_ReadLumpTable( wad )) - return NULL; - break; - } + MsgDev( D_ERROR, "W_ReadLumpTable: %s has corrupted lump allocation table\n", wad->filename ); + if( error ) *error = WAD_LOAD_CORRUPTED; + Mem_Free( srclumps ); + W_Close( wad ); + return NULL; } + + // starting to add lumps + wad->lumps = (dlumpinfo_t *)Mem_Alloc( wad->mempool, lat_size ); + wad->numlumps = 0; + + // sort lumps for binary search + for( i = 0; i < lumpcount; i++ ) + { + char name[16]; + int k; + + // cleanup lumpname + Q_strnlwr( srclumps[i].name, name, sizeof( srclumps[i].name )); + + // check for '*' symbol issues (quake1) + k = Q_strlen( Q_strrchr( name, '*' )); + if( k ) name[Q_strlen( name ) - k] = '!'; + + W_AddFileToWad( name, wad, &srclumps[i] ); + } + + // release source lumps + Mem_Free( srclumps ); + + // if we are in append mode - we need started from infotableofs poisition + // overwrite lumptable as well, we have her copy in wad->lumps + if( wad->mode == O_APPEND ) + lseek( wad->handle, wad->infotableofs, SEEK_SET ); } - // and leaves the file open + + // and leave the file open return wad; } +/* +=========== +W_Close + +finalize wad or just close +=========== +*/ void W_Close( wfile_t *wad ) { - long ofs; - if( !wad ) return; if( wad->handle >= 0 && ( wad->mode == O_APPEND || wad->mode == O_WRONLY )) { dwadinfo_t hdr; + long ofs; // write the lumpinfo ofs = tell( wad->handle ); write( wad->handle, wad->lumps, wad->numlumps * sizeof( dlumpinfo_t )); - + // write the header hdr.ident = IDWAD3HEADER; hdr.numlumps = wad->numlumps; @@ -3421,7 +3497,9 @@ void W_Close( wfile_t *wad ) } Mem_FreePool( &wad->mempool ); - if( wad->handle >= 0 ) close( wad->handle ); + if( wad->handle >= 0 ) + close( wad->handle ); + Mem_Free( wad ); // free himself } @@ -3432,6 +3510,126 @@ FILESYSTEM IMPLEMENTATION ============================================================================= */ +/* +=========== +W_SaveLump + +write new or replace existed lump +=========== +*/ +size_t W_SaveFile( wfile_t *wad, const char *lump, const void *data, size_t datasize, char type, qboolean replace ) +{ + dlumpinfo_t *find, newlump; + size_t lat_size, oldpos; + char hint, lumpname[64]; + + if( !wad || !lump ) return -1; + + if( !data || !datasize ) + { + MsgDev( D_WARN, "W_SaveLump: ignore blank lump %s - nothing to save\n", lump ); + return -1; + } + + if( wad->mode == O_RDONLY ) + { + MsgDev( D_ERROR, "W_SaveLump: %s opened in readonly mode\n", wad->filename ); + return -1; + } + + if( wad->numlumps >= MAX_FILES_IN_WAD ) + { + MsgDev( D_ERROR, "W_SaveLump: %s is full\n", wad->filename ); + return -1; + } + + find = W_FindLump( wad, lump, type ); + + if( find != NULL && replace ) + { + if( FBitSet( find->attribs, ATTR_READONLY )) + { + // g-cont. i left this limitation as a protect of the replacement of compressed lumps + MsgDev( D_ERROR, "W_ReplaceLump: %s is read-only\n", find->name ); + return -1; + } + + if( datasize != find->size ) + { + MsgDev( D_ERROR, "W_ReplaceLump: %s [%s] should be [%s]\n", + lumpname, Q_memprint( datasize ), Q_memprint( find->size )); + return -1; + } + + oldpos = tell( wad->handle ); // don't forget restore original position + + if( lseek( wad->handle, find->filepos, SEEK_SET ) == -1 ) + { + MsgDev( D_ERROR, "W_ReplaceLump: %s is corrupted\n", find->name ); + lseek( wad->handle, oldpos, SEEK_SET ); + return -1; + } + + if( write( wad->handle, data, datasize ) != find->disksize ) + MsgDev( D_WARN, "W_ReplaceLump: %s probably replaced with errors\n", find->name ); + + // restore old position + lseek( wad->handle, oldpos, SEEK_SET ); + + return wad->numlumps; + } + else + { + MsgDev( D_ERROR, "W_SaveLump: %s already exist\n", lump ); + return -1; + } + + // prepare lump name + Q_strncpy( lumpname, lump, sizeof( lumpname )); + + // extract image hint + hint = W_HintFromSuf( lumpname ); + + if( hint != IMG_DIFFUSE ) + lumpname[Q_strlen( lumpname ) - HINT_NAMELEN] = '\0'; // kill the suffix + + if( Q_strlen( lumpname ) >= WAD3_NAMELEN ) + { + // name is too long + MsgDev( D_ERROR, "W_SaveLump: %s more than %i symbols\n", lumpname, WAD3_NAMELEN ); + return -1; + } + + lat_size = sizeof( dlumpinfo_t ) * (wad->numlumps + 1); + + // reallocate lumptable + wad->lumps = (dlumpinfo_t *)Mem_Realloc( wad->mempool, wad->lumps, lat_size ); + + memset( &newlump, 0, sizeof( newlump )); + + // write header + Q_strnupr( lumpname, newlump.name, WAD3_NAMELEN ); + newlump.filepos = tell( wad->handle ); + newlump.attribs = ATTR_NONE; + newlump.img_type = hint; + newlump.type = type; + + if( !W_WriteLump( wad, &newlump, data, datasize )) + return -1; + + // record entry and re-sort table + W_AddFileToWad( lumpname, wad, &newlump ); + + return wad->numlumps; +} + +/* +=========== +W_LoadFile + +loading lump into the tmp buffer +=========== +*/ static byte *W_LoadFile( const char *path, long *lumpsizeptr, qboolean gamedironly ) { searchpath_t *search; diff --git a/engine/common/filesystem.h b/engine/common/filesystem.h index 54583ec9..2d56e62c 100644 --- a/engine/common/filesystem.h +++ b/engine/common/filesystem.h @@ -58,9 +58,6 @@ file_n: byte[dwadinfo_t[num]->disksize] infotable dlumpinfo_t[dwadinfo_t->numlumps] ======================================================================== */ -#define IDWAD2HEADER (('2'<<24)+('D'<<16)+('A'<<8)+'W') // little-endian "WAD2" quake1 gfx.wad -#define IDWAD3HEADER (('3'<<24)+('D'<<16)+('A'<<8)+'W') // little-endian "WAD3" half-life wads - #define WAD3_NAMELEN 16 #define HINT_NAMELEN 5 // e.g. _mask, _norm #define MAX_FILES_IN_WAD 65535 // real limit as above <2Gb size not a lumpcount @@ -73,9 +70,9 @@ infotable dlumpinfo_t[dwadinfo_t->numlumps] typedef struct { - int ident; // should be IWAD, WAD2 or WAD3 + int ident; // should be WAD3 int numlumps; // num files - int infotableofs; + int infotableofs; // LUT offset } dwadinfo_t; typedef struct diff --git a/engine/common/gamma.c b/engine/common/gamma.c index 1eca92d4..c0632896 100644 --- a/engine/common/gamma.c +++ b/engine/common/gamma.c @@ -22,8 +22,6 @@ GNU General Public License for more details. //----------------------------------------------------------------------------- static byte gammatable[256]; static byte texgammatable[256]; // palette is sent through this to convert to screen gamma -static float texturetolinear[256]; // texture (0..255) to linear (0..1) -static int lineartotexture[1024]; // linear (0..1) to texture (0..255) void BuildGammaTable( float gamma, float texGamma ) { @@ -49,18 +47,6 @@ void BuildGammaTable( float gamma, float texGamma ) inf = (int)(f + 0.5f); gammatable[i] = bound( 0, inf, 255 ); } - - for( i = 0; i < 256; i++ ) - { - // convert from nonlinear texture space (0..255) to linear space (0..1) - texturetolinear[i] = pow( i / 255.0, GAMMA ); - } - - for( i = 0; i < 1024; i++ ) - { - // convert from linear space (0..1) to nonlinear texture space (0..255) - lineartotexture[i] = pow( i / 1023.0, INVGAMMA ) * 255; - } } byte TextureToTexGamma( byte b ) @@ -79,10 +65,4 @@ byte TextureToGamma( byte b ) b = bound( 0, b, 255 ); return gammatable[b]; -} - -// convert texture to linear 0..1 value -float TextureToLinear( int c ) { return texturetolinear[bound( 0, c, 255 )]; } - -// convert texture to linear 0..1 value -int LinearToTexture( float f ) { return lineartotexture[bound( 0, (int)(f * 1023), 1023 )]; } \ No newline at end of file +} \ No newline at end of file diff --git a/engine/common/host.c b/engine/common/host.c index 1419fc5c..e0c5e3b8 100644 --- a/engine/common/host.c +++ b/engine/common/host.c @@ -234,10 +234,10 @@ void Host_Exec_f( void ) return; } - // HACKHACK: don't execute listenserver.cfg in singleplayer + // don't execute listenserver.cfg in singleplayer if( !Q_stricmp( Cvar_VariableString( "lservercfgfile" ), Cmd_Argv( 1 ))) { - if( Cvar_VariableValue( "maxplayers" ) == 1.0f ) + if( Cvar_VariableInteger( "maxplayers" ) == 1 ) return; } @@ -828,7 +828,9 @@ void Host_InitCommon( const char *progname, qboolean bChangeGame ) host.mempool = Mem_AllocPool( "Zone Engine" ); - if( Sys_CheckParm( "-console" )) host.developer = 1; + if( Sys_CheckParm( "-console" )) + host.developer = 1; + if( Sys_CheckParm( "-dev" )) { if( Sys_GetParmFromCmdLine( "-dev", dev_level )) @@ -1044,8 +1046,8 @@ int EXPORT Host_Main( const char *progname, int bChangeGame, pfnChangeGame func // we need to execute it again here Cmd_ExecuteString( "exec config.cfg\n" ); - oldtime = Sys_DoubleTime(); - SCR_CheckStartupVids(); // must be last + oldtime = Sys_DoubleTime() - 0.1; + SCR_CheckStartupVids(); // must be last // main window message loop while( !host.crashed ) diff --git a/engine/common/imagelib/img_wad.c b/engine/common/imagelib/img_wad.c index eb61625c..cb94e666 100644 --- a/engine/common/imagelib/img_wad.c +++ b/engine/common/imagelib/img_wad.c @@ -257,24 +257,12 @@ qboolean Image_LoadLMP( const char *name, const byte *buffer, size_t filesize ) if( Q_stristr( name, "palette.lmp" )) return Image_LoadPAL( name, buffer, filesize ); - // greatest hack from id software - if( image.hint != IL_HINT_HL && Q_stristr( name, "conchars" )) - { - image.width = image.height = 128; - image.flags |= IMAGE_HAS_ALPHA; - rendermode = LUMP_QFONT; - filesize += sizeof(lmp); - fin = (byte *)buffer; - } - else - { - fin = (byte *)buffer; - memcpy( &lmp, fin, sizeof( lmp )); - image.width = lmp.width; - image.height = lmp.height; - rendermode = LUMP_NORMAL; - fin += sizeof(lmp); - } + fin = (byte *)buffer; + memcpy( &lmp, fin, sizeof( lmp )); + image.width = lmp.width; + image.height = lmp.height; + rendermode = LUMP_NORMAL; + fin += sizeof( lmp ); pixels = image.width * image.height; diff --git a/engine/common/input.c b/engine/common/input.c index 34bda414..3b62498c 100644 --- a/engine/common/input.c +++ b/engine/common/input.c @@ -105,8 +105,8 @@ static int Host_MapKey( int key ) case 0x0D: return K_KP_ENTER; case 0x2F: return K_KP_SLASH; case 0xAF: return K_KP_PLUS; + default: return result; } - return result; } } @@ -290,7 +290,7 @@ void IN_DeactivateMouse( void ) /* ================ -IN_Mouse +IN_MouseMove ================ */ void IN_MouseMove( void ) @@ -331,12 +331,12 @@ void IN_MouseEvent( int mstate ) // perform button actions for( i = 0; i < in_mouse_buttons; i++ ) { - if(( mstate & ( 1< 0 ) { Key_Event( K_MWHEELUP, true ); @@ -478,17 +479,12 @@ LONG IN_WndProc( HWND hWnd, UINT uMsg, UINT wParam, LONG lParam ) case WM_ACTIVATE: if( host.state == HOST_SHUTDOWN ) break; // no need to activate - if( host.state != HOST_RESTART ) - { - if( HIWORD( wParam )) - host.state = HOST_SLEEP; - else if( LOWORD( wParam ) == WA_INACTIVE ) - host.state = HOST_NOFOCUS; - else host.state = HOST_FRAME; - fActivate = (host.state == HOST_FRAME) ? true : false; - } - else fActivate = true; // video sucessfully restarted - + if( HIWORD( wParam )) + host.state = HOST_SLEEP; + else if( LOWORD( wParam ) == WA_INACTIVE ) + host.state = HOST_NOFOCUS; + else host.state = HOST_FRAME; + fActivate = (host.state == HOST_FRAME) ? true : false; wnd_caption = GetSystemMetrics( SM_CYCAPTION ) + WND_BORDER; S_Activate( fActivate, host.hWnd ); @@ -500,7 +496,7 @@ LONG IN_WndProc( HWND hWnd, UINT uMsg, UINT wParam, LONG lParam ) SetForegroundWindow( hWnd ); ShowWindow( hWnd, SW_RESTORE ); } - else if( Cvar_VariableInteger( "fullscreen" ) && host.state != HOST_RESTART ) + else if( Cvar_VariableInteger( "fullscreen" )) { ShowWindow( hWnd, SW_MINIMIZE ); } diff --git a/engine/common/keys.c b/engine/common/keys.c index 4de073c6..80505699 100644 --- a/engine/common/keys.c +++ b/engine/common/keys.c @@ -726,9 +726,7 @@ void Key_ClearStates( void ) } if( clgame.hInstance ) - { clgame.dllFuncs.IN_ClearStates(); - } } /* diff --git a/engine/common/library.c b/engine/common/library.c index d41fdfa0..784cfae5 100644 --- a/engine/common/library.c +++ b/engine/common/library.c @@ -53,10 +53,10 @@ typedef BOOL (WINAPI *DllEntryProc)( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID static void CopySections( const byte *data, PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module ) { - int i, size; - byte *dest; - byte *codeBase = module->codeBase; - PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION( module->headers ); + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION( module->headers ); + byte *codeBase = module->codeBase; + int i, size; + byte *dest; for( i = 0; i < module->headers->FileHeader.NumberOfSections; i++, section++ ) { @@ -85,9 +85,9 @@ static void CopySections( const byte *data, PIMAGE_NT_HEADERS old_headers, PMEMO static void FreeSections( PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module ) { - int i, size; - byte *codeBase = module->codeBase; - PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); + PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(module->headers); + byte *codeBase = module->codeBase; + int i, size; for( i = 0; i < module->headers->FileHeader.NumberOfSections; i++, section++ ) { @@ -96,13 +96,13 @@ static void FreeSections( PIMAGE_NT_HEADERS old_headers, PMEMORYMODULE module ) size = old_headers->OptionalHeader.SectionAlignment; if( size > 0 ) { - VirtualFree( codeBase + section->VirtualAddress, size, MEM_DECOMMIT ); + VirtualFree((byte *)CALCULATE_ADDRESS( codeBase, section->VirtualAddress ), size, MEM_DECOMMIT ); section->Misc.PhysicalAddress = 0; } continue; } - VirtualFree( codeBase + section->VirtualAddress, section->SizeOfRawData, MEM_DECOMMIT ); + VirtualFree((byte *)CALCULATE_ADDRESS( codeBase, section->VirtualAddress ), section->SizeOfRawData, MEM_DECOMMIT ); section->Misc.PhysicalAddress = 0; } } @@ -154,9 +154,9 @@ static void FinalizeSections( MEMORYMODULE *module ) static void PerformBaseRelocation( MEMORYMODULE *module, DWORD delta ) { - DWORD i; - byte *codeBase = module->codeBase; - PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_BASERELOC ); + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_BASERELOC ); + byte *codeBase = module->codeBase; + DWORD i; if( directory->Size > 0 ) { @@ -200,12 +200,12 @@ static void PerformBaseRelocation( MEMORYMODULE *module, DWORD delta ) static FARPROC MemoryGetProcAddress( void *module, const char *name ) { - int idx = -1; - DWORD i, *nameRef; - WORD *ordinal; - PIMAGE_EXPORT_DIRECTORY exports; - byte *codeBase = ((PMEMORYMODULE)module)->codeBase; - PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((MEMORYMODULE *)module, IMAGE_DIRECTORY_ENTRY_EXPORT ); + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY((MEMORYMODULE *)module, IMAGE_DIRECTORY_ENTRY_EXPORT ); + byte *codeBase = ((PMEMORYMODULE)module)->codeBase; + PIMAGE_EXPORT_DIRECTORY exports; + int idx = -1; + DWORD i, *nameRef; + WORD *ordinal; if( directory->Size == 0 ) { @@ -253,9 +253,9 @@ static FARPROC MemoryGetProcAddress( void *module, const char *name ) static int BuildImportTable( MEMORYMODULE *module ) { - int result=1; - byte *codeBase = module->codeBase; - PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_IMPORT ); + PIMAGE_DATA_DIRECTORY directory = GET_HEADER_DICTIONARY( module, IMAGE_DIRECTORY_ENTRY_IMPORT ); + byte *codeBase = module->codeBase; + int result = 1; if( directory->Size > 0 ) { diff --git a/engine/common/sys_win.c b/engine/common/sys_win.c index 9207c5b1..097b4213 100644 --- a/engine/common/sys_win.c +++ b/engine/common/sys_win.c @@ -534,8 +534,8 @@ print into window console void Sys_Print( const char *pMsg ) { const char *msg; - char buffer[32768]; - char logbuf[32768]; + char buffer[MAX_PRINT_MSG]; + char logbuf[MAX_PRINT_MSG]; char *b = buffer; char *c = logbuf; int i = 0; @@ -604,7 +604,7 @@ formatted message void Msg( const char *pMsg, ... ) { va_list argptr; - char text[8192]; + char text[MAX_PRINT_MSG]; va_start( argptr, pMsg ); Q_vsnprintf( text, sizeof( text ), pMsg, argptr ); @@ -623,7 +623,7 @@ formatted developer message void MsgDev( int level, const char *pMsg, ... ) { va_list argptr; - char text[8192]; + char text[MAX_PRINT_MSG]; if( host.developer < level ) return; diff --git a/mainui/basemenu.cpp b/mainui/basemenu.cpp index 64e2bab6..5871be91 100644 --- a/mainui/basemenu.cpp +++ b/mainui/basemenu.cpp @@ -253,9 +253,14 @@ void UI_DrawString( int x, int y, int w, int h, const char *string, const int co { if( IsColorString( l )) { - if( !forceColor ) + int colorNum = ColorIndex( *(l+1) ); + + if( colorNum == 7 && color != 0 ) + { + modulate = color; + } + else if( !forceColor ) { - int colorNum = ColorIndex( *(l+1) ); modulate = PackAlpha( g_iColorTable[colorNum], UnpackAlpha( color )); } @@ -1535,7 +1540,7 @@ void UI_Init( void ) Cmd_AddCommand( "menu_multiplayer", UI_MultiPlayer_Menu ); Cmd_AddCommand( "menu_options", UI_Options_Menu ); Cmd_AddCommand( "menu_langame", UI_LanGame_Menu ); - Cmd_AddCommand( "menu_intenetgames", UI_InternetGames_Menu ); + Cmd_AddCommand( "menu_internetgames", UI_InternetGames_Menu ); Cmd_AddCommand( "menu_playersetup", UI_PlayerSetup_Menu ); Cmd_AddCommand( "menu_controls", UI_Controls_Menu ); Cmd_AddCommand( "menu_advcontrols", UI_AdvControls_Menu ); @@ -1579,7 +1584,7 @@ void UI_Shutdown( void ) Cmd_RemoveCommand( "menu_saveload" ); Cmd_RemoveCommand( "menu_multiplayer" ); Cmd_RemoveCommand( "menu_options" ); - Cmd_RemoveCommand( "menu_intenetgames" ); + Cmd_RemoveCommand( "menu_internetgames" ); Cmd_RemoveCommand( "menu_langame" ); Cmd_RemoveCommand( "menu_playersetup" ); Cmd_RemoveCommand( "menu_controls" ); diff --git a/mainui/basemenu.h b/mainui/basemenu.h index fd20ce54..fc82c5a4 100644 --- a/mainui/basemenu.h +++ b/mainui/basemenu.h @@ -74,7 +74,7 @@ GNU General Public License for more details. #define UI_OUTLINE_WIDTH uiStatic.outlineWidth // outline thickness #define UI_MAXGAMES 900 // slots for savegame/demos -#define UI_MAX_SERVERS 32 +#define UI_MAX_SERVERS 64 #define UI_MAX_BGMAPS 32 #define MAX_HINT_TEXT 512 diff --git a/mainui/menu_creategame.cpp b/mainui/menu_creategame.cpp index 04a231a7..95a3d4e2 100644 --- a/mainui/menu_creategame.cpp +++ b/mainui/menu_creategame.cpp @@ -375,7 +375,7 @@ static void UI_CreateGame_Init( void ) uiCreateGame.hostName.generic.width = 205; uiCreateGame.hostName.generic.height = 32; uiCreateGame.hostName.generic.callback = UI_CreateGame_Callback; - uiCreateGame.hostName.maxLength = 16; + uiCreateGame.hostName.maxLength = 28; strcpy( uiCreateGame.hostName.buffer, CVAR_GET_STRING( "hostname" )); uiCreateGame.maxClients.generic.id = ID_MAXCLIENTS; diff --git a/mainui/menu_internetgames.cpp b/mainui/menu_internetgames.cpp index d88bb7c7..e8b45f4c 100644 --- a/mainui/menu_internetgames.cpp +++ b/mainui/menu_internetgames.cpp @@ -41,9 +41,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define ID_YES 130 #define ID_NO 131 -#define GAME_LENGTH 18 +#define GAME_LENGTH 28 #define MAPNAME_LENGTH 20+GAME_LENGTH -#define TYPE_LENGTH 16+MAPNAME_LENGTH +#define TYPE_LENGTH 10+MAPNAME_LENGTH #define MAXCL_LENGTH 15+TYPE_LENGTH typedef struct @@ -118,24 +118,30 @@ UI_InternetGames_GetGamesList static void UI_InternetGames_GetGamesList( void ) { int i; - const char *info; + const char *info, *host, *map; + int colorOffset[2]; for( i = 0; i < uiStatic.numServers; i++ ) { if( i >= UI_MAX_SERVERS ) break; info = uiStatic.serverNames[i]; - StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "host" ), GAME_LENGTH ); - StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, GAME_LENGTH ); - StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "map" ), MAPNAME_LENGTH ); - StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, MAPNAME_LENGTH ); + host = Info_ValueForKey( info, "host" ); + colorOffset[0] = ColorPrexfixCount( host ); + StringConcat( uiInternetGames.gameDescription[i], host, GAME_LENGTH ); + StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, GAME_LENGTH + colorOffset[0] ); + map = Info_ValueForKey( info, "map" ); + colorOffset[1] = ColorPrexfixCount( map ); + StringConcat( uiInternetGames.gameDescription[i], map, MAPNAME_LENGTH ); + StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, MAPNAME_LENGTH + colorOffset[0] + colorOffset[1] ); if( !strcmp( Info_ValueForKey( info, "dm" ), "1" )) - StringConcat( uiInternetGames.gameDescription[i], "deathmatch", TYPE_LENGTH ); + StringConcat( uiInternetGames.gameDescription[i], "dm", TYPE_LENGTH ); else if( !strcmp( Info_ValueForKey( info, "coop" ), "1" )) StringConcat( uiInternetGames.gameDescription[i], "coop", TYPE_LENGTH ); else if( !strcmp( Info_ValueForKey( info, "team" ), "1" )) - StringConcat( uiInternetGames.gameDescription[i], "teamplay", TYPE_LENGTH ); - StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, TYPE_LENGTH ); + StringConcat( uiInternetGames.gameDescription[i], "team", TYPE_LENGTH ); + else StringConcat( uiInternetGames.gameDescription[i], "???", TYPE_LENGTH ); + StringConcat( uiInternetGames.gameDescription[i], uiEmptyString, TYPE_LENGTH + colorOffset[0] + colorOffset[1] ); StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "numcl" ), MAXCL_LENGTH ); StringConcat( uiInternetGames.gameDescription[i], "\\", MAXCL_LENGTH ); StringConcat( uiInternetGames.gameDescription[i], Info_ValueForKey( info, "maxcl" ), MAXCL_LENGTH ); @@ -274,7 +280,7 @@ static void UI_InternetGames_Init( void ) StringConcat( uiInternetGames.hintText, uiEmptyString, MAPNAME_LENGTH ); StringConcat( uiInternetGames.hintText, "Type", TYPE_LENGTH ); StringConcat( uiInternetGames.hintText, uiEmptyString, TYPE_LENGTH ); - StringConcat( uiInternetGames.hintText, "Num/Max Clients", MAXCL_LENGTH ); + StringConcat( uiInternetGames.hintText, "Clients", MAXCL_LENGTH ); StringConcat( uiInternetGames.hintText, uiEmptyString, MAXCL_LENGTH ); uiInternetGames.background.generic.id = ID_BACKGROUND; diff --git a/mainui/menu_langame.cpp b/mainui/menu_langame.cpp index 7c355af2..1b4b65f8 100644 --- a/mainui/menu_langame.cpp +++ b/mainui/menu_langame.cpp @@ -41,9 +41,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define ID_YES 130 #define ID_NO 131 -#define GAME_LENGTH 18 +#define GAME_LENGTH 28 #define MAPNAME_LENGTH 20+GAME_LENGTH -#define TYPE_LENGTH 16+MAPNAME_LENGTH +#define TYPE_LENGTH 10+MAPNAME_LENGTH #define MAXCL_LENGTH 15+TYPE_LENGTH typedef struct @@ -118,24 +118,30 @@ UI_LanGame_GetGamesList static void UI_LanGame_GetGamesList( void ) { int i; - const char *info; + const char *info, *host, *map; + int colorOffset[2]; for( i = 0; i < uiStatic.numServers; i++ ) { if( i >= UI_MAX_SERVERS ) break; info = uiStatic.serverNames[i]; - StringConcat( uiLanGame.gameDescription[i], Info_ValueForKey( info, "host" ), GAME_LENGTH ); - StringConcat( uiLanGame.gameDescription[i], uiEmptyString, GAME_LENGTH ); - StringConcat( uiLanGame.gameDescription[i], Info_ValueForKey( info, "map" ), MAPNAME_LENGTH ); - StringConcat( uiLanGame.gameDescription[i], uiEmptyString, MAPNAME_LENGTH ); + host = Info_ValueForKey( info, "host" ); + colorOffset[0] = ColorPrexfixCount( host ); + StringConcat( uiLanGame.gameDescription[i], host, GAME_LENGTH ); + StringConcat( uiLanGame.gameDescription[i], uiEmptyString, GAME_LENGTH + colorOffset[0] ); + map = Info_ValueForKey( info, "map" ); + colorOffset[1] = ColorPrexfixCount( map ); + StringConcat( uiLanGame.gameDescription[i], map, MAPNAME_LENGTH ); + StringConcat( uiLanGame.gameDescription[i], uiEmptyString, MAPNAME_LENGTH + colorOffset[0] + colorOffset[1] ); if( !strcmp( Info_ValueForKey( info, "dm" ), "1" )) - StringConcat( uiLanGame.gameDescription[i], "deathmatch", TYPE_LENGTH ); + StringConcat( uiLanGame.gameDescription[i], "dm", TYPE_LENGTH ); else if( !strcmp( Info_ValueForKey( info, "coop" ), "1" )) StringConcat( uiLanGame.gameDescription[i], "coop", TYPE_LENGTH ); else if( !strcmp( Info_ValueForKey( info, "team" ), "1" )) - StringConcat( uiLanGame.gameDescription[i], "teamplay", TYPE_LENGTH ); - StringConcat( uiLanGame.gameDescription[i], uiEmptyString, TYPE_LENGTH ); + StringConcat( uiLanGame.gameDescription[i], "team", TYPE_LENGTH ); + else StringConcat( uiLanGame.gameDescription[i], "???", TYPE_LENGTH ); + StringConcat( uiLanGame.gameDescription[i], uiEmptyString, TYPE_LENGTH + colorOffset[0] + colorOffset[1] ); StringConcat( uiLanGame.gameDescription[i], Info_ValueForKey( info, "numcl" ), MAXCL_LENGTH ); StringConcat( uiLanGame.gameDescription[i], "\\", MAXCL_LENGTH ); StringConcat( uiLanGame.gameDescription[i], Info_ValueForKey( info, "maxcl" ), MAXCL_LENGTH ); @@ -274,7 +280,7 @@ static void UI_LanGame_Init( void ) StringConcat( uiLanGame.hintText, uiEmptyString, MAPNAME_LENGTH ); StringConcat( uiLanGame.hintText, "Type", TYPE_LENGTH ); StringConcat( uiLanGame.hintText, uiEmptyString, TYPE_LENGTH ); - StringConcat( uiLanGame.hintText, "Num/Max Clients", MAXCL_LENGTH ); + StringConcat( uiLanGame.hintText, "Clients", MAXCL_LENGTH ); StringConcat( uiLanGame.hintText, uiEmptyString, MAXCL_LENGTH ); uiLanGame.background.generic.id = ID_BACKGROUND; diff --git a/mainui/utils.cpp b/mainui/utils.cpp index 0295c9a8..843e6dc9 100644 --- a/mainui/utils.cpp +++ b/mainui/utils.cpp @@ -67,6 +67,30 @@ int ColorStrlen( const char *str ) return len; } +int ColorPrexfixCount( const char *str ) +{ + const char *p; + + if( !str ) + return 0; + + int len = 0; + p = str; + + while( *p ) + { + if( IsColorString( p )) + { + len += 2; + p += 2; + continue; + } + p++; + } + + return len; +} + void StringConcat( char *dst, const char *src, size_t size ) { register char *d = dst; diff --git a/mainui/utils.h b/mainui/utils.h index 747c1113..97e368a3 100644 --- a/mainui/utils.h +++ b/mainui/utils.h @@ -109,6 +109,7 @@ inline float RemapVal( float val, float A, float B, float C, float D) } extern int ColorStrlen( const char *str ); // returns string length without color symbols +extern int ColorPrexfixCount( const char *str ); extern const int g_iColorTable[8]; extern void COM_FileBase( const char *in, char *out ); // ripped out from hlsdk 2.3 extern int UI_FadeAlpha( int starttime, int endtime );