aboutsummaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2022-06-03 22:58:28 -0700
committerrtk0c <[email protected]>2022-06-03 22:58:28 -0700
commit8510a85f79f706b93982b4e398b187b5f77081dd (patch)
tree996c27f54f748d940f58454f7ef1e1570d1a31d5 /source
parentbd07ae3f4e1bcdedc3e373460671ca9713a03de5 (diff)
Changeset: 61 [BUGGED] Move object kind enums to use generated ToString and FromStrong
The old mechanism rely on a specific prefix to Ires and GameObject string representations, but the generator currently leaves the enum value. Therefore all editor (e.g. drag & drop) and IO (e.g. ires loading) mechanisms are broken.
Diffstat (limited to 'source')
-rw-r--r--source/10-common/LookupTable.hpp78
-rw-r--r--source/20-codegen-compiler/CodegenUtils.cpp4
-rw-r--r--source/20-codegen-compiler/main.cpp34
-rw-r--r--source/20-codegen-compiler/test/examples/TestEnum.hpp.txt5
-rw-r--r--source/30-game/EditorAttachmentImpl.cpp4
-rw-r--r--source/30-game/EditorCorePrivate.cpp27
-rw-r--r--source/30-game/GameObject.cpp44
-rw-r--r--source/30-game/GameObject.hpp30
-rw-r--r--source/30-game/Ires.cpp48
-rw-r--r--source/30-game/Ires.hpp34
-rw-r--r--source/30-game/Level.cpp65
-rw-r--r--source/30-game/Level.hpp27
-rw-r--r--source/30-game/Material.cpp10
13 files changed, 256 insertions, 154 deletions
diff --git a/source/10-common/LookupTable.hpp b/source/10-common/LookupTable.hpp
index 360cc2b..54548f2 100644
--- a/source/10-common/LookupTable.hpp
+++ b/source/10-common/LookupTable.hpp
@@ -5,60 +5,60 @@
// BIDI stands for bi-directional
#define BIDI_LUT_DECL(name, aType, aCount, bType, bCount) \
- int gLut_##name##_A2B[aCount]; \
- int gLut_##name##_B2A[bCount]; \
+ int gLutBidi_##name##_A2B[aCount]; \
+ int gLutBidi_##name##_B2A[bCount]; \
using name##AType = aType; \
using name##BType = bType; \
- void InitializeLut##name()
-#define BIDI_LUT_MAP_FOR(name) \
- int* lutMappingA2B = gLut_##name##_A2B; \
- int* lutMappingB2A = gLut_##name##_B2A
+ void InitializeLutBidi##name()
+#define BIDI_LUT_MAP_FOR(name) \
+ int* lutMappingA2B = gLutBidi_##name##_A2B; \
+ int* lutMappingB2A = gLutBidi_##name##_B2A
#define BIDI_LUT_MAP(from, to) \
lutMappingA2B[from] = to; \
lutMappingB2A[to] = from
-#define BIDI_LUT_INIT(name) InitializeLut##name()
-#define BIDI_LUT_A2B_LOOKUP(name, from) (name##BType)(gLut_##name##_A2B[from])
-#define BIDI_LUT_B2A_LOOKUP(name, to) (name##AType)(gLut_##name##_B2A[to])
+#define BIDI_LUT_INIT(name) InitializeLutBidi##name()
+#define BIDI_LUT_A2B_LOOKUP(name, from) (name##BType)(gLutBidi_##name##_A2B[from])
+#define BIDI_LUT_B2A_LOOKUP(name, to) (name##AType)(gLutBidi_##name##_B2A[to])
// Forward string lookup
-#define FSTR_LUT_DECL(name, enumMinValue, enumMaxValue) \
- constexpr int kLutMinVal_##name = enumMinValue; \
- const char* gLut_##name[(int)enumMaxValue - (int)enumMinValue]; \
- void InitializeLut##name()
-#define FSTR_LUT_MAP_FOR(name) \
- const char** lutMapping = gLut_##name; \
- int lutMappingMinValue = kLutMinVal_##name
+#define FSTR_LUT_DECL(name, enumMinValue, enumMaxValue) \
+ constexpr int kLutFwMinVal_##name = enumMinValue; \
+ const char* gLutFw_##name[(int)enumMaxValue - (int)enumMinValue]; \
+ void InitializeLutFw##name()
+#define FSTR_LUT_MAP_FOR(name) \
+ const char** lutMapping = gLutFw_##name; \
+ int lutMappingMinValue = kLutFwMinVal_##name
#define FSTR_LUT_MAP(value, text) lutMapping[value - lutMappingMinValue] = text
#define FSTR_LUT_MAP_ENUM(enumValue) FSTR_LUT_MAP(enumValue, #enumValue)
-#define FSTR_LUT_LOOKUP(name, enumValue) gLut_##name[enumValue - kLutMinVal_##name]
-#define FSTR_LUT_INIT(name) InitializeLut##name()
+#define FSTR_LUT_LOOKUP(name, enumValue) gLutFw_##name[enumValue - kLutFwMinVal_##name]
+#define FSTR_LUT_INIT(name) InitializeLutFw##name()
// RSTR stands for reverse-string lookup
-#define RSTR_LUT_DECL(name, enumMinValue, enumMaxValue) \
- robin_hood::unordered_flat_map<std::string_view, decltype(enumMaxValue)> gLut_##name; \
- void InitializeLut##name()
-#define RSTR_LUT_MAP_FOR(name) auto& lutMapping = gLut_##name;
+#define RSTR_LUT_DECL(name, enumMinValue, enumMaxValue) \
+ robin_hood::unordered_flat_map<std::string_view, decltype(enumMaxValue)> gLutRv_##name; \
+ void InitializeLutRv##name()
+#define RSTR_LUT_MAP_FOR(name) auto& lutMapping = gLutRv_##name;
#define RSTR_LUT_MAP(value, text) lutMapping.insert_or_assign(std::string_view(text), value);
-#define RSTR_LUT(name) gLut_##name
-#define BSTR_LUT_LOOKUP(name, string) gLut_##name.find(std::string_view(text))->second
-#define RSTR_LUT_INIT(name) InitializeLut##name()
+#define RSTR_LUT(name) gLutRv_##name
+#define BSTR_LUT_LOOKUP(name, string) gLutRv_##name.find(std::string_view(text))->second
+#define RSTR_LUT_INIT(name) InitializeLutRv##name()
// BSTR stands for bi-directional string lookup
-#define BSTR_LUT_DECL(name, enumMinValue, enumMaxValue) \
- constexpr int kLutMinVal_##name = enumMinValue; \
- const char* gLut_##name##_V2S[(int)enumMaxValue - (int)enumMinValue]; \
- robin_hood::unordered_flat_map<std::string_view, decltype(enumMaxValue)> gLut_##name##_S2V; \
- void InitializeLut##name()
-#define BSTR_LUT_MAP_FOR(name) \
- const char** lutMappingV2S = gLut_##name##_V2S; \
- auto& lutMappingS2V = gLut_##name##_S2V; \
- int lutMappingMinValue = kLutMinVal_##name
+#define BSTR_LUT_DECL(name, enumMinValue, enumMaxValue) \
+ constexpr int kLutBstrMinVal_##name = enumMinValue; \
+ const char* gLutBstr_##name##_V2S[(int)enumMaxValue - (int)enumMinValue]; \
+ robin_hood::unordered_flat_map<std::string_view, decltype(enumMaxValue)> gLutBstr_##name##_S2V; \
+ void InitializeLutBstr##name()
+#define BSTR_LUT_MAP_FOR(name) \
+ const char** lutMappingV2S = gLutBstr_##name##_V2S; \
+ auto& lutMappingS2V = gLutBstr_##name##_S2V; \
+ int lutMappingMinValue = kLutBstrMinVal_##name
#define BSTR_LUT_MAP(value, text) \
lutMappingV2S[value - lutMappingMinValue] = text; \
lutMappingS2V.insert_or_assign(std::string_view(text), value);
#define BSTR_LUT_MAP_ENUM(enumValue) BSTR_LUT_MAP(enumValue, #enumValue)
-#define BSTR_LUT_V2S(name) gLut_##name##_V2S
-#define BSTR_LUT_S2V(name) gLut_##name##_S2V
-#define BSTR_LUT_V2S_LOOKUP(name, enumValue) gLut_##name##_V2S[enumValue - kLutMinVal_##name]
-#define BSTR_LUT_S2V_LOOKUP(name, string) gLut_##name##_S2V.find(std::string_view(text))->second
-#define BSTR_LUT_INIT(name) InitializeLut##name()
+#define BSTR_LUT_V2S(name) gLutBstr_##name##_V2S
+#define BSTR_LUT_S2V(name) gLutBstr_##name##_S2V
+#define BSTR_LUT_V2S_LOOKUP(name, enumValue) gLutBstr_##name##_V2S[enumValue - kLutBstrMinVal_##name]
+#define BSTR_LUT_S2V_LOOKUP(name, string) gLutBstr_##name##_S2V.find(std::string_view(text))->second
+#define BSTR_LUT_INIT(name) InitializeLutBstr##name()
diff --git a/source/20-codegen-compiler/CodegenUtils.cpp b/source/20-codegen-compiler/CodegenUtils.cpp
index a43b72c..0c70cb6 100644
--- a/source/20-codegen-compiler/CodegenUtils.cpp
+++ b/source/20-codegen-compiler/CodegenUtils.cpp
@@ -120,10 +120,7 @@ void Utils::ProduceGeneratedHeader(const char* headerFilename, CodegenOutput& he
headerOut.text += &R"""(
// This file is generated. Any changes will be overidden when building.
#pragma once
-
#include <MetadataBase.hpp>
-#include <MetadataDetails.hpp>
-
#include <cstddef>
#include <cstdint>
)"""[1];
@@ -132,6 +129,7 @@ void Utils::ProduceGeneratedHeader(const char* headerFilename, CodegenOutput& he
APPEND_LIT_LN(sourceOut.text, "// This file is generated. Any changes will be overidden when building.");
APPEND_FMT_LN(sourceOut.text, "#include \"%s\"", headerFilename);
sourceOut.text += &R"""(
+#include <MetadataDetails.hpp>
#include <frozen/string.h>
#include <frozen/unordered_map.h>
using namespace std::literals;
diff --git a/source/20-codegen-compiler/main.cpp b/source/20-codegen-compiler/main.cpp
index bb7c996..5e052a3 100644
--- a/source/20-codegen-compiler/main.cpp
+++ b/source/20-codegen-compiler/main.cpp
@@ -66,6 +66,18 @@ FSTR_LUT_DECL(ClexNames, CLEX_eof, CLEX_ext_COUNT) {
FSTR_LUT_MAP_ENUM(CLEX_ext_dot_dot_dot);
}
+FSTR_LUT_DECL(EnumUnderlyingType, 0, EUT_COUNT) {
+ FSTR_LUT_MAP_FOR(EnumUnderlyingType);
+ FSTR_LUT_MAP(EUT_Int8, "int8_t");
+ FSTR_LUT_MAP(EUT_Int16, "int16_t");
+ FSTR_LUT_MAP(EUT_Int32, "int32_t");
+ FSTR_LUT_MAP(EUT_Int64, "int64_t");
+ FSTR_LUT_MAP(EUT_Uint8, "uint8_t");
+ FSTR_LUT_MAP(EUT_Uint16, "uint16_t");
+ FSTR_LUT_MAP(EUT_Uint32, "uint32_t");
+ FSTR_LUT_MAP(EUT_Uint64, "uint64_t");
+}
+
RSTR_LUT_DECL(EnumUnderlyingType, 0, EUT_COUNT) {
RSTR_LUT_MAP_FOR(EnumUnderlyingType);
@@ -352,16 +364,25 @@ void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const D
int minVal = filteredElements.empty() ? 0 : filteredElements.front().value;
int maxVal = filteredElements.empty() ? 0 : filteredElements.back().value;
+ CodegenOutputThing lookupFunctionDecl;
+ {
+ auto& o = lookupFunctionDecl.text;
+ APPEND_LIT_LN(o, "template <>");
+ APPEND_FMT_LN(o, "std::string_view Metadata::EnumToString<%s>(%s value);", enumName, enumName);
+ }
+
CodegenOutputThing lookupFunctionDef;
{
auto& o = lookupFunctionDef.text;
APPEND_LIT_LN(o, "template <>");
APPEND_FMT_LN(o, "std::string_view Metadata::EnumToString<%s>(%s value) {", enumName, enumName);
- APPEND_FMT_LN(o, " if (value < %d || value > %d) return {};", minVal, maxVal);
- APPEND_FMT_LN(o, " return %s[value - %d];", val2StrName, minVal);
+ APPEND_FMT_LN(o, " auto intVal = (%s)value;", FSTR_LUT_LOOKUP(EnumUnderlyingType, decl.underlyingType));
+ APPEND_FMT_LN(o, " if (intVal < %d || intVal > %d) return {};", minVal, maxVal);
+ APPEND_FMT_LN(o, " return %s[intVal - %d];", val2StrName, minVal);
APPEND_LIT_LN(o, "}");
}
+ headerOut.AddOutputThing(std::move(lookupFunctionDecl));
sourceOut.AddOutputThing(std::move(lookupFunctionDef));
} break;
@@ -395,6 +416,13 @@ void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const D
}
// Generate lookup function
+ CodegenOutputThing lookupFunctionDecl;
+ {
+ auto& o = lookupFunctionDecl.text;
+ APPEND_LIT_LN(o, "template <>");
+ APPEND_FMT_LN(o, "std::optional<%s> Metadata::EnumFromString<%s>(std::string_view value);", enumName, enumName);
+ }
+
CodegenOutputThing lookupFunctionDef;
{
auto& o = lookupFunctionDef.text;
@@ -410,6 +438,7 @@ void GenerateForEnum(CodegenOutput& headerOut, CodegenOutput& sourceOut, const D
}
sourceOut.AddOutputThing(std::move(lookupTable));
+ headerOut.AddOutputThing(std::move(lookupFunctionDecl));
sourceOut.AddOutputThing(std::move(lookupFunctionDef));
}
}
@@ -1032,6 +1061,7 @@ InputOpcode ParseInputOpcode(std::string_view text) {
int main(int argc, char* argv[]) {
FSTR_LUT_INIT(ClexNames);
+ FSTR_LUT_INIT(EnumUnderlyingType);
RSTR_LUT_INIT(EnumUnderlyingType);
FSTR_LUT_INIT(EnumValuePattern);
RSTR_LUT_INIT(CppKeyword);
diff --git a/source/20-codegen-compiler/test/examples/TestEnum.hpp.txt b/source/20-codegen-compiler/test/examples/TestEnum.hpp.txt
index 441d97c..30c36c0 100644
--- a/source/20-codegen-compiler/test/examples/TestEnum.hpp.txt
+++ b/source/20-codegen-compiler/test/examples/TestEnum.hpp.txt
@@ -5,7 +5,8 @@ enum MyEnum {
};
BRUSSEL_ENUM(MyEnum, ToString FromString);
-enum CountedEnumAll {
+// Let's also test enum class
+enum class CountedEnumAll {
CEA_Foo,
CEA_Bar,
CEA_COUNT,
@@ -21,7 +22,7 @@ enum CountedEnum {
BRUSSEL_ENUM(CountedEnum, ToString FromString ExcludeHeuristics);
namespace MyNamespace {
-enum MyNamespacedEnum {
+enum class MyNamespacedEnum {
MNE_Foo,
MNE_Bar,
};
diff --git a/source/30-game/EditorAttachmentImpl.cpp b/source/30-game/EditorAttachmentImpl.cpp
index 62d15eb..b09c133 100644
--- a/source/30-game/EditorAttachmentImpl.cpp
+++ b/source/30-game/EditorAttachmentImpl.cpp
@@ -1,6 +1,8 @@
#include "EditorAttachmentImpl.hpp"
#include "EditorAttachment.hpp"
+#include <Metadata.hpp>
+
EditorAttachment::EditorAttachment() {
}
@@ -15,7 +17,7 @@ std::unique_ptr<EditorAttachment> EaGameObject::Create(GameObject* object) {
default: result = new EaGameObject(); break;
}
- result->name = GameObject::ToString(kind);
+ result->name = Metadata::EnumToString(kind);
result->eulerAnglesRotation = glm::eulerAngles(object->GetRotation());
return std::unique_ptr<EditorAttachment>(result);
}
diff --git a/source/30-game/EditorCorePrivate.cpp b/source/30-game/EditorCorePrivate.cpp
index 9fd6087..43857a8 100644
--- a/source/30-game/EditorCorePrivate.cpp
+++ b/source/30-game/EditorCorePrivate.cpp
@@ -8,13 +8,15 @@
#include "EditorNotification.hpp"
#include "EditorUtils.hpp"
#include "GameObject.hpp"
-#include "Macros.hpp"
#include "Mesh.hpp"
#include "Player.hpp"
#include "SceneThings.hpp"
-#include "ScopeGuard.hpp"
#include "VertexIndex.hpp"
-#include "YCombinator.hpp"
+
+#include <Macros.hpp>
+#include <Metadata.hpp>
+#include <ScopeGuard.hpp>
+#include <YCombinator.hpp>
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
@@ -146,9 +148,9 @@ void EditorContentBrowser::Show(bool* open) {
ImGui::OpenPopup("New Ires");
}
if (ImGui::BeginPopup("New Ires")) {
- for (int i = 0; i < IresObject::KD_COUNT; ++i) {
+ for (int i = 0; i < (int)IresObject::KD_COUNT; ++i) {
auto kind = static_cast<IresObject::Kind>(i);
- if (ImGui::MenuItem(IresObject::ToString(kind).data())) {
+ if (ImGui::MenuItem(Metadata::EnumToString(kind).data())) {
auto ires = IresObject::Create(kind);
auto [DISCARD, success] = IresManager::instance->Add(ires.get());
if (success) {
@@ -228,7 +230,7 @@ void EditorContentBrowser::Show(bool* open) {
}
if (!mInspector->renaming) {
if (ImGui::BeginDragDropSource()) {
- auto kindName = IresObject::ToString(ires->GetKind());
+ auto kindName = Metadata::EnumToString(ires->GetKind());
// Reason: intentionally using pointer as payload
ImGui::SetDragDropPayload(kindName.data(), &ires, sizeof(ires)); // NOLINT(bugprone-sizeof-expression)
ImGui::Text("%s '%s'", kindName.data(), name.c_str());
@@ -249,6 +251,11 @@ void EditorContentBrowser::Show(bool* open) {
mInspector->renamingScratchBuffer = ldObj.name;
}
+ if (ImGui::Button("Save", !isIttLevel)) {
+ auto ldObj = static_cast<LevelManager::LoadableObject*>(origItPtr);
+ LevelManager::instance->SaveLevel(ldObj->level->GetUid());
+ }
+
auto& objects = LevelManager::instance->mObjByUid;
for (auto it = objects.begin(); it != objects.end(); ++it) {
auto& uid = it->first;
@@ -779,7 +786,9 @@ void EditorInstance::ShowInspector(LevelManager::LoadableObject* ldObj) {
ImGui::InputText("Name", &ldObj->name);
ImGui::InputTextMultiline("Desciption", &ldObj->description);
- // TODO level object explorer
+ if (ImGui::CollapsingHeader("Instanciation Entries")) {
+ ldObj->level->ShowInstanciationEntries(*this);
+ }
}
void EditorInstance::ShowInspector(GameObject* object) {
@@ -915,7 +924,7 @@ void EditorInstance::ShowInspector(GameObject* object) {
ImGui::SameLine();
IresObject::ShowReferenceSafe(*this, ea->confSprite.Get());
if (ImGui::BeginDragDropTarget()) {
- if (auto payload = ImGui::AcceptDragDropPayload(IresObject::ToString(IresObject::KD_Spritesheet).data())) {
+ if (auto payload = ImGui::AcceptDragDropPayload(Metadata::EnumToString(IresObject::KD_Spritesheet).data())) {
auto spritesheet = *static_cast<IresSpritesheet* const*>(payload->Data);
ea->confSprite.Attach(spritesheet);
auto def = spritesheet->GetInstance();
@@ -929,7 +938,7 @@ void EditorInstance::ShowInspector(GameObject* object) {
ImGui::SameLine();
IresObject::ShowReferenceSafe(*this, ea->confMaterial.Get());
if (ImGui::BeginDragDropTarget()) {
- if (auto payload = ImGui::AcceptDragDropPayload(IresObject::ToString(IresObject::KD_Material).data())) {
+ if (auto payload = ImGui::AcceptDragDropPayload(Metadata::EnumToString(IresObject::KD_Material).data())) {
auto material = *static_cast<IresMaterial* const*>(payload->Data);
ea->confMaterial.Attach(material);
player->SetMaterial(material->GetInstance());
diff --git a/source/30-game/GameObject.cpp b/source/30-game/GameObject.cpp
index 8bb3ec7..3b15111 100644
--- a/source/30-game/GameObject.cpp
+++ b/source/30-game/GameObject.cpp
@@ -2,11 +2,14 @@
#include "Level.hpp"
#include "Player.hpp"
-#include "RapidJsonHelper.hpp"
#include "SceneThings.hpp"
#include "World.hpp"
+#include <Metadata.hpp>
+#include <RapidJsonHelper.hpp>
+
#include <rapidjson/document.h>
+#include <cassert>
#include <string_view>
#include <utility>
@@ -14,11 +17,12 @@ using namespace std::literals;
namespace ProjectBrussel_UNITY_ID {
GameObject* CreateGameObject(GameObject::Kind kind, GameWorld* world) {
+ using enum Tags::GameObjectKind;
switch (kind) {
- case GameObject::KD_Generic: return new GameObject(world);
- case GameObject::KD_SimpleGeometry: return new SimpleGeometryObject(world);
- case GameObject::KD_Building: return new BuildingObject(world);
- case GameObject::KD_LevelWrapper: return new LevelWrapperObject(world);
+ case KD_Generic: return new GameObject(world);
+ case KD_SimpleGeometry: return new SimpleGeometryObject(world);
+ case KD_Building: return new BuildingObject(world);
+ case KD_LevelWrapper: return new LevelWrapperObject(world);
default: break;
}
return nullptr;
@@ -60,27 +64,6 @@ GameObject::~GameObject() {
}
}
-std::string_view GameObject::ToString(Kind kind) {
- switch (kind) {
- case KD_Generic: return "GameObject"sv;
- case KD_Player: return "Player"sv;
- case KD_SimpleGeometry: return "SimpleGeometry"sv;
- case KD_Building: return "Building"sv;
- case KD_LevelWrapper: return "LevelWrapper"sv;
- case KD_COUNT: break;
- }
- return std::string_view();
-}
-
-GameObject::Kind GameObject::FromString(std::string_view name) {
- if (name == "GameObject"sv) return KD_Generic;
- if (name == "Player"sv) return KD_Player;
- if (name == "SimpleGeometry"sv) return KD_SimpleGeometry;
- if (name == "Building"sv) return KD_Building;
- if (name == "LevelWrapper"sv) return KD_LevelWrapper;
- return KD_COUNT;
-}
-
GameObject::Kind GameObject::GetKind() const {
return mKind;
}
@@ -204,7 +187,7 @@ void GameObject::Update() {
rapidjson::Value GameObject::Serialize(GameObject* obj, rapidjson::Document& root) {
rapidjson::Value result(rapidjson::kObjectType);
- result.AddMember("Type", rapidjson::StringRef(ToString(obj->GetKind())), root.GetAllocator());
+ result.AddMember("Type", rapidjson::StringRef(Metadata::EnumToString(obj->GetKind())), root.GetAllocator());
rapidjson::Value rvValue(rapidjson::kObjectType);
obj->WriteSaveFormat(rvValue, root);
@@ -222,8 +205,9 @@ std::unique_ptr<GameObject> GameObject::Deserialize(const rapidjson::Value& valu
auto rvValue = rapidjson::GetProperty(value, rapidjson::kObjectType, "Value"sv);
if (!rvValue) return nullptr;
- auto kind = FromString(rapidjson::AsStringView(*rvType));
- auto obj = std::unique_ptr<GameObject>(CreateGameObject(kind, world));
+ auto kind = Metadata::EnumFromString<Kind>(rapidjson::AsStringView(*rvType));
+ assert(kind.has_value());
+ auto obj = std::unique_ptr<GameObject>(CreateGameObject(kind.value(), world));
if (!obj) return nullptr;
obj->ReadSaveFormat(*rvValue);
@@ -242,3 +226,5 @@ void GameObject::SetParent(GameObject* parent) {
// needUpdate();
}
}
+
+#include <generated/GameObject.gs.inl>
diff --git a/source/30-game/GameObject.hpp b/source/30-game/GameObject.hpp
index 77488b9..f975803 100644
--- a/source/30-game/GameObject.hpp
+++ b/source/30-game/GameObject.hpp
@@ -2,27 +2,35 @@
#include "EditorAttachment.hpp"
#include "Material.hpp"
-#include "PodVector.hpp"
#include "Renderer.hpp"
#include "VertexIndex.hpp"
+#include <MacrosCodegen.hpp>
+#include <PodVector.hpp>
+
#include <rapidjson/fwd.h>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include <span>
#include <vector>
+namespace Tags {
+enum class GameObjectKind {
+ KD_Generic,
+ KD_Player,
+ KD_SimpleGeometry,
+ KD_Building,
+ KD_LevelWrapper,
+ KD_COUNT,
+};
+BRUSSEL_ENUM(GameObjectKind, ToString FromString ExcludeHeuristics);
+} // namespace Tags
+
class GameWorld;
class GameObject {
public:
- enum Kind {
- KD_Generic,
- KD_Player,
- KD_SimpleGeometry,
- KD_Building,
- KD_LevelWrapper,
- KD_COUNT,
- };
+ using Kind = Tags::GameObjectKind;
+ using enum Tags::GameObjectKind;
private:
std::unique_ptr<EditorAttachment> mEditorAttachment;
@@ -50,8 +58,6 @@ public:
GameObject(GameObject&&) = default;
GameObject& operator=(GameObject&&) = default;
- static std::string_view ToString(Kind kind);
- static Kind FromString(std::string_view name);
Kind GetKind() const;
GameWorld* GetWorld() const;
@@ -92,3 +98,5 @@ public:
protected:
void SetParent(GameObject* parent);
};
+
+#include <generated/GameObject.gh.inl>
diff --git a/source/30-game/Ires.cpp b/source/30-game/Ires.cpp
index 10a6867..bfa4cdf 100644
--- a/source/30-game/Ires.cpp
+++ b/source/30-game/Ires.cpp
@@ -3,14 +3,16 @@
#include "AppConfig.hpp"
#include "EditorCore.hpp"
#include "EditorUtils.hpp"
-#include "Macros.hpp"
#include "Material.hpp"
-#include "RapidJsonHelper.hpp"
-#include "ScopeGuard.hpp"
#include "Shader.hpp"
#include "Sprite.hpp"
#include "Texture.hpp"
-#include "Utils.hpp"
+
+#include <Macros.hpp>
+#include <Metadata.hpp>
+#include <RapidJsonHelper.hpp>
+#include <ScopeGuard.hpp>
+#include <Utils.hpp>
#include <imgui.h>
#include <misc/cpp/imgui_stdlib.h>
@@ -29,27 +31,6 @@ IresObject::IresObject(Kind kind)
: mKind{ 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;
- case KD_COUNT: break;
- }
- return std::string_view();
-}
-
-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;
- return KD_COUNT;
-}
-
std::unique_ptr<IresObject> IresObject::Create(Kind kind) {
switch (kind) {
case KD_Texture: return std::make_unique<IresTexture>();
@@ -128,7 +109,7 @@ void IresObject::ShowReference(IEditor& editor) {
}
void IresObject::ShowEditor(IEditor& editor) {
- ImGui::Text("%s", ToString(mKind).data());
+ ImGui::Text("%.*s", PRINTF_STRING_VIEW(Metadata::EnumToString(mKind)));
bool isAnnoymous = mName.empty();
if (isAnnoymous) {
@@ -148,7 +129,7 @@ void IresObject::WriteFull(IresWritingContext& ctx, IresObject* ires, rapidjson:
rapidjson::Value rvIres(rapidjson::kObjectType);
ires->Write(ctx, rvIres, root);
- value.AddMember("Type", rapidjson::StringRef(ToString(ires->GetKind())), root.GetAllocator());
+ value.AddMember("Type", rapidjson::StringRef(Metadata::EnumToString(ires->GetKind())), root.GetAllocator());
value.AddMember("Uid", ires->mUid.Write(root), root.GetAllocator());
value.AddMember("Value", rvIres, root.GetAllocator());
}
@@ -169,8 +150,9 @@ std::unique_ptr<IresObject> IresObject::ReadFull(IresLoadingContext& ctx, const
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));
- auto ires = Create(kind);
+ auto kind = Metadata::EnumFromString<Kind>(rapidjson::AsStringView(*rvType));
+ assert(kind.has_value());
+ auto ires = Create(kind.value());
if (!ires) return nullptr;
auto rvUid = rapidjson::GetProperty(value, rapidjson::kArrayType, "Uid"sv);
@@ -212,7 +194,7 @@ void IresManager::DiscoverFiles(const fs::path& dir) {
std::vector<std::vector<LoadCandidate*>> candidatesByKind;
IresLoadTimeContext() {
- candidatesByKind.resize(IresObject::KD_COUNT);
+ candidatesByKind.resize((int)IresObject::KD_COUNT);
}
std::vector<LoadCandidate*>& GetByKind(IresObject::Kind kind) {
@@ -282,7 +264,7 @@ void IresManager::DiscoverFiles(const fs::path& dir) {
// 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) {
+ for (int i = 0; i < (int)IresObject::KD_COUNT; ++i) {
auto kind = static_cast<IresObject::Kind>(i);
auto& list = ctx.GetByKind(kind);
for (auto cand : list) {
@@ -302,7 +284,7 @@ void IresManager::DiscoverFiles(const fs::path& dir) {
std::pair<IresObject*, bool> IresManager::Add(IresObject* ires) {
auto& name = ires->mName;
if (name.empty()) {
- name = Utils::MakeRandomNumberedName(IresObject::ToString(ires->GetKind()).data());
+ name = Utils::MakeRandomNumberedName(Metadata::EnumToString(ires->GetKind()).data());
}
auto& uid = ires->mUid;
@@ -423,3 +405,5 @@ IresObject* IresManager::FindIres(const Uid& uid) const {
return nullptr;
}
}
+
+#include <generated/Ires.gs.inl>
diff --git a/source/30-game/Ires.hpp b/source/30-game/Ires.hpp
index 83ca175..b6420f3 100644
--- a/source/30-game/Ires.hpp
+++ b/source/30-game/Ires.hpp
@@ -2,9 +2,11 @@
#include "EditorAttachment.hpp"
#include "EditorCore.hpp"
-#include "RcPtr.hpp"
-#include "Uid.hpp"
-#include "Utils.hpp"
+
+#include <MacrosCodegen.hpp>
+#include <RcPtr.hpp>
+#include <Uid.hpp>
+#include <Utils.hpp>
#include <rapidjson/fwd.h>
#include <robin_hood.h>
@@ -17,18 +19,24 @@ class IresManager;
class IresWritingContext;
class IresLoadingContext;
+namespace Tags {
+enum class IresObjectKind {
+ KD_Texture,
+ KD_Shader,
+ KD_Material,
+ KD_SpriteFiles,
+ KD_Spritesheet,
+ KD_COUNT,
+};
+BRUSSEL_ENUM(IresObjectKind, ToString FromString ExcludeHeuristics);
+} // namespace Tags
+
class IresObject : public RefCounted {
friend class IresManager;
public:
- enum Kind {
- KD_Texture,
- KD_Shader,
- KD_Material,
- KD_SpriteFiles,
- KD_Spritesheet,
- KD_COUNT,
- };
+ using Kind = Tags::IresObjectKind;
+ using enum Tags::IresObjectKind;
private:
std::string mName; // Serialized as filename
@@ -41,8 +49,6 @@ public:
IresObject(Kind kind);
virtual ~IresObject() = default;
- static std::string_view ToString(Kind kind);
- static Kind FromString(std::string_view name);
static std::unique_ptr<IresObject> Create(Kind kind);
Kind GetKind() const { return mKind; }
@@ -115,3 +121,5 @@ public:
const auto& GetObjects() const { return mObjByUid; }
virtual IresObject* FindIres(const Uid& uid) const override;
};
+
+#include <generated/Ires.gh.inl>
diff --git a/source/30-game/Level.cpp b/source/30-game/Level.cpp
index 5881084..076e5d5 100644
--- a/source/30-game/Level.cpp
+++ b/source/30-game/Level.cpp
@@ -1,21 +1,24 @@
#include "Level.hpp"
#include "AppConfig.hpp"
-#include "PodVector.hpp"
-#include "RapidJsonHelper.hpp"
-#include "ScopeGuard.hpp"
-#include "Utils.hpp"
+#include <PodVector.hpp>
+#include <RapidJsonHelper.hpp>
+#include <ScopeGuard.hpp>
+#include <Utils.hpp>
+
+#include <imgui.h>
#include <rapidjson/document.h>
#include <rapidjson/filereadstream.h>
#include <rapidjson/filewritestream.h>
-#include <rapidjson/writer.h>
+#include <rapidjson/prettywriter.h>
#include <cstdio>
#include <filesystem>
using namespace std::literals;
namespace fs = std::filesystem;
+constexpr auto kParentToRootObject = std::numeric_limits<size_t>::max();
constexpr auto kInvalidEntryId = std::numeric_limits<size_t>::max();
struct Level::InstanciationEntry {
@@ -29,6 +32,23 @@ Level::Level() = default;
Level::~Level() = default;
void Level::Instanciate(GameObject* relRoot) const {
+ auto objectsLut = std::make_unique<GameObject*[]>(mEntries.size());
+ for (auto& entry : mEntries) {
+ GameObject* parent;
+ if (entry.parentId == kParentToRootObject) {
+ parent = relRoot;
+ } else {
+ parent = objectsLut[entry.parentId];
+ }
+
+ // TODO deser object
+ }
+}
+
+void Level::ShowInstanciationEntries(IEditor& editor) {
+ for (auto& entry : mEntries) {
+ // TODO
+ }
}
void LevelManager::DiscoverFilesDesignatedLocation() {
@@ -92,6 +112,7 @@ Level* LevelManager::LoadLevel(const Uid& uid) {
ldObj.level.Attach(level = new Level());
level->mMan = this;
+ level->mUid = uid;
#if defined(BRUSSEL_DEV_ENV)
BRUSSEL_JSON_GET_DEFAULT(root, "Name", std::string, ldObj.name, BRUSSEL_DEF_LEVEL_NAME);
@@ -123,8 +144,9 @@ void LevelManager::PrepareLevel(const Uid& uid) {
}
LevelManager::LoadableObject& LevelManager::AddLevel(const Uid& uid) {
- auto&& [iter, inserted] = mObjByUid.try_emplace(uid, LoadableObject{});
+ auto&& [iter, inserted] = mObjByUid.try_emplace(uid);
auto& ldObj = iter->second;
+ ldObj.level->mUid = uid;
#if defined(BRUSSEL_DEV_ENV)
ldObj.name = BRUSSEL_DEF_LEVEL_NAME;
ldObj.description = BRUSSEL_DEF_LEVEL_DESC;
@@ -132,6 +154,37 @@ LevelManager::LoadableObject& LevelManager::AddLevel(const Uid& uid) {
return ldObj;
}
+void LevelManager::SaveLevel(const Uid& uid) const {
+ auto iter = mObjByUid.find(uid);
+ if (iter == mObjByUid.end()) return;
+ auto& obj = iter->second;
+
+ SaveLevelImpl(obj, obj.filePath);
+}
+
+void LevelManager::SaveLevel(const Uid& uid, const std::filesystem::path& path) const {
+ auto iter = mObjByUid.find(uid);
+ if (iter == mObjByUid.end()) return;
+ auto& obj = iter->second;
+
+ SaveLevelImpl(obj, path);
+}
+
+void LevelManager::SaveLevelImpl(const LoadableObject& obj, const std::filesystem::path& path) const {
+ rapidjson::Document root;
+
+ // TODO
+
+ auto file = Utils::OpenCstdioFile(path, Utils::WriteTruncate);
+ if (!file) return;
+ DEFER { fclose(file); };
+
+ char writerBuffer[65536];
+ rapidjson::FileWriteStream stream(file, writerBuffer, sizeof(writerBuffer));
+ rapidjson::Writer<rapidjson::FileWriteStream> writer(stream);
+ root.Accept(writer);
+}
+
LevelWrapperObject::LevelWrapperObject(GameWorld* world)
: GameObject(KD_LevelWrapper, world) //
{
diff --git a/source/30-game/Level.hpp b/source/30-game/Level.hpp
index c1170a3..9114a64 100644
--- a/source/30-game/Level.hpp
+++ b/source/30-game/Level.hpp
@@ -1,8 +1,10 @@
#pragma once
+#include "EditorCore.hpp"
#include "GameObject.hpp"
-#include "RcPtr.hpp"
-#include "Uid.hpp"
+
+#include <RcPtr.hpp>
+#include <Uid.hpp>
#include <robin_hood.h>
#include <filesystem>
@@ -20,6 +22,7 @@ private:
struct InstanciationEntry;
LevelManager* mMan;
+ Uid mUid;
std::vector<InstanciationEntry> mEntries;
public:
@@ -27,6 +30,12 @@ public:
~Level();
void Instanciate(GameObject* relRoot) const;
+
+ LevelManager* GetLinkedLevelManager() const { return mMan; }
+ const Uid& GetUid() const { return mUid; }
+
+ // Editor stuff
+ void ShowInstanciationEntries(IEditor& editor);
};
class LevelManager {
@@ -34,12 +43,16 @@ public:
static inline LevelManager* instance = nullptr;
public: // NOTE: public for the editor; actual game components should not modify the map using this
+ // TODO maybe cut this struct to only the first RcPtr<Level> field in release mode?
struct LoadableObject {
RcPtr<Level> level; // TODO make weak pointer
std::filesystem::path filePath;
// NOTE: these fields are only loaded in dev mode
std::string name;
std::string description;
+
+ // Editor book keeping fields
+ bool edited = false;
};
// We want pointer stability here for the editor (inspector object)
robin_hood::unordered_node_map<Uid, LoadableObject> mObjByUid;
@@ -54,8 +67,16 @@ public:
/// Send the given level to be loaded on another thread
void PrepareLevel(const Uid& uid);
- // These should only be used by the editor
+ /// Create and add a new level object with the given uid.
+ /// Should only be used by the editor.
LoadableObject& AddLevel(const Uid& uid);
+ /// Should only be used by the editor.
+ void SaveLevel(const Uid& uid) const;
+ /// Should only be used by the editor.
+ void SaveLevel(const Uid& uid, const std::filesystem::path& path) const;
+
+private:
+ void SaveLevelImpl(const LoadableObject& obj, const std::filesystem::path& path) const;
};
class LevelWrapperObject : public GameObject {
diff --git a/source/30-game/Material.cpp b/source/30-game/Material.cpp
index e648970..9b0c42d 100644
--- a/source/30-game/Material.cpp
+++ b/source/30-game/Material.cpp
@@ -3,9 +3,11 @@
#include "AppConfig.hpp"
#include "EditorCore.hpp"
#include "EditorUtils.hpp"
-#include "RapidJsonHelper.hpp"
-#include "ScopeGuard.hpp"
-#include "Utils.hpp"
+
+#include <Metadata.hpp>
+#include <RapidJsonHelper.hpp>
+#include <ScopeGuard.hpp>
+#include <Utils.hpp>
#include <imgui.h>
#include <rapidjson/document.h>
@@ -349,7 +351,7 @@ void IresMaterial::ShowEditor(IEditor& editor) {
IresObject::ShowReferenceNull(editor);
}
if (ImGui::BeginDragDropTarget()) {
- if (auto payload = ImGui::AcceptDragDropPayload(ToString(KD_Shader).data())) {
+ if (auto payload = ImGui::AcceptDragDropPayload(Metadata::EnumToString(KD_Shader).data())) {
auto shader = *static_cast<IresShader* const*>(payload->Data);
mInstance->SetShader(shader->GetInstance());
}