added /shaderinfo

This commit is contained in:
myT 2022-05-28 16:50:42 +02:00
parent 049793f8f9
commit e56a11b638
8 changed files with 190 additions and 17 deletions

View file

@ -4,6 +4,8 @@ See the end of this file for known issues.
DD Mmm 20 - 1.53
add: /shaderinfo <shadername> [code] prints where the shader was loaded from and optionally the code
add: console mark mode (selection mode) can be toggled with Ctrl-M
use arrow keys, home/end or page up/down to move the cursor or extend the area when pressing shift
Ctrl-C/enter copies the selected text to the clipboard without color codes and exits mark mode

View file

@ -1797,10 +1797,12 @@ static void CL_InitRef()
ri.Hunk_FreeTempMemory = Hunk_FreeTempMemory;
ri.CM_DrawDebugSurface = CM_DrawDebugSurface;
ri.FS_ReadFile = FS_ReadFile;
ri.FS_ReadFilePak = FS_ReadFilePak;
ri.FS_FreeFile = FS_FreeFile;
ri.FS_WriteFile = FS_WriteFile;
ri.FS_FreeFileList = FS_FreeFileList;
ri.FS_ListFiles = FS_ListFiles;
ri.FS_GetPakPath = FS_GetPakPath;
ri.Cvar_Get = Cvar_Get;
ri.Cvar_SetHelp = Cvar_SetHelp;
ri.Cvar_Set = Cvar_Set;

View file

@ -868,7 +868,7 @@ separate file or a ZIP file.
*/
extern qbool com_fullyInitialized;
int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qbool uniqueFILE ) {
int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qbool uniqueFILE, int *pakChecksum ) {
searchpath_t *search;
char *netpath;
pack_t *pak;
@ -881,6 +881,9 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qbool uniqueFILE
char demoExt[16];
hash = 0;
if ( pakChecksum ) {
*pakChecksum = 0;
}
if ( !fs_searchpaths ) {
Com_Error( ERR_FATAL, "Filesystem call made without initialization\n" );
@ -902,6 +905,9 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qbool uniqueFILE
// case and separator insensitive comparisons
if ( !FS_FilenameCompare( pakFile->name, filename ) ) {
// found it!
if ( pakChecksum ) {
*pakChecksum = pak->checksum;
}
return qtrue;
}
pakFile = pakFile->next;
@ -1024,6 +1030,10 @@ int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qbool uniqueFILE
unzOpenCurrentFile( fsh[*file].handleFiles.file.z );
fsh[*file].zipFilePos = pakFile->pos;
if ( pakChecksum ) {
*pakChecksum = pak->checksum;
}
if ( fs_debug->integer ) {
Com_Printf( "FS_FOpenFileRead: %s (found in '%s')\n",
filename, pak->pakFilename );
@ -1359,7 +1369,7 @@ Filename are relative to the quake search path
a null buffer will just return the file length without loading
============
*/
int FS_ReadFile( const char *qpath, void **buffer ) {
int FS_ReadFilePak( const char *qpath, void **buffer, int *pakChecksum ) {
fileHandle_t h;
byte* buf;
qbool isConfig;
@ -1374,6 +1384,9 @@ int FS_ReadFile( const char *qpath, void **buffer ) {
}
buf = NULL; // quiet compiler warning
if ( pakChecksum ) {
*pakChecksum = 0;
}
// if this is a .cfg file and we are playing back a journal, read
// it from the journal file
@ -1421,7 +1434,7 @@ int FS_ReadFile( const char *qpath, void **buffer ) {
}
// look for it in the filesystem or pack files
len = FS_FOpenFileRead( qpath, &h, qfalse );
len = FS_FOpenFileRead( qpath, &h, qfalse, pakChecksum );
if ( h == 0 ) {
if ( buffer ) {
*buffer = NULL;
@ -1468,6 +1481,10 @@ int FS_ReadFile( const char *qpath, void **buffer ) {
return len;
}
int FS_ReadFile( const char *qpath, void **buffer ) {
return FS_ReadFilePak( qpath, buffer, NULL );
}
/*
=============
FS_FreeFile
@ -3229,3 +3246,14 @@ void FS_FilenameCompletion( const char *dir, const char *ext, qbool stripExt,
}
FS_FreeFileList( filenames );
}
qbool FS_GetPakPath( char *name, int nameSize, int pakChecksum ) {
for ( searchpath_t *search = fs_searchpaths; search; search = search->next ) {
if ( search->pack && search->pack->checksum == pakChecksum ) {
Com_sprintf( name, nameSize, "%s/%s.pk3", search->pack->pakGamename, search->pack->pakBasename );
return qtrue;
}
}
return qfalse;
}

View file

@ -657,7 +657,7 @@ fileHandle_t FS_FOpenFileWrite( const char *qpath );
fileHandle_t FS_SV_FOpenFileWrite( const char *filename );
int FS_SV_FOpenFileRead( const char *filename, fileHandle_t *fp );
void FS_SV_Rename( const char *from, const char *to );
int FS_FOpenFileRead( const char *qpath, fileHandle_t *file, qbool uniqueFILE );
int FS_FOpenFileRead( const char *qpath, fileHandle_t *file, qbool uniqueFILE, int *pakChecksum = NULL );
// if uniqueFILE is qtrue, then a new FILE will be fopened even if the file
// is found in an already open pak file. If uniqueFILE is qfalse, you must call
// FS_FCloseFile instead of fclose, otherwise the pak FILE would be improperly closed
@ -676,6 +676,7 @@ void FS_FCloseFile( fileHandle_t f );
// note: you can't just fclose from another DLL, due to MS libc issues
int FS_ReadFile( const char *qpath, void **buffer );
int FS_ReadFilePak( const char *qpath, void **buffer, int *pakChecksum );
// returns the length of the file
// a null buffer will just return the file length without loading
// as a quick check for existance. -1 length == not present
@ -750,6 +751,8 @@ void FS_HomeRemove( const char *homePath );
void FS_FilenameCompletion( const char *dir, const char *ext, qbool stripExt,
void (*callback)(const char *s), int filters );
qbool FS_GetPakPath( char *name, int nameSize, int pakChecksum );
/*
==============================================================

View file

@ -339,6 +339,7 @@ static const cmdTableItem_t r_cmds[] =
{ "gfxinfo", GfxInfo_f, NULL, "prints display mode info" },
{ "imagelist", R_ImageList_f, NULL, "prints loaded images" },
{ "shaderlist", R_ShaderList_f, NULL, "prints loaded shaders" },
{ "shaderinfo", R_ShaderInfo_f, R_CompleteShaderName_f, "prints info for a specific shader" },
{ "skinlist", R_SkinList_f, NULL, "prints loaded skins" },
{ "modellist", R_Modellist_f, NULL, "prints loaded models" },
{ "screenshot", R_ScreenShotTGA_f, NULL, "takes a TARGA (.tga) screenshot" },

View file

@ -426,6 +426,10 @@ struct shader_t {
qbool greyscaleCTF;
// extra info for /shaderinfo
int fileIndex;
const char* text;
shader_t* next;
};
@ -1200,6 +1204,8 @@ shader_t *R_FindShader( const char *name, int lightmapIndex, qbool mipRawImage )
const shader_t* R_GetShaderByHandle( qhandle_t hShader );
void R_InitShaders();
void R_ShaderList_f( void );
void R_ShaderInfo_f();
void R_CompleteShaderName_f( int startArg, int compArg );
/*
====================================================================

View file

@ -222,10 +222,12 @@ typedef struct {
// a -1 return means the file does not exist
// NULL can be passed for buf to just determine existance
int (*FS_ReadFile)( const char *name, void **buf );
int (*FS_ReadFilePak)( const char *name, void **buf, int* pakChecksum );
void (*FS_FreeFile)( void *buf );
char** (*FS_ListFiles)( const char *name, const char *extension, int *numfilesfound );
void (*FS_FreeFileList)( char **filelist );
void (*FS_WriteFile)( const char *qpath, const void *buffer, int size );
qbool (*FS_GetPakPath)( char *name, int nameSize, int pakChecksum );
// cinematic stuff
qbool (*CIN_GrabCinematic)( int handle, int* w, int* h, const byte** data, int* client, qbool* dirty );

View file

@ -44,6 +44,11 @@ const float r_depthFadeBias[DFT_COUNT][4] =
};
static char* s_shaderText = 0;
static int s_numShaderFiles = 0;
static char* s_shaderFileNames = 0;
static int* s_shaderFileOffsets = 0;
static int* s_shaderFileNameOffsets = 0;
static int* s_shaderPakChecksums = 0;
// the shader is parsed into these global variables, then copied into
// dynamically allocated memory if it is valid.
@ -2638,11 +2643,23 @@ shader_t* R_FindShader( const char *name, int lightmapIndex, qbool mipRawImage )
#if 0 // enable this when building a pak file to get a global list of all explicit shaders
ri.Printf( PRINT_ALL, "*SHADER* %s\n", name );
#endif
const int textOffset = (int)( shaderText - s_shaderText );
if ( !ParseShader( &shaderText ) ) {
// had errors, so use default shader
shader.defaultShader = qtrue;
}
sh = FinishShader();
int fileIndex = -1;
for ( int i = 0; i < s_numShaderFiles; ++i ) {
if ( textOffset >= s_shaderFileOffsets[i] ) {
fileIndex = i;
}
}
sh->fileIndex = fileIndex;
sh->text = s_shaderText + textOffset;
return sh;
}
@ -2852,6 +2869,100 @@ void R_ShaderList_f( void )
}
static void AutoCompleteShaderName( fieldCallback_t callback )
{
for ( int i = 0; i < tr.numShaders; i++ ) {
callback( tr.shaders[i]->name );
}
}
void R_CompleteShaderName_f( int startArg, int compArg )
{
if ( startArg + 1 == compArg )
Field_AutoCompleteCustom( startArg, compArg, &AutoCompleteShaderName );
}
void R_ShaderInfo_f()
{
if ( Cmd_Argc() <= 1 ) {
ri.Printf( PRINT_ALL, "usage: %s <shadername> [code]\n", Cmd_Argv(0) );
return;
}
const char* const name = Cmd_Argv(1);
const shader_t* shader = NULL;
for ( int i = 0; i < tr.numShaders; i++ ) {
if ( !Q_stricmp( tr.shaders[i]->name, name ) ) {
shader = tr.shaders[i];
break;
}
}
if ( shader == NULL ) {
ri.Printf( PRINT_ALL, "shader not found\n" );
return;
}
if ( shader->text == NULL ) {
const char* type;
switch ( shader->lightmapIndex ) {
case LIGHTMAP_BROKEN: type = "broken lit surface"; break;
case LIGHTMAP_2D: type = "UI element"; break;
case LIGHTMAP_BY_VERTEX: type = "vertex-lit surface"; break;
case LIGHTMAP_NONE: type = "opaque surface"; break;
default: type = "lit surface"; break;
}
ri.Printf( PRINT_ALL, "shader has no code (type: %s)\n", type );
return;
}
const int fileIndex = shader->fileIndex;
if ( fileIndex >= 0 && fileIndex < s_numShaderFiles ) {
const int nameOffset = s_shaderFileNameOffsets[fileIndex];
const char* const fileName = s_shaderFileNames + nameOffset;
ri.Printf( PRINT_ALL, "File: scripts/%s\n", fileName );
char pakName[256];
const int pakChecksum = s_shaderPakChecksums[fileIndex];
if( FS_GetPakPath( pakName, sizeof(pakName), pakChecksum ) ) {
ri.Printf( PRINT_ALL, "Pak : %s\n", pakName );
}
}
if ( Q_stricmp( Cmd_Argv(2), "code" ) ) {
return;
}
const char* s = shader->text;
int tabs = 0;
for ( ;; ) {
const char c0 = s[0];
const char c1 = s[1];
if ( c0 == '{' ) {
tabs++;
ri.Printf( PRINT_ALL, "{" );
} else if ( c0 == '\n' ) {
ri.Printf( PRINT_ALL, "\n" );
if ( c1 == '}' ) {
tabs--;
if ( tabs == 0 ) {
ri.Printf( PRINT_ALL, "}\n" );
return;
}
}
for( int i = 0; i < tabs; i++ ) {
ri.Printf( PRINT_ALL, " " );
}
} else {
ri.Printf( PRINT_ALL, "%c", c0 );
}
s++;
}
}
// finds and loads all .shader files, combining them into
// a single large text block that can be scanned for shader names
// note that this does a lot of things very badly, e.g. still loads superceded shaders
@ -2865,46 +2976,64 @@ static void ScanAndLoadShaderFiles()
int i;
char* p;
int numShaders;
char** shaderFiles = ri.FS_ListFiles( "scripts", ".shader", &numShaders );
int numShaderFiles;
char** shaderFileNames = ri.FS_ListFiles( "scripts", ".shader", &numShaderFiles );
if ( !shaderFiles || !numShaders )
if ( !shaderFileNames || !numShaderFiles )
{
ri.Printf( PRINT_WARNING, "WARNING: no shader files found\n" );
return;
}
if ( numShaders > MAX_SHADER_FILES )
if ( numShaderFiles > MAX_SHADER_FILES )
ri.Error( ERR_DROP, "Shader file limit exceeded" );
s_shaderFileOffsets = RI_New<int>( numShaderFiles );
s_shaderFileNameOffsets = RI_New<int>( numShaderFiles );
s_shaderPakChecksums = RI_New<int>( numShaderFiles );
s_numShaderFiles = numShaderFiles;
long sum = 0;
long sumNames = 0;
// load and parse shader files
for ( i = 0; i < numShaders; i++ )
for ( i = 0; i < numShaderFiles; i++ )
{
char filename[MAX_QPATH];
Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFiles[i] );
ri.FS_ReadFile( filename, (void **)&buffers[i] );
Com_sprintf( filename, sizeof( filename ), "scripts/%s", shaderFileNames[i] );
ri.FS_ReadFilePak( filename, (void **)&buffers[i], &s_shaderPakChecksums[i] );
if ( !buffers[i] )
ri.Error( ERR_DROP, "Couldn't load %s", filename );
len[i] = COM_Compress( buffers[i] );
sum += len[i];
sumNames += strlen( shaderFileNames[i] );
}
s_shaderText = RI_New<char>( sum + numShaders + 1 );
s_shaderText = RI_New<char>( sum + numShaderFiles + 1 );
s_shaderFileNames = RI_New<char>( sumNames );
char* s = s_shaderText;
for ( i = 0; i < numShaders; i++ ) {
char* s = s_shaderFileNames;
for ( i = 0; i < numShaderFiles; i++ ) {
s_shaderFileNameOffsets[i] = (int)( s - s_shaderFileNames );
const int l = strlen( shaderFileNames[i] );
Com_Memcpy( s, shaderFileNames[i], l );
s += l;
*s++ = '\0';
}
s = s_shaderText;
for ( i = 0; i < numShaderFiles; i++ ) {
s_shaderFileOffsets[i] = (int)( s - s_shaderText );
Com_Memcpy( s, buffers[i], len[i] );
s += len[i];
*s++ = '\n';
}
*s = 0;
*s = '\0';
// the files have to be freed backwards because the hunk isn't a real MM
for (i = numShaders - 1; i >= 0; --i)
for (i = numShaderFiles - 1; i >= 0; --i)
ri.FS_FreeFile( buffers[i] );
ri.FS_FreeFileList( shaderFiles );
ri.FS_FreeFileList( shaderFileNames );
int shaderTextHashTableSizes[MAX_SHADERTEXT_HASH];
Com_Memset(shaderTextHashTableSizes, 0, sizeof(shaderTextHashTableSizes));