diff options
Diffstat (limited to 'source/Ires.cpp')
-rw-r--r-- | source/Ires.cpp | 180 |
1 files changed, 139 insertions, 41 deletions
diff --git a/source/Ires.cpp b/source/Ires.cpp index 6b161d4..f60fcb7 100644 --- a/source/Ires.cpp +++ b/source/Ires.cpp @@ -7,6 +7,7 @@ #include "Material.hpp" #include "RapidJsonHelper.hpp" #include "ScopeGuard.hpp" +#include "Shader.hpp" #include "Sprite.hpp" #include "Texture.hpp" #include "Utils.hpp" @@ -16,8 +17,10 @@ #include <rapidjson/document.h> #include <rapidjson/filereadstream.h> #include <rapidjson/filewritestream.h> +#include <rapidjson/prettywriter.h> #include <rapidjson/writer.h> #include <algorithm> +#include <cassert> namespace fs = std::filesystem; using namespace std::literals; @@ -29,6 +32,7 @@ IresObject::IresObject(Kind kind) std::string_view IresObject::ToString(Kind kind) { switch (kind) { case KD_Texture: return BRUSSEL_TAG_PREFIX_Ires "Texture"sv; + case KD_Shader: return BRUSSEL_TAG_PREFIX_Ires "Shader"sv; case KD_Material: return BRUSSEL_TAG_PREFIX_Ires "Material"sv; case KD_SpriteFiles: return BRUSSEL_TAG_PREFIX_Ires "SpriteFiles"sv; case KD_Spritesheet: return BRUSSEL_TAG_PREFIX_Ires "Spritesheet"sv; @@ -39,6 +43,7 @@ std::string_view IresObject::ToString(Kind kind) { IresObject::Kind IresObject::FromString(std::string_view name) { if (name == BRUSSEL_TAG_PREFIX_Ires "Texture"sv) return KD_Texture; + if (name == BRUSSEL_TAG_PREFIX_Ires "Shader"sv) return KD_Shader; if (name == BRUSSEL_TAG_PREFIX_Ires "Material"sv) return KD_Material; if (name == BRUSSEL_TAG_PREFIX_Ires "SpriteFiles"sv) return KD_SpriteFiles; if (name == BRUSSEL_TAG_PREFIX_Ires "Spritesheet"sv) return KD_Spritesheet; @@ -48,6 +53,7 @@ IresObject::Kind IresObject::FromString(std::string_view name) { std::unique_ptr<IresObject> IresObject::Create(Kind kind) { switch (kind) { case KD_Texture: return std::make_unique<IresTexture>(); + case KD_Shader: return std::make_unique<IresShader>(); case KD_Material: return std::make_unique<IresMaterial>(); case KD_SpriteFiles: return std::make_unique<IresSpriteFiles>(); case KD_Spritesheet: return std::make_unique<IresSpritesheet>(); @@ -68,6 +74,10 @@ void IresObject::SetName(std::string name) { } } +void IresObject::ShowNullName(EditorInstance& editor, Kind kind) { + ImGui::Text("<null>"); +} + void IresObject::ShowName() const { if (IsAnnoymous()) { ImGui::Text("<annoymous %p>", (void*)this); @@ -84,6 +94,13 @@ void IresObject::ShowFullName() const { } } +void IresObject::ShowNullReference(EditorInstance& editor, Kind kind) { + ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_ButtonHovered]); + ImGui::Text("<null>"); + ImGui::PopStyleColor(); + ImGui::AddUnderLine(ImGui::GetStyle().Colors[ImGuiCol_Button]); +} + void IresObject::ShowReference(EditorInstance& editor) { ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_ButtonHovered]); if (IsAnnoymous()) { @@ -119,16 +136,29 @@ void IresObject::ShowEditor(EditorInstance& editor) { } } -void IresObject::WriteFull(IresObject* ires, rapidjson::Value& value, rapidjson::Document& root) { +void IresObject::WriteFull(IresWritingContext& ctx, IresObject* ires, rapidjson::Value& value, rapidjson::Document& root) { rapidjson::Value rvIres(rapidjson::kObjectType); - ires->Write(rvIres, root); + ires->Write(ctx, rvIres, root); value.AddMember("Type", rapidjson::StringRef(ToString(ires->GetKind())), root.GetAllocator()); value.AddMember("Uid", ires->mUid.Write(root), root.GetAllocator()); value.AddMember("Value", rvIres, root.GetAllocator()); } -std::unique_ptr<IresObject> IresObject::ReadFull(const rapidjson::Value& value) { +std::unique_ptr<IresObject> IresObject::ReadFull(IresLoadingContext& ctx, const rapidjson::Value& value) { + auto ires = ReadBasic(value); + if (!ires) { + return nullptr; + } + + if (!ReadPartial(ctx, ires.get(), value)) { + return nullptr; + } + + return ires; +} + +std::unique_ptr<IresObject> IresObject::ReadBasic(const rapidjson::Value& value) { auto rvType = rapidjson::GetProperty(value, rapidjson::kStringType, "Type"sv); if (!rvType) return nullptr; auto kind = FromString(rapidjson::AsStringView(*rvType)); @@ -139,24 +169,20 @@ std::unique_ptr<IresObject> IresObject::ReadFull(const rapidjson::Value& value) if (!rvUid) return nullptr; ires->mUid.Read(*rvUid); - if (!ReadPartial(ires.get(), value)) { - return nullptr; - } - return ires; } -bool IresObject::ReadPartial(IresObject* ires, const rapidjson::Value& value) { +bool IresObject::ReadPartial(IresLoadingContext& ctx, IresObject* ires, const rapidjson::Value& value) { auto rvValue = rapidjson::GetProperty(value, "Value"sv); if (!rvValue) return false; - ires->Read(*rvValue); + ires->Read(ctx, *rvValue); return true; } -void IresObject::Write(rapidjson::Value& value, rapidjson::Document& root) const { +void IresObject::Write(IresWritingContext& ctx, rapidjson::Value& value, rapidjson::Document& root) const { } -void IresObject::Read(const rapidjson::Value& value) { +void IresObject::Read(IresLoadingContext& ctx, const rapidjson::Value& value) { } void IresManager::DiscoverFilesDesignatedLocation() { @@ -165,8 +191,38 @@ void IresManager::DiscoverFilesDesignatedLocation() { } void IresManager::DiscoverFiles(const fs::path& dir) { - // NOTE: by default does not follow symlinks - // for (auto& item : fs::recursive_directory_iterator(dir)) { + struct LoadCandidate { + fs::path path; + rapidjson::Document data; + RcPtr<IresObject> ires; + }; + + class IresLoadTimeContext final : public IresLoadingContext { + public: + // NOTE: pointer stability required + robin_hood::unordered_node_map<Uid, LoadCandidate> candidates; + std::vector<std::vector<LoadCandidate*>> candidatesByKind; + + IresLoadTimeContext() { + candidatesByKind.resize(IresObject::KD_COUNT); + } + + std::vector<LoadCandidate*>& GetByKind(IresObject::Kind kind) { + int i = static_cast<int>(kind); + return candidatesByKind[i]; + } + + virtual IresObject* FindIres(const Uid& uid) const override { + auto iter = candidates.find(uid); + if (iter != candidates.end()) { + auto& cand = iter->second; + return cand.ires.Get(); + } else { + return nullptr; + } + } + } ctx; + for (auto& item : fs::directory_iterator(dir)) { if (!item.is_regular_file()) { continue; @@ -175,9 +231,62 @@ void IresManager::DiscoverFiles(const fs::path& dir) { continue; } - auto ires = Load(item.path()); + auto file = Utils::OpenCstdioFile(item.path(), Utils::Read); + if (!file) { + fprintf(stderr, "Ires file [" PLATFORM_PATH_STR "] Failed to open file.", item.path().c_str()); + continue; + } + DEFER { fclose(file); }; + + char readerBuffer[65536]; + rapidjson::FileReadStream stream(file, readerBuffer, sizeof(readerBuffer)); + + rapidjson::Document root; + root.ParseStream(stream); + + auto ires = IresObject::ReadBasic(root); if (!ires) { - fprintf(stderr, "Failed to load Ires at '" PLATFORM_PATH_STR "'.", item.path().c_str()); + fprintf(stderr, "Ires file: [" PLATFORM_PATH_STR "] Failed to parse header.", item.path().c_str()); + continue; + } + + // Load name from filename + ires->mName = item.path().filename().replace_extension().string(); + auto& iresName = ires->mName; + + // Load uid should be handled by IresObject::ReadBasic + assert(!ires->mUid.IsNull()); + auto iresUid = ires->GetUid(); + + auto iresKind = ires->GetKind(); + + auto&& [iter, DISCARD] = ctx.candidates.try_emplace( + iresUid, + LoadCandidate{ + .path = item.path(), + .data = std::move(root), + .ires = RcPtr(ires.release()), + }); + auto& cand = iter->second; + + ctx.GetByKind(iresKind).push_back(&cand); + } + + // Load Ires in order by type, there are dependencies between them + // TODO full arbitary dependency between Ires + for (int i = 0; i < IresObject::KD_COUNT; ++i) { + auto kind = static_cast<IresObject::Kind>(i); + auto& list = ctx.GetByKind(kind); + for (auto cand : list) { + auto& ires = cand->ires; + + if (!IresObject::ReadPartial(ctx, ires.Get(), cand->data)) { + fprintf(stderr, "Ires file: [" PLATFORM_PATH_STR "] Failed to parse object data.", cand->path.c_str()); + continue; + } + + ires->mMan = this; + mObjByUid.try_emplace(ires->GetUid(), ires); } } } @@ -218,7 +327,7 @@ IresObject* IresManager::Load(const fs::path& filePath) { rapidjson::Document root; root.ParseStream(stream); - auto ires = IresObject::ReadFull(root); + auto ires = IresObject::ReadFull(*this, root); if (!ires) { return nullptr; } @@ -229,32 +338,24 @@ IresObject* IresManager::Load(const fs::path& filePath) { ires->mName = filePath.filename().replace_extension().string(); Add(ires.get()); - // TODO subdirectory support -#if 0 - auto iden = fs::path(filePath).replace_extension().lexically_relative(dir).string(); - std::replace(iden.begin(), iden.end(), '\\', '/'); - - std::string_view idenView(iden); - - // Trim heading slashes - while (idenView.front() == '/') { - idenView = std::string_view(idenView.data() + 1, idenView.size()); - } - // Trim trailing slashes - while (idenView.back() == '/') { - idenView = std::string_view(idenView.data(), idenView.size() - 1); - } -#endif - return ires.release(); } +static fs::path GetDesignatedPath(IresObject* ires) { + return AppConfig::assetDirPath / "Ires" / fs::path(ires->GetName()).replace_extension(".json"); +} + void IresManager::Delete(IresObject* ires) { // TODO } bool IresManager::Rename(IresObject* ires, std::string newName) { + auto oldPath = GetDesignatedPath(ires); ires->mName = std::move(newName); + auto newPath = GetDesignatedPath(ires); + if (fs::exists(oldPath)) { + fs::rename(oldPath, newPath); + } // TODO validate no name duplication #if 0 @@ -276,10 +377,6 @@ bool IresManager::Rename(IresObject* ires, std::string newName) { return true; } -static fs::path GetDesignatedPath(IresObject* ires) { - return AppConfig::assetDirPath / "Ires" / fs::path(ires->GetName()).replace_extension(".json"); -} - void IresManager::Reload(IresObject* ires) { auto file = Utils::OpenCstdioFile(GetDesignatedPath(ires), Utils::Read); if (!file) return; @@ -291,7 +388,7 @@ void IresManager::Reload(IresObject* ires) { rapidjson::Document root; root.ParseStream(stream); - IresObject::ReadPartial(ires, root); + IresObject::ReadPartial(*this, ires, root); } void IresManager::Save(IresObject* ires) { @@ -301,7 +398,7 @@ void IresManager::Save(IresObject* ires) { void IresManager::Save(IresObject* ires, const fs::path& filePath) { rapidjson::Document root(rapidjson::kObjectType); - IresObject::WriteFull(ires, root, root); + IresObject::WriteFull(*this, ires, root, root); auto file = Utils::OpenCstdioFile(filePath, Utils::WriteTruncate); if (!file) return; @@ -309,11 +406,12 @@ void IresManager::Save(IresObject* ires, const fs::path& filePath) { char writerBuffer[65536]; rapidjson::FileWriteStream stream(file, writerBuffer, sizeof(writerBuffer)); - rapidjson::Writer<rapidjson::FileWriteStream> writer(stream); + rapidjson::PrettyWriter<rapidjson::FileWriteStream> writer(stream); + writer.SetFormatOptions(rapidjson::PrettyFormatOptions::kFormatSingleLineArray); root.Accept(writer); } -IresObject* IresManager::FindIres(const Uid& uid) { +IresObject* IresManager::FindIres(const Uid& uid) const { auto iter = mObjByUid.find(uid); if (iter != mObjByUid.end()) { return iter->second.Get(); |