Elevate Engine 1
Loading...
Searching...
No Matches
ComponentRegistry.h
Go to the documentation of this file.
1#pragma once
2
3#include <initializer_list>
4#include <map>
5#include <string>
6#include <type_traits>
7#include <typeindex>
8#include <typeinfo>
9#include <variant>
10
11#include <entt/entt.hpp>
12#include <glm/fwd.hpp>
13
20
21#ifdef EE_RELEASE
22 #undef EE_REGISTRY_LOG
23#endif
24
25namespace Elevate
26{
27 class GameObject;
28
29 template<typename T, typename = void>
30 struct has_super : std::false_type {};
31 template<typename T>
32 struct has_super<T, std::void_t<typename T::Super>> : std::true_type {};
33
34 template<typename T, bool = has_super<T>::value>
36 static std::vector<ComponentField> Get() { return {}; }
37 };
38
39 template<typename T>
40 struct ParentFieldsHelper<T, true> {
41 static std::vector<ComponentField> Get() {
42 using Super = typename T::Super;
43 if constexpr (!std::is_same_v<Super, void> && std::is_base_of_v<Component, Super>) {
44 return Super::generated_classEntry.ClassFieldStack;
45 }
46 else {
47 return {};
48 }
49 }
50 };
51
52 // Field / Component Property Tag ------------------------------------------------------
54 #define HideInInspector HideInInspectorTag{}
55
56 struct FlattenTag {};
57 #define Flatten FlattenTag{}
58
59 struct DisplayNameTag { const char* value; };
60 #define DisplayName(x) DisplayNameTag{x}
61
62 struct TooltipTag { const char* text; };
63 #define Tooltip(x) TooltipTag{x}
64
65 struct ReadOnlyTag {};
66 #define ReadOnly ReadOnlyTag{}
67
68 struct ColorTag {};
69 #define ColorPicker ColorTag{}
70
72 {
73 std::string Path;
74 };
75 #define EditorIcon(path) EditorIconTag{path}
76
77 using FieldOption = std::variant<
80 >;
81
82 struct FieldMeta {
83 bool flatten = false;
84 std::string displayName = "";
85 std::string tooltip;
86 bool readOnly = false;
87 bool isColor = false;
88 std::string IconPath;
89 };
90
91 template<typename T>
96
97 template<> struct EngineDataTypeTrait<float> { static constexpr EngineDataType value = EngineDataType::Float; };
98 template<> struct EngineDataTypeTrait<int> { static constexpr EngineDataType value = EngineDataType::Int; };
99 template<> struct EngineDataTypeTrait<bool> { static constexpr EngineDataType value = EngineDataType::Bool; };
100 template<> struct EngineDataTypeTrait<glm::vec2> { static constexpr EngineDataType value = EngineDataType::Float2; };
101 template<> struct EngineDataTypeTrait<glm::vec3> { static constexpr EngineDataType value = EngineDataType::Float3; };
102 template<> struct EngineDataTypeTrait<glm::vec4> { static constexpr EngineDataType value = EngineDataType::Float4; };
103
105 public:
106 template<typename T>
107 static auto GetParentFieldsIfPossible(const T* obj) -> std::vector<ComponentField> {
108 return ParentFieldsHelper<T>::Get(obj);
109 }
110
111 struct Entry
112 {
113 std::string name;
114 std::type_index type{ typeid(void) };
116 GameObjectComponentGetter getter; // method to get the type of component from a gameobject
117 GameObjectComponentFactory factory; // factory to create / add to a gameObject
118 GameObjectComponentDestructor destructor; // component destructor / remove from a gameObject
120 std::string editorIconPath; // TODO RESTRAIN TO INSIDE THE EDITOR
121 };
122
123 template<typename T>
124 static void Register(const std::string& name, EECategory category, std::vector<FieldOption>& options);
125
126 static std::unordered_map<std::type_index, Entry>& GetEntries() {
127 static std::unordered_map<std::type_index, Entry> entries;
128 return entries;
129 }
130
131 static std::string GetName(const std::type_info& type);
132
133 static std::vector<std::string>& ClassPaths() {
134 static std::vector<std::string> paths;
135 return paths;
136 }
137
138 static std::vector<std::string>& CompilationClassStack() {
139 static std::vector<std::string> stack;
140 return stack;
141 }
142
143 static inline std::vector<ComponentField>& CompilationClassFieldStack()
144 {
145 static std::vector<ComponentField> stack;
146 return stack;
147 }
148
149 template<typename T>
151 {
153 }
154
155 // Simple method to convert a variable or class name to a display name, ex: m_myProperty -> My Property
156 static std::string GetCleanedName(std::string rawName);
157
158 static void AddClassToStack(std::string newClass);
159 static void PopClassStack();
160
161 static std::map<std::string, std::vector<ComponentField>>& GetCustomComponentFields()
162 {
163 static std::map<std::string, std::vector<ComponentField>> m_customComponentFields;
164 return m_customComponentFields;
165 }
166
167 template<typename Class, typename FieldType>
168 static void AddProperty(FieldType Class::* member, const std::string& name, std::initializer_list<FieldOption> options);
169 };
170}
171
172#define EECATEGORY(name) \
173 private: \
174 inline static struct categoryRegistrar { \
175 categoryRegistrar() { \
176 generated_classEntry.Category = EECategory(name); \
177 } \
178 } generated_categoryRegistrar; \
179 virtual EECategory GetCategory() const override { return generated_classEntry.Category; } \
180 public:
181
182// =======================================================
183// BEGIN_COMPONENT / EXPOSE / END_COMPONENT
184// =======================================================
185#include "ComponentRegistry.inl"
186
187#define BEGIN_COMPONENT(T, ...) \
188private: \
189using ThisType = T; \
190public: \
191inline static struct T##ClassEntry { \
192 T##ClassEntry() { \
193 FieldStartIndex = ::Elevate::ComponentRegistry::CompilationClassFieldStack().size(); \
194 ::Elevate::ComponentRegistry::AddClassToStack(#T); \
195 ClassName = ::Elevate::ComponentRegistry::GetCleanedName(#T); \
196 HasBaseClass = false; \
197 Options = { __VA_ARGS__ }; \
198 } \
199 std::vector<FieldOption> Options; \
200 EECategory Category; \
201 size_t FieldStartIndex = 0; \
202 std::string ClassName; \
203 std::vector<Elevate::ComponentField> ClassFieldStack; \
204 bool HasBaseClass = false; \
205} generated_classEntry; \
206public: \
207 virtual bool RemoveFromGameObject() override { \
208 if (gameObject) { \
209 gameObject->RemoveComponent<T>(); \
210 return true; \
211 } \
212 return false; \
213 }
214
215#define EXPOSE(param, ...) \
216public: \
217inline static struct param##PropertyEntry { \
218 param##PropertyEntry() { \
219 using MemberT = decltype(ThisType::param); \
220 ::Elevate::ComponentRegistry::AddProperty<ThisType, MemberT>( \
221 &ThisType::param, \
222 #param, \
223 { __VA_ARGS__ } \
224 ); \
225 } \
226} generated_##param##PropertyEntry;
227
228#define END_COMPONENT() \
229private: \
230 inline static struct ClassEntryEnd { \
231 ClassEntryEnd() { \
232 ::Elevate::ComponentRegistry::Register<ThisType>( \
233 generated_classEntry.ClassName, \
234 generated_classEntry.Category, \
235 generated_classEntry.Options \
236 ); \
237 ::Elevate::ComponentRegistry::PopClassStack(); \
238 auto& global = ::Elevate::ComponentRegistry::CompilationClassFieldStack(); \
239 size_t start = generated_classEntry.FieldStartIndex; \
240 for (size_t i = start; i < global.size(); ++i) { \
241 generated_classEntry.ClassFieldStack.push_back(global[i]); \
242 } \
243 if (start < global.size()) { \
244 global.erase(global.begin() + start, global.end()); \
245 } \
246 } \
247 } generated_classEntryEnd; \
248public: \
249 inline virtual std::string GetName() const override { return generated_classEntry.ClassName; } \
250 inline virtual Elevate::ComponentLayout GetLayout() const override { \
251 std::vector<Elevate::ComponentField> instanceFields; \
252 if (generated_classEntry.HasBaseClass) { \
253 auto parentFields = ParentFieldsHelper<ThisType>::Get(); \
254 for (const Elevate::ComponentField& field : parentFields) { \
255 const void* fieldPtr = reinterpret_cast<const char*>(this) + field.offset; \
256 instanceFields.push_back(Elevate::ComponentField( \
257 field, fieldPtr \
258 )); \
259 } \
260 } \
261 for (const Elevate::ComponentField& field : generated_classEntry.ClassFieldStack) { \
262 const void* fieldPtr = reinterpret_cast<const char*>(this) + field.offset; \
263 instanceFields.push_back(Elevate::ComponentField(field, fieldPtr)); \
264 } \
265 return Elevate::ComponentLayout(generated_classEntry.ClassName, instanceFields); \
266 } \
267 virtual Component* Clone() override { \
268 ThisType* clone = new ThisType(); \
269 for (auto& field : ComponentRegistry::GetCustomComponentFields()[typeid(ThisType).name()]) { \
270 field.CopyValue(this, clone); \
271 } \
272 return clone; \
273 } \
274 virtual void CopyFrom(Component* other) override { \
275 if (auto o = dynamic_cast<ThisType*>(other)) { \
276 if (generated_classEntry.HasBaseClass) { \
277 auto parentFields = ParentFieldsHelper<ThisType>::Get(); \
278 for (const Elevate::ComponentField& field : parentFields) { \
279 field.CopyValue(o, this); \
280 } \
281 } \
282 for (const Elevate::ComponentField& field : generated_classEntry.ClassFieldStack) { \
283 field.CopyValue(o, this); \
284 } \
285 } \
286 else { \
287 EE_ERROR("Error: Tried setting a %s from a %s component in CopyFrom(Component*)", \
288 this->GetName(), other ? other->GetName() : "null"); \
289 } \
290 } \
291 virtual Elevate::GameObjectComponentFactory GetFactory() const override { \
292 auto& entries = ComponentRegistry::GetEntries(); \
293 auto it = entries.find(typeid(ThisType)); \
294 if (it != entries.end()) { \
295 return it->second.factory; \
296 } \
297 return nullptr; \
298 } \
299 virtual Elevate::GameObjectComponentDestructor GetDestructor() const override { \
300 auto& entries = ComponentRegistry::GetEntries(); \
301 auto it = entries.find(typeid(ThisType)); \
302 if (it != entries.end()) { \
303 return it->second.destructor; \
304 } \
305 return nullptr; \
306 } \
307 virtual const void* GetEditorIconHandle() const override { \
308 auto& entries = ComponentRegistry::GetEntries(); \
309 auto it = entries.find(typeid(ThisType)); \
310 if (it != entries.end()) { \
311 if(!it->second.editorIconPath.empty()) { \
312 return Texture::CreateFromFile(it->second.editorIconPath)->GetNativeHandle(); \
313 } \
314 } \
315 return nullptr; \
316 } \
317 virtual std::type_index GetTypeIndex() const override { return typeid(ThisType); }
318
319#define DECLARE_BASE(BaseType) \
320using Super = BaseType; \
321inline static struct BaseType##BaseClassDeclaration { \
322 BaseType##BaseClassDeclaration() { \
323 generated_classEntry.HasBaseClass = true; \
324 } \
325} generated_baseDeclaration;
326
327// =======================================================
328// BEGIN_STRUCT / END_STRUCT
329// =======================================================
330
331#define BEGIN_STRUCT(T) \
332 private: \
333 using ThisType = T; \
334 inline static struct T##StructEntry { \
335 T##StructEntry() { \
336 ::Elevate::ComponentRegistry::AddClassToStack(#T); \
337 FieldStartIndex = ::Elevate::ComponentRegistry::CompilationClassFieldStack().size(); \
338 StructName = ::Elevate::ComponentRegistry::GetCleanedName(#T); \
339 StructTypeName = typeid(T).name(); \
340 } \
341 size_t FieldStartIndex = 0; \
342 std::string StructName; \
343 std::string StructTypeName; \
344 std::vector<Elevate::ComponentField> StructFieldStack; \
345 } generated_structEntry; \
346 public:
347
348#define END_STRUCT() \
349 private: \
350 inline static struct StructEntryEnd { \
351 StructEntryEnd() { \
352 auto& global = ::Elevate::ComponentRegistry::CompilationClassFieldStack(); \
353 size_t start = generated_structEntry.FieldStartIndex; \
354 for (size_t i = start; i < global.size(); ++i) { \
355 generated_structEntry.StructFieldStack.push_back(global[i]); \
356 } \
357 if (start < global.size()) { \
358 global.erase(global.begin() + start, global.end()); \
359 } \
360 ::Elevate::ComponentRegistry::GetCustomComponentFields()[generated_structEntry.StructTypeName] = generated_structEntry.StructFieldStack; \
361 } \
362 } generated_structEntryEnd;
static std::vector< std::string > & ClassPaths()
static std::vector< std::string > & CompilationClassStack()
static void Register(const std::string &name, EECategory category, std::vector< FieldOption > &options)
static auto GetParentFieldsIfPossible(const T *obj) -> std::vector< ComponentField >
static std::unordered_map< std::type_index, Entry > & GetEntries()
static std::map< std::string, std::vector< ComponentField > > & GetCustomComponentFields()
static std::string GetCleanedName(std::string rawName)
static constexpr EngineDataType DeduceEngineDataType()
static void AddClassToStack(std::string newClass)
static void AddProperty(FieldType Class::*member, const std::string &name, std::initializer_list< FieldOption > options)
static std::string GetName(const std::type_info &type)
static std::vector< ComponentField > & CompilationClassFieldStack()
EngineDataType
Definition Data.h:106
std::variant< HideInInspectorTag, EditorIconTag, FlattenTag, DisplayNameTag, TooltipTag, ReadOnlyTag, ColorTag > FieldOption
std::function< Component *(std::weak_ptr< GameObject >)> GameObjectComponentFactory
Definition Component.h:21
std::function< Component *(std::weak_ptr< GameObject >)> GameObjectComponentGetter
Definition Component.h:20
std::function< void(std::weak_ptr< GameObject >)> GameObjectComponentDestructor
Definition Component.h:22
GameObjectComponentGetter getter
GameObjectComponentDestructor destructor
GameObjectComponentFactory factory
static constexpr EngineDataType value
static std::vector< ComponentField > Get()
static std::vector< ComponentField > Get()