Skip to content

Commit 09109f6

Browse files
authored
Preview embedded model assets in asset browser (#742)
1 parent f7dee62 commit 09109f6

2 files changed

Lines changed: 251 additions & 64 deletions

File tree

Sources/OvEditor/src/OvEditor/Core/Editor.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@
1212
#include <OvCore/Helpers/GUIDrawer.h>
1313
#include <OvCore/Helpers/GUIHelpers.h>
1414

15+
#include <OvCore/ResourceManagement/MaterialManager.h>
1516
#include <OvCore/ResourceManagement/ModelManager.h>
1617
#include <OvCore/ResourceManagement/TextureManager.h>
17-
#include <OvCore/ResourceManagement/MaterialManager.h>
1818

19-
#include <OvTools/Utils/SystemCalls.h>
19+
#include <OvRendering/Resources/Parsers/EmbeddedAssetPath.h>
20+
2021
#include <OvTools/Utils/PathParser.h>
22+
#include <OvTools/Utils/SystemCalls.h>
2123

2224
#include <OvEditor/Core/Editor.h>
2325
#include <OvEditor/Panels/AssetBrowser.h>
@@ -87,6 +89,8 @@ void OvEditor::Core::Editor::SetupUI()
8789
using EFileType = OvTools::Utils::PathParser::EFileType;
8890
const auto fileType = OvTools::Utils::PathParser::GetFileType(p_path);
8991
const auto path = OvTools::Utils::PathParser::MakeNonWindowsStyle(p_path);
92+
const auto embeddedAssetPath = ParseEmbeddedAssetPath(path);
93+
const bool isEmbeddedTexture = embeddedAssetPath && ParseEmbeddedTextureIndex(embeddedAssetPath->assetName).has_value();
9094

9195
auto openInAssetView = [&](auto* p_resource)
9296
{
@@ -97,7 +101,7 @@ void OvEditor::Core::Editor::SetupUI()
97101
assetView.Focus();
98102
};
99103

100-
if (fileType == EFileType::TEXTURE)
104+
if (fileType == EFileType::TEXTURE || isEmbeddedTexture)
101105
{
102106
openInAssetView(OVSERVICE(TextureManager).GetResource(path));
103107
}

Sources/OvEditor/src/OvEditor/Panels/AssetBrowser.cpp

Lines changed: 244 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,17 @@
99
#include <fstream>
1010
#include <iostream>
1111
#include <regex>
12+
#include <utility>
1213
#include <vector>
1314
#include <tinyxml2.h>
1415

16+
#include <OvCore/Global/ServiceLocator.h>
1517
#include <OvCore/Helpers/GUIDrawer.h>
1618
#include <OvCore/Helpers/GUIHelpers.h>
17-
#include <OvCore/Global/ServiceLocator.h>
19+
#include <OvCore/ResourceManagement/MaterialManager.h>
1820
#include <OvCore/ResourceManagement/ModelManager.h>
19-
#include <OvCore/ResourceManagement/TextureManager.h>
2021
#include <OvCore/ResourceManagement/ShaderManager.h>
22+
#include <OvCore/ResourceManagement/TextureManager.h>
2123

2224
#include <OvDebug/Logger.h>
2325

@@ -29,6 +31,8 @@
2931
#include <OvEditor/Panels/MaterialEditor.h>
3032
#include <OvEditor/Settings/EditorSettings.h>
3133

34+
#include <OvRendering/Resources/Parsers/EmbeddedAssetPath.h>
35+
3236
#include <OvTools/Utils/PathParser.h>
3337
#include <OvTools/Utils/String.h>
3438
#include <OvTools/Utils/SystemCalls.h>
@@ -761,6 +765,69 @@ namespace
761765
}
762766
};
763767

