diff options
Diffstat (limited to 'source/Ires.cpp')
-rw-r--r-- | source/Ires.cpp | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/source/Ires.cpp b/source/Ires.cpp new file mode 100644 index 0000000..f700ed6 --- /dev/null +++ b/source/Ires.cpp @@ -0,0 +1,176 @@ +#include "Ires.hpp" + +#include "AppConfig.hpp" +#include "RapidJsonHelper.hpp" +#include "ScopeGuard.hpp" +#include "Sprite.hpp" +#include "Texture.hpp" +#include "Utils.hpp" + +#include <rapidjson/document.h> +#include <rapidjson/filereadstream.h> +#include <rapidjson/filewritestream.h> +#include <rapidjson/writer.h> +#include <algorithm> + +namespace fs = std::filesystem; +using namespace std::literals; + +IresObject::IresObject(Kind kind) + : mKind{ kind } { +} + +std::string_view IresObject::ToString(Kind kind) { + switch (kind) { + case KD_Texture: return "Texture"sv; + case KD_SpriteFiles: return "SpriteFiles"sv; + case KD_Spritesheet: return "Spritesheet"sv; + case KD_COUNT: break; + } + return std::string_view(); +} + +IresObject::Kind IresObject::FromString(std::string_view name) { + if (name == "Texture"sv) return KD_Texture; + if (name == "SpriteFiles"sv) return KD_SpriteFiles; + if (name == "Spritesheet"sv) return KD_Spritesheet; + return KD_COUNT; +} + +std::unique_ptr<IresObject> IresObject::Create(Kind kind) { + switch (kind) { + case KD_Texture: return std::make_unique<IresTexture>(); + case KD_SpriteFiles: return std::make_unique<IresSpriteFiles>(); + case KD_Spritesheet: return std::make_unique<IresSpritesheet>(); + case KD_COUNT: break; + } + return nullptr; +} + +bool IresObject::IsAnnoymous() const { + return mName.empty(); +} + +rapidjson::Value IresObject::WriteFull(const IresObject& ires, rapidjson::Document& root) { + rapidjson::Value rvIres; + ires.Write(rvIres, root); + + rapidjson::Value result; + result.AddMember("Type", rapidjson::StringRef(ToString(ires.GetKind())), root.GetAllocator()); + result.AddMember("Value", rvIres, root.GetAllocator()); + return result; +} + +std::unique_ptr<IresObject> IresObject::ReadFull(const rapidjson::Value& value) { + auto rvType = rapidjson::GetProperty(value, rapidjson::kStringType, "Type"sv); + if (!rvType) return nullptr; + auto kind = FromString(rapidjson::AsStringView(*rvType)); + auto ires = Create(kind); + if (!ires) return nullptr; + + auto rvValue = rapidjson::GetProperty(value, "Value"sv); + if (!rvValue) return nullptr; + ires->Read(*rvValue); + + return ires; +} + +void IresManager::DiscoverFilesDesignatedLocation() { + auto path = AppConfig::assetDirPath / "Ires"; + DiscoverFiles(path); +} + +void IresManager::DiscoverFiles(const fs::path& dir) { + // NOTE: by default does not follow symlinks + // for (auto& item : fs::recursive_directory_iterator(dir)) { + for (auto& item : fs::directory_iterator(dir)) { + if (!item.is_regular_file()) { + continue; + } + if (item.path().extension() != ".json") { + continue; + } + + auto file = Utils::OpenCstdioFile(item.path(), Utils::Read); + if (!file) continue; + DEFER { fclose(file); }; + + char readerBuffer[65536]; + rapidjson::FileReadStream stream(file, readerBuffer, sizeof(readerBuffer)); + + rapidjson::Document root; + root.ParseStream(stream); + + auto ires = IresObject::ReadFull(root); + if (!ires) { + continue; + } + + auto iden = fs::path(item.path()).replace_extension().lexically_relative(dir).string(); + std::replace(iden.begin(), iden.end(), '\\', '/'); + +#if 0 + 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 + mObjects.try_emplace(std::move(iden), ires.release()); + } +} + +std::pair<IresObject*, bool> IresManager::Add(IresObject* ires) { + auto& name = ires->mName; + if (name.empty()) { + int n = std::rand(); + // NOTE: does not include null-terminator + int size = snprintf(nullptr, 0, "Unnamed %s #%d", IresObject::ToString(ires->GetKind()).data(), n); + name.resize(size); // std::string::resize handles storage for null-terminator alreaedy + snprintf(name.data(), size, "Unnamed %s #%d", IresObject::ToString(ires->GetKind()).data(), n); + } + + auto [iter, inserted] = mObjects.try_emplace(name, ires); + if (inserted) { + ires->mMan = this; + return { ires, true }; + } else { + return { iter->second.Get(), false }; + } +} + +void IresManager::Delete(IresObject* ires) { + // TODO +} + +bool IresManager::Rename(IresObject* ires, std::string newName) { + if (mObjects.contains(newName)) { + return false; + } + + // Keep the material from being deleted, in case the old entry in map is the only one existing + RcPtr rc(ires); + + // Remove old entry (must do before replacing Material::mName, because the std::string_view in the map is a reference to it) + mObjects.erase(ires->GetName()); + + // Add new entry + ires->mName = std::move(newName); + mObjects.try_emplace(ires->GetName(), ires); + + return true; +} + +IresObject* IresManager::FindIres(std::string_view path) { + auto iter = mObjects.find(path); + if (iter != mObjects.end()) { + return iter->second.Get(); + } else { + return nullptr; + } +} |