...
 
Commits (8)
......@@ -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)
......
......@@ -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
{
......
......@@ -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;
......
......@@ -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;
}
......
......@@ -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;
}
......@@ -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() );
}
......
......@@ -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();
}
......@@ -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
......