768+
class EmbeddedFileContextualMenu : public OvUI::Plugins::ContextualMenu
769+
{
770+
public:
771+
EmbeddedFileContextualMenu(std::string p_resourcePath) : m_resourcePath(std::move(p_resourcePath)) {}
772+
773+
void CreateList()
774+
{
775+
auto& openAction = CreateWidget<OvUI::Widgets::Menu::MenuItem>("Open");
776+
openAction.ClickedEvent += [this] {
777+
OvCore::Helpers::GUIHelpers::Open(m_resourcePath);
778+
};
779+
}
780+
781+
virtual void Execute(OvUI::Plugins::EPluginExecutionContext p_context) override
782+
{
783+
if (!m_widgets.empty())
784+
{
785+
OvUI::Plugins::ContextualMenu::Execute(p_context);
786+
}
787+
}
788+
789+
protected:
790+
std::string m_resourcePath;
791+
};
792+
793+
void CreateEmbeddedModelAssetEntry(
794+
OvUI::Widgets::Layout::TreeNode& p_root,
795+
const std::string& p_resourcePath,
796+
OvTools::Utils::PathParser::EFileType p_fileType
797+
)
798+
{
799+
const auto embeddedPath = OvRendering::Resources::Parsers::ParseEmbeddedAssetPath(p_resourcePath);
800+
if (!embeddedPath)
801+
{
802+
return;
803+
}
804+
805+
const std::string itemName = embeddedPath->assetName;
806+
auto& itemGroup = p_root.CreateWidget<Layout::Group>();
807+
const uint32_t iconTextureID = EDITOR_CONTEXT(editorResources)->GetFileIcon(itemName)->GetTexture().GetID();
808+
itemGroup.CreateWidget<Visual::Image>(iconTextureID, OvMaths::FVector2{ 16, 16 }).lineBreak = false;
809+
810+
auto& clickableText = itemGroup.CreateWidget<Texts::TextClickable>(itemName);
811+
clickableText.AddPlugin<OvUI::Plugins::DDSource<std::pair<std::string, Layout::Group*>>>(
812+
"File",
813+
OvTools::Utils::PathParser::GetFriendlyPath(p_resourcePath),
814+
std::make_pair(p_resourcePath, &itemGroup)
815+
);
816+
817+
if (p_fileType == OvTools::Utils::PathParser::EFileType::TEXTURE)
818+
{
819+
auto& texturePreview = clickableText.AddPlugin<TexturePreview>();
820+
texturePreview.SetPath(p_resourcePath);
821+
}
822+
823+
auto& contextMenu = clickableText.AddPlugin<EmbeddedFileContextualMenu>(p_resourcePath);
824+
contextMenu.CreateList();
825+
826+
clickableText.DoubleClickedEvent += [resourcePath = p_resourcePath] {
827+
OvCore::Helpers::GUIHelpers::Open(resourcePath);
828+
};
829+
}
830+
764831
FileContextualMenu& CreateFileContextualMenu(
765832
OvUI::Widgets::AWidget& p_root,
766833
OvTools::Utils::PathParser::EFileType p_fileType,
@@ -1104,86 +1171,202 @@ void OvEditor::Panels::AssetBrowser::ConsiderItem(OvUI::Widgets::Layout::TreeNod
11041171
}
11051172
else
11061173
{
1107-
auto& clickableText = itemGroup.CreateWidget<Texts::TextClickable>(itemname);
1174+
if (fileType == OvTools::Utils::PathParser::EFileType::MODEL)
1175+
{
1176+
auto& treeNode = itemGroup.CreateWidget<Layout::TreeNode>(itemname);
11081177

1109-
FileContextualMenu& contextMenu = CreateFileContextualMenu(
1110-
clickableText,
1111-
fileType,
1112-
path,
1113-
protectedItem
1114-
);
1178+
FileContextualMenu& contextMenu = CreateFileContextualMenu(
1179+
treeNode,
1180+
fileType,
1181+
path,
1182+
protectedItem
1183+
);
11151184

1116-
contextMenu.CreateList();
1185+
contextMenu.CreateList();
11171186

1118-
contextMenu.DestroyedEvent += [&itemGroup](std::filesystem::path p_deletedPath) {
1119-
itemGroup.Destroy();
1187+
contextMenu.DestroyedEvent += [&itemGroup](std::filesystem::path p_deletedPath) {
1188+
itemGroup.Destroy();
11201189

1121-
if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_deletedPath) // Modify current scene source path if the renamed file is the current scene
1122-
{
1123-
EDITOR_CONTEXT(sceneManager).ForgetCurrentSceneSourcePath();
1124-
}
1125-
};
1190+
if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_deletedPath)
1191+
{
1192+
EDITOR_CONTEXT(sceneManager).ForgetCurrentSceneSourcePath();
1193+
}
1194+
};
11261195

1127-
auto& ddSource = clickableText.AddPlugin<OvUI::Plugins::DDSource<std::pair<std::string, Layout::Group*>>>(
1128-
"File",
1129-
OvTools::Utils::PathParser::GetFriendlyPath(resourceFormatPath),
1130-
std::make_pair(resourceFormatPath, &itemGroup)
1131-
);
1196+
auto& ddSource = treeNode.AddPlugin<OvUI::Plugins::DDSource<std::pair<std::string, Layout::Group*>>>(
1197+
"File",
1198+
OvTools::Utils::PathParser::GetFriendlyPath(resourceFormatPath),
1199+
std::make_pair(resourceFormatPath, &itemGroup)
1200+
);
11321201

1133-
contextMenu.RenamedEvent += [&ddSource, &clickableText, fileType](
1134-
std::filesystem::path p_prev,
1135-
std::filesystem::path p_newPath
1136-
) {
1137-
if (p_newPath != p_prev)
1138-
{
1139-
if (!std::filesystem::exists(p_newPath))
1202+
contextMenu.RenamedEvent += [&ddSource, &treeNode, fileType](
1203+
std::filesystem::path p_prev,
1204+
std::filesystem::path p_newPath
1205+
) {
1206+
if (p_newPath != p_prev)
11401207
{
1141-
RenameAsset(p_prev, p_newPath);
1142-
const auto elementName = p_newPath.filename();
1143-
ddSource.data.first = (std::filesystem::path{ ddSource.data.first }.parent_path() / elementName).string();
1144-
ddSource.tooltip = OvTools::Utils::PathParser::GetFriendlyPath(ddSource.data.first);
1208+
if (!std::filesystem::exists(p_newPath))
1209+
{
1210+
RenameAsset(p_prev, p_newPath);
1211+
const auto elementName = p_newPath.filename();
1212+
ddSource.data.first = (std::filesystem::path{ ddSource.data.first }.parent_path() / elementName).string();
1213+
ddSource.tooltip = OvTools::Utils::PathParser::GetFriendlyPath(ddSource.data.first);
11451214

1146-
EDITOR_EXEC(PropagateFileRename(p_prev.string(), p_newPath.string()));
1215+
EDITOR_EXEC(PropagateFileRename(p_prev.string(), p_newPath.string()));
11471216

1148-
if (fileType != OvTools::Utils::PathParser::EFileType::SCRIPT)
1149-
{
1150-
if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_prev) // Modify current scene source path if the renamed file is the current scene
1217+
if (fileType != OvTools::Utils::PathParser::EFileType::SCRIPT)
11511218
{
1152-
EDITOR_CONTEXT(sceneManager).StoreCurrentSceneSourcePath(p_newPath.string());
1219+
if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_prev)
1220+
{
1221+
EDITOR_CONTEXT(sceneManager).StoreCurrentSceneSourcePath(p_newPath.string());
1222+
}
11531223
}
1154-
}
11551224

1156-
clickableText.content = elementName.string();
1225+
treeNode.name = elementName.string();
1226+
}
1227+
else
1228+
{
1229+
using namespace OvWindowing::Dialogs;
1230+
1231+
MessageBox errorMessage(
1232+
"File already exists",
1233+
"You can't rename this file because the given name is already taken",
1234+
MessageBox::EMessageType::ERROR,
1235+
MessageBox::EButtonLayout::OK
1236+
);
1237+
}
11571238
}
1158-
else
1239+
};
1240+
1241+
contextMenu.DuplicateEvent += [this, p_root, p_isEngineItem](std::filesystem::path newItem) {
1242+
EDITOR_EXEC(DelayAction(std::bind(&AssetBrowser::ConsiderItem, this, p_root, std::filesystem::directory_entry{ newItem }, p_isEngineItem, false), 0));
1243+
};
1244+
1245+
treeNode.DoubleClickedEvent += [&contextMenu, p_isEngineItem] {
1246+
OvCore::Helpers::GUIHelpers::Open(EDITOR_EXEC(GetResourcePath(contextMenu.filePath.string(), p_isEngineItem)));
1247+
};
1248+
1249+
treeNode.OpenedEvent += [this, &treeNode, &contextMenu, p_isEngineItem] {
1250+
treeNode.RemoveAllWidgets();
1251+
1252+
const std::string modelResourcePath = EDITOR_EXEC(GetResourcePath(contextMenu.filePath.string(), p_isEngineItem));
1253+
const auto* model = OVSERVICE(OvCore::ResourceManagement::ModelManager).GetResource(modelResourcePath);
1254+
if (!model)
11591255
{
1160-
using namespace OvWindowing::Dialogs;
1256+
return;
1257+
}
11611258

1162-
MessageBox errorMessage(
1163-
"File already exists",
1164-
"You can't rename this file because the given name is already taken",
1165-
MessageBox::EMessageType::ERROR,
1166-
MessageBox::EButtonLayout::OK
1167-
);
1259+
const auto& embeddedMaterials = model->GetEmbeddedMaterials();
1260+
for (size_t materialIndex = 0; materialIndex < embeddedMaterials.size(); ++materialIndex)
1261+
{
1262+
const std::string materialPath = OvRendering::Resources::Parsers::MakeEmbeddedMaterialPath(modelResourcePath, static_cast<uint32_t>(materialIndex));
1263+
CreateEmbeddedModelAssetEntry(treeNode, materialPath, OvTools::Utils::PathParser::EFileType::MATERIAL);
11681264
}
1169-
}
1170-
};
11711265

