Cogs.Core
EntityWriter.cpp
1#include "EntityWriter.h"
2
3#include "Context.h"
4#include "EntityStore.h"
5#include "Types.h"
6
7#include "Components/Core/TransformComponent.h"
8#include "Components/Core/ModelComponent.h"
9#include "Components/Core/SceneComponent.h"
10
11#include "Resources/Resources.h"
12#include "Resources/Model.h"
13#include "Resources/Texture.h"
14#include "Resources/MaterialInstance.h"
15#include "Resources/Mesh.h"
16#include "Resources/MaterialManager.h"
17
18#include "Foundation/Logging/Logger.h"
19#include "Foundation/Reflection/TypeDatabase.h"
20
21#include <bit>
22#include <cmath>
23
24
25using namespace rapidjson;
26using namespace Cogs::Reflection;
27
28namespace
29{
30 Cogs::Logging::Log logger = Cogs::Logging::getLogger("EntityWriter");
31}
32
33
34namespace Cogs::Core
35{
36 template<typename T, typename AllocatorType>
37 void writeVectorVec(Value & object, const StringView & key, const std::vector<T>& values, const std::vector<T> defaultValue, AllocatorType & a)
38 {
39 if (values == defaultValue) return;
40
41 Value vec(kArrayType);
42
43 for (const auto & value : values)
44 {
45 for (int i = 0; i < value.length(); ++i) {
46 vec.PushBack((double)value[i], a);
47 }
48 }
49
50 Value v(key.data(), a);
51 object.AddMember(v, vec, a);
52 }
53
54 template<typename T, typename AllocatorType>
55 void writeVectorInt(Value & object, const StringView & key, const std::vector<T>& values, const std::vector<T> defaultValue, AllocatorType & a)
56 {
57 if (values == defaultValue) return;
58
59 Value vec(kArrayType);
60
61 for (const auto & value : values)
62 {
63 vec.PushBack((int)value, a);
64 }
65
66 Value v(key.data(), a);
67 object.AddMember(v, vec, a);
68 }
69
70 template<typename T, typename AllocatorType>
71 void writeVectorDouble(Value & object, const StringView & key, const std::vector<T>& values, const std::vector<T> defaultValue, AllocatorType & a)
72 {
73 if (values == defaultValue) return;
74
75 Value vec(kArrayType);
76
77 for (const auto & value : values)
78 {
79 vec.PushBack((double)value, a);
80 }
81
82 Value v(key.data(), a);
83 object.AddMember(v, vec, a);
84 }
85
86 template<typename T, typename AllocatorType>
87 void writeVec(Value & object, const StringView & key, T value, T defaultValue, AllocatorType & a)
88 {
89 if (value == defaultValue) return;
90
91 Value vec(kArrayType);
92
93 for (int i = 0; i < value.length(); ++i) {
94 vec.PushBack((double)value[i], a);
95 }
96
97 Value v(key.data(), a);
98 object.AddMember(v, vec, a);
99 }
100
101 template<typename AllocatorType>
102 void writeMat(Value& object, const StringView& key, const glm::mat4& value, const glm::mat4& defaultValue, AllocatorType& a)
103 {
104 if (value == defaultValue) return;
105
106 Value vec(kArrayType);
107
108 for (int i = 0; i < 16; ++i) {
109 vec.PushBack((double)glm::value_ptr(value)[i], a);
110 }
111
112 Value v(key.data(), a);
113 object.AddMember(v, vec, a);
114 }
115
116 template<typename AllocatorType>
117 void writeDouble(Value & object, const StringView & key, const double value, const double defaultValue, AllocatorType & a)
118 {
119 if (value == defaultValue) return;
120
121 // NaN plays havoc on JSon output (no output after Nan).
122 if (std::isnan(value)) {
123 if (std::isnan(defaultValue)) {
124 LOG_WARNING(logger, "Skipped serialization of NaN value in %s", key.data());
125 }
126
127 return;
128 }
129
130 Value v(key.data(), a);
131 object.AddMember(v, (double)value, a);
132 }
133
134 template<typename T, typename AllocatorType>
135 void writeInteger(Value & object, const StringView & key, T value, T defaultValue, AllocatorType & a)
136 {
137 if (value == defaultValue) return;
138
139 Value v(key.data(), a);
140 object.AddMember(v, (int)value, a);
141 }
142
143 template<typename AllocatorType>
144 void writeBool(Value & object, const StringView & key, bool value, bool defaultValue, AllocatorType & a)
145 {
146 if (value == defaultValue) return;
147
148 Value b;
149 b.SetBool(value);
150
151 Value v(key.data(), a);
152 object.AddMember(v, b, a);
153 }
154
155 template<typename AllocatorType>
156 void writeString(Value & object, const StringView & key, StringView value, StringView defaultValue, AllocatorType & a)
157 {
158 if (value == defaultValue) return;
159
160 Value v(key.data(), a);
161 Value vv(value.data(), a);
162 object.AddMember(v, vv, a);
163 }
164
165 std::string getUniqueMaterialName(Context * context)
166 {
167 static int resId = 0;
168
169 std::vector<ResourceBase*> allocated = context->materialInstanceManager->getAllocatedResources();
170
171 auto name = "_MaterialInstance" + std::to_string(resId++);
172
173 while (true) {
174 bool found = false;
175 for (auto & m : allocated) {
176 if (m->getName() == name) {
177 found = true;
178 }
179 }
180
181 if (!found) break;
182
183 name = "_MaterialInstance" + std::to_string(resId++);
184 }
185
186 return name;
187 }
188
189 std::string getResourceName(Context * context, ResourceHandleBase * fieldValue, std::unordered_set<ResourceHandleBase> * resources)
190 {
191 if (fieldValue && *fieldValue) {
192 auto resource = fieldValue->get();
193
194 if (resource->getName().empty()) {
195 if (resource->getType() == ResourceTypes::Mesh) {
196 static int resId = 0;
197 resource->setName("_Mesh" + std::to_string(resId++));
198 } else if (resource->getType() == ResourceTypes::Texture) {
199 static int resId = 0;
200 resource->setName("_Texture" + std::to_string(resId++));
201 } else if (resource->getType() == ResourceTypes::Model) {
202 static int resId = 0;
203 resource->setName("_Model" + std::to_string(resId++));
204 } else if (resource->getType() == ResourceTypes::MaterialInstance) {
205 resource->setName(getUniqueMaterialName(context));
206 }
207 }
208
209 if (resources) {
210 resources->insert(*fieldValue);
211 }
212
213 std::string fieldName = "$" + resource->getName().to_string();
214 return fieldName;
215 }
216
217 return {};
218 }
219}
220
221void Cogs::Core::writeEntity(Context * context, ComponentModel::Entity * entity, rapidjson::Value & entityValue, rapidjson::Document & d, SerializationContext * sc, const AssetWriteFlags flags)
222{
223 auto & a = d.GetAllocator();
224 const bool saveGeometry = (flags & AssetWriteFlags::Geometry) == AssetWriteFlags::Geometry;
225
226 entityValue.AddMember("name", Value(entity->getName().c_str(), a), a);
227
228 size_t templateId = static_cast<const EntityData *>(entity->getUserData())->templateId;
229 const EntityDefinition* definition = context->store->getEntityDefinition(templateId);
230
231 if (definition) {
232 entityValue.AddMember("type", Value(definition->name.c_str(), a), a);
233 }
234
235 for (const auto & c : entity->getComponents()) {
236 Value compValue(kObjectType);
237
238 auto component = c.resolve();
239
240 auto type = &Reflection::TypeDatabase::getType(c.typeId);
241 auto typeName = type->getName();
242 auto defaultComponent = TypeDatabase::createInstance(*type);
243
244 if (type->getName() == "TransformComponent") {
245 auto transform = c.resolveComponent<TransformComponent>();
246 auto defaultTransform = (TransformComponent *)defaultComponent;
247
248 if (transform->transformFlags != defaultTransform->transformFlags) {
249 entityValue.AddMember("transformFlags", transform->transformFlags, a);
250 }
251
252 if (!transform->transformFlags) {
253 writeVec(compValue, "coordinates", transform->coordinates, defaultTransform->coordinates, a);
254 writeVec(compValue, "position", transform->position, defaultTransform->position, a);
255 writeVec(compValue, "rotation", transform->rotation, defaultTransform->rotation, a);
256 writeVec(compValue, "scale", transform->scale, defaultTransform->scale, a);
257 }
258 else {
259 glm::mat4 defaultMat = glm::mat4(1.0f);
260 writeMat(compValue, "transform", transform->transform, defaultMat, a);
261 }
262 } else {
263 while (type) {
264 size_t numFields = type->getNumFields();
265
266 for (FieldId f = 0; f < numFields; ++f) {
267 const Cogs::Reflection::Field* field = type->getField(f);
269 continue;
270 }
271 auto & fieldName = field->getName();
272
273 auto & fieldHeader = fieldName.getName();
274
275 auto & fieldType = TypeDatabase::getType(field->getTypeId());
276
277 if (fieldType.isEnum()) {
278 uint32_t value = *field->getPtr<uint32_t>(component);
279 uint32_t defaultFieldValue = *field->getPtr<uint32_t>(defaultComponent);
280 if (value != defaultFieldValue) {
281 // Store ORed set of values, e.g. "EnableRender|EnablePicking"
282 if (fieldType.isEnumFlags()) {
283 std::string valueStr;
284 size_t numEnums = fieldType.getNumEnumerators();
285
286 for (size_t i = 0; i < numEnums; ++i) {
287 auto enumerator = fieldType.getEnumerator(i);
288 uint32_t enumeratorValue = static_cast<uint32_t>(enumerator->getValue());
289
290 // use exact match (can be ORed values)
291 if (value == enumeratorValue) {
292 valueStr = enumerator->getName().getName();
293 break;
294 }
295
296 if (std::popcount(enumeratorValue) == 1 && value & enumeratorValue) {
297 if (!valueStr.empty()) valueStr += '|';
298 valueStr += enumerator->getName().getName();
299 }
300 }
301
302 writeString(compValue, fieldHeader, valueStr.c_str(), "", a);
303 }
304 else if (value < fieldType.getNumEnumerators()) {
305 for (size_t i = 0; i < fieldType.getNumEnumerators(); ++i) {
306 auto fieldEnum = fieldType.getEnumerator(i);
307 if (static_cast<uint32_t>(fieldEnum->getValue()) == value) {
308 writeString(compValue, fieldHeader, fieldEnum->getName().c_str(), "", a);
309 break;
310 }
311 }
312 }
313 else {
314 writeInteger(compValue, fieldHeader, value, ~value, a);
315 }
316 }
317 } else if (fieldType == TypeDatabase::getType<bool>()) {
318 auto fieldValue = field->getPtr<bool>(component);
319 auto defaultFieldValue = field->getPtr<bool>(defaultComponent);
320
321 if (*fieldValue != *defaultFieldValue) {
322 writeBool(compValue, fieldHeader, *fieldValue, *defaultFieldValue, a);
323 }
324 } else if (fieldType == TypeDatabase::getType<int32_t>()) {
325 auto fieldValue = field->getPtr<int32_t>(component);
326 auto defaultFieldValue = field->getPtr<int32_t>(defaultComponent);
327
328 if (*fieldValue != *defaultFieldValue) {
329 writeInteger(compValue, fieldHeader, *fieldValue, *defaultFieldValue, a);
330 }
331 } else if (fieldType == TypeDatabase::getType<uint32_t>()) {
332 auto fieldValue = field->getPtr<uint32_t>(component);
333 auto defaultFieldValue = field->getPtr<uint32_t>(defaultComponent);
334
335 if (*fieldValue != *defaultFieldValue) {
336 writeInteger(compValue, fieldHeader, *fieldValue, *defaultFieldValue, a);
337 }
338 } else if (fieldType == TypeDatabase::getType<float>()) {
339 auto fieldValue = field->getPtr<float>(component);
340 auto defaultFieldValue = field->getPtr<float>(defaultComponent);
341
342 if (*fieldValue != *defaultFieldValue) {
343 writeDouble(compValue, fieldHeader, *fieldValue, *defaultFieldValue, a);
344 }
345 } else if (fieldType == TypeDatabase::getType<glm::vec2>()) {
346 auto fieldValue = field->getPtr<glm::vec2>(component);
347 auto defaultFieldValue = field->getPtr<glm::vec2>(defaultComponent);
348
349 writeVec(compValue, fieldHeader, *fieldValue, *defaultFieldValue, a);
350 } else if (fieldType == TypeDatabase::getType<glm::vec3>()) {
351 auto fieldValue = field->getPtr<glm::vec3>(component);
352 auto defaultFieldValue = field->getPtr<glm::vec3>(defaultComponent);
353
354 writeVec(compValue, fieldHeader, *fieldValue, *defaultFieldValue, a);
355 } else if (fieldType == TypeDatabase::getType<glm::vec4>()) {
356 auto fieldValue = field->getPtr<glm::vec4>(component);
357 auto defaultFieldValue = field->getPtr<glm::vec4>(defaultComponent);
358
359 writeVec(compValue, fieldHeader, *fieldValue, *defaultFieldValue, a);
360 } else if (fieldType == TypeDatabase::getType<glm::quat>()) {
361 auto fieldValue = field->getPtr<glm::quat>(component);
362 auto defaultFieldValue = field->getPtr<glm::quat>(defaultComponent);
363
364 writeVec(compValue, fieldHeader, *fieldValue, *defaultFieldValue, a);
365 } else if (fieldType == TypeDatabase::getType<glm::dvec2>()) {
366 auto fieldValue = field->getPtr<glm::dvec2>(component);
367 auto defaultFieldValue = field->getPtr<glm::dvec2>(defaultComponent);
368
369 writeVec(compValue, fieldHeader, *fieldValue, *defaultFieldValue, a);
370 } else if (fieldType == TypeDatabase::getType<glm::dvec3>()) {
371 auto fieldValue = field->getPtr<glm::dvec3>(component);
372 auto defaultFieldValue = field->getPtr<glm::dvec3>(defaultComponent);
373
374 writeVec(compValue, fieldHeader, *fieldValue, *defaultFieldValue, a);
375 } else if (fieldType == TypeDatabase::getType<glm::dvec4>()) {
376 auto fieldValue = field->getPtr<glm::dvec4>(component);
377 auto defaultFieldValue = field->getPtr<glm::dvec4>(defaultComponent);
378
379 writeVec(compValue, fieldHeader, *fieldValue, *defaultFieldValue, a);
380 } else if (fieldType == TypeDatabase::getType<glm::mat4>()) {
381 auto fieldValue = field->getPtr<glm::mat4>(component);
382 auto defaultFieldValue = field->getPtr<glm::mat4>(defaultComponent);
383
384 writeMat(compValue, fieldHeader, *fieldValue, *defaultFieldValue, a);
385 } else if (fieldType == TypeDatabase::getType<std::string>()) {
386 auto name = *field->getPtr<std::string>(component);
387 writeString(compValue, fieldHeader, name, "", a);
388 } else if (fieldType == TypeDatabase::getType<std::vector<std::string>>()) {
389 auto names = field->getPtr<std::vector<std::string>>(component);
390 if (!names->empty()) {
391 Value fieldValues(kArrayType);
392 for (auto& entry : *names) {
393 fieldValues.PushBack(rapidjson::StringRef(entry.data()), a);
394 }
395
396 compValue.AddMember(rapidjson::StringRef(fieldHeader.c_str()), fieldValues, a);
397 }
398 } else if (fieldType == TypeDatabase::getType<AssetHandle>()) {
399 auto resourceName = getResourceName(context, field->getPtr<AssetHandle>(component), sc ? &sc->assets : nullptr);
400
401 writeString(compValue, fieldHeader, resourceName, "", a);
402 } else if (fieldType == TypeDatabase::getType<ModelHandle>()) {
403 auto resourceName = getResourceName(context, field->getPtr<ModelHandle>(component), sc ? &sc->models : nullptr);
404
405 writeString(compValue, fieldHeader, resourceName, "", a);
406 } else if (fieldType == TypeDatabase::getType<MeshHandle>()) {
407 auto resourceName = getResourceName(context, field->getPtr<MeshHandle>(component), sc ? &sc->meshes : nullptr);
408
409 writeString(compValue, fieldHeader, resourceName, "", a);
410 } else if (fieldType == TypeDatabase::getType<TextureHandle>()) {
411 auto resourceName = getResourceName(context, field->getPtr<TextureHandle>(component), sc ? &sc->textures : nullptr);
412
413 writeString(compValue, fieldHeader, resourceName, "", a);
414 } else if (fieldType == TypeDatabase::getType<MaterialInstanceHandle>()) {
415 auto resourceName = getResourceName(context, field->getPtr<MaterialInstanceHandle>(component), sc ? &sc->materialInstances : nullptr);
416
417 writeString(compValue, fieldHeader, resourceName, "", a);
418 } else if (fieldType == TypeDatabase::getType<MaterialInstanceHandle>()) {
419 auto resourceName = getResourceName(context, field->getPtr<MaterialInstanceHandle>(component), sc ? &sc->materialInstances : nullptr);
420
421 writeString(compValue, fieldHeader, resourceName, "", a);
422 }
423 else if (fieldType == TypeDatabase::getType<std::vector<glm::vec4>>()) {
424 if (saveGeometry) {
425 auto fieldValue = field->getPtr<std::vector<glm::vec4>>(component);
426 auto defaultFieldValue = field->getPtr<std::vector<glm::vec4>>(defaultComponent);
427
428 writeVectorVec(compValue, fieldHeader, *fieldValue, *defaultFieldValue, a);
429 }
430 }
431 else if (fieldType == TypeDatabase::getType<std::vector<glm::vec3>>()) {
432 if (saveGeometry) {
433 auto fieldValue = field->getPtr<std::vector<glm::vec3>>(component);
434 auto defaultFieldValue = field->getPtr<std::vector<glm::vec3>>(defaultComponent);
435
436 writeVectorVec(compValue, fieldHeader, *fieldValue, *defaultFieldValue, a);
437 }
438 } else if (fieldType == TypeDatabase::getType<std::vector<glm::vec2>>()) {
439 if (saveGeometry) {
440 auto fieldValue = field->getPtr<std::vector<glm::vec2>>(component);
441 auto defaultFieldValue = field->getPtr<std::vector<glm::vec2>>(defaultComponent);
442
443 writeVectorVec(compValue, fieldHeader, *fieldValue, *defaultFieldValue, a);
444 }
445 } else if (fieldType == TypeDatabase::getType<std::vector<int>>()) {
446 if (saveGeometry) {
447 auto fieldValue = field->getPtr<std::vector<int>>(component);
448 auto defaultFieldValue = field->getPtr<std::vector<int>>(defaultComponent);
449
450 writeVectorInt(compValue, fieldHeader, *fieldValue, *defaultFieldValue, a);
451 }
452 }
453 else if (fieldType == TypeDatabase::getType<std::vector<float>>()) {
454 if (saveGeometry) {
455 auto fieldValue = field->getPtr<std::vector<float>>(component);
456 auto defaultFieldValue = field->getPtr<std::vector<float>>(defaultComponent);
457
458 writeVectorDouble(compValue, fieldHeader, *fieldValue, *defaultFieldValue, a);
459 }
460 }
461 else if (fieldType == TypeDatabase::getType<std::vector<EntityPtr>>() && type->getName() == "SceneComponent") {
462 // SceneComponent::children Written later if enabled
463 }
464 else if (fieldType == TypeDatabase::getType<EntityPtr>()) {
465 // Ref to another entity
466 const EntityPtr& fieldValue = *field->getPtr<EntityPtr>(component);
467 if (fieldValue) {
468 const std::string& name = fieldValue->getName();
469 if (name.empty()) {
470 LOG_WARNING(logger, "Link to unnamed entity unsupported: Component: %s, Field: %s", type->getName().c_str(), fieldName.c_str());
471 }
472 else {
473 writeString(compValue, fieldHeader, "$" + name, "", a);
474 }
475 }
476 }
477 else if (fieldType == TypeDatabase::getType<WeakEntityPtr>()) {
478 // Ref to another entity
479 const EntityPtr& fieldValue = field->getPtr<WeakEntityPtr>(component)->lock();
480 if (fieldValue) {
481 const std::string& name = fieldValue->getName();
482 if (name.empty()) {
483 LOG_WARNING(logger, "Link to unnamed entity unsupported: Component: %s, Field: %s", type->getName().c_str(), fieldName.c_str());
484 }
485 else {
486 writeString(compValue, fieldHeader, "$" + name, "", a);
487 }
488 }
489 }
490 else {
491 // Write nothing
492 LOG_WARNING(logger, "Unsupported Field data type:%s, Component: %s, Field: %s",
493 fieldType.getName().c_str(), type->getName().c_str(), fieldName.c_str());
494 }
495 }
496
497 type = type->getBase();
498 }
499 }
500
501 entityValue.AddMember(Value(typeName.c_str(), a), compValue, a);
502 }
503
504 auto sceneComponent = entity->getComponent<SceneComponent>();
505 if (sceneComponent && entity->getComponent<ModelComponent>()) {
506 LOG_DEBUG(logger, "Skipping children of ModelComponent");
507 }
508 else if (sceneComponent && sceneComponent->children.size()) {
509 Value childrenValue(kArrayType);
510
511 for (auto & child : sceneComponent->children) {
512 Value childValue(kObjectType);
513
514 if ((flags & AssetWriteFlags::Hierarchy) == AssetWriteFlags::Hierarchy || context->store->hasEntityOwnership(child->getId())) {
515 writeEntity(context, child.get(), childValue, d, sc, flags);
516
517 childrenValue.PushBack(childValue, a);
518 }
519 }
520
521 entityValue.AddMember("children", childrenValue, a);
522 }
523}
524
525rapidjson::Document Cogs::Core::writeEntity(Context * context, ComponentModel::Entity * entity, const AssetWriteFlags flags)
526{
527 Document d;
528 d.SetObject();
529
530 writeEntity(context, entity, d, d, nullptr, flags);
531
532 return d;
533}
Container for components, providing composition of dynamic entities.
Definition: Entity.h:18
T * getComponent() const
Get a pointer to the first component implementing the given type in the entity.
Definition: Entity.h:35
void getComponents(ComponentCollection< T > &collection) const
Get all the components implementing the templated type.
Definition: Entity.h:52
const std::string & getName() const noexcept
Get the name of this entity.
Definition: Entity.h:120
constexpr void * getUserData() const noexcept
Get user data.
Definition: Entity.h:137
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Definition: Context.h:83
class EntityStore * store
Entity store.
Definition: Context.h:231
const EntityDefinition * getEntityDefinition(const StringView &name) const
Fetch the entity definition with the given name from the store.
Definition: EntityStore.cpp:92
bool hasEntityOwnership(const EntityId entityId) const
Check if the given entityId has global ownership in EntityStore.
Definition: EntityStore.h:260
Contains information on how the entity behaves in the scene.
Defines a 4x4 transformation matrix for the entity and a global offset for root entities.
uint32_t transformFlags
Transform flags.
glm::vec3 scale
Scale factor to apply to each of the axes.
glm::dvec3 coordinates
Global coordinates.
glm::quat rotation
Rotation given as a quaternion.
glm::vec3 position
Local position relative to the global coordinates, or the parent coordinate system if the parent fiel...
Log implementation class.
Definition: LogManager.h:139
Field definition describing a single data member of a data structure.
Definition: Field.h:68
const Name & getName() const
Get the name of the field.
Definition: Field.h:136
FieldFlags getFlags() const
Get the field flags.
Definition: Field.h:148
TypeId getTypeId() const
Get the type id of the field.
Definition: Field.h:140
FieldValueType * getPtr(void *container) const
Get a pointer to this field on the given container.
Definition: Field.h:112
static T * createInstance(const StringView &name)
Create an instance of the type with the given name.
Definition: TypeDatabase.h:206
static const Type & getType()
Get the Type of the given template argument.
Definition: TypeDatabase.h:168
constexpr const Name & getName() const
Get the unique name of the type.
Definition: Type.h:198
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
constexpr const char * data() const noexcept
Get the sequence of characters referenced by the string view.
Definition: StringView.h:171
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
std::shared_ptr< ComponentModel::Entity > EntityPtr
Smart pointer for Entity access.
Definition: EntityPtr.h:12
std::weak_ptr< ComponentModel::Entity > WeakEntityPtr
Weak Smart pointer for Entity access.
Definition: EntityPtr.h:18
AssetWriteFlags
Flags that control serialization of assets.
void COGSCORE_DLL_API writeEntity(Context *context, ComponentModel::Entity *entity, rapidjson::Value &object, rapidjson::Document &d, SerializationContext *sc=nullptr, const AssetWriteFlags flags=AssetWriteFlags::None)
Serialize entity adding entity to the given parent 'object'.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
Contains reflection support.
Definition: Component.h:11
@ NoSerialize
Skip Serialize field.
Holds extra housekeeping data for an Entity instance.
Definition: EntityStore.h:24
Defines how to construct entities of a certain type by a list of components to instantiate and defaul...
Contains a model reference to instance as children to the entity the ModelComponent belongs to.
const std::string & getName() const
Get the string name. This can be empty, even in valid instances of Name.
Definition: Name.h:112