mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-08-05 15:48:51 +00:00
VideoCommon: add graphics mod editor asset browser panel
This commit is contained in:
parent
e75b0d78e4
commit
7759460bf7
2 changed files with 604 additions and 0 deletions
|
@ -0,0 +1,537 @@
|
||||||
|
// Copyright 2023 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "VideoCommon/GraphicsModEditor/Panels/AssetBrowserPanel.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <misc/cpp/imgui_stdlib.h>
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/FileUtil.h"
|
||||||
|
#include "Common/StringUtil.h"
|
||||||
|
#include "Common/VariantUtil.h"
|
||||||
|
#include "Core/System.h"
|
||||||
|
#include "VideoCommon/Assets/CustomAssetLoader.h"
|
||||||
|
#include "VideoCommon/GraphicsModEditor/Controls/MaterialGenerateWindow.h"
|
||||||
|
#include "VideoCommon/GraphicsModEditor/Controls/MeshImportWindow.h"
|
||||||
|
#include "VideoCommon/GraphicsModEditor/EditorEvents.h"
|
||||||
|
#include "VideoCommon/GraphicsModEditor/MaterialGeneration.h"
|
||||||
|
#include "VideoCommon/GraphicsModEditor/RenderTargetGeneration.h"
|
||||||
|
#include "VideoCommon/GraphicsModEditor/ShaderGeneration.h"
|
||||||
|
#include "VideoCommon/Present.h"
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::string FindNewName(const std::string& base_name, const std::string& extension,
|
||||||
|
const std::filesystem::path& base_path)
|
||||||
|
{
|
||||||
|
u32 index = 1;
|
||||||
|
std::string new_name = base_name + extension;
|
||||||
|
while (std::filesystem::exists(base_path / new_name))
|
||||||
|
{
|
||||||
|
new_name = fmt::format("{} {}{}", base_name, index, extension);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_name;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace GraphicsModEditor::Panels
|
||||||
|
{
|
||||||
|
AssetBrowserPanel::AssetBrowserPanel(EditorState& state) : m_state(state)
|
||||||
|
{
|
||||||
|
ResetCurrentPath();
|
||||||
|
|
||||||
|
m_browse_event = EditorEvents::JumpToAssetInBrowserEvent::Register(
|
||||||
|
[this](const VideoCommon::CustomAssetLibrary::AssetID& asset_id) { BrowseEvent(asset_id); },
|
||||||
|
"EditorAssetBrowserPanel");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetBrowserPanel::ResetCurrentPath()
|
||||||
|
{
|
||||||
|
m_current_path = m_state.m_user_data.m_current_mod_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetBrowserPanel::DrawImGui()
|
||||||
|
{
|
||||||
|
const ImGuiViewport* main_viewport = ImGui::GetMainViewport();
|
||||||
|
u32 default_window_height = g_presenter->GetTargetRectangle().GetHeight() * 0.2;
|
||||||
|
u32 default_window_width = g_presenter->GetTargetRectangle().GetWidth() * 0.95;
|
||||||
|
ImGui::SetNextWindowPos(ImVec2(main_viewport->WorkPos.x + default_window_width * 0.1,
|
||||||
|
main_viewport->WorkPos.y +
|
||||||
|
g_presenter->GetTargetRectangle().GetHeight() -
|
||||||
|
default_window_height),
|
||||||
|
ImGuiCond_FirstUseEver);
|
||||||
|
ImGui::SetNextWindowSize(ImVec2(default_window_width, default_window_height),
|
||||||
|
ImGuiCond_FirstUseEver);
|
||||||
|
|
||||||
|
ImGui::Begin("Asset Browser Panel");
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
auto dir_iter = std::filesystem::directory_iterator(m_current_path, ec);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
ImGui::Text(
|
||||||
|
"%s",
|
||||||
|
fmt::format("Error viewing current directory '{}'", PathToString(m_current_path)).c_str());
|
||||||
|
ImGui::End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::vector<std::filesystem::path> directory_entries;
|
||||||
|
for (const auto& entry : dir_iter)
|
||||||
|
{
|
||||||
|
directory_entries.push_back(entry.path());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split the current path into pieces from the root
|
||||||
|
const auto relative_path =
|
||||||
|
std::filesystem::relative(m_current_path, m_state.m_user_data.m_current_mod_path, ec);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
ImGui::Text("%s", fmt::format("Error getting relative path from directory '{}' to root '{}'",
|
||||||
|
PathToString(m_current_path),
|
||||||
|
PathToString(m_state.m_user_data.m_current_mod_path))
|
||||||
|
.c_str());
|
||||||
|
ImGui::End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path full_path = m_state.m_user_data.m_current_mod_path;
|
||||||
|
if (ImGui::Button("Assets"))
|
||||||
|
{
|
||||||
|
m_current_path = full_path;
|
||||||
|
}
|
||||||
|
if (relative_path != std::filesystem::path{"."})
|
||||||
|
{
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text(" > ");
|
||||||
|
|
||||||
|
const std::vector<std::filesystem::path> path_pieces(relative_path.begin(),
|
||||||
|
relative_path.end());
|
||||||
|
for (const auto& piece : path_pieces)
|
||||||
|
{
|
||||||
|
ImGui::SameLine();
|
||||||
|
full_path /= piece;
|
||||||
|
if (ImGui::Button(PathToString(piece).c_str()))
|
||||||
|
{
|
||||||
|
m_current_path = full_path;
|
||||||
|
}
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text(" > ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const float search_size = 200.0f;
|
||||||
|
const float search_padding = 50.0f;
|
||||||
|
if (ImGui::GetWindowSize().x > (search_size + search_padding))
|
||||||
|
{
|
||||||
|
const ImVec2 dummy_size =
|
||||||
|
ImVec2(ImGui::GetWindowSize().x - search_size - search_padding, ImGui::GetTextLineHeight());
|
||||||
|
ImGui::Dummy(dummy_size);
|
||||||
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
ImGui::SetNextItemWidth(search_size);
|
||||||
|
ImGui::InputTextWithHint("##", "Search...", &m_filter_text);
|
||||||
|
|
||||||
|
const u32 column_count =
|
||||||
|
static_cast<u32>(ImGui::GetContentRegionAvail().x) / (thumbnail_size + padding);
|
||||||
|
u32 columns_displayed = 0;
|
||||||
|
|
||||||
|
if (ImGui::BeginTable("AsetBrowserContentTable", column_count))
|
||||||
|
{
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
|
||||||
|
for (const auto& entry : directory_entries)
|
||||||
|
{
|
||||||
|
if (std::filesystem::is_directory(entry))
|
||||||
|
{
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
if (ImGui::ImageButton(PathToString(entry).c_str(),
|
||||||
|
*m_state.m_editor_data.m_name_to_texture["folder"].get(),
|
||||||
|
thumbnail_imgui_size))
|
||||||
|
{
|
||||||
|
m_current_path = entry;
|
||||||
|
}
|
||||||
|
ImGui::Text("%s", PathToString(entry.filename()).c_str());
|
||||||
|
ImGui::EndGroup();
|
||||||
|
columns_displayed++;
|
||||||
|
if (columns_displayed == column_count)
|
||||||
|
{
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
columns_displayed = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& entry : directory_entries)
|
||||||
|
{
|
||||||
|
if (std::filesystem::is_regular_file(entry))
|
||||||
|
{
|
||||||
|
const std::string filename = PathToString(entry.filename());
|
||||||
|
if (!m_filter_text.empty() && filename.find(m_filter_text) == std::string::npos)
|
||||||
|
continue;
|
||||||
|
auto ext = entry.extension().string();
|
||||||
|
Common::ToLower(&ext);
|
||||||
|
if (ext == ".dds" || ext == ".png")
|
||||||
|
{
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
HandleAsset(entry, m_state.m_editor_data.m_name_to_texture["image"].get(),
|
||||||
|
"TextureAsset");
|
||||||
|
ImGui::EndGroup();
|
||||||
|
columns_displayed++;
|
||||||
|
}
|
||||||
|
else if (ext == ".rastershader")
|
||||||
|
{
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
HandleAsset(entry, m_state.m_editor_data.m_name_to_texture["code"].get(),
|
||||||
|
"RasterShaderAsset");
|
||||||
|
ImGui::EndGroup();
|
||||||
|
columns_displayed++;
|
||||||
|
}
|
||||||
|
else if (ext == ".dolmesh")
|
||||||
|
{
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
HandleAsset(entry, m_state.m_editor_data.m_name_to_texture["file"].get(), "MeshAsset");
|
||||||
|
ImGui::EndGroup();
|
||||||
|
columns_displayed++;
|
||||||
|
}
|
||||||
|
else if (ext == ".gltf")
|
||||||
|
{
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.5);
|
||||||
|
ImGui::ImageButton(PathToString(entry).c_str(),
|
||||||
|
*m_state.m_editor_data.m_name_to_texture["file"].get(),
|
||||||
|
thumbnail_imgui_size);
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
if (ImGui::BeginPopupContextItem())
|
||||||
|
{
|
||||||
|
if (ImGui::Selectable("Import"))
|
||||||
|
{
|
||||||
|
m_is_mesh_import_active = true;
|
||||||
|
m_mesh_import_filename = WithUnifiedPathSeparators(PathToString(full_path / entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
ImGui::OpenPopupOnItemClick(PathToString(entry).c_str(),
|
||||||
|
ImGuiPopupFlags_MouseButtonRight);
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.5);
|
||||||
|
ImGui::TextWrapped("%s", PathToString(entry.stem()).c_str());
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
ImGui::EndGroup();
|
||||||
|
columns_displayed++;
|
||||||
|
}
|
||||||
|
else if (ext == ".rastermaterial")
|
||||||
|
{
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
HandleAsset(entry, m_state.m_editor_data.m_name_to_texture["file"].get(),
|
||||||
|
"RasterMaterialAsset");
|
||||||
|
ImGui::EndGroup();
|
||||||
|
columns_displayed++;
|
||||||
|
}
|
||||||
|
else if (ext == ".rendertarget")
|
||||||
|
{
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::BeginGroup();
|
||||||
|
HandleAsset(entry, m_state.m_editor_data.m_name_to_texture["image"].get(),
|
||||||
|
"RenderTargetAsset");
|
||||||
|
ImGui::EndGroup();
|
||||||
|
columns_displayed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (columns_displayed == column_count)
|
||||||
|
{
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
columns_displayed = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_is_mesh_import_active)
|
||||||
|
{
|
||||||
|
if (Controls::ShowMeshImportWindow(m_mesh_import_filename, &m_mesh_import_import_materials))
|
||||||
|
{
|
||||||
|
m_is_mesh_import_active = false;
|
||||||
|
m_mesh_import_import_materials = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_is_generate_material_active)
|
||||||
|
{
|
||||||
|
if (Controls::ShowMaterialGenerateWindow(&m_material_generation_context))
|
||||||
|
{
|
||||||
|
m_is_generate_material_active = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginPopupContextWindow("AssetBrowserGenericContextMenu",
|
||||||
|
ImGuiPopupFlags_NoOpenOverItems |
|
||||||
|
ImGuiPopupFlags_MouseButtonRight |
|
||||||
|
ImGuiPopupFlags_NoOpenOverExistingPopup))
|
||||||
|
{
|
||||||
|
if (ImGui::BeginMenu("Create"))
|
||||||
|
{
|
||||||
|
if (ImGui::MenuItem("Material"))
|
||||||
|
{
|
||||||
|
const std::string name = FindNewName("New Material", ".rastermaterial", m_current_path);
|
||||||
|
const auto asset = GenerateMaterial(
|
||||||
|
name, m_current_path, m_state.m_editor_data.m_name_to_template["raster_material"],
|
||||||
|
m_state.m_user_data.m_asset_library.get());
|
||||||
|
if (asset)
|
||||||
|
{
|
||||||
|
EditorEvents::ItemsSelectedEvent::Trigger(std::set<SelectableType>{asset});
|
||||||
|
GraphicsModEditor::EditorEvents::ChangeOccurredEvent::Trigger();
|
||||||
|
BeginRename(asset->m_asset_id, PathToString(asset->m_asset_path.stem()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem("Shader"))
|
||||||
|
{
|
||||||
|
const auto metadata_name = FindNewName("New Shader", ".rastershader", m_current_path);
|
||||||
|
const std::string pixel_name = FindNewName("New Shader.ps", ".glsl", m_current_path);
|
||||||
|
const std::string vertex_name = FindNewName("New Shader.vs", ".glsl", m_current_path);
|
||||||
|
|
||||||
|
const auto asset =
|
||||||
|
GenerateShader(m_current_path, pixel_name, vertex_name, metadata_name,
|
||||||
|
m_state.m_editor_data.m_name_to_template["raster_shader_ps"],
|
||||||
|
m_state.m_editor_data.m_name_to_template["raster_shader_vs"],
|
||||||
|
m_state.m_editor_data.m_name_to_template["raster_shader_meta"],
|
||||||
|
m_state.m_user_data.m_asset_library.get());
|
||||||
|
if (asset)
|
||||||
|
{
|
||||||
|
EditorEvents::ItemsSelectedEvent::Trigger(std::set<SelectableType>{asset});
|
||||||
|
GraphicsModEditor::EditorEvents::ChangeOccurredEvent::Trigger();
|
||||||
|
BeginRename(asset->m_asset_id, PathToString(asset->m_asset_path.stem()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem("Render Target"))
|
||||||
|
{
|
||||||
|
const std::string name =
|
||||||
|
FindNewName("New Render Target", ".rendertarget", m_current_path);
|
||||||
|
VideoCommon::RenderTargetData data;
|
||||||
|
data.m_texture_format = AbstractTextureFormat::RGBA8;
|
||||||
|
data.m_sampler = {};
|
||||||
|
const auto asset =
|
||||||
|
GenerateRenderTarget(m_current_path, data, m_state.m_user_data.m_asset_library.get());
|
||||||
|
if (asset)
|
||||||
|
{
|
||||||
|
EditorEvents::ItemsSelectedEvent::Trigger(std::set<SelectableType>{asset});
|
||||||
|
GraphicsModEditor::EditorEvents::ChangeOccurredEvent::Trigger();
|
||||||
|
BeginRename(asset->m_asset_id, PathToString(asset->m_asset_path.stem()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem("Generate Materials From Textures..."))
|
||||||
|
{
|
||||||
|
m_material_generation_context = {};
|
||||||
|
m_material_generation_context.state = &m_state;
|
||||||
|
m_is_generate_material_active = true;
|
||||||
|
m_material_generation_context.input_path = PathToString(m_current_path);
|
||||||
|
m_material_generation_context.output_path =
|
||||||
|
PathToString(m_state.m_user_data.m_current_mod_path / "materials");
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool window_clicked = (!ImGui::IsAnyItemHovered() &&
|
||||||
|
ImGui::IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows) &&
|
||||||
|
ImGui::IsMouseClicked(ImGuiMouseButton_Left));
|
||||||
|
if (ImGui::IsKeyPressed(ImGuiKey_Escape) || window_clicked)
|
||||||
|
{
|
||||||
|
EndRename();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (directory_entries.size() == 0)
|
||||||
|
{
|
||||||
|
ImGui::Text("No items in folder");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetBrowserPanel::HandleAsset(const std::filesystem::path& asset_path,
|
||||||
|
AbstractTexture* icon_texture, std::string_view drag_drop_name)
|
||||||
|
{
|
||||||
|
EditorAsset* asset = m_state.m_user_data.m_asset_library->GetAssetFromPath(asset_path);
|
||||||
|
if (asset)
|
||||||
|
{
|
||||||
|
AbstractTexture* texture =
|
||||||
|
m_state.m_user_data.m_asset_library->GetAssetPreview(asset->m_asset_id);
|
||||||
|
m_state.m_editor_data.m_assets_waiting_for_preview.erase(asset->m_asset_id);
|
||||||
|
if (!texture)
|
||||||
|
texture = icon_texture;
|
||||||
|
|
||||||
|
if (ImGui::ImageButton(PathToString(asset_path).c_str(), *texture, thumbnail_imgui_size))
|
||||||
|
{
|
||||||
|
EndRename();
|
||||||
|
EditorEvents::ItemsSelectedEvent::Trigger(std::set<SelectableType>{asset});
|
||||||
|
}
|
||||||
|
if (ImGui::BeginPopupContextItem())
|
||||||
|
{
|
||||||
|
EndRename();
|
||||||
|
if (ImGui::MenuItem("Remove from project"))
|
||||||
|
{
|
||||||
|
m_state.m_user_data.m_asset_library->RemoveAsset(asset_path);
|
||||||
|
EditorEvents::ItemsSelectedEvent::Trigger(std::set<SelectableType>{});
|
||||||
|
GraphicsModEditor::EditorEvents::ChangeOccurredEvent::Trigger();
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem("Rename"))
|
||||||
|
{
|
||||||
|
BeginRename(asset->m_asset_id, PathToString(asset_path.stem()));
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
ImGui::OpenPopupOnItemClick(PathToString(asset_path).c_str(), ImGuiPopupFlags_MouseButtonRight);
|
||||||
|
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
|
||||||
|
{
|
||||||
|
ImGui::SetDragDropPayload(drag_drop_name.data(), asset->m_asset_id.c_str(),
|
||||||
|
asset->m_asset_id.size());
|
||||||
|
|
||||||
|
ImGui::Text("%s", PathToString(asset->m_asset_path.stem()).c_str());
|
||||||
|
ImGui::EndDragDropSource();
|
||||||
|
}
|
||||||
|
if (m_renamed_asset_id == asset->m_asset_id)
|
||||||
|
{
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0);
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, {0, 0});
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_FrameBg, 0);
|
||||||
|
if (!m_is_rename_focused)
|
||||||
|
{
|
||||||
|
ImGui::SetKeyboardFocusHere();
|
||||||
|
m_is_rename_focused = true;
|
||||||
|
}
|
||||||
|
if (ImGui::InputText("##AssetRename", &m_rename_text, ImGuiInputTextFlags_EnterReturnsTrue))
|
||||||
|
{
|
||||||
|
m_does_rename_have_error = false;
|
||||||
|
|
||||||
|
const auto old_path = asset_path;
|
||||||
|
const auto new_path =
|
||||||
|
asset_path.parent_path() / (m_rename_text + PathToString(asset_path.extension()));
|
||||||
|
if (m_state.m_user_data.m_asset_library->RenameAsset(old_path, new_path))
|
||||||
|
{
|
||||||
|
EndRename();
|
||||||
|
GraphicsModEditor::EditorEvents::ChangeOccurredEvent::Trigger();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!m_does_rename_have_error)
|
||||||
|
{
|
||||||
|
ImGui::OpenPopup("##RenameHasError");
|
||||||
|
|
||||||
|
// Focus seems to be stolen so tell input to focus again
|
||||||
|
m_is_rename_focused = false;
|
||||||
|
}
|
||||||
|
m_does_rename_have_error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
ImGui::SetNextWindowPos(ImVec2(ImGui::GetItemRectMax().x + 10, ImGui::GetItemRectMin().y));
|
||||||
|
if (ImGui::BeginPopup("##RenameHasError",
|
||||||
|
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove |
|
||||||
|
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_ChildWindow))
|
||||||
|
{
|
||||||
|
const ImVec4 red_tint(1, 0, 0, 1);
|
||||||
|
ImGui::Image(*m_state.m_editor_data.m_name_to_texture["error"].get(), ImVec2(25, 25),
|
||||||
|
ImVec2(0, 0), ImVec2(1, 1), red_tint);
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text("File already exists, choose a different name");
|
||||||
|
if (!m_does_rename_have_error)
|
||||||
|
{
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string asset_path_filename = PathToString(asset_path.stem());
|
||||||
|
ImGui::TextWrapped("%s", asset_path_filename.c_str());
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
{
|
||||||
|
if (ImGui::IsMouseReleased(ImGuiMouseButton_Left))
|
||||||
|
BeginRename(asset->m_asset_id, std::move(asset_path_filename));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.5);
|
||||||
|
if (ImGui::ImageButton(PathToString(asset_path).c_str(), *icon_texture, thumbnail_imgui_size))
|
||||||
|
{
|
||||||
|
EndRename();
|
||||||
|
}
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
if (ImGui::BeginPopupContextItem())
|
||||||
|
{
|
||||||
|
EndRename();
|
||||||
|
if (ImGui::MenuItem("Add to project"))
|
||||||
|
{
|
||||||
|
m_state.m_user_data.m_asset_library->AddAsset(asset_path);
|
||||||
|
GraphicsModEditor::EditorEvents::ChangeOccurredEvent::Trigger();
|
||||||
|
|
||||||
|
asset = m_state.m_user_data.m_asset_library->GetAssetFromPath(asset_path);
|
||||||
|
if (asset)
|
||||||
|
{
|
||||||
|
auto& system = Core::System::GetInstance();
|
||||||
|
auto& loader = system.GetCustomAssetLoader();
|
||||||
|
// TODO: generate previews for other assets...
|
||||||
|
if (asset->m_asset_map.find("texture") != asset->m_asset_map.end())
|
||||||
|
{
|
||||||
|
m_state.m_editor_data.m_assets_waiting_for_preview.try_emplace(
|
||||||
|
asset->m_asset_id,
|
||||||
|
loader.LoadGameTexture(asset->m_asset_id, m_state.m_user_data.m_asset_library));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
ImGui::OpenPopupOnItemClick(PathToString(asset_path).c_str(), ImGuiPopupFlags_MouseButtonRight);
|
||||||
|
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, 0.5);
|
||||||
|
ImGui::TextWrapped("%s", PathToString(asset_path.stem()).c_str());
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetBrowserPanel::BeginRename(const VideoCommon::CustomAssetLibrary::AssetID& asset_id,
|
||||||
|
std::string rename_text)
|
||||||
|
{
|
||||||
|
m_renamed_asset_id = asset_id;
|
||||||
|
m_rename_text = std::move(rename_text);
|
||||||
|
m_is_rename_focused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetBrowserPanel::EndRename()
|
||||||
|
{
|
||||||
|
m_renamed_asset_id.reset();
|
||||||
|
m_rename_text = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetBrowserPanel::BrowseEvent(const VideoCommon::CustomAssetLibrary::AssetID& asset_id)
|
||||||
|
{
|
||||||
|
EditorAsset* asset = m_state.m_user_data.m_asset_library->GetAssetFromID(asset_id);
|
||||||
|
if (asset)
|
||||||
|
{
|
||||||
|
m_current_path = asset->m_asset_path.parent_path();
|
||||||
|
EditorEvents::ItemsSelectedEvent::Trigger(std::set<SelectableType>{asset});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace GraphicsModEditor::Panels
|
|
@ -0,0 +1,67 @@
|
||||||
|
// Copyright 2023 Dolphin Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <optional>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include "Common/HookableEvent.h"
|
||||||
|
#include "VideoCommon/Assets/CustomAssetLibrary.h"
|
||||||
|
#include "VideoCommon/GraphicsModEditor/EditorState.h"
|
||||||
|
#include "VideoCommon/GraphicsModEditor/MaterialGeneration.h"
|
||||||
|
|
||||||
|
class AbstractTexture;
|
||||||
|
|
||||||
|
namespace GraphicsModEditor::Panels
|
||||||
|
{
|
||||||
|
class AssetBrowserPanel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit AssetBrowserPanel(EditorState& state);
|
||||||
|
|
||||||
|
void ResetCurrentPath();
|
||||||
|
|
||||||
|
// Renders ImGui windows to the currently-bound framebuffer.
|
||||||
|
void DrawImGui();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr u32 thumbnail_size = 150;
|
||||||
|
static constexpr u32 padding = 32;
|
||||||
|
static constexpr ImVec2 thumbnail_imgui_size{thumbnail_size, thumbnail_size};
|
||||||
|
|
||||||
|
void HandleAsset(const std::filesystem::path& asset_path, AbstractTexture* icon_texture,
|
||||||
|
std::string_view drag_drop_name);
|
||||||
|
void BeginRename(const VideoCommon::CustomAssetLibrary::AssetID& asset_id,
|
||||||
|
std::string rename_text);
|
||||||
|
void EndRename();
|
||||||
|
void BrowseEvent(const VideoCommon::CustomAssetLibrary::AssetID& asset_id);
|
||||||
|
|
||||||
|
Common::EventHook m_browse_event;
|
||||||
|
|
||||||
|
EditorState& m_state;
|
||||||
|
|
||||||
|
std::filesystem::path m_current_path;
|
||||||
|
|
||||||
|
// Filter
|
||||||
|
std::string m_filter_text;
|
||||||
|
|
||||||
|
// Rename
|
||||||
|
std::optional<VideoCommon::CustomAssetLibrary::AssetID> m_renamed_asset_id = std::nullopt;
|
||||||
|
std::string m_rename_text;
|
||||||
|
bool m_is_rename_focused = false;
|
||||||
|
bool m_does_rename_have_error = false;
|
||||||
|
|
||||||
|
// Import mesh
|
||||||
|
bool m_is_mesh_import_active = false;
|
||||||
|
bool m_mesh_import_import_materials = false;
|
||||||
|
std::string m_mesh_import_filename;
|
||||||
|
|
||||||
|
// Generate materials
|
||||||
|
bool m_is_generate_material_active = false;
|
||||||
|
RasterMaterialGenerationContext m_material_generation_context;
|
||||||
|
};
|
||||||
|
} // namespace GraphicsModEditor::Panels
|
Loading…
Add table
Add a link
Reference in a new issue