1172-
contextMenu.DuplicateEvent += [this, &clickableText, p_root, p_isEngineItem] (std::filesystem::path newItem) {
1173-
EDITOR_EXEC(DelayAction(std::bind(&AssetBrowser::ConsiderItem, this, p_root, std::filesystem::directory_entry{ newItem }, p_isEngineItem, false), 0));
1174-
};
1266+
const auto& embeddedTextures = model->GetEmbeddedTextures();
1267+
for (size_t textureIndex = 0; textureIndex < embeddedTextures.size(); ++textureIndex)
1268+
{
1269+
const auto& textureData = embeddedTextures[textureIndex];
11751270

1176-
if (fileType == OvTools::Utils::PathParser::EFileType::TEXTURE)
1177-
{
1178-
auto& texturePreview = clickableText.AddPlugin<TexturePreview>();
1179-
texturePreview.SetPath(resourceFormatPath);
1180-
}
1271+
using ESourceType = OvRendering::Resources::EmbeddedTextureData::ESourceType;
1272+
if (textureData.sourceType == ESourceType::EXTERNAL_FILE)
1273+
{
1274+
continue;
1275+
}
11811276

1182-
if (fileType != OvTools::Utils::PathParser::EFileType::UNKNOWN)
1277+
const std::string extension = textureData.extension.empty() ? "bin" : textureData.extension;
1278+
const std::string texturePath = OvRendering::Resources::Parsers::MakeEmbeddedTexturePath(modelResourcePath, static_cast<uint32_t>(textureIndex), extension);
1279+
CreateEmbeddedModelAssetEntry(treeNode, texturePath, OvTools::Utils::PathParser::EFileType::TEXTURE);
1280+
}
1281+
};
1282+
1283+
treeNode.ClosedEvent += [&treeNode] {
1284+
treeNode.RemoveAllWidgets();
1285+
};
1286+
}
1287+
else
11831288
{
1184-
clickableText.DoubleClickedEvent += [&contextMenu, p_isEngineItem] {
1185-
OvCore::Helpers::GUIHelpers::Open(EDITOR_EXEC(GetResourcePath(contextMenu.filePath.string(), p_isEngineItem)));
1289+
auto& clickableText = itemGroup.CreateWidget<Texts::TextClickable>(itemname);
1290+
1291+
FileContextualMenu& contextMenu = CreateFileContextualMenu(
1292+
clickableText,
1293+
fileType,
1294+
path,
1295+
protectedItem
1296+
);
1297+
1298+
contextMenu.CreateList();
1299+
1300+
contextMenu.DestroyedEvent += [&itemGroup](std::filesystem::path p_deletedPath) {
1301+
itemGroup.Destroy();
1302+
1303+
if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_deletedPath) // Modify current scene source path if the renamed file is the current scene
1304+
{
1305+
EDITOR_CONTEXT(sceneManager).ForgetCurrentSceneSourcePath();
1306+
}
11861307
};
1308+
1309+
auto& ddSource = clickableText.AddPlugin<OvUI::Plugins::DDSource<std::pair<std::string, Layout::Group*>>>(
1310+
"File",
1311+
OvTools::Utils::PathParser::GetFriendlyPath(resourceFormatPath),
1312+
std::make_pair(resourceFormatPath, &itemGroup)
1313+
);
1314+
1315+
contextMenu.RenamedEvent += [&ddSource, &clickableText, fileType](
1316+
std::filesystem::path p_prev,
1317+
std::filesystem::path p_newPath
1318+
) {
1319+
if (p_newPath != p_prev)
1320+
{
1321+
if (!std::filesystem::exists(p_newPath))
1322+
{
1323+
RenameAsset(p_prev, p_newPath);
1324+
const auto elementName = p_newPath.filename();
1325+
ddSource.data.first = (std::filesystem::path{ ddSource.data.first }.parent_path() / elementName).string();
1326+
ddSource.tooltip = OvTools::Utils::PathParser::GetFriendlyPath(ddSource.data.first);
1327+
1328+
EDITOR_EXEC(PropagateFileRename(p_prev.string(), p_newPath.string()));
1329+
1330+
if (fileType != OvTools::Utils::PathParser::EFileType::SCRIPT)
1331+
{
1332+
if (EDITOR_CONTEXT(sceneManager).GetCurrentSceneSourcePath() == p_prev) // Modify current scene source path if the renamed file is the current scene
1333+
{
1334+
EDITOR_CONTEXT(sceneManager).StoreCurrentSceneSourcePath(p_newPath.string());
1335+
}
1336+
}
1337+
1338+
clickableText.content = elementName.string();
1339+
}
1340+
else
1341+
{
1342+
using namespace OvWindowing::Dialogs;
1343+
1344+
MessageBox errorMessage(
1345+
"File already exists",
1346+
"You can't rename this file because the given name is already taken",
1347+
MessageBox::EMessageType::ERROR,
1348+
MessageBox::EButtonLayout::OK
1349+
);
1350+
}
1351+
}
1352+
};
1353+
1354+
contextMenu.DuplicateEvent += [this, &clickableText, p_root, p_isEngineItem] (std::filesystem::path newItem) {
1355+
EDITOR_EXEC(DelayAction(std::bind(&AssetBrowser::ConsiderItem, this, p_root, std::filesystem::directory_entry{ newItem }, p_isEngineItem, false), 0));
1356+
};
1357+
1358+
if (fileType == OvTools::Utils::PathParser::EFileType::TEXTURE)
1359+
{
1360+
auto& texturePreview = clickableText.AddPlugin<TexturePreview>();
1361+
texturePreview.SetPath(resourceFormatPath);
1362+
}
1363+
1364+
if (fileType != OvTools::Utils::PathParser::EFileType::UNKNOWN)
1365+
{
1366+
clickableText.DoubleClickedEvent += [&contextMenu, p_isEngineItem] {
1367+
OvCore::Helpers::GUIHelpers::Open(EDITOR_EXEC(GetResourcePath(contextMenu.filePath.string(), p_isEngineItem)));
1368+
};
1369+
}
11871370
}
11881371
}
11891372
}

0 commit comments

Comments
 (0)