aboutsummaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/CMakeLists.txt1
-rw-r--r--source/EditorCore.cpp2
-rw-r--r--source/Ires.cpp131
-rw-r--r--source/Ires.hpp23
-rw-r--r--source/Sprite.cpp6
-rw-r--r--source/Uid.cpp47
-rw-r--r--source/Uid.hpp32
-rw-r--r--source/Utils.hpp6
8 files changed, 189 insertions, 59 deletions
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index ea0c4c4..f37d4a9 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -21,6 +21,7 @@ PRIVATE
SmallVector.cpp
Sprite.cpp
Texture.cpp
+ Uid.cpp
World.cpp
)
diff --git a/source/EditorCore.cpp b/source/EditorCore.cpp
index ec500e0..11eea8a 100644
--- a/source/EditorCore.cpp
+++ b/source/EditorCore.cpp
@@ -248,7 +248,7 @@ void EditorContentBrowser::Show(bool* open) {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, { 0, 0 });
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0);
ImGui::SetKeyboardFocusHere();
- if (ImGui::InputText("##Rename", &mInspector->renamingScratchBuffer, ImGuiInputTextFlags_EnterReturnsTrue)) {
+ if (ImGui::InputText("##Rename", &mInspector->renamingScratchBuffer, ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue)) {
// Confirm
ires->SetName(std::move(mInspector->renamingScratchBuffer));
mInspector->renaming = false;
diff --git a/source/Ires.cpp b/source/Ires.cpp
index 255c221..dde4ace 100644
--- a/source/Ires.cpp
+++ b/source/Ires.cpp
@@ -63,11 +63,19 @@ void IresObject::SetName(std::string name) {
}
void IresObject::ShowEditor(EditorInstance& editor) {
+ ImGui::Text("%s", ToString(mKind).data());
+
bool isAnnoymous = mName.empty();
if (isAnnoymous) {
- ImGui::Text("<Annoymous Ires at %p>", (void*)this);
+ ImGui::Text("Name: <annoymous: %p>", (void*)this);
+ } else {
+ ImGui::Text("Name: %s", mName.c_str());
+ }
+
+ if (mUid.IsNull()) {
+ ImGui::TextUnformatted("Uid: <none>");
} else {
- ImGui::Text("%s", mName.c_str());
+ ImGui::Text("Uid: %lx-%lx", mUid.upper, mUid.lower);
}
}
@@ -76,6 +84,7 @@ void IresObject::WriteFull(IresObject* ires, rapidjson::Value& value, rapidjson:
ires->Write(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());
}
@@ -86,6 +95,10 @@ std::unique_ptr<IresObject> IresObject::ReadFull(const rapidjson::Value& value)
auto ires = Create(kind);
if (!ires) return nullptr;
+ auto rvUid = rapidjson::GetProperty(value, rapidjson::kArrayType, "Uid"sv);
+ if (!rvUid) return nullptr;
+ ires->mUid.Read(*rvUid);
+
if (!ReadPartial(ires.get(), value)) {
return nullptr;
}
@@ -100,6 +113,12 @@ bool IresObject::ReadPartial(IresObject* ires, const rapidjson::Value& value) {
return true;
}
+void IresObject::Write(rapidjson::Value& value, rapidjson::Document& root) const {
+}
+
+void IresObject::Read(const rapidjson::Value& value) {
+}
+
void IresManager::DiscoverFilesDesignatedLocation() {
auto path = AppConfig::assetDirPath / "Ires";
DiscoverFiles(path);
@@ -116,39 +135,7 @@ void IresManager::DiscoverFiles(const fs::path& dir) {
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
- ires->mName = std::move(iden);
- std::string_view key(ires->mName);
- mObjects.try_emplace(key, ires.release());
+ Load(item.path());
}
}
@@ -162,21 +149,73 @@ std::pair<IresObject*, bool> IresManager::Add(IresObject* ires) {
snprintf(name.data(), size, "Unnamed %s #%d", IresObject::ToString(ires->GetKind()).data(), n);
}
- auto [iter, inserted] = mObjects.try_emplace(name, ires);
+ auto& uid = ires->mUid;
+ if (uid.IsNull()) {
+ uid = Uid::Create();
+ }
+
+ auto [iter, inserted] = mObjByUid.try_emplace(uid, ires);
if (inserted) {
ires->mMan = this;
+ // TODO handle full path
return { ires, true };
} else {
return { iter->second.Get(), false };
}
}
+IresObject* IresManager::Load(const fs::path& filePath) {
+ auto file = Utils::OpenCstdioFile(filePath, Utils::Read);
+ if (!file) return nullptr;
+ 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) {
+ return nullptr;
+ }
+
+ // Load uid should be handled by IresObject::ReadFull
+ assert(!ires->mUid.IsNull());
+ // Load name from filename
+ 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();
+}
+
void IresManager::Delete(IresObject* ires) {
// TODO
}
bool IresManager::Rename(IresObject* ires, std::string newName) {
- if (mObjects.contains(newName)) {
+ ires->mName = std::move(newName);
+
+ // TODO validate no name duplication
+#if 0
+ if (mObjByPath.contains(newName)) {
return false;
}
@@ -184,20 +223,16 @@ bool IresManager::Rename(IresObject* ires, std::string newName) {
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());
+ mObjByPath.erase(ires->GetName());
// Add new entry
ires->mName = std::move(newName);
- mObjects.try_emplace(ires->GetName(), ires);
-
+ // TODO handle full path
+ mObjByPath.try_emplace(ires->GetName(), ires);
+#endif
return true;
}
-IresObject* IresManager::Load(const fs::path& path) {
- // TODO
- return nullptr;
-}
-
static fs::path GetDesignatedPath(IresObject* ires) {
return AppConfig::assetDirPath / "Ires" / fs::path(ires->GetName()).replace_extension(".json");
}
@@ -235,9 +270,9 @@ void IresManager::Save(IresObject* ires, const fs::path& filePath) {
root.Accept(writer);
}
-IresObject* IresManager::FindIres(std::string_view path) {
- auto iter = mObjects.find(path);
- if (iter != mObjects.end()) {
+IresObject* IresManager::FindIres(const Uid& uid) {
+ auto iter = mObjByUid.find(uid);
+ if (iter != mObjByUid.end()) {
return iter->second.Get();
} else {
return nullptr;
diff --git a/source/Ires.hpp b/source/Ires.hpp
index 9b055af..f821d87 100644
--- a/source/Ires.hpp
+++ b/source/Ires.hpp
@@ -2,6 +2,7 @@
#include "EditorAttachment.hpp"
#include "RcPtr.hpp"
+#include "Uid.hpp"
#include "Utils.hpp"
#include <rapidjson/fwd.h>
@@ -26,10 +27,11 @@ public:
};
private:
- std::string mName;
- std::unique_ptr<EditorAttachment> mEditorAttachment;
- IresManager* mMan = nullptr;
- Kind mKind;
+ std::string mName; // Serialized as filename
+ Uid mUid; // Serialized in full mode
+ std::unique_ptr<EditorAttachment> mEditorAttachment; // Transient
+ IresManager* mMan = nullptr; // Transient
+ Kind mKind; // Serialized in full mode
public:
IresObject(Kind kind);
@@ -44,6 +46,7 @@ public:
bool IsAnnoymous() const;
const std::string& GetName() const { return mName; }
void SetName(std::string name);
+ const Uid& GetUid() const { return mUid; }
virtual void ShowEditor(EditorInstance& editor);
@@ -53,8 +56,8 @@ public:
static void WriteFull(IresObject* ires, rapidjson::Value& value, rapidjson::Document& root);
static std::unique_ptr<IresObject> ReadFull(const rapidjson::Value& value);
static bool ReadPartial(IresObject* ires, const rapidjson::Value& value);
- virtual void Write(rapidjson::Value& value, rapidjson::Document& root) const = 0;
- virtual void Read(const rapidjson::Value& value) = 0;
+ virtual void Write(rapidjson::Value& value, rapidjson::Document& root) const;
+ virtual void Read(const rapidjson::Value& value);
};
class IresManager {
@@ -62,21 +65,21 @@ public:
static inline IresManager* instance = nullptr;
private:
- robin_hood::unordered_map<std::string_view, RcPtr<IresObject>> mObjects;
+ robin_hood::unordered_map<Uid, RcPtr<IresObject>> mObjByUid;
public:
void DiscoverFilesDesignatedLocation();
void DiscoverFiles(const std::filesystem::path& dir);
std::pair<IresObject*, bool> Add(IresObject* mat);
+ IresObject* Load(const std::filesystem::path& filePath);
void Delete(IresObject* ires);
bool Rename(IresObject* ires, std::string newName);
- IresObject* Load(const std::filesystem::path& path);
void Reload(IresObject* ires);
void Save(IresObject* ires);
void Save(IresObject* ires, const std::filesystem::path& filePath);
- const auto& GetObjects() const { return mObjects; }
- IresObject* FindIres(std::string_view path);
+ const auto& GetObjects() const { return mObjByUid; }
+ IresObject* FindIres(const Uid& uid);
};
diff --git a/source/Sprite.cpp b/source/Sprite.cpp
index 6cd575e..d539452 100644
--- a/source/Sprite.cpp
+++ b/source/Sprite.cpp
@@ -70,12 +70,15 @@ void IresSpriteFiles::InvalidateInstance() {
}
void IresSpriteFiles::Write(rapidjson::Value& value, rapidjson::Document& root) const {
+ IresObject::Write(value, root);
value.AddMember("Sprites", rapidjson::WriteVectorPrimitives(root, spriteFiles.begin(), spriteFiles.end()), root.GetAllocator());
}
void IresSpriteFiles::Read(const rapidjson::Value& value) {
InvalidateInstance();
+ IresObject::Read(value);
+
auto rvFileList = rapidjson::GetProperty(value, rapidjson::kArrayType, "Sprites"sv);
if (!rvFileList) return;
spriteFiles.clear();
@@ -259,6 +262,7 @@ void IresSpritesheet::ShowEditor(EditorInstance& editor) {
}
void IresSpritesheet::Write(rapidjson::Value& value, rapidjson::Document& root) const {
+ IresObject::Write(value, root);
value.AddMember("SpriteSheet", spritesheetFile, root.GetAllocator());
value.AddMember("WSplit", sheetWSplit, root.GetAllocator());
value.AddMember("HSplit", sheetHSplit, root.GetAllocator());
@@ -269,6 +273,8 @@ void IresSpritesheet::Write(rapidjson::Value& value, rapidjson::Document& root)
void IresSpritesheet::Read(const rapidjson::Value& value) {
InvalidateInstance();
+
+ IresObject::Read(value);
BRUSSEL_JSON_GET(value, "SpriteSheet", std::string, spritesheetFile, return );
BRUSSEL_JSON_GET(value, "WSplit", int, sheetWSplit, return );
BRUSSEL_JSON_GET(value, "HSplit", int, sheetHSplit, return );
diff --git a/source/Uid.cpp b/source/Uid.cpp
new file mode 100644
index 0000000..2520d1e
--- /dev/null
+++ b/source/Uid.cpp
@@ -0,0 +1,47 @@
+#include "Uid.hpp"
+
+#include "RapidJsonHelper.hpp"
+
+#include <rapidjson/document.h>
+#include <random>
+
+Uid Uid::Create() {
+ std::random_device rd;
+ std::mt19937_64 gen(rd());
+ std::uniform_int_distribution<uint64_t> dist(
+ std::numeric_limits<uint64_t>::min(),
+ std::numeric_limits<uint64_t>::max());
+
+ Uid uid;
+ uid.upper = dist(gen);
+ uid.lower = dist(gen);
+ return uid;
+}
+
+bool Uid::IsNull() const {
+ return upper == 0 && lower == 0;
+}
+
+void Uid::Read(const rapidjson::Value& value) {
+ assert(value.IsArray());
+ assert(value.Size() == 2);
+ auto& upper = value[0];
+ assert(upper.IsUint64());
+ auto& lower = value[1];
+ assert(lower.IsUint64());
+
+ this->upper = upper.GetUint64();
+ this->lower = lower.GetUint64();
+}
+
+void Uid::WriteInto(rapidjson::Value& value, rapidjson::Document& root) {
+ value.Reserve(2, root.GetAllocator());
+ value.PushBack((uint64_t)upper, root.GetAllocator());
+ value.PushBack((uint64_t)lower, root.GetAllocator());
+}
+
+rapidjson::Value Uid::Write(rapidjson::Document& root) {
+ rapidjson::Value result(rapidjson::kArrayType);
+ WriteInto(result, root);
+ return result;
+}
diff --git a/source/Uid.hpp b/source/Uid.hpp
new file mode 100644
index 0000000..a076533
--- /dev/null
+++ b/source/Uid.hpp
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "Utils.hpp"
+
+#include <rapidjson/fwd.h>
+#include <cstdint>
+#include <functional>
+
+struct Uid {
+ uint64_t upper = 0;
+ uint64_t lower = 0;
+
+ static Uid Create();
+
+ bool IsNull() const;
+
+ void Read(const rapidjson::Value& value);
+ void WriteInto(rapidjson::Value& value, rapidjson::Document& root);
+ rapidjson::Value Write(rapidjson::Document& root);
+
+ auto operator<=>(const Uid&) const = default;
+};
+
+template <>
+struct std::hash<Uid> {
+ size_t operator()(const Uid& uid) const {
+ size_t hash = 0;
+ Utils::HashCombine(hash, uid.upper);
+ Utils::HashCombine(hash, uid.lower);
+ return hash;
+ }
+};
diff --git a/source/Utils.hpp b/source/Utils.hpp
index 6239667..63e610f 100644
--- a/source/Utils.hpp
+++ b/source/Utils.hpp
@@ -23,8 +23,14 @@ constexpr float Abs(float v) noexcept {
bool InRangeInclusive(int n, int lower, int upper);
bool LineContains(glm::ivec2 p1, glm::ivec2 p2, glm::ivec2 candidate);
+
bool IsColinear(glm::ivec2 p1, glm::ivec2 p2);
+template <class T>
+void HashCombine(std::size_t& seed, const T& v) {
+ seed ^= std::hash<T>{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+}
+
} // namespace Utils
struct StringHash {