Skip to content

Commit

Permalink
#5568: Hide unrelated textures when looking for cube map textures, an…
Browse files Browse the repository at this point in the history
…d vice versa when looking for regular textures
  • Loading branch information
codereader committed Mar 23, 2021
1 parent 0a534f7 commit d97287f
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 128 deletions.
1 change: 1 addition & 0 deletions radiant/CMakeLists.txt
Expand Up @@ -41,6 +41,7 @@ add_executable(darkradiant
ui/common/CommandEntry.cpp
ui/common/DefinitionView.cpp
ui/common/EntityChooser.cpp
ui/common/ImageFilePopulator.cpp
ui/common/ImageFileSelector.cpp
ui/common/MapPreview.cpp
ui/common/MaterialPopulator.cpp
Expand Down
139 changes: 139 additions & 0 deletions radiant/ui/common/ImageFilePopulator.cpp
@@ -0,0 +1,139 @@
#include "ImageFilePopulator.h"

#include "ifilesystem.h"
#include "gamelib.h"
#include "string/case_conv.h"
#include "string/predicate.h"
#include "string/trim.h"
#include "os/path.h"
#include "wxutil/Bitmap.h"

namespace ui
{

namespace
{
const char* const TEXTURE_ICON = "icon_texture.png";
const char* const FOLDER_ICON = "folder16.png";
}

class ImageFileFunctor :
public wxutil::VFSTreePopulator
{
private:
const ImageFileSelector::Columns& _columns;

wxIcon _fileIcon;
wxIcon _folderIcon;

std::set<std::string> _cubemapSuffixes;

public:
// Constructor
ImageFileFunctor(const wxutil::TreeModel::Ptr& treeStore,
const ImageFileSelector::Columns& columns) :
VFSTreePopulator(treeStore),
_columns(columns),
_cubemapSuffixes({ "_nx", "_ny", "_nz", "_px", "_py", "_pz",
"_forward", "_back", "_left", "_right", "_up", "_down" })
{
_fileIcon.CopyFromBitmap(wxutil::GetLocalBitmap(TEXTURE_ICON));
_folderIcon.CopyFromBitmap(wxutil::GetLocalBitmap(FOLDER_ICON));
}

void addFile(const vfs::FileInfo& fileInfo)
{
const std::string ddsPrefix = "dds/";
std::string fullPath = fileInfo.fullPath();

// Sort into the tree and set the values
addPath(fullPath, [&](wxutil::TreeModel::Row& row, const std::string& path,
const std::string& leafName, bool isFolder)
{
// The map expressions don't need any file extensions
auto imageFilePath = os::removeExtension(path);

// Cut off the dds prefix, it won't be valid when set in a material
if (string::istarts_with(path, ddsPrefix))
{
imageFilePath = imageFilePath.substr(ddsPrefix.length());
}

bool isCubeMapTexture = false;

// For cubemaps, cut off the suffixes
if (string::istarts_with(imageFilePath, "env/"))
{
auto underscorePos = imageFilePath.find_last_of('_');

if (underscorePos != std::string::npos)
{
auto suffix = imageFilePath.substr(underscorePos);
string::to_lower(suffix);

if (_cubemapSuffixes.count(suffix) != 0)
{
imageFilePath = imageFilePath.substr(0, imageFilePath.length() - suffix.length());
isCubeMapTexture = true;
}
}
}

row[_columns.iconAndName] = wxVariant(wxDataViewIconText(leafName, isFolder ? _folderIcon : _fileIcon));
row[_columns.leafName] = leafName;
row[_columns.fullName] = imageFilePath;
row[_columns.isFolder] = isFolder;
row[_columns.isFavourite] = false;
row[_columns.isCubeMapTexture] = isCubeMapTexture;

row.SendItemAdded();
});
}
};

ImageFilePopulator::ImageFilePopulator(const ImageFileSelector::Columns& columns) :
ThreadedResourceTreePopulator(columns),
_columns(columns)
{
auto texTypes = game::current::getNodes(GKEY_IMAGE_TYPES);

for (const auto& node : texTypes)
{
// Get the file extension, store it as lowercase
std::string extension = node.getContent();
_extensions.emplace(string::to_lower_copy(extension));
}
}

ImageFilePopulator::~ImageFilePopulator()
{
EnsureStopped();
}

void ImageFilePopulator::PopulateModel(const wxutil::TreeModel::Ptr& model)
{
ImageFileFunctor functor(model, _columns);

GlobalFileSystem().forEachFile(
"", "*",
[&](const vfs::FileInfo& fileInfo)
{
ThrowIfCancellationRequested();

if (_extensions.count(string::to_lower_copy(os::getExtension(fileInfo.name))) == 0)
{
return;
}

functor.addFile(fileInfo);
},
99
);
}

void ImageFilePopulator::SortModel(const wxutil::TreeModel::Ptr& model)
{
model->SortModelFoldersFirst(_columns.iconAndName, _columns.isFolder);
}

}
132 changes: 7 additions & 125 deletions radiant/ui/common/ImageFilePopulator.h
@@ -1,150 +1,32 @@
#pragma once

#include "ifilesystem.h"
#include "gamelib.h"
#include "string/case_conv.h"
#include "string/predicate.h"
#include "string/trim.h"
#include "os/path.h"
#include "wxutil/dataview/ThreadedResourceTreePopulator.h"
#include "wxutil/dataview/ResourceTreeView.h"
#include "wxutil/dataview/VFSTreePopulator.h"
#include "wxutil/Bitmap.h"

namespace ui
{
#include "ImageFileSelector.h"

namespace
{
const char* const TEXTURE_ICON = "icon_texture.png";
const char* const FOLDER_ICON = "folder16.png";
}

class ImageFileFunctor :
public wxutil::VFSTreePopulator
namespace ui
{
private:
const wxutil::ResourceTreeView::Columns& _columns;

wxIcon _fileIcon;
wxIcon _folderIcon;

std::set<std::string> _cubemapSuffixes;

public:
// Constructor
ImageFileFunctor(const wxutil::TreeModel::Ptr& treeStore,
const wxutil::ResourceTreeView::Columns& columns) :
VFSTreePopulator(treeStore),
_columns(columns),
_cubemapSuffixes({ "_nx", "_ny", "_nz", "_px", "_py", "_pz",
"_forward", "_back", "_left", "_right", "_up", "_down" })
{
_fileIcon.CopyFromBitmap(wxutil::GetLocalBitmap(TEXTURE_ICON));
_folderIcon.CopyFromBitmap(wxutil::GetLocalBitmap(FOLDER_ICON));
}

void addFile(const vfs::FileInfo& fileInfo)
{
const std::string ddsPrefix = "dds/";
std::string fullPath = fileInfo.fullPath();

// Sort the shader into the tree and set the values
addPath(fullPath, [&](wxutil::TreeModel::Row& row, const std::string& path,
const std::string& leafName, bool isFolder)
{
// The map expressions don't need any file extensions
auto imageFilePath = os::removeExtension(path);

// Cut off the dds prefix, it won't be valid when set in a material
if (string::istarts_with(path, ddsPrefix))
{
imageFilePath = imageFilePath.substr(ddsPrefix.length());
}

// For cubemaps, cut off the suffixes
if (string::istarts_with(imageFilePath, "env/"))
{
auto underscorePos = imageFilePath.find_last_of('_');

if (underscorePos != std::string::npos)
{
auto suffix = imageFilePath.substr(underscorePos);
string::to_lower(suffix);

if (_cubemapSuffixes.count(suffix) != 0)
{
imageFilePath = imageFilePath.substr(0, imageFilePath.length() - suffix.length());
}
}
}

row[_columns.iconAndName] = wxVariant(wxDataViewIconText(leafName, isFolder ? _folderIcon : _fileIcon));
row[_columns.leafName] = leafName;
row[_columns.fullName] = imageFilePath;
row[_columns.isFolder] = isFolder;
row[_columns.isFavourite] = false;

row.SendItemAdded();
});
}
};

class ImageFilePopulator final :
public wxutil::ThreadedResourceTreePopulator
{
private:
const wxutil::ResourceTreeView::Columns& _columns;
const ImageFileSelector::Columns& _columns;
const char* const GKEY_IMAGE_TYPES = "/filetypes/texture//extension";
std::set<std::string> _extensions;

public:
// Construct and initialise variables
ImageFilePopulator(const wxutil::ResourceTreeView::Columns& columns) :
ThreadedResourceTreePopulator(columns),
_columns(columns)
{
auto texTypes = game::current::getNodes(GKEY_IMAGE_TYPES);

for (const auto& node : texTypes)
{
// Get the file extension, store it as lowercase
std::string extension = node.getContent();
_extensions.emplace(string::to_lower_copy(extension));
}
}
ImageFilePopulator(const ImageFileSelector::Columns& columns);

~ImageFilePopulator()
{
EnsureStopped();
}
~ImageFilePopulator();

protected:
void PopulateModel(const wxutil::TreeModel::Ptr& model) override
{
ImageFileFunctor functor(model, _columns);

GlobalFileSystem().forEachFile(
"", "*",
[&](const vfs::FileInfo& fileInfo)
{
ThrowIfCancellationRequested();

if (_extensions.count(string::to_lower_copy(os::getExtension(fileInfo.name))) == 0)
{
return;
}

functor.addFile(fileInfo);
},
99
);
}

void SortModel(const wxutil::TreeModel::Ptr& model) override
{
model->SortModelFoldersFirst(_columns.iconAndName, _columns.isFolder);
}
void PopulateModel(const wxutil::TreeModel::Ptr& model) override;
void SortModel(const wxutil::TreeModel::Ptr& model) override;
};

}
42 changes: 41 additions & 1 deletion radiant/ui/common/ImageFileSelector.cpp
Expand Up @@ -10,14 +10,49 @@ namespace
const char* const WINDOW_TITLE = N_("Select Image File");
}

class ImageFileTreeView final :
public wxutil::ResourceTreeView
{
private:
const ImageFileSelector::Columns& _columns;

int _textureTypesToShow;

public:
ImageFileTreeView(wxWindow* parent, const ImageFileSelector::Columns& columns) :
ResourceTreeView(parent, columns, wxDV_NO_HEADER),
_columns(columns)
{}

void SetVisibleTextureTypes(int typesToShow)
{
_textureTypesToShow = typesToShow;
}

protected:
bool IsTreeModelRowVisible(wxutil::TreeModel::Row& row) override
{
bool isCubeMap = row[_columns.isCubeMapTexture].getBool();

if (!row[_columns.isFolder].getBool() &&
isCubeMap && (_textureTypesToShow & ImageFileSelector::TextureType::CubeMap) == 0 ||
!isCubeMap && (_textureTypesToShow & ImageFileSelector::TextureType::Map) == 0)
{
return false;
}

return ResourceTreeView::IsTreeModelRowVisible(row);
}
};

ImageFileSelector::ImageFileSelector(wxWindow* parent, wxTextCtrl* targetControl) :
DialogBase(_(WINDOW_TITLE), parent),
_okButton(nullptr),
_targetControl(targetControl)
{
SetSizer(new wxBoxSizer(wxVERTICAL));

_treeView = new wxutil::ResourceTreeView(this, _columns, wxDV_NO_HEADER);
_treeView = new ImageFileTreeView(this, _columns);

_treeView->AppendIconTextColumn(_("File"), _columns.iconAndName.getColumnIndex(),
wxDATAVIEW_CELL_INERT, wxCOL_WIDTH_AUTOSIZE, wxALIGN_NOT, wxDATAVIEW_COL_SORTABLE);
Expand Down Expand Up @@ -75,6 +110,11 @@ std::string ImageFileSelector::GetSelectedImageFilePath()
return row[_columns.fullName];
}

void ImageFileSelector::SetVisibleTextureTypes(int typesToShow)
{
_treeView->SetVisibleTextureTypes(typesToShow);
}

void ImageFileSelector::onTreeSelectionChanged(wxDataViewEvent& ev)
{
auto item = _treeView->GetSelection();
Expand Down

0 comments on commit d97287f

Please sign in to comment.