mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-07 21:00:41 +08:00
engine: bring back texture replacement
This commit is contained in:
@@ -2981,8 +2981,47 @@ int GAME_EXPORT CL_DecalIndex( int id )
|
||||
|
||||
if( cl.decal_index[id] == 0 )
|
||||
{
|
||||
int gl_texturenum = 0;
|
||||
|
||||
Image_SetForceFlags( IL_LOAD_DECAL );
|
||||
cl.decal_index[id] = ref.dllFuncs.GL_LoadTexture( host.draw_decals[id], NULL, 0, TF_DECAL );
|
||||
|
||||
if( Mod_AllowMaterials( ))
|
||||
{
|
||||
string decalname;
|
||||
|
||||
if( Q_snprintf( decalname, sizeof( decalname ), "materials/decals/%s.tga", host.draw_decals[id] ) > 0 )
|
||||
{
|
||||
if( g_fsapi.FileExists( decalname, false ))
|
||||
{
|
||||
gl_texturenum = ref.dllFuncs.GL_LoadTexture( decalname, NULL, 0, TF_DECAL );
|
||||
if( host_allow_materials.value == 2.0f )
|
||||
Con_Printf( "Looking for %s decal replacement...%s (%s)\n", host.draw_decals[id], gl_texturenum != 0 ? S_GREEN "OK" : S_RED "FAIL", decalname );
|
||||
}
|
||||
else if( host_allow_materials.value == 2.0f )
|
||||
Con_Printf( "Looking for %s decal replacement..." S_YELLOW "MISS (%s)\n", host.draw_decals[id], decalname );
|
||||
}
|
||||
else if( host_allow_materials.value == 2.0f )
|
||||
Con_Printf( "Looking for %s decal replacement..." S_YELLOW "MISS (overflow)\n", host.draw_decals[id] );
|
||||
|
||||
if( gl_texturenum )
|
||||
{
|
||||
byte *fin;
|
||||
|
||||
Q_snprintf( decalname, sizeof( decalname ), "decals.wad/%s", host.draw_decals[id] );
|
||||
|
||||
if(( fin = g_fsapi.LoadFile( decalname, NULL, false )) != NULL )
|
||||
{
|
||||
mip_t *mip = (mip_t *)fin;
|
||||
ref.dllFuncs.R_OverrideTextureSourceSize( gl_texturenum, mip->width, mip->height );
|
||||
Mem_Free( fin );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( !gl_texturenum )
|
||||
gl_texturenum = ref.dllFuncs.GL_LoadTexture( host.draw_decals[id], NULL, 0, TF_DECAL );
|
||||
|
||||
cl.decal_index[id] = gl_texturenum;
|
||||
Image_ClearForceFlags();
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ extern convar_t gl_vsync;
|
||||
extern convar_t scr_loading;
|
||||
extern convar_t scr_download;
|
||||
extern convar_t cmd_scripting;
|
||||
extern convar_t cl_allow_levelshots;
|
||||
extern convar_t host_allow_materials;
|
||||
extern convar_t host_developer;
|
||||
extern convar_t host_limitlocal;
|
||||
extern convar_t host_maxfps;
|
||||
@@ -165,6 +165,8 @@ extern convar_t sys_timescale;
|
||||
extern convar_t cl_filterstuffcmd;
|
||||
extern convar_t rcon_password;
|
||||
|
||||
#define Mod_AllowMaterials() ( host_allow_materials.value != 0.0f && !FBitSet( host.features, ENGINE_DISABLE_HDTEXTURES ))
|
||||
|
||||
/*
|
||||
==============================================================
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ CVAR_DEFINE( host_maxfps, "fps_max", "72", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "host
|
||||
static CVAR_DEFINE_AUTO( host_framerate, "0", FCVAR_FILTERABLE, "locks frame timing to this value in seconds" );
|
||||
static CVAR_DEFINE( host_sleeptime, "sleeptime", "1", FCVAR_ARCHIVE|FCVAR_FILTERABLE, "milliseconds to sleep for each frame. higher values reduce fps accuracy" );
|
||||
static CVAR_DEFINE_AUTO( host_sleeptime_debug, "0", 0, "print sleeps between frames" );
|
||||
CVAR_DEFINE_AUTO( host_allow_materials, "0", FCVAR_LATCH|FCVAR_ARCHIVE, "allow texture replacements from materials/ folder" );
|
||||
CVAR_DEFINE( con_gamemaps, "con_mapfilter", "1", FCVAR_ARCHIVE, "when true show only maps in game folder" );
|
||||
|
||||
typedef struct feature_message_s
|
||||
@@ -1327,6 +1328,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||
Cmd_AddRestrictedCommand ( "crash", Host_Crash_f, "a way to force a bus error for development reasons");
|
||||
}
|
||||
|
||||
Cvar_RegisterVariable( &host_allow_materials );
|
||||
Cvar_RegisterVariable( &host_serverstate );
|
||||
Cvar_RegisterVariable( &host_maxfps );
|
||||
Cvar_RegisterVariable( &host_framerate );
|
||||
@@ -1372,6 +1374,9 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
|
||||
Wcon_InitConsoleCommands ();
|
||||
#endif
|
||||
|
||||
// disable texture replacements for dedicated
|
||||
Cvar_FullSet( "host_allow_materials", "0", FCVAR_READ_ONLY );
|
||||
|
||||
Cmd_AddRestrictedCommand( "quit", Sys_Quit, "quit the game" );
|
||||
Cmd_AddRestrictedCommand( "exit", Sys_Quit, "quit the game" );
|
||||
}
|
||||
|
||||
@@ -2066,7 +2066,39 @@ static qboolean Mod_LooksLikeWaterTexture( const char *name )
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Mod_InitSkyClouds( mip_t *mt, texture_t *tx, qboolean custom_palette )
|
||||
static void Mod_TextureReplacementReport( const char *modelname, const char *texname, const char *type, int gl_texturenum, const char *foundpath )
|
||||
{
|
||||
if( host_allow_materials.value != 2.0f )
|
||||
return;
|
||||
|
||||
if( gl_texturenum > 0 ) // found and loaded successfully
|
||||
Con_Printf( "Looking for %s:%s%s tex replacement..." S_GREEN "OK (%s)\n", modelname, texname, type, foundpath );
|
||||
else if( gl_texturenum < 0 ) // not found
|
||||
Con_Printf( "Looking for %s:%s%s tex replacement..." S_YELLOW "MISS (%s)\n", modelname, texname, type, foundpath );
|
||||
else // found but not loaded
|
||||
Con_Printf( "Looking for %s:%s%s tex replacement..." S_RED "FAIL (%s)\n", modelname, texname, type, foundpath );
|
||||
}
|
||||
|
||||
static qboolean Mod_SearchForTextureReplacement( char *out, size_t size, const char *modelname, const char *texname, const char *type )
|
||||
{
|
||||
const char *subdirs[] = { modelname, "common" };
|
||||
int i;
|
||||
|
||||
for( i = 0; i < ARRAYSIZE( subdirs ); i++ )
|
||||
{
|
||||
if( Q_snprintf( out, size, "materials/%s/%s%s.tga", subdirs[i], texname, type ) < 0 )
|
||||
continue; // truncated name
|
||||
|
||||
if( g_fsapi.FileExists( out, false ))
|
||||
return true; // found, load it
|
||||
}
|
||||
|
||||
Mod_TextureReplacementReport( modelname, texname, type, -1, "not found" );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void Mod_InitSkyClouds( model_t *mod, mip_t *mt, texture_t *tx, qboolean custom_palette )
|
||||
{
|
||||
#if !XASH_DEDICATED
|
||||
rgbdata_t r_temp, *r_sky;
|
||||
@@ -2074,12 +2106,47 @@ static void Mod_InitSkyClouds( mip_t *mt, texture_t *tx, qboolean custom_palette
|
||||
uint transpix;
|
||||
int r, g, b;
|
||||
int i, j, p;
|
||||
char texname[32];
|
||||
int solidskyTexture, alphaskyTexture;
|
||||
string texname;
|
||||
int solidskyTexture = 0, alphaskyTexture = 0;
|
||||
|
||||
if( !ref.initialized )
|
||||
return;
|
||||
|
||||
if( Mod_AllowMaterials( ))
|
||||
{
|
||||
rgbdata_t *pic;
|
||||
|
||||
if( Mod_SearchForTextureReplacement( texname, sizeof( texname ), mod->name, mt->name, "_solid" ))
|
||||
{
|
||||
pic = FS_LoadImage( texname, NULL, 0 );
|
||||
if( pic )
|
||||
{
|
||||
// need to do rename texture to properly cleanup these textures on reload
|
||||
solidskyTexture = GL_LoadTextureInternal( "solid_sky", pic, TF_NOMIPMAP );
|
||||
Mod_TextureReplacementReport( mod->name, mt->name, "_solid", solidskyTexture, texname );
|
||||
FS_FreeImage( pic );
|
||||
}
|
||||
}
|
||||
|
||||
if( Mod_SearchForTextureReplacement( texname, sizeof( texname ), mod->name, mt->name, "_alpha" ))
|
||||
{
|
||||
pic = FS_LoadImage( texname, NULL, 0 );
|
||||
if( pic )
|
||||
{
|
||||
alphaskyTexture = GL_LoadTextureInternal( "alpha_sky", pic, TF_NOMIPMAP );
|
||||
Mod_TextureReplacementReport( mod->name, mt->name, "_alpha", alphaskyTexture, texname );
|
||||
FS_FreeImage( pic );
|
||||
}
|
||||
}
|
||||
|
||||
if( !solidskyTexture || !alphaskyTexture )
|
||||
{
|
||||
ref.dllFuncs.GL_FreeTexture( solidskyTexture );
|
||||
ref.dllFuncs.GL_FreeTexture( alphaskyTexture );
|
||||
}
|
||||
else goto done; // replacements found, notify the renderer and exit
|
||||
}
|
||||
|
||||
Q_snprintf( texname, sizeof( texname ), "%s%s.mip", ( mt->offsets[0] > 0 ) ? "#" : "", tx->name );
|
||||
|
||||
if( mt->offsets[0] > 0 )
|
||||
@@ -2170,6 +2237,14 @@ static void Mod_InitSkyClouds( mip_t *mt, texture_t *tx, qboolean custom_palette
|
||||
FS_FreeImage( r_sky );
|
||||
Mem_Free( trans );
|
||||
|
||||
if( !solidskyTexture || !alphaskyTexture )
|
||||
{
|
||||
ref.dllFuncs.GL_FreeTexture( solidskyTexture );
|
||||
ref.dllFuncs.GL_FreeTexture( alphaskyTexture );
|
||||
return;
|
||||
}
|
||||
|
||||
done:
|
||||
// notify the renderer
|
||||
ref.dllFuncs.R_SetSkyCloudsTextures( solidskyTexture, alphaskyTexture );
|
||||
|
||||
@@ -2184,6 +2259,9 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
|
||||
mip_t *mipTex = NULL;
|
||||
qboolean usesCustomPalette = false;
|
||||
uint32_t txFlags = 0;
|
||||
char texpath[MAX_VA_STRING];
|
||||
char safemtname[16]; // only for external textures
|
||||
qboolean load_external = false;
|
||||
|
||||
// don't load texture data on dedicated server, as there is no renderer.
|
||||
// but count the wadusage for automatic precache
|
||||
@@ -2192,6 +2270,14 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
|
||||
// but there is no facility for this yet
|
||||
texture = mod->textures[textureIndex];
|
||||
mipTex = Mod_GetMipTexForTexture( bmod, textureIndex );
|
||||
usesCustomPalette = Mod_CalcMipTexUsesCustomPalette( mod, bmod, textureIndex );
|
||||
|
||||
// check for multi-layered sky texture (quake1 specific)
|
||||
if( bmod->isworld && Q_strncmp( mipTex->name, "sky", 3 ) == 0 && ( mipTex->width / mipTex->height ) == 2 )
|
||||
{
|
||||
Mod_InitSkyClouds( mod, mipTex, texture, usesCustomPalette ); // load quake sky
|
||||
return;
|
||||
}
|
||||
|
||||
if( FBitSet( host.features, ENGINE_IMPROVED_LINETRACE ) && mipTex->name[0] == '{' )
|
||||
SetBits( txFlags, TF_KEEP_SOURCE ); // Paranoia2 texture alpha-tracing
|
||||
@@ -2200,23 +2286,31 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
|
||||
if( Mod_LooksLikeWaterTexture( mipTex->name ))
|
||||
SetBits( txFlags, TF_KEEP_SOURCE | TF_EXPAND_SOURCE );
|
||||
|
||||
usesCustomPalette = Mod_CalcMipTexUsesCustomPalette( mod, bmod, textureIndex );
|
||||
// Texture loading order:
|
||||
// 1. HQ from disk
|
||||
// 2. From WAD
|
||||
// 3. Internal from map
|
||||
|
||||
// check for multi-layered sky texture (quake1 specific)
|
||||
if( bmod->isworld && Q_strncmp( mipTex->name, "sky", 3 ) == 0 && ( mipTex->width / mipTex->height ) == 2 )
|
||||
texture->gl_texturenum = 0;
|
||||
Q_strncpy( safemtname, mipTex->name, sizeof( safemtname ));
|
||||
if( safemtname[0] == '*' )
|
||||
safemtname[0] = '!'; // replace unexpected symbol
|
||||
|
||||
if( Mod_AllowMaterials( ))
|
||||
{
|
||||
Mod_InitSkyClouds( mipTex, texture, usesCustomPalette ); // load quake sky
|
||||
return;
|
||||
#if !XASH_DEDICATED
|
||||
if( Mod_SearchForTextureReplacement( texpath, sizeof( texpath ), mod->name, safemtname, "" ))
|
||||
{
|
||||
texture->gl_texturenum = ref.dllFuncs.GL_LoadTexture( texpath, NULL, 0, txFlags );
|
||||
load_external = texture->gl_texturenum != 0;
|
||||
Mod_TextureReplacementReport( mod->name, safemtname, "", texture->gl_texturenum, texpath );
|
||||
}
|
||||
#endif // !XASH_DEDICATED
|
||||
}
|
||||
|
||||
// Texture loading order:
|
||||
// 1. From WAD
|
||||
// 2. Internal from map
|
||||
|
||||
// Try WAD texture (force while r_wadtextures is 1)
|
||||
if(( r_wadtextures.value && bmod->wadlist.count > 0 ) || mipTex->offsets[0] <= 0 )
|
||||
if( !texture->gl_texturenum && (( r_wadtextures.value && bmod->wadlist.count > 0 ) || mipTex->offsets[0] <= 0 ))
|
||||
{
|
||||
char texpath[MAX_VA_STRING];
|
||||
int wadIndex = Mod_FindTextureInWadList( &bmod->wadlist, mipTex->name, texpath, sizeof( texpath ));
|
||||
|
||||
if( wadIndex >= 0 )
|
||||
@@ -2251,9 +2345,20 @@ static void Mod_LoadTextureData( model_t *mod, dbspmodel_t *bmod, int textureInd
|
||||
}
|
||||
|
||||
// Check for luma texture
|
||||
if( FBitSet( REF_GET_PARM( PARM_TEX_FLAGS, texture->gl_texturenum ), TF_HAS_LUMA ))
|
||||
texture->fb_texturenum = 0;
|
||||
if( load_external ) // external textures will not have TF_HAS_LUMA flag because it set only from WAD images loader
|
||||
{
|
||||
if( Mod_SearchForTextureReplacement( texpath, sizeof( texpath ), mod->name, safemtname, "_luma" ))
|
||||
{
|
||||
texture->fb_texturenum = ref.dllFuncs.GL_LoadTexture( texpath, NULL, 0, TF_MAKELUMA );
|
||||
Mod_TextureReplacementReport( mod->name, safemtname, "_luma", texture->fb_texturenum, texpath );
|
||||
}
|
||||
}
|
||||
|
||||
if( FBitSet( REF_GET_PARM( PARM_TEX_FLAGS, texture->gl_texturenum ), TF_HAS_LUMA ) && !texture->fb_texturenum )
|
||||
{
|
||||
char texName[64];
|
||||
|
||||
Q_snprintf( texName, sizeof( texName ), "#%s:%s_luma.mip", loadstat.name, mipTex->name );
|
||||
|
||||
if( mipTex->offsets[0] > 0 )
|
||||
|
||||
@@ -568,6 +568,7 @@ typedef struct ref_interface_s
|
||||
int (*GL_LoadTextureArray)( const char **names, int flags );
|
||||
int (*GL_CreateTextureArray)( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags );
|
||||
void (*GL_FreeTexture)( unsigned int texnum );
|
||||
void (*R_OverrideTextureSourceSize)( unsigned int texnum, unsigned int srcWidth, unsigned int srcHeight ); // used to override decal size for texture replacement
|
||||
|
||||
// Decals manipulating (draw & remove)
|
||||
void (*DrawSingleDecal)( struct decal_s *pDecal, struct msurface_s *fa );
|
||||
@@ -673,6 +674,7 @@ typedef int (*REFAPI)( int version, ref_interface_t *pFunctionTable, ref_api_t*
|
||||
ENGINE_SHARED_CVAR( f, r_sprite_lighting ) \
|
||||
ENGINE_SHARED_CVAR( f, r_drawviewmodel ) \
|
||||
ENGINE_SHARED_CVAR( f, r_glowshellfreq ) \
|
||||
ENGINE_SHARED_CVAR( f, host_allow_materials ) \
|
||||
|
||||
#define DECLARE_ENGINE_SHARED_CVAR_LIST() \
|
||||
ENGINE_SHARED_CVAR_LIST( DECLARE_ENGINE_SHARED_CVAR )
|
||||
|
||||
Reference in New Issue
Block a user