]> de.git.xonotic.org Git - xonotic/netradiant.git/commitdiff
Merge branch 'vfs' into 'master'
authorThomas Debesse <dev@illwieckz.net>
Mon, 25 May 2020 08:54:22 +0000 (08:54 +0000)
committerThomas Debesse <dev@illwieckz.net>
Mon, 25 May 2020 08:54:22 +0000 (08:54 +0000)
Some VFS fixes: attempt to load .pak and .wad, load png fallback even if game does not support png, do not load engine path twice

Closes #141 and #139

See merge request xonotic/netradiant!166

include/ishaders.h
libs/os/path.h
plugins/shaders/shaders.cpp
plugins/vfspk3/vfs.cpp
radiant/image.cpp
radiant/qe3.cpp
radiant/textures.cpp
radiant/texwindow.cpp

index f588c287440e2e1c91355920729e98ca86ae76a9..e1ce6261fbcf92da9c55d9e26bbf5e96bb6ff5f5 100644 (file)
@@ -108,6 +108,8 @@ virtual qtexture_t* getBump() const = 0;
 virtual qtexture_t* getSpecular() const = 0;
 // get shader name
 virtual const char* getName() const = 0;
+virtual const char* getWadName() const = 0;
+virtual void setWadName( const char* name ) = 0;
 virtual bool IsInUse() const = 0;
 virtual void SetInUse( bool bInUse ) = 0;
 // get the editor flags (QER_NOCARVE QER_TRANS)
index a3db167cb484ad84abbff192fc9289ae3408fcc1..9cbbc2b1361c49a21b48acb82be6b95af3e69831 100644 (file)
@@ -72,6 +72,12 @@ inline bool path_equal( const char* path, const char* other ){
 #endif
 }
 
+/// \brief Returns true if \p path and \p other refer to the same file or directory, case insensitively.
+/// O(n)
+inline bool path_equal_i( const char* path, const char* other ){
+       return string_equal_nocase( path, other );
+}
+
 /// \brief Returns true if the first \p n bytes of \p path and \p other form paths that refer to the same file or directory.
 /// If the paths are UTF-8 encoded, [\p path, \p path + \p n) must be a complete path.
 /// O(n)
@@ -175,6 +181,12 @@ inline bool extension_equal( const char* extension, const char* other ){
        return path_equal( extension, other );
 }
 
