Merge branch 'master' of github.com:TTimo/GtkRadiant

This commit is contained in:
Timothee Besset 2018-01-27 15:14:51 -06:00
commit b0d239fd81
7 changed files with 236 additions and 82 deletions

View file

@ -111,6 +111,9 @@ typedef void ( WINAPI * PFN_RELOADSHADERS )();
// load all shaders in a given directory
// this will scan the list of in-memory shaders, and load the related qtexture_t if needed
typedef int ( WINAPI * PFN_LOADSHADERSFROMDIR )( const char* path );
// count all shaders in a given directory
// this will scan the list of in-memory shaders
typedef bool ( WINAPI * PFN_ISDIRCONTAININGSHADER )( const char* path );
// load a shader file (ie a set of shaders)
// after LoadShaderFile shaders will be in memory, next step is to load the qtexture_t Radiant uses to represent them
// if a shader with the same name exists, new one will not be loaded - don't use this to refresh the shaders!
@ -178,6 +181,7 @@ struct _QERShadersTable
PFN_FREESHADERS m_pfnFreeShaders;
PFN_RELOADSHADERS m_pfnReloadShaders;
PFN_LOADSHADERSFROMDIR m_pfnLoadShadersFromDir;
PFN_ISDIRCONTAININGSHADER m_pfnIsDirContainingShaders;
PFN_LOADSHADERFILE m_pfnLoadShaderFile;
PFN_RELOADSHADERFILE m_pfnReloadShaderFile;
PFN_HASSHADER m_pfnHasShader;
@ -219,7 +223,7 @@ struct _QERShadersTable
#define QERApp_ColorShader_ForName __SHADERSTABLENAME.m_pfnColorShader_ForName
#define QERApp_Shader_ForName_NoLoad __SHADERSTABLENAME.m_pfnShader_ForName_NoLoad
#define QERApp_LoadShadersFromDir __SHADERSTABLENAME.m_pfnLoadShadersFromDir
#define QERApp_LoadShadersFromDir __SHADERSTABLENAME.m_pfnLoadShadersFromDir
#define QERApp_IsDirContainingShaders __SHADERSTABLENAME.m_pfnIsDirContainingShaders
#define QERApp_CreateShader_ForTextureName __SHADERSTABLENAME.m_pfnCreateShader_ForTextureName
#define QERApp_GetActiveShaderCount __SHADERSTABLENAME.m_pfnGetActiveShaderCount
#define QERApp_ActiveShaders_SetDisplayed __SHADERSTABLENAME.m_pfnActiveShaders_SetDisplayed

View file

@ -404,32 +404,90 @@ void WINAPI QERApp_ReloadShaders(){
int WINAPI QERApp_LoadShadersFromDir( const char *path ){
int count = 0;
// some code adds a trailing slash
gchar* keyword = g_strdup(path);
if ( g_str_has_suffix( keyword, "/" ) ) {
keyword[ strlen(keyword) -1 ] = '\0';
}
gchar* around = g_strconcat("/", keyword, ".", NULL);
gchar* prefix = g_strconcat("textures/", keyword, "/", NULL);
// scan g_Shaders, and call QERApp_Shader_ForName for each in the given path
// this will load the texture if needed and will set it in use..
int nSize = g_Shaders.GetSize();
for ( int i = 0; i < nSize; i++ )
{
CShader *pShader = reinterpret_cast < CShader * >( g_Shaders[i] );
if ( strstr( pShader->getShaderFileName(), path ) || strstr( pShader->getName(), path ) ) {
// does not uselessly load shader with path not starting with "textures/"
// they will not be displayed by texture browser, because they can't be
// applied to a surface
if ( !g_str_has_prefix( pShader->getName(), "textures/" ) ) {
continue;
}
// - proceed if shader script base name is <path>
// for example: "scripts/eerie.shader" with "eerie" path
// - proceed if shader script base name is <path> and shader path starts with "textures/<path>"
// for example: "scripts/eerie.shader" providing "textures/eerie/blackness" with "eerie" path
if ( strstr( pShader->getShaderFileName(), around ) != NULL || g_str_has_prefix( pShader->getName(), prefix ) ) {
count++;
#ifdef _DEBUG
// request the shader, this will load the texture if needed and set "inuse"
//++timo FIXME: should we put an Activate member on CShader?
// this QERApp_Shader_ForName call is a kind of hack
IShader *pFoo = QERApp_Shader_ForName( pShader->getName() );
#ifdef _DEBUG
// check we activated the right shader
// NOTE: if there was something else loaded, the size of g_Shaders may have changed and strange behaviours are to be expected
if ( pFoo != pShader ) {
Sys_FPrintf( SYS_WRN, "WARNING: unexpected pFoo != pShader in QERApp_LoadShadersFromDir\n" );
}
#else
pFoo = NULL; // leo: shut up the compiler
QERApp_Shader_ForName( pShader->getName() );
#endif
}
}
g_free(keyword);
g_free(around);
g_free(prefix);
return count;
}
bool WINAPI QERApp_IsDirContainingShaders( const char *path ){
int nSize = g_Shaders.GetSize();
// exclude shaders that are not starting with "textures/"
// they will not be displayed and are not applicable to surfaces
// exclude shaders from other paths,
// they are not the ones we are looking for
gchar* around = g_strconcat("/", path, ".", NULL);
gchar* prefix = g_strconcat("textures/", path, "/", NULL);
for ( int i = 0; i < nSize; i++ )
{
CShader *pShader = reinterpret_cast < CShader * >( g_Shaders[i] );
// - returns true if shader script basename is <path> and shader path starts with "textures/"
// for example: "scripts/rockyvalley.shader" with "rockyvalley" path providing "textures/amethyst7/rockyvalley/rockyvalley_skybox/"
// - returns true if shader <path> startswith "textures/<path>"
// for example: "scripts/eerie.shader" with "eerie" path providing "textures/eerie/blackness"
if ( ( strstr( pShader->getShaderFileName(), around ) != NULL && g_str_has_prefix( pShader->getName(), "textures/" ) ) || g_str_has_prefix( pShader->getName(), prefix ) ) {
g_free(around);
g_free(prefix);
return true;
}
}
g_free(around);
g_free(prefix);
return false;
}
bool CShader::Parse(){
char *token = g_ScripLibTable.m_pfnToken();
@ -924,6 +982,7 @@ bool CSynapseClientShaders::RequestAPI( APIDescriptor_t *pAPI ){
pTable->m_pfnFreeShaders = QERApp_FreeShaders;
pTable->m_pfnReloadShaders = QERApp_ReloadShaders;
pTable->m_pfnLoadShadersFromDir = QERApp_LoadShadersFromDir;
pTable->m_pfnIsDirContainingShaders = QERApp_IsDirContainingShaders;
pTable->m_pfnReloadShaderFile = QERApp_ReloadShaderFile;
pTable->m_pfnLoadShaderFile = QERApp_LoadShaderFile;
pTable->m_pfnHasShader = QERApp_HasShader;

View file

@ -552,6 +552,7 @@ gint HandleCommand( GtkWidget *widget, gpointer data ){
case ID_TEXTURES_LOAD: g_pParentWnd->OnTexturesLoad(); break;
case ID_TEXTURES_RELOADSHADERS: g_pParentWnd->OnTexturesReloadshaders(); break;
case ID_TEXTURES_SHADERS_SHOW: g_pParentWnd->OnTexturesShadersShow(); break;
case ID_TEXTURES_EMPTYDIRS_HIDE: g_pParentWnd->OnTexturesEmptyDirsHide(); break;
case ID_TEXTURES_TEXTUREWINDOWSCALE_200:
case ID_TEXTURES_TEXTUREWINDOWSCALE_100:
case ID_TEXTURES_TEXTUREWINDOWSCALE_50:
@ -1402,6 +1403,9 @@ void MainFrame::create_main_menu( GtkWidget *window, GtkWidget *vbox ){
item = create_check_menu_item_with_mnemonic( menu, _( "shaderlist.txt only" ),
G_CALLBACK( HandleCommand ), ID_TEXTURES_SHADERLISTONLY, FALSE );
g_object_set_data( G_OBJECT( window ), "menu_textures_shaderlistonly", item );
item = create_check_menu_item_with_mnemonic( menu, _( "Hide empty directories" ),
G_CALLBACK( HandleCommand ), ID_TEXTURES_EMPTYDIRS_HIDE, FALSE );
g_object_set_data( G_OBJECT( window ), "menu_textures_emptydirs_hide", item );
item = menu_separator( menu );
menu_in_menu = create_menu_in_menu_with_mnemonic( menu, _( "Texture Directories" ) );
@ -3108,6 +3112,8 @@ void MainFrame::Create(){
g_bIgnoreCommands++;
item = GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "menu_textures_shaders_show" ) );
gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( item ), g_PrefsDlg.m_bShowShaders ? TRUE : FALSE );
item = GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "menu_textures_emptydirs_hide" ) );
gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( item ), g_PrefsDlg.m_bHideEmptyDirs ? TRUE : FALSE );
item = GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "menu_textures_shaderlistonly" ) );
gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( item ), g_PrefsDlg.m_bTexturesShaderlistOnly ? TRUE : FALSE );
g_bIgnoreCommands--;
@ -5951,6 +5957,20 @@ void MainFrame::OnTexturesReloadshaders(){
ClearGSList( texdirs );
}
void MainFrame::OnTexturesEmptyDirsHide(){
g_PrefsDlg.m_bHideEmptyDirs ^= 1;
GtkWidget *item = GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "menu_textures_emptydirs_hide" ) );
g_bIgnoreCommands++;
gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM( item ), g_PrefsDlg.m_bHideEmptyDirs ? TRUE : FALSE );
g_bIgnoreCommands--;
GSList *texdirs = NULL;
FillTextureList( &texdirs );
FillTextureMenu( texdirs );
FillTextureDirListWidget( texdirs );
ClearGSList( texdirs );
}
void MainFrame::OnTexturesShadersShow(){
g_PrefsDlg.m_bShowShaders ^= 1;
GtkWidget *item = GTK_WIDGET( g_object_get_data( G_OBJECT( m_pWidget ), "menu_textures_shaders_show" ) );

View file

@ -216,6 +216,7 @@ struct SKeyInfo
#define ID_VIEW_HIDESHOW_SHOWHIDDEN 33007
#define ID_TEXTURES_SHADERS_SHOW 33008
//#define ID_SELECTION_CSGADD 33009
#define ID_TEXTURES_EMPTYDIRS_HIDE 33010
#define ID_SELECTION_CSGMERGE 33011
#define ID_TEXTURES_FLUSH_UNUSED 33014
#define ID_DROP_GROUP_REMOVE 33016
@ -863,6 +864,7 @@ void OnViewCrosshair();
void OnViewHideshowHideselected();
void OnViewHideshowShowhidden();
void OnTexturesShadersShow();
void OnTexturesEmptyDirsHide();
void OnViewGroups();
void OnDropGroupAddtoWorld();
void OnDropGroupName();

View file

@ -119,6 +119,7 @@
#define TEXTURESUBSET_KEY "UseTextureSubsetLoading"
#define TEXTUREQUALITY_KEY "TextureQuality"
#define SHOWSHADERS_KEY "ShowShaders"
#define HIDEEMPTYDIRS_KEY "HideEmptyDirs"
#define SHADERTEST_KEY "ShaderTest"
#define GLLIGHTING_KEY "UseGLLighting"
#define LOADSHADERS_KEY "LoadShaders"
@ -644,6 +645,7 @@ PrefsDlg::PrefsDlg (){
m_bSelectWholeEntities = TRUE;
m_nTextureQuality = 3;
m_bShowShaders = TRUE;
m_bHideEmptyDirs = FALSE;
m_bGLLighting = FALSE;
m_nShader = 0;
m_nUndoLevels = 30;
@ -3076,6 +3078,7 @@ void PrefsDlg::LoadPrefs(){
mLocalPrefs.GetPref( SWITCHCLIP_KEY, &m_bSwitchClip, TRUE );
mLocalPrefs.GetPref( SELWHOLEENTS_KEY, &m_bSelectWholeEntities, TRUE );
mLocalPrefs.GetPref( SHOWSHADERS_KEY, &m_bShowShaders, TRUE );
mLocalPrefs.GetPref( HIDEEMPTYDIRS_KEY, &m_bHideEmptyDirs, FALSE );
mLocalPrefs.GetPref( GLLIGHTING_KEY, &m_bGLLighting, FALSE );
mLocalPrefs.GetPref( NOSTIPPLE_KEY, &m_bNoStipple, FALSE );
mLocalPrefs.GetPref( UNDOLEVELS_KEY, &m_nUndoLevels, 30 );

View file

@ -639,6 +639,7 @@ bool m_bTextureScrollbar;
bool m_bDisplayLists;
bool m_bAntialiasedPointsAndLines; // Fishman - Add antialiazed points and lines support. 09/03/00
bool m_bShowShaders;
bool m_bHideEmptyDirs;
int m_nShader;
bool m_bNoStipple;
int m_nUndoLevels;

View file

@ -529,6 +529,129 @@ void BuildShaderList(){
}
}
bool IsValidTextureName(char* name){
CString strTemp;
StripExtension( name );
strTemp = name;
strTemp.MakeLower();
// avoid effect textures for Q3 texture sets
if ( strTemp.Find( ".specular" ) >= 0 ||
strTemp.Find( ".glow" ) >= 0 ||
strTemp.Find( ".bump" ) >= 0 ||
strTemp.Find( ".diffuse" ) >= 0 ||
strTemp.Find( ".blend" ) >= 0 ||
strTemp.Find( ".alpha" ) >= 0 ) {
return false;
}
if ( g_str_has_suffix( name, "_g" ) ||
// avoid glow, heightmap, normalmap and specular maps for Q4 texture sets
g_str_has_suffix( name, "_h" ) ||
g_str_has_suffix( name, "_local" ) ||
g_str_has_suffix( name, "_nm" ) ||
g_str_has_suffix( name, "_s" ) ||
g_str_has_suffix( name, "_bump" ) ||
g_str_has_suffix( name, "_gloss" ) ||
g_str_has_suffix( name, "_luma" ) ||
g_str_has_suffix( name, "_norm" ) ||
// more well-known suffixes
g_str_has_suffix( name, "_p" ) || // preview (used by qer_editorimage)
g_str_has_suffix( name, "_g" ) || // gloss
g_str_has_suffix( name, "_n" ) // normal
) {
return false;
}
// avoid ever loading a texture name with spaces
if ( strTemp.Find( " " ) >= 0 ) {
Sys_FPrintf( SYS_WRN, "WARNING: Skipping texture name with spaces [%s]\n", strTemp.GetBuffer() );
return false;
}
return true;
}
bool IsDirContainingTextures(const char* path){
char name[1024];
char dirstring[1024];
GSList *files = NULL, *temp;
sprintf( dirstring, "textures/%s", path );
g_ImageManager.BeginExtensionsScan();
const char* ext;
while ( ( ext = g_ImageManager.GetNextExtension() ) != NULL )
{
files = g_slist_concat( files, vfsGetFileList( dirstring, ext ) );
}
for ( temp = files; temp; temp = temp->next )
{
sprintf( name, "%s", (char*)temp->data );
if ( IsValidTextureName( name ) ) {
vfsClearFileDirList( &files );
return true;
}
}
vfsClearFileDirList( &files );
return false;
}
void Texture_ListDirectory(){
char name[1024];
char dirstring[1024];
int shaders_count = 0;
int textures_count = 0;
GSList *files = NULL, *temp;
// load texture_directory.shader
// NOTE: because of above call to Texture_ClearInuse, g_ActiveShaders will have the newly loaded shaders only
// we'll use that later to check if textures have a shader associated or not
// NOTE: all shaders loaded through QERApp_LoadShadersFromDir will get their InUse flag to True, we'll need a call to Texture_ShowInUse for later cleanup/adjustment
// NOTE: QERApp_LoadShadersFromDir has two criterions for loading a shader:
// the shaderfile is texture_directory (like "museum" will load everything in museum.shader)
// the shader name contains texture_directory (like "base_floor" will load museum.shader::base_floor/concfloor_rain)
shaders_count = QERApp_LoadShadersFromDir( texture_directory );
// load remaining texture files
// if a texture is already in use to represent a shader, ignore it
// need this function "GSList *lst SynapseServer::GetMinorList(char *major_name);"
sprintf( dirstring, "textures/%s", texture_directory );
g_ImageManager.BeginExtensionsScan();
const char* ext;
while ( ( ext = g_ImageManager.GetNextExtension() ) != NULL )
{
files = g_slist_concat( files, vfsGetFileList( dirstring, ext ) );
}
for ( temp = files; temp; temp = temp->next )
{
sprintf( name, "%s%s", texture_directory, (char*)temp->data );
if ( !IsValidTextureName( name ) ) {
continue;
}
// build a texture name that fits the conventions for qtexture_t::name
char stdName[1024];
sprintf( stdName, "textures/%s", name );
// check if this texture doesn't have a shader
if ( !QERApp_ActiveShader_ForTextureName( stdName ) ) {
QERApp_CreateShader_ForTextureName( stdName );
textures_count++;
}
}
Sys_Printf( "Loaded %d shaders and created default shader for %d orphan textures.\n",
shaders_count, textures_count );
vfsClearFileDirList( &files );
}
/*
==================
FillTextureMenu
@ -562,7 +685,14 @@ void FillTextureList( GSList** pArray )
// Hydra: erm, this didn't used to do anything except leak memory...
// For Halflife support this is required to work however.
// g_slist_append(texdirs, p->data);
texdirs = g_slist_append( texdirs, g_strdup( (char *)p->data ) );
if ( !g_PrefsDlg.m_bHideEmptyDirs || IsDirContainingTextures( (char*)p->data ) )
{
texdirs = g_slist_append( texdirs, g_strdup( (char *)p->data ) );
}
else
{
Sys_Printf( "Hiding empty texture dir: %s\n", g_strdup( (char *)p->data ) );
}
}
vfsClearFileDirList( &texdirs_tmp );
}
@ -589,13 +719,22 @@ void FillTextureList( GSList** pArray )
}
for ( GSList *tmp = texdirs; tmp; tmp = g_slist_next( tmp ) )
{
if ( !strcasecmp( (char*)tmp->data, shaderfile ) ) {
found = TRUE;
break;
}
}
if ( !found ) {
texdirs = g_slist_prepend( texdirs, g_strdup( shaderfile ) );
if( !g_PrefsDlg.m_bHideEmptyDirs || QERApp_IsDirContainingShaders( shaderfile ) )
{
texdirs = g_slist_prepend( texdirs, g_strdup( shaderfile ) );
}
else
{
Sys_Printf( "Hiding empty shader dir: %s\n", g_strdup ( shaderfile ) );
}
}
free( l_shaderfiles->data );
@ -788,13 +927,9 @@ void Texture_ShowDirectory_by_path( const char* pPath )
( the GL textures are not flushed though)
==============
*/
void Texture_ShowDirectory(){
char name[1024];
char dirstring[1024];
CString strTemp;
int shaders_count = 0;
int textures_count = 0;
GSList *files = NULL, *temp;
g_bScreenUpdates = false;
@ -805,78 +940,8 @@ void Texture_ShowDirectory(){
// NOTE: shaders that are not in use but have been loaded previously are still in memory. But they don't get displayed.
g_qeglobals.d_texturewin.originy = 0;
// load texture_directory.shader
// NOTE: because of above call to Texture_ClearInuse, g_ActiveShaders will have the newly loaded shaders only
// we'll use that later to check if textures have a shader associated or not
// NOTE: all shaders loaded through QERApp_LoadShadersFromDir will get their InUse flag to True, we'll need a call to Texture_ShowInUse for later cleanup/adjustment
// NOTE: QERApp_LoadShadersFromDir has two criterions for loading a shader:
// the shaderfile is texture_directory (like "museum" will load everything in museum.shader)
// the shader name contains texture_directory (like "base_floor" will load museum.shader::base_floor/concfloor_rain)
shaders_count = QERApp_LoadShadersFromDir( texture_directory );
// load remaining texture files
// if a texture is already in use to represent a shader, ignore it
// need this function "GSList *lst SynapseServer::GetMinorList(char *major_name);"
sprintf( dirstring, "textures/%s", texture_directory );
g_ImageManager.BeginExtensionsScan();
const char* ext;
while ( ( ext = g_ImageManager.GetNextExtension() ) != NULL )
{
files = g_slist_concat( files, vfsGetFileList( dirstring, ext ) );
}
for ( temp = files; temp; temp = temp->next )
{
sprintf( name, "%s%s", texture_directory, (char*)temp->data );
StripExtension( name );
strTemp = name;
strTemp.MakeLower();
// avoid effect textures for Q3 texture sets
if ( strTemp.Find( ".specular" ) >= 0 ||
strTemp.Find( ".glow" ) >= 0 ||
strTemp.Find( ".bump" ) >= 0 ||
strTemp.Find( ".diffuse" ) >= 0 ||
strTemp.Find( ".blend" ) >= 0 ||
strTemp.Find( ".alpha" ) >= 0 ) {
continue;
}
// avoid glow, heightmap, normalmap and specular maps for Q4 texture sets
if ( g_str_has_suffix( name, "_g" ) ||
g_str_has_suffix( name, "_h" ) ||
g_str_has_suffix( name, "_local" ) ||
g_str_has_suffix( name, "_nm" ) ||
g_str_has_suffix( name, "_s" ) ||
g_str_has_suffix( name, "_bump" ) ||
g_str_has_suffix( name, "_gloss" ) ||
g_str_has_suffix( name, "_luma" ) ||
g_str_has_suffix( name, "_norm" ) ) {
continue;
}
// avoid ever loading a texture name with spaces
if ( strTemp.Find( " " ) >= 0 ) {
Sys_FPrintf( SYS_WRN, "WARNING: Skipping texture name with spaces [%s]\n", strTemp.GetBuffer() );
continue;
}
// build a texture name that fits the conventions for qtexture_t::name
char stdName[1024];
sprintf( stdName, "textures/%s", name );
// check if this texture doesn't have a shader
if ( !QERApp_ActiveShader_ForTextureName( stdName ) ) {
QERApp_CreateShader_ForTextureName( stdName );
textures_count++;
}
}
Sys_Printf( "Loaded %d shaders and created default shader for %d orphan textures.\n",
shaders_count, textures_count );
vfsClearFileDirList( &files );
Texture_ListDirectory();
// sort for displaying
QERApp_SortActiveShaders();