diff --git a/engine/client/gl_alias.c b/engine/client/gl_alias.c index 8fff0b48..ae512086 100644 --- a/engine/client/gl_alias.c +++ b/engine/client/gl_alias.c @@ -1102,7 +1102,7 @@ void GL_DrawAliasFrame( aliashdr_t *paliashdr ) VectorLerp( m_bytenormals[verts0->lightnormalindex], g_alias.lerpfrac, m_bytenormals[verts1->lightnormalindex], norm ); VectorNormalize( norm ); R_AliasLighting( &lv_tmp, norm ); - pglColor3f( g_alias.lightcolor[0] * lv_tmp, g_alias.lightcolor[1] * lv_tmp, g_alias.lightcolor[2] * lv_tmp ); + pglColor4f( g_alias.lightcolor[0] * lv_tmp, g_alias.lightcolor[1] * lv_tmp, g_alias.lightcolor[2] * lv_tmp, tr.blend ); VectorLerp( verts0->v, g_alias.lerpfrac, verts1->v, vert ); pglVertex3fv( vert ); verts0++, verts1++; @@ -1369,6 +1369,8 @@ void R_DrawAliasModel( cl_entity_t *e ) m_pAliasHeader = (aliashdr_t *)Mod_AliasExtradata( RI.currententity->model ); if( !m_pAliasHeader ) return; + GL_SetupFogColorForModels(); + // init time R_AliasSetupTimings(); @@ -1399,6 +1401,7 @@ void R_DrawAliasModel( cl_entity_t *e ) // model and frame independant R_AliasSetupLighting( &lighting ); + GL_SetRenderMode( e->curstate.rendermode ); pglTranslatef( m_pAliasHeader->scale_origin[0], m_pAliasHeader->scale_origin[1], m_pAliasHeader->scale_origin[2] ); @@ -1421,7 +1424,6 @@ void R_DrawAliasModel( cl_entity_t *e ) } pglShadeModel( GL_SMOOTH ); - R_SetupAliasFrame( e, m_pAliasHeader ); if( m_pAliasHeader->fb_texturenum[skin][anim] ) @@ -1459,6 +1461,8 @@ void R_DrawAliasModel( cl_entity_t *e ) // HACKHACK: keep the angles unchanged VectorCopy( angles, e->angles ); + + GL_ResetFogColor(); } //================================================================================== \ No newline at end of file diff --git a/engine/client/gl_cull.c b/engine/client/gl_cull.c index 08d7c0f7..5c4d01ec 100644 --- a/engine/client/gl_cull.c +++ b/engine/client/gl_cull.c @@ -102,8 +102,11 @@ qboolean R_CullSurface( msurface_t *surf, gl_frustum_t *frustum, uint clipflags if( !surf || !surf->texinfo || !surf->texinfo->texture ) return true; - if( surf->flags & SURF_WATERCSG && !( e->curstate.effects & EF_NOWATERCSG )) - return true; + if( !FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE )) + { + if( surf->flags & SURF_WATERCSG && !( e->curstate.effects & EF_NOWATERCSG )) + return true; + } // don't cull transparent surfaces because we should be draw decals on them if( surf->pdecals && ( e->curstate.rendermode == kRenderTransTexture || e->curstate.rendermode == kRenderTransAdd )) diff --git a/engine/client/gl_local.h b/engine/client/gl_local.h index d339a864..96b7b1ec 100644 --- a/engine/client/gl_local.h +++ b/engine/client/gl_local.h @@ -401,6 +401,7 @@ void R_DrawBrushModel( cl_entity_t *e ); void GL_SubdivideSurface( msurface_t *fa ); void GL_BuildPolygonFromSurface( model_t *mod, msurface_t *fa ); void GL_SetupFogColorForSurfaces( void ); +void GL_SetupFogColorForModels( void ); void GL_RebuildLightmaps( void ); void GL_InitRandomTable( void ); void GL_BuildLightmaps( void ); diff --git a/engine/client/gl_rmain.c b/engine/client/gl_rmain.c index 6ac1791a..64739f33 100644 --- a/engine/client/gl_rmain.c +++ b/engine/client/gl_rmain.c @@ -704,6 +704,20 @@ static void R_CheckFog( void ) gltexture_t *tex; int i, cnt, count; + // quake global fog + if( clgame.movevars.fog_settings != 0 && FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE )) + { + // quake-style global fog + RI.fogColor[0] = ((clgame.movevars.fog_settings & 0xFF000000) >> 24) / 255.0f; + RI.fogColor[1] = ((clgame.movevars.fog_settings & 0xFF0000) >> 16) / 255.0f; + RI.fogColor[2] = ((clgame.movevars.fog_settings & 0xFF00) >> 8) / 255.0f; + RI.fogDensity = ((clgame.movevars.fog_settings & 0xFF) / 255.0f) * 0.015625f; + RI.fogStart = RI.fogEnd = 0.0f; + RI.fogCustom = false; + RI.fogEnabled = true; + return; + } + RI.fogEnabled = false; if( cl.local.waterlevel < 2 || !RI.drawWorld || !RI.viewleaf ) diff --git a/engine/client/gl_rsurf.c b/engine/client/gl_rsurf.c index 76f88d91..7c16fa05 100644 --- a/engine/client/gl_rsurf.c +++ b/engine/client/gl_rsurf.c @@ -242,6 +242,28 @@ void GL_SetupFogColorForSurfaces( void ) pglFogfv( GL_FOG_COLOR, fogColor ); } +void GL_SetupFogColorForModels( void ) +{ + vec3_t fogColor; + float factor, div; + + if(( !RI.fogEnabled && !RI.fogCustom ) || RI.onlyClientDraw || !RI.currententity ) + return; + + if( RI.currententity->curstate.rendermode == kRenderTransTexture ) + { + pglFogfv( GL_FOG_COLOR, RI.fogColor ); + return; + } + + div = 2.0f; + factor = 1.0f; + fogColor[0] = pow( RI.fogColor[0] / div, ( 1.0f / factor )); + fogColor[1] = pow( RI.fogColor[1] / div, ( 1.0f / factor )); + fogColor[2] = pow( RI.fogColor[2] / div, ( 1.0f / factor )); + pglFogfv( GL_FOG_COLOR, fogColor ); +} + void GL_ResetFogColor( void ) { // restore fog here @@ -1395,6 +1417,7 @@ void R_DrawBrushModel( cl_entity_t *e ) qboolean need_sort = false; vec3_t origin_l, oldorigin; vec3_t mins, maxs; + int rendermode; msurface_t *psurf; model_t *clmodel; qboolean rotated; @@ -1432,8 +1455,12 @@ void R_DrawBrushModel( cl_entity_t *e ) return; memset( gl_lms.lightmap_surfaces, 0, sizeof( gl_lms.lightmap_surfaces )); + rendermode = e->curstate.rendermode; gl_lms.dynamic_surfaces = NULL; + if( FBitSet( clmodel->flags, MODEL_TRANSPARENT ) && FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE )) + rendermode = kRenderTransAlpha; + if( rotated ) R_RotateForEntity( e ); else R_TranslateForEntity( e ); @@ -1456,14 +1483,14 @@ void R_DrawBrushModel( cl_entity_t *e ) } // setup the rendermode - GL_SetRenderMode( e->curstate.rendermode ); + GL_SetRenderMode( rendermode ); GL_SetupFogColorForSurfaces (); - if( e->curstate.rendermode == kRenderTransTexture && r_lighting_extended->value >= 2.0f ) + if( rendermode == kRenderTransTexture && r_lighting_extended->value >= 2.0f ) pglBlendFunc( GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA ); // setup the color and alpha - switch( e->curstate.rendermode ) + switch( rendermode ) { case kRenderTransAdd: if( RI.fogCustom ) @@ -1514,7 +1541,7 @@ void R_DrawBrushModel( cl_entity_t *e ) for( i = 0; i < num_sorted; i++ ) R_RenderBrushPoly( world.draw_surfaces[i] ); - if( e->curstate.rendermode == kRenderTransColor ) + if( rendermode == kRenderTransColor ) pglEnable( GL_TEXTURE_2D ); GL_ResetFogColor(); @@ -1523,7 +1550,7 @@ void R_DrawBrushModel( cl_entity_t *e ) R_RenderDetails(); // restore fog here - if( e->curstate.rendermode == kRenderTransAdd ) + if( rendermode == kRenderTransAdd ) { if( RI.fogCustom ) pglEnable( GL_FOG ); diff --git a/engine/client/gl_sprite.c b/engine/client/gl_sprite.c index 0bf6c2c5..b7f44bda 100644 --- a/engine/client/gl_sprite.c +++ b/engine/client/gl_sprite.c @@ -30,6 +30,7 @@ convar_t *r_sprite_lerping; convar_t *r_sprite_lighting; char group_suffix[8]; static uint r_texFlags = 0; +static int sprite_version; float sprite_radius; /* @@ -58,14 +59,17 @@ static dframetype_t *R_SpriteLoadFrame( model_t *mod, void *pin, mspriteframe_t char texname[128], sprname[128]; qboolean load_external = false; int gl_texturenum = 0; + int bytes = 1; pinframe = (dspriteframe_t *)pin; + if( sprite_version == SPRITE_VERSION_32 ) + bytes = 4; // build uinque frame name if( FBitSet( mod->flags, MODEL_CLIENT )) // it's a HUD sprite { Q_snprintf( texname, sizeof( texname ), "#HUD/%s_%s_%i%i.spr", mod->name, group_suffix, num / 10, num % 10 ); - gl_texturenum = GL_LoadTexture( texname, pin, pinframe->width * pinframe->height, r_texFlags, NULL ); + gl_texturenum = GL_LoadTexture( texname, pin, pinframe->width * pinframe->height * bytes, r_texFlags, NULL ); } else { @@ -87,7 +91,7 @@ static dframetype_t *R_SpriteLoadFrame( model_t *mod, void *pin, mspriteframe_t if( !load_external ) { Q_snprintf( texname, sizeof( texname ), "#%s_%s_%i%i.spr", mod->name, group_suffix, num / 10, num % 10 ); - gl_texturenum = GL_LoadTexture( texname, pin, pinframe->width * pinframe->height, r_texFlags, NULL ); + gl_texturenum = GL_LoadTexture( texname, pin, pinframe->width * pinframe->height * bytes, r_texFlags, NULL ); } else MsgDev( D_NOTE, "loading HQ: %s\n", texname ); } @@ -103,7 +107,7 @@ static dframetype_t *R_SpriteLoadFrame( model_t *mod, void *pin, mspriteframe_t pspriteframe->gl_texturenum = gl_texturenum; *ppframe = pspriteframe; - return (dframetype_t *)((byte *)(pinframe + 1) + pinframe->width * pinframe->height ); + return (dframetype_t *)((byte *)(pinframe + 1) + pinframe->width * pinframe->height * bytes ); } /* @@ -181,15 +185,16 @@ void Mod_LoadSpriteModel( model_t *mod, const void *buffer, qboolean *loaded, ui return; } - if( i != SPRITE_VERSION_Q1 && i != SPRITE_VERSION_HL ) + if( i != SPRITE_VERSION_Q1 && i != SPRITE_VERSION_HL && i != SPRITE_VERSION_32 ) { MsgDev( D_ERROR, "%s has wrong version number (%i should be %i or %i)\n", mod->name, i, SPRITE_VERSION_Q1, SPRITE_VERSION_HL ); return; } mod->mempool = Mem_AllocPool( va( "^2%s^7", mod->name )); + sprite_version = i; - if( i == SPRITE_VERSION_Q1 ) + if( i == SPRITE_VERSION_Q1 || i == SPRITE_VERSION_32 ) { pinq1 = (dsprite_q1_t *)buffer; size = sizeof( msprite_t ) + ( pinq1->numframes - 1 ) * sizeof( psprite->frames ); diff --git a/engine/client/gl_warp.c b/engine/client/gl_warp.c index b498b373..e0ae7763 100644 --- a/engine/client/gl_warp.c +++ b/engine/client/gl_warp.c @@ -391,7 +391,7 @@ void R_DrawSkyBox( void ) RI.isSkyVisible = true; // don't fogging skybox (this fix old Half-Life bug) - if( !RI.fogCustom ) + if( !RI.fogCustom && !FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE )) pglDisable( GL_FOG ); pglDisable( GL_BLEND ); pglDisable( GL_ALPHA_TEST ); diff --git a/engine/common/filesystem.c b/engine/common/filesystem.c index ef979ebd..43f29ef0 100644 --- a/engine/common/filesystem.c +++ b/engine/common/filesystem.c @@ -106,10 +106,9 @@ 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_basedir[MAX_SYSPATH]; // base game directory char fs_gamedir[MAX_SYSPATH]; // game current directory -char gs_basedir[MAX_SYSPATH]; // initial dir before loading gameinfo.txt (used for compilers too) +char fs_writedir[MAX_SYSPATH]; // path that game allows to overwrite, delete and rename files (and create new of course) qboolean fs_ext_path = false; // attempt to read\write from ./ or ../ pathes static const wadtype_t wad_hints[10]; @@ -634,7 +633,7 @@ static qboolean FS_AddPak_Fullpath( const char *pakfile, qboolean *already_loade ================ FS_AddGameDirectory -Sets fs_gamedir, adds the directory to the head of the path, +Sets fs_writedir, adds the directory to the head of the path, then loads and adds pak1.pak pak2.pak ... ================ */ @@ -646,7 +645,7 @@ void FS_AddGameDirectory( const char *dir, int flags ) int i; if( !FBitSet( flags, FS_NOWRITE_PATH )) - Q_strncpy( fs_gamedir, dir, sizeof( fs_gamedir )); + Q_strncpy( fs_writedir, dir, sizeof( fs_writedir )); stringlistinit( &list ); listdirectory( &list, dir ); @@ -694,7 +693,7 @@ FS_AddGameHierarchy void FS_AddGameHierarchy( const char *dir, int flags ) { // Add the common game directory - if( dir && *dir ) FS_AddGameDirectory( va( "%s%s/", fs_basedir, dir ), flags ); + if( dir && *dir ) FS_AddGameDirectory( va( "%s/", dir ), flags ); } /* @@ -886,13 +885,10 @@ FS_WriteGameInfo assume GameInfo is valid ================ */ -static qboolean FS_WriteGameInfo( const char *filepath, gameinfo_t *GameInfo ) +static void FS_WriteGameInfo( const char *filepath, gameinfo_t *GameInfo ) { - file_t *f; - - if( !GameInfo ) return false; - f = FS_Open( filepath, "w", false ); // we in binary-mode - if( !f ) return false; + file_t *f = FS_Open( filepath, "w", false ); // we in binary-mode + if( !f ) Sys_Error( "FS_WriteGameInfo: can't write %s\n", filepath ); // may be disk-space is out? FS_Print( f, "// generated by Xash3D\n\n\n" ); @@ -968,8 +964,6 @@ static qboolean FS_WriteGameInfo( const char *filepath, gameinfo_t *GameInfo ) FS_Print( f, "\n\n\n" ); FS_Close( f ); // all done - - return true; } /* @@ -992,8 +986,8 @@ void FS_CreateDefaultGameInfo( const char *filename ) defGI.falldir[0] = '\0'; Q_strncpy( defGI.title, "New Game", sizeof( defGI.title )); - Q_strncpy( defGI.gamedir, gs_basedir, sizeof( defGI.gamedir )); - Q_strncpy( defGI.basedir, SI.basedirName, sizeof( defGI.basedir )); + Q_strncpy( defGI.gamedir, fs_gamedir, sizeof( defGI.gamedir )); + Q_strncpy( defGI.basedir, fs_basedir, sizeof( defGI.basedir )); Q_strncpy( defGI.sp_entity, "info_player_start", sizeof( defGI.sp_entity )); Q_strncpy( defGI.mp_entity, "info_player_deathmatch", sizeof( defGI.mp_entity )); Q_strncpy( defGI.dll_path, "cl_dlls", sizeof( defGI.dll_path )); @@ -1029,7 +1023,7 @@ static qboolean FS_ParseLiblistGam( const char *filename, const char *gamedir, g Q_strncpy( GameInfo->title, "New Game", sizeof( GameInfo->title )); Q_strncpy( GameInfo->gamedir, gamedir, sizeof( GameInfo->gamedir )); - Q_strncpy( GameInfo->basedir, SI.basedirName, sizeof( GameInfo->basedir )); + Q_strncpy( GameInfo->basedir, fs_basedir, sizeof( GameInfo->basedir )); Q_strncpy( GameInfo->sp_entity, "info_player_start", sizeof( GameInfo->sp_entity )); Q_strncpy( GameInfo->mp_entity, "info_player_deathmatch", sizeof( GameInfo->mp_entity )); Q_strncpy( GameInfo->game_dll, "dlls/hl.dll", sizeof( GameInfo->game_dll )); @@ -1153,34 +1147,16 @@ void FS_ConvertGameInfo( const char *gamedir, const char *gameinfo_path, const c if( FS_ParseLiblistGam( liblist_path, gamedir, &GameInfo )) { - if( FS_WriteGameInfo( gameinfo_path, &GameInfo )) - MsgDev( D_INFO, "Convert %s to %s\n", liblist_path, gameinfo_path ); + MsgDev( D_INFO, "Convert %s to %s\n", liblist_path, gameinfo_path ); + FS_WriteGameInfo( gameinfo_path, &GameInfo ); } } -/* -================ -FS_ParseGameInfo -================ -*/ -static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo ) +static qboolean FS_ReadGameInfo( const char *filepath, const char *gamedir, gameinfo_t *GameInfo ) { char *afile, *pfile; - string fs_path, filepath; - string liblist, token; - - Q_snprintf( filepath, sizeof( filepath ), "%s/gameinfo.txt", gamedir ); - Q_snprintf( liblist, sizeof( liblist ), "%s/liblist.gam", gamedir ); - - // if user change liblist.gam update the gameinfo.txt - if( FS_FileTime( liblist, false ) > FS_FileTime( filepath, false )) - FS_ConvertGameInfo( gamedir, filepath, liblist ); - - // force to create gameinfo for specified game if missing - if( !Q_stricmp( gs_basedir, gamedir ) && !FS_FileExists( filepath, false )) - FS_CreateDefaultGameInfo( filepath ); - - if( !GameInfo ) return false; // no dest + char token[1204]; + string fs_path; afile = FS_LoadFile( filepath, NULL, false ); if( !afile ) return false; @@ -1329,7 +1305,7 @@ static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo ) if( ambientNum < 0 || ambientNum > ( NUM_AMBIENTS - 1 )) { - MsgDev( D_ERROR, "FS_ParseGameInfo: Invalid ambient number %i. Ignored.\n", ambientNum ); + MsgDev( D_ERROR, "FS_ReadGameInfo: Invalid ambient number %i. Ignored.\n", ambientNum ); } else { @@ -1342,6 +1318,7 @@ static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo ) if( !FS_SysFolderExists( va( "%s\\%s", host.rootdir, GameInfo->gamedir ))) Q_strncpy( GameInfo->gamedir, gamedir, sizeof( GameInfo->gamedir )); + // make sure what fallback_dir is really exist if( !FS_SysFolderExists( va( "%s\\%s", host.rootdir, GameInfo->falldir ))) GameInfo->falldir[0] = '\0'; @@ -1351,6 +1328,48 @@ static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo ) return true; } +/* +================ +FS_ParseGameInfo +================ +*/ +static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo ) +{ + string liblist_path, gameinfo_path; + string default_gameinfo_path; + gameinfo_t tmpGameInfo; + + Q_snprintf( default_gameinfo_path, sizeof( default_gameinfo_path ), "%s/gameinfo.txt", fs_basedir ); + Q_snprintf( gameinfo_path, sizeof( gameinfo_path ), "%s/gameinfo.txt", gamedir ); + Q_snprintf( liblist_path, sizeof( liblist_path ), "%s/liblist.gam", gamedir ); + + // if user change liblist.gam update the gameinfo.txt + if( FS_FileTime( liblist_path, false ) > FS_FileTime( gameinfo_path, false )) + FS_ConvertGameInfo( gamedir, gameinfo_path, liblist_path ); + + // force to create gameinfo for specified game if missing + if( !Q_stricmp( fs_gamedir, gamedir ) && !FS_FileExists( gameinfo_path, false )) + { + memset( &tmpGameInfo, 0, sizeof( tmpGameInfo )); + + if( FS_ReadGameInfo( default_gameinfo_path, gamedir, &tmpGameInfo )) + { + // now we have copy of game info from basedir but needs to change gamedir + MsgDev( D_INFO, "converting %s to %s\n", default_gameinfo_path, gameinfo_path ); + Q_strncpy( tmpGameInfo.gamedir, gamedir, sizeof( tmpGameInfo.gamedir )); + FS_WriteGameInfo( gameinfo_path, &tmpGameInfo ); + } + else FS_CreateDefaultGameInfo( gameinfo_path ); + } + + if( !GameInfo || !FS_FileExists( gameinfo_path, false )) + return false; // no dest + + if( FS_ReadGameInfo( gameinfo_path, gamedir, GameInfo )) + return true; + return false; +} + /* ================ FS_LoadGameInfo @@ -1365,8 +1384,8 @@ void FS_LoadGameInfo( const char *rootfolder ) // lock uplevel of gamedir for read\write fs_ext_path = false; - if( rootfolder ) Q_strcpy( gs_basedir, rootfolder ); - MsgDev( D_NOTE, "FS_LoadGameInfo( %s )\n", gs_basedir ); + if( rootfolder ) Q_strcpy( fs_gamedir, rootfolder ); + MsgDev( D_NOTE, "FS_LoadGameInfo( %s )\n", fs_gamedir ); // clear any old pathes FS_ClearSearchPath(); @@ -1374,12 +1393,12 @@ void FS_LoadGameInfo( const char *rootfolder ) // validate gamedir for( i = 0; i < SI.numgames; i++ ) { - if( !Q_stricmp( SI.games[i]->gamefolder, gs_basedir )) + if( !Q_stricmp( SI.games[i]->gamefolder, fs_gamedir )) break; } if( i == SI.numgames ) - Sys_Error( "Couldn't find game directory '%s'\n", gs_basedir ); + Sys_Error( "Couldn't find game directory '%s'\n", fs_gamedir ); SI.GameInfo = SI.games[i]; FS_Rescan(); // create new filesystem @@ -1395,7 +1414,8 @@ FS_Init void FS_Init( void ) { stringlist_t dirs; - qboolean hasDefaultDir = false; + qboolean hasBaseDir = false; + qboolean hasGameDir = false; int i; FS_InitMemory(); @@ -1411,30 +1431,38 @@ void FS_Init( void ) listdirectory( &dirs, "./" ); stringlistsort( &dirs ); SI.numgames = 0; - - if( !Sys_GetParmFromCmdLine( "-game", gs_basedir )) - Q_strcpy( gs_basedir, SI.basedirName ); // default dir - if( FS_CheckNastyPath( gs_basedir, true )) + Q_strncpy( fs_basedir, SI.basedirName, sizeof( fs_basedir )); // default dir + + if( !Sys_GetParmFromCmdLine( "-game", fs_gamedir )) + Q_strncpy( fs_gamedir, fs_basedir, sizeof( fs_gamedir )); // gamedir == basedir + + if( FS_CheckNastyPath( fs_basedir, true )) { - MsgDev( D_ERROR, "FS_Init: invalid game directory \"%s\"\n", gs_basedir ); - Q_strcpy( gs_basedir, SI.basedirName ); // default dir + // this is completely fatal... + Sys_Error( "FS_Init: invalid base directory \"%s\"\n", fs_basedir ); + } + + if( FS_CheckNastyPath( fs_gamedir, true )) + { + MsgDev( D_ERROR, "FS_Init: invalid game directory \"%s\"\n", fs_gamedir ); + Q_strncpy( fs_gamedir, fs_basedir, sizeof( fs_gamedir )); // default dir } // validate directories for( i = 0; i < dirs.numstrings; i++ ) { - if( !Q_stricmp( SI.basedirName, dirs.strings[i] )) - hasDefaultDir = true; + if( !Q_stricmp( fs_basedir, dirs.strings[i] )) + hasBaseDir = true; - if( !Q_stricmp( gs_basedir, dirs.strings[i] )) - break; + if( !Q_stricmp( fs_gamedir, dirs.strings[i] )) + hasGameDir = true; } - if( i == dirs.numstrings ) + if( !hasGameDir ) { - MsgDev( D_INFO, "FS_Init: game directory \"%s\" not exist\n", gs_basedir ); - if( hasDefaultDir ) Q_strncpy( gs_basedir, SI.basedirName, sizeof( gs_basedir )); // default dir + MsgDev( D_ERROR, "FS_Init: game directory \"%s\" not exist\n", fs_gamedir ); + if( hasBaseDir ) Q_strncpy( fs_gamedir, fs_basedir, sizeof( fs_gamedir )); } // build list of game directories here @@ -1442,10 +1470,10 @@ void FS_Init( void ) for( i = 0; i < dirs.numstrings; i++ ) { - if( !FS_SysFolderExists( dirs.strings[i] ) || (!Q_stricmp( dirs.strings[i], ".." ) && !fs_ext_path )) + if( !FS_SysFolderExists( dirs.strings[i] ) || ( !Q_stricmp( dirs.strings[i], ".." ) && !fs_ext_path )) continue; - if( !SI.games[SI.numgames] ) + if( SI.games[SI.numgames] == NULL ) SI.games[SI.numgames] = (gameinfo_t *)Mem_Alloc( fs_mempool, sizeof( gameinfo_t )); if( FS_ParseGameInfo( dirs.strings[i], SI.games[SI.numgames] )) @@ -1853,7 +1881,7 @@ file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly ) char real_path[MAX_SYSPATH]; // open the file on disk directly - Q_sprintf( real_path, "%s/%s", fs_gamedir, filepath ); + Q_sprintf( real_path, "%s/%s", fs_writedir, filepath ); FS_CreatePath( real_path );// Create directories up to the file return FS_SysOpen( real_path, mode ); } @@ -2552,8 +2580,8 @@ qboolean FS_Rename( const char *oldname, const char *newname ) if( !oldname || !newname || !*oldname || !*newname ) return false; - Q_snprintf( oldpath, sizeof( oldpath ), "%s%s", fs_gamedir, oldname ); - Q_snprintf( newpath, sizeof( newpath ), "%s%s", fs_gamedir, newname ); + Q_snprintf( oldpath, sizeof( oldpath ), "%s%s", fs_writedir, oldname ); + Q_snprintf( newpath, sizeof( newpath ), "%s%s", fs_writedir, newname ); COM_FixSlashes( oldpath ); COM_FixSlashes( newpath ); @@ -2578,7 +2606,7 @@ qboolean FS_Delete( const char *path ) if( !path || !*path ) return false; - Q_snprintf( real_path, sizeof( real_path ), "%s%s", fs_gamedir, path ); + Q_snprintf( real_path, sizeof( real_path ), "%s%s", fs_writedir, path ); COM_FixSlashes( real_path ); iRet = remove( real_path ); @@ -2840,11 +2868,6 @@ search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly ) void FS_InitMemory( void ) { fs_mempool = Mem_AllocPool( "FileSystem Pool" ); - - // add a path separator to the end of the basedir if it lacks one - if( fs_basedir[0] && fs_basedir[Q_strlen(fs_basedir) - 1] != '/' && fs_basedir[Q_strlen(fs_basedir) - 1] != '\\' ) - Q_strncat( fs_basedir, "/", sizeof( fs_basedir )); - fs_searchpaths = NULL; } diff --git a/engine/common/imagelib/img_wad.c b/engine/common/imagelib/img_wad.c index 7aa70b0a..f7e53b25 100644 --- a/engine/common/imagelib/img_wad.c +++ b/engine/common/imagelib/img_wad.c @@ -188,6 +188,7 @@ Image_LoadSPR qboolean Image_LoadSPR( const char *name, const byte *buffer, size_t filesize ) { dspriteframe_t *pin; // identical for q1\hl sprites + qboolean truecolor = false; if( image.hint == IL_HINT_HL ) { @@ -217,9 +218,12 @@ qboolean Image_LoadSPR( const char *name, const byte *buffer, size_t filesize ) return false; } + if( filesize == ( image.width * image.height * 4 )) + truecolor = true; + // sorry, can't validate palette rendermode if( !Image_LumpValidSize( name )) return false; - image.type = PF_INDEXED_32; // 32-bit palete + image.type = (truecolor) ? PF_RGBA_32 : PF_INDEXED_32; // 32-bit palete image.depth = 1; // detect alpha-channel by palette type @@ -232,6 +236,16 @@ qboolean Image_LoadSPR( const char *name, const byte *buffer, size_t filesize ) break; } + if( truecolor ) + { + // spr32 support + image.size = image.width * image.height * 4; + image.rgba = Mem_Alloc( host.imagepool, image.size ); + memcpy( image.rgba, (byte *)(pin + 1), image.size ); + SetBits( image.flags, IMAGE_HAS_COLOR ); // Color. True Color! + return true; + } + return Image_AddIndexedImageToPack( (byte *)(pin + 1), image.width, image.height ); } @@ -261,7 +275,7 @@ qboolean Image_LoadLMP( const char *name, const byte *buffer, size_t filesize ) if( image.hint != IL_HINT_HL && Q_stristr( name, "conchars" )) { image.width = image.height = 128; - rendermode = LUMP_MASKED; + rendermode = LUMP_QUAKE1; filesize += sizeof( lmp ); fin = (byte *)buffer; @@ -411,10 +425,10 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, size_t filesize ) hl_texture = false; - // check for luma pixels + // check for luma and alpha pixels for( i = 0; i < image.width * image.height; i++ ) { - if( fin[i] > 224 ) + if( fin[i] > 224 && fin[i] != 255 ) { // don't apply luma to water surfaces because // we use glpoly->next for store luma chain each frame @@ -427,6 +441,19 @@ qboolean Image_LoadMIP( const char *name, const byte *buffer, size_t filesize ) } } + // Arcane Dimensions has the transparent textures + if( Q_strrchr( name, '{' )) + { + for( i = 0; i < image.width * image.height; i++ ) + { + if( fin[i] == 255 ) + { + image.flags |= IMAGE_HAS_ALPHA; + break; + } + } + } + Image_GetPaletteQ1(); } else diff --git a/engine/common/mod_local.h b/engine/common/mod_local.h index c3723eb8..41795b51 100644 --- a/engine/common/mod_local.h +++ b/engine/common/mod_local.h @@ -52,6 +52,7 @@ GNU General Public License for more details. #define MODEL_CONVEYOR BIT( 0 ) #define MODEL_HAS_ORIGIN BIT( 1 ) #define MODEL_LIQUID BIT( 2 ) // model has only point hull +#define MODEL_TRANSPARENT BIT( 3 ) // have transparent surfaces #define MODEL_CLIENT BIT( 30 ) // client sprite diff --git a/engine/common/model.c b/engine/common/model.c index ae92992d..e60999b9 100644 --- a/engine/common/model.c +++ b/engine/common/model.c @@ -2318,6 +2318,9 @@ static void Mod_LoadBrushModel( model_t *mod, const void *buffer, qboolean *load if( surf->flags & SURF_CONVEYOR ) mod->flags |= MODEL_CONVEYOR; + if( surf->flags & SURF_TRANSPARENT ) + mod->flags |= MODEL_TRANSPARENT; + // kill water backplanes for submodels (half-life rules) if( surf->flags & SURF_DRAWTURB ) { diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index fd652a62..4d1f8790 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -58,6 +58,7 @@ CVAR_DEFINE_AUTO( logsdir, "logs", 0, "place to store multiplayer logs" ); CVAR_DEFINE_AUTO( bannedcfgfile, "banned.cfg", 0, "name of list of banned users" ); CVAR_DEFINE_AUTO( deathmatch, "0", 0, "deathmatch mode in multiplayer game" ); CVAR_DEFINE_AUTO( coop, "0", 0, "cooperative mode in multiplayer game" ); +CVAR_DEFINE_AUTO( teamplay, "0", 0, "team mode in multiplayer game" ); CVAR_DEFINE_AUTO( skill, "1", 0, "skill level in singleplayer game" ); // physic-related variables @@ -732,6 +733,7 @@ void SV_Init( void ) Cvar_RegisterVariable (&motdfile); Cvar_RegisterVariable (&deathmatch); Cvar_RegisterVariable (&coop); + Cvar_RegisterVariable (&teamplay); Cvar_RegisterVariable (&skill); Cvar_RegisterVariable (&rcon_password); diff --git a/engine/sprite.h b/engine/sprite.h index 00d90c99..69c2e170 100644 --- a/engine/sprite.h +++ b/engine/sprite.h @@ -29,6 +29,7 @@ SPRITE MODELS #define SPRITE_VERSION_Q1 1 // Quake sprites #define SPRITE_VERSION_HL 2 // Half-Life sprites +#define SPRITE_VERSION_32 32 // Captain Obvious mode on // must match definition in alias.h #ifndef SYNCTYPE_T