+/// \brief Returns true if \p extension is of the same type as \p other, case insensitively.
+/// O(n)
+inline bool extension_equal_i( const char* extension, const char* other ){
+       return path_equal_i( extension, other );
+}
+
 template<typename Functor>
 class MatchFileExtension
 {
index f982605e85157f05acd6f5cb1e35cdb08b8be9c0..fe54556444a5cfdf740117277667d33732119822 100644 (file)
@@ -273,6 +273,7 @@ class ShaderTemplate
 {
 std::size_t m_refcount;
 CopiedString m_Name;
+CopiedString m_WadName;
 public:
 
 ShaderParameters m_params;
@@ -844,6 +845,7 @@ const ShaderArguments& m_args;
 const char* m_filename;
 // name is shader-name, otherwise texture-name ( if not a real shader )
 CopiedString m_Name;
+CopiedString m_WadName;
 
 qtexture_t* m_pTexture;
 qtexture_t* m_notfound;
@@ -921,6 +923,10 @@ const char* getName() const {
        return m_Name.c_str();
 }
 
+const char* getWadName() const {
+       return m_WadName.c_str();
+}
+
 bool IsInUse() const {
        return m_bInUse;
 }
@@ -1056,6 +1062,10 @@ void setName( const char* name ){
        m_Name = name;
 }
 
+void setWadName( const char* name ){
+       m_WadName = name;
+}
+
 class MapLayer : public ShaderLayer
 {
 qtexture_t* m_texture;
index 1cd50a31bd9cf7ed852e6a9f2a7477d0c4ee38da..ded3d048f817a5278b0dec1f05762c96339965f2 100644 (file)
@@ -144,7 +144,7 @@ static Archive* InitPakFile( ArchiveModules& archiveModules, const char *filenam
                entry.archive = table->m_pfnOpenArchive( filename );
                entry.is_pakfile = true;
                g_archives.push_back( entry );
-               globalOutputStream() << "  pak file: " << filename << "\n";
+               globalOutputStream() << "pak file: " << filename << "\n";
 
                return entry.archive;
        }
@@ -282,9 +282,10 @@ bool operator()( const CopiedString& self, const CopiedString& other ) const {
 
 typedef std::set<CopiedString, PakLess> Archives;
 
-Archive* AddPk3Dir( const char* fullpath ){
+Archive* AddPakDir( const char* fullpath ){
        if ( g_numDirs == VFS_MAXDIRS ) return 0;
 
+       globalOutputStream() << "pak directory: " << fullpath << "\n";
        strncpy( g_strDirs[g_numDirs], fullpath, PATH_MAX );
        g_strDirs[g_numDirs][PATH_MAX] = '\0';
        g_numDirs++;
@@ -300,16 +301,16 @@ Archive* AddPk3Dir( const char* fullpath ){
        }
 }
 
-// for Daemon DPK vfs
+// for Daemon DPK VFS
 
 Archive* AddDpkDir( const char* fullpath ){
-       return AddPk3Dir( fullpath );
+       return AddPakDir( fullpath );
 }
 
 struct pakfile_path_t
 {
        CopiedString fullpath;  // full pak dir or pk3dir name
-       bool is_pakfile;  // defines is it .pk3dir or .pk3 file
+       bool is_pakfile;  // tells it is .pk3dir or .pk3 file
 };
 
 typedef std::pair<CopiedString, pakfile_path_t> PakfilePathsKV;
@@ -453,6 +454,7 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){
 
        g_numForbiddenDirs = 0;
        StringTokeniser st( GlobalRadiant().getGameDescriptionKeyValue( "forbidden_paths" ), " " );
+
        for ( j = 0; j < VFS_MAXDIRS; ++j )
        {
                const char *t = st.getToken();
@@ -478,6 +480,7 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){
                }
                g_free( dbuf );
        }
+
        if ( j < g_numForbiddenDirs ) {
                printf( "Directory %s matched by forbidden dirs, removed\n", directory );
                return;
@@ -508,20 +511,22 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){
 
                GDir* dir = g_dir_open( path, 0, 0 );
 
-               if ( dir != 0 ) {
+               if ( dir != NULL ) {
                        globalOutputStream() << "vfs directory: " << path << "\n";
 
                        Archives archives;
                        Archives archivesOverride;
                        const char* ignore_prefix = "";
                        const char* override_prefix = "";
-                       bool is_pk3_vfs, is_pk4_vfs, is_dpk_vfs;
+                       bool is_wad_vfs, is_pak_vfs, is_pk3_vfs, is_pk4_vfs, is_dpk_vfs;
 
-                       is_pk3_vfs = GetArchiveTable( archiveModules, "pk3" );
-                       is_pk4_vfs = GetArchiveTable( archiveModules, "pk4" );
-                       is_dpk_vfs = GetArchiveTable( archiveModules, "dpk" );
+                       is_wad_vfs = !!GetArchiveTable( archiveModules, "wad" );
+                       is_pak_vfs = !!GetArchiveTable( archiveModules, "pak" );
+                       is_pk3_vfs = !!GetArchiveTable( archiveModules, "pk3" );
+                       is_pk4_vfs = !!GetArchiveTable( archiveModules, "pk4" );
+                       is_dpk_vfs = !!GetArchiveTable( archiveModules, "dpk" );
 
-                       if ( !is_dpk_vfs ) {
+                       if ( is_dpk_vfs ) {
                                // See if we are in "sp" or "mp" mapping mode
                                const char* gamemode = gamemode_get();
 
@@ -535,10 +540,11 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){
                                }
                        }
 
-                       for (;; )
+                       while ( true )
                        {
                                const char* name = g_dir_read_name( dir );
-                               if ( name == 0 ) {
+
+                               if ( name == nullptr ) {
                                        break;
                                }
 
@@ -550,6 +556,7 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){
                                                break;
                                        }
                                }
+
                                if ( j < g_numForbiddenDirs ) {
                                        continue;
                                }
@@ -557,29 +564,28 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){
                                const char *ext = strrchr( name, '.' );
                                char tmppath[PATH_MAX];
 
-                               if ( is_dpk_vfs ) {
-                                       if ( !!ext && !string_compare_nocase_upper( ext, ".dpkdir" ) ) {
+                               if ( ext != nullptr ) {
+                                       if ( is_dpk_vfs && !string_compare_nocase_upper( ext, ".dpkdir" ) ) {
                                                snprintf( tmppath, PATH_MAX, "%s%s/", path, name );
                                                tmppath[PATH_MAX] = '\0';
                                                FixDOSName( tmppath );
                                                AddSlash( tmppath );
                                                AddDpkPak( CopiedString( StringRange( name, ext ) ).c_str(), tmppath, false );
                                        }
-                               }
 
-                               if ( is_pk3_vfs || is_pk4_vfs ) {
-                                       if ( !!ext && ( !string_compare_nocase_upper( ext, ".pk3dir" )
-                                               || !string_compare_nocase_upper( ext, ".pk4dir" ) ) ) {
+                                       else if ( ( is_wad_vfs && !string_compare_nocase_upper( ext, ".pakdir" ) )
+                                               || ( is_pk3_vfs && !string_compare_nocase_upper( ext, ".pk3dir" ) )
+                                               || ( is_pk4_vfs && !string_compare_nocase_upper( ext, ".pk4dir" ) ) ) {
                                                snprintf( tmppath, PATH_MAX, "%s%s/", path, name );
                                                tmppath[PATH_MAX] = '\0';
                                                FixDOSName( tmppath );
                                                AddSlash( tmppath );
-                                               AddPk3Dir( tmppath );
+                                               AddPakDir( tmppath );
                                        }
                                }
 
                                // GetArchiveTable() needs "pk3" if ext is ".pk3"
-                               if ( ( ext == 0 ) || *( ext + 1 ) == '\0' || GetArchiveTable( archiveModules, ext + 1 ) == 0 ) {
+                               if ( ( ext == nullptr ) || *( ext + 1 ) == '\0' || GetArchiveTable( archiveModules, ext + 1 ) == 0 ) {
                                        continue;
                                }
 
@@ -587,16 +593,18 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){
                                if ( !string_empty( ignore_prefix ) && strncmp( name, ignore_prefix, strlen( ignore_prefix ) ) == 0 ) {
                                        continue;
                                }
+
                                if ( !string_empty( override_prefix ) && strncmp( name, override_prefix, strlen( override_prefix ) ) == 0 ) {
                                        if ( !string_compare_nocase_upper( ext, ".dpk" ) ) {
                                                if ( is_dpk_vfs ) {
                                                        archives.insert( name );
+                                                       continue;
                                                }
                                        }
                                        else {
                                                archivesOverride.insert( name );
+                                               continue;
                                        }
-                                       continue;
                                }
 
                                archives.insert( name );
@@ -610,7 +618,8 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){
                                for ( Archives::iterator i = archives.begin(); i != archives.end(); ++i ) {
                                        const char* name = i->c_str();
                                        const char* ext = strrchr( name, '.' );
-                                       if ( !string_compare_nocase_upper( ext, ".dpk" ) ) {
+                                       if ( !string_compare_nocase_upper( ext, ".dpk" ) )
+                                       {
                                                CopiedString name_final = CopiedString( StringRange( name, ext ) );
                                                fullpath = string_new_concat( path, name );
                                                AddDpkPak( name_final.c_str(), fullpath, true );
@@ -618,24 +627,30 @@ void InitDirectory( const char* directory, ArchiveModules& archiveModules ){
                                        }
                                }
                        }
-                       if ( is_pk3_vfs || is_pk4_vfs ) {
+                       else
+                       {
                                for ( Archives::iterator i = archivesOverride.begin(); i != archivesOverride.end(); ++i )
                                {
                                        const char* name = i->c_str();
                                        const char* ext = strrchr( name, '.' );
-                                       if ( !string_compare_nocase_upper( ext, ".pk3" )
-                                               || !string_compare_nocase_upper( ext, ".pk4" ) ) {
+                                       if ( ( is_wad_vfs && !string_compare_nocase_upper( ext, ".wad" ) )
+                                               || ( is_pak_vfs && !string_compare_nocase_upper( ext, ".pak" ) )
+                                               || ( is_pk3_vfs && !string_compare_nocase_upper( ext, ".pk3" ) )
+                                               || ( is_pk4_vfs && !string_compare_nocase_upper( ext, ".pk4" ) ) ) {
                                                fullpath = string_new_concat( path, i->c_str() );
                                                InitPakFile( archiveModules, fullpath );
                                                string_release( fullpath, string_length( fullpath ) );
                                        }
                                }
+
                                for ( Archives::iterator i = archives.begin(); i != archives.end(); ++i )
                                {
                                        const char* name = i->c_str();
                                        const char* ext = strrchr( name, '.' );
-                                       if ( !string_compare_nocase_upper( ext, ".pk3" )
-                                               || !string_compare_nocase_upper( ext, ".pk4" ) ) {
+                                       if ( ( is_wad_vfs && !string_compare_nocase_upper( ext, ".wad" ) )
+                                               || ( is_pak_vfs && !string_compare_nocase_upper( ext, ".pak" ) )
+                                               || ( is_pk3_vfs && !string_compare_nocase_upper( ext, ".pk3" ) )
+                                               || ( is_pk4_vfs && !string_compare_nocase_upper( ext, ".pk4" ) ) ) {
                                                fullpath = string_new_concat( path, i->c_str() );
                                                InitPakFile( archiveModules, fullpath );
                                                string_release( fullpath, string_length( fullpath ) );
@@ -805,7 +820,7 @@ void initialise(){
 
 void load(){
        ArchiveModules& archiveModules = FileSystemQ3API_getArchiveModules();
-       bool is_dpk_vfs = GetArchiveTable( archiveModules, "dpk" );
+       bool is_dpk_vfs = !!GetArchiveTable( archiveModules, "dpk" );
 
        if ( is_dpk_vfs ) {
                const char* pakname;
@@ -919,6 +934,9 @@ Archive* getArchive( const char* archiveName, bool pakonly ){
                if ( path_equal( ( *i ).name.c_str(), archiveName ) ) {
                        return ( *i ).archive;
                }
+               else if ( path_equal( path_get_filename_start( ( *i ).name.c_str() ), archiveName ) ) {
+                       return ( *i ).archive;
+               }
        }
        return 0;
 }
index c81b3617ab7fe5527d9c8c45ac2fc6c83623db2b..c9014294f639c0dc07c762355b414b0a87b310cc 100644 (file)
@@ -30,9 +30,9 @@
 #include "os/path.h"
 #include "stream/stringstream.h"
 
-
 typedef Modules<_QERPlugImageTable> ImageModules;
 ImageModules& Textures_getImageModules();
+ImageModules& Textures_getFallbackImageModules();
 
 /// \brief Returns a new image for the first file matching \p name in one of the available texture formats, or 0 if no file is found.
 Image* QERApp_LoadImage( void* environment, const char* name ){
@@ -60,5 +60,12 @@ public:
 
        Textures_getImageModules().foreachModule( LoadImageVisitor( name, image ) );
 
+       // Games can provide their own fallback, so only do this when previous
+       // loading attempt did not work.
+       if ( image == 0 && !!string_compare_nocase( name, "textures/radiant" ) )
+       {
+               Textures_getFallbackImageModules().foreachModule( LoadImageVisitor( name, image ) );
+       }
+
        return image;
 }
index bc1b6ed8a63f2363cbfe9604ca4b9bb488fb139b..e5881bb0717a3679c620bdc5d3efbdaf3498c3a0 100644 (file)
@@ -79,44 +79,58 @@ void QE_InitVFS(){
        // we need to call in order, the mod ones first, then the base ones .. they will be searched in this order
        // *nix systems have a dual filesystem in ~/.q3a, which is searched first .. so we need to add that too
 
-       const char* gamename = gamename_get();
+       const char* enginepath = EnginePath_get();
+       const char* homepath = g_qeglobals.m_userEnginePath.c_str(); // returns enginepath if not homepath is not set
+
        const char* basegame = basegame_get();
-       const char* userRoot = g_qeglobals.m_userEnginePath.c_str();
-       const char* globalRoot = EnginePath_get();
+       const char* gamename = gamename_get(); // returns basegame if gamename is not set
 
        // editor builtin VFS
        StringOutputStream editorGamePath( 256 );
        editorGamePath << GlobalRadiant().getDataPath() << DEFAULT_EDITORVFS_DIRNAME;
        GlobalFileSystem().initDirectory( editorGamePath.c_str() );
 
+       globalOutputStream() << "engine path: " << enginepath << "\n";
+       globalOutputStream() << "home path: " << homepath << "\n";
+       globalOutputStream() << "base game: " << basegame << "\n";
+       globalOutputStream() << "game name: " << gamename << "\n";
+
        // if we have a mod dir
        if ( !string_equal( gamename, basegame ) ) {
-               // ~/.<gameprefix>/<fs_game>
-               if ( userRoot && !g_disableHomePath ) {
-                       StringOutputStream userGamePath( 256 );
-                       userGamePath << userRoot << gamename << '/';
-                       GlobalFileSystem().initDirectory( userGamePath.c_str() );
+               // if we have a home dir
+               if ( !string_equal( homepath, enginepath ) )
+               {
+                       // ~/.<gameprefix>/<fs_game>
+                       if ( homepath && !g_disableHomePath ) {
+                               StringOutputStream userGamePath( 256 );
+                               userGamePath << homepath << gamename << '/';
+                               GlobalFileSystem().initDirectory( userGamePath.c_str() );
+                       }
                }
 
                // <fs_basepath>/<fs_game>
                if ( !g_disableEnginePath ) {
                        StringOutputStream globalGamePath( 256 );
-                       globalGamePath << globalRoot << gamename << '/';
+                       globalGamePath << enginepath << gamename << '/';
                        GlobalFileSystem().initDirectory( globalGamePath.c_str() );
                }
        }
 
-       // ~/.<gameprefix>/<fs_main>
-       if ( userRoot && !g_disableHomePath ) {
-               StringOutputStream userBasePath( 256 );
-               userBasePath << userRoot << basegame << '/';
-               GlobalFileSystem().initDirectory( userBasePath.c_str() );
+       // if we have a home dir
+       if ( !string_equal( homepath, enginepath ) )
+       {
+               // ~/.<gameprefix>/<fs_main>
+               if ( homepath && !g_disableHomePath ) {
+                       StringOutputStream userBasePath( 256 );
+                       userBasePath << homepath << basegame << '/';
+                       GlobalFileSystem().initDirectory( userBasePath.c_str() );
+               }
        }
 
        // <fs_basepath>/<fs_main>
        if ( !g_disableEnginePath ) {
                StringOutputStream globalBasePath( 256 );
-               globalBasePath << globalRoot << basegame << '/';
+               globalBasePath << enginepath << basegame << '/';
                GlobalFileSystem().initDirectory( globalBasePath.c_str() );
        }
 
index 02f706b90e0629d6df7808ea62f3f88067abcba7..afa8d4e05c1d180b5c3f9b2e48d0e365edc60c67 100644 (file)
@@ -815,13 +815,18 @@ class TexturesDependencies :
        public GlobalPreferenceSystemModuleRef
 {
 ImageModulesRef m_image_modules;
+ImageModulesRef m_fallback_image_modules;
 public:
 TexturesDependencies() :
-       m_image_modules( GlobalRadiant().getRequiredGameDescriptionKeyValue( "texturetypes" ) ){
+       m_image_modules( GlobalRadiant().getRequiredGameDescriptionKeyValue( "texturetypes" ) ),
+       m_fallback_image_modules( "png" ){
 }
 ImageModules& getImageModules(){
        return m_image_modules.get();
 }
+ImageModules& getFallbackImageModules(){
+       return m_fallback_image_modules.get();
+}
 };
 
 class TexturesAPI
@@ -851,3 +856,6 @@ StaticRegisterModule staticRegisterTextures( StaticTexturesModule::instance() );
 ImageModules& Textures_getImageModules(){
        return StaticTexturesModule::instance().getDependencies().getImageModules();
 }
+ImageModules& Textures_getFallbackImageModules(){
+       return StaticTexturesModule::instance().getDependencies().getFallbackImageModules();
+}
index fee615cfe0fc246562715feb995e3ff343b32f8e..75d3788d607f55a0f3e34de14d917f82f0f2b976 100644 (file)
@@ -101,12 +101,7 @@ typedef std::set<CopiedString> TextureGroups;
 
 void TextureGroups_addWad( TextureGroups& groups, const char* archive ){
        if ( extension_equal( path_get_extension( archive ), "wad" ) ) {
-#if 1
                groups.insert( archive );
-#else
-               CopiedString archiveBaseName( path_get_filename_start( archive ), path_get_filename_base_end( archive ) );
-               groups.insert( archiveBaseName );
-#endif
        }
 }
 
@@ -574,7 +569,15 @@ bool Texture_IsShown( IShader* shader, bool show_shaders, bool hideUnused ){
                }
        }
        else {
-               if ( !shader_equal_prefix( shader_get_textureName( shader->getName() ), g_TextureBrowser_currentDirectory.c_str() ) ) {
+               if ( TextureBrowser_showWads() )
+               {
+                       if ( g_TextureBrowser_currentDirectory != ""
+                               && !string_equal( shader->getWadName(), g_TextureBrowser_currentDirectory.c_str() ) )
+                       {
+                               return false;
+                       }
+               }
+               else if ( !shader_equal_prefix( shader_get_textureName( shader->getName() ), g_TextureBrowser_currentDirectory.c_str() ) ) {
                        return false;
                }
        }
@@ -769,6 +772,7 @@ public:
 void visit( const char* name ){
        IShader* shader = QERApp_Shader_ForName( CopiedString( StringRange( name, path_get_filename_base_end( name ) ) ).c_str() );
        shader->DecRef();
+       shader->setWadName( g_TextureBrowser_currentDirectory.c_str() );
 }
 };
 
@@ -845,10 +849,19 @@ void visit( const char* minor, const _QERPlugImageTable& table ) const {
 
 void TextureBrowser_ShowDirectory( TextureBrowser& textureBrowser, const char* directory ){
        if ( TextureBrowser_showWads() ) {
+               g_TextureBrowser_currentDirectory = directory;
+               TextureBrowser_heightChanged( textureBrowser );
+
                Archive* archive = GlobalFileSystem().getArchive( directory );
-               ASSERT_NOTNULL( archive );
-               LoadShaderVisitor visitor;
-               archive->forEachFile( Archive::VisitorFunc( visitor, Archive::eFiles, 0 ), "textures/" );
+               if ( archive != nullptr )
+               {
+                       LoadShaderVisitor visitor;
+                       archive->forEachFile( Archive::VisitorFunc( visitor, Archive::eFiles, 0 ), "textures/" );
+               }
+               else if ( extension_equal_i( path_get_extension( directory ), "wad" ) )
+               {
+                       globalErrorStream() << "Failed to load " << directory << "\n";
+               }
        }
        else
        {
@@ -1527,6 +1540,17 @@ void TextureBrowser_ToggleHideUnused(){
        }
 }
 
+const char* TextureGroups_transformDirName( const char* dirName, StringOutputStream *archiveName )
+{
+       if ( TextureBrowser_showWads() ) {
+               archiveName->clear();
+               *archiveName << StringRange( path_get_filename_start( dirName ), path_get_filename_base_end( dirName ) ) \
+                       << "." << path_get_extension( dirName );
+               return archiveName->c_str();
+       }
+       return dirName;
+}
+
 void TextureGroups_constructTreeModel( TextureGroups groups, ui::TreeStore store ){
        // put the information from the old textures menu into a treeview
        GtkTreeIter iter, child;
@@ -1534,23 +1558,27 @@ void TextureGroups_constructTreeModel( TextureGroups groups, ui::TreeStore store
        TextureGroups::const_iterator i = groups.begin();
        while ( i != groups.end() )
        {
-               const char* dirName = ( *i ).c_str();
+               StringOutputStream archiveName;
+               StringOutputStream nextArchiveName;
+               const char* dirName = TextureGroups_transformDirName( ( *i ).c_str(), &archiveName );
+
                const char* firstUnderscore = strchr( dirName, '_' );
                StringRange dirRoot( dirName, ( firstUnderscore == 0 ) ? dirName : firstUnderscore + 1 );
 
                TextureGroups::const_iterator next = i;
                ++next;
+
                if ( firstUnderscore != 0
                         && next != groups.end()
-                        && string_equal_start( ( *next ).c_str(), dirRoot ) ) {
+                        && string_equal_start( TextureGroups_transformDirName( ( *next ).c_str(), &nextArchiveName ), dirRoot ) ) {
                        gtk_tree_store_append( store, &iter, NULL );
                        gtk_tree_store_set( store, &iter, 0, CopiedString( StringRange( dirName, firstUnderscore ) ).c_str(), -1 );
 
                        // keep going...
-                       while ( i != groups.end() && string_equal_start( ( *i ).c_str(), dirRoot ) )
+                       while ( i != groups.end() && string_equal_start( TextureGroups_transformDirName( ( *i ).c_str(), &nextArchiveName ), dirRoot ) )
                        {
                                gtk_tree_store_append( store, &child, &iter );
-                               gtk_tree_store_set( store, &child, 0, ( *i ).c_str(), -1 );
+                               gtk_tree_store_set( store, &child, 0, TextureGroups_transformDirName( ( *i ).c_str(), &nextArchiveName ), -1 );
                                ++i;
                        }
                }
@@ -1718,7 +1746,7 @@ ui::MenuItem TextureBrowser_constructViewMenu( ui::Menu menu ){
        create_menu_item_with_mnemonic( menu, "Show All", "ShowAllTextures" );
 
        // we always want to show shaders but don't want a "Show Shaders" menu for doom3 and .wad file games
-       if ( g_pGameDescription->mGameType == "doom3" || !string_empty( g_pGameDescription->getKeyValue( "show_wads" ) ) ) {
+       if ( g_pGameDescription->mGameType == "doom3" || TextureBrowser_showWads() ) {
                g_TextureBrowser.m_showShaders = true;
        }
        else