1#include "EntityInspector.h"
5#include "EntityStore.h"
8#include "Editor/IEditor.h"
10#include "InspectorGuiHelper.h"
11#include "Inspectors.h"
13#include "Components/Core/PropertiesComponent.h"
14#include "Components/Core/SceneComponent.h"
16#include "Resources/Resources.h"
17#include "Resources/TextureManager.h"
18#include "Renderer/Renderer.h"
19#include "Renderer/RenderTexture.h"
20#include "Resources/MaterialInstance.h"
21#include "Resources/Model.h"
22#include "Resources/Mesh.h"
24#include "Foundation/ComponentModel/Entity.h"
25#include "Foundation/Reflection/TypeDatabase.h"
29#define ENABLE_XML_EXPORT
30#if defined(ENABLE_XML_EXPORT)
31 #include "Foundation/Platform/IO.h"
36#include <glm/vec2.hpp>
37#include <glm/vec3.hpp>
38#include <glm/vec4.hpp>
39#include <glm/mat4x4.hpp>
40#include <glm/ext/quaternion_float.hpp>
52#if defined(ENABLE_XML_EXPORT)
55 void exportEntity(Context* context,
Entity* entity, std::string& dest) {
58 sprintf(buffer,
"<entity name='%s' id='%zu'>", entity->
getName().c_str(), entity->
getId());
62 const Component* component = componentHandle.resolve();
66 dest +=
"<component name='";
70 if (type == &TypeDatabase::getType<PropertiesComponent>()) {
71 const PropertiesComponent* propertiesComp =
static_cast<const PropertiesComponent*
>(component);
73 for (
const PropertyInfo& header : propertiesComp->properties.getHeaders()) {
74 StringView name = propertiesComp->properties.getKey(header);
81 switch (header.type) {
82 case PropertyType::Bool:
83 dest += header.boolValue ?
"true" :
"false";
85 case PropertyType::Integer:
86 sprintf(buffer,
"%d", header.intValue);
89 case PropertyType::UnsignedInteger:
90 sprintf(buffer,
"%u", header.uintValue);
93 case PropertyType::Float:
94 sprintf(buffer,
"%f", header.floatValue);
97 case PropertyType::Float2:
98 sprintf(buffer,
"%f,%f", header.float2Value[0], header.float2Value[1]);
101 case PropertyType::StringRef:
102 case PropertyType::String:
103 dest += propertiesComp->properties.getString(header).to_string();
105 case PropertyType::FloatArray:
106 for (
float value : propertiesComp->properties.getFloatArray(header.index)) {
107 sprintf(buffer,
"%f,", value);
110 dest.resize(dest.size() - 1);
120 for (; type; type = type->
getBase()) {
121 for (
size_t fieldIdx = 0, fieldCount = type->
getNumFields(); fieldIdx < fieldCount; ++fieldIdx) {
131 if (fieldType == TypeDatabase::getType<bool>()) {
132 dest += field->
getPtr<
bool>(component) ?
"true" :
"false";
134 else if (fieldType == TypeDatabase::getType<int32_t>()) {
135 sprintf(buffer,
"%d", *field->
getPtr<int32_t>(component));
138 else if (fieldType == TypeDatabase::getType<uint32_t>()) {
139 sprintf(buffer,
"%u", *field->
getPtr<uint32_t>(component));
142 else if (fieldType == TypeDatabase::getType<float>()) {
143 sprintf(buffer,
"%f", *field->
getPtr<
float>(component));
146 else if (fieldType == TypeDatabase::getType<glm::vec2>()) {
147 const glm::vec2* value = field->
getPtr<glm::vec2>(component);
148 sprintf(buffer,
"%f,%f", value->x, value->y);
151 else if (fieldType == TypeDatabase::getType<glm::vec3>()) {
152 const glm::vec3* value = field->
getPtr<glm::vec3>(component);
153 sprintf(buffer,
"%f,%f,%f", value->x, value->y, value->z);
156 else if (fieldType == TypeDatabase::getType<glm::vec4>()) {
157 const glm::vec4* value = field->
getPtr<glm::vec4>(component);
158 sprintf(buffer,
"%f,%f,%f,%f", value->x, value->y, value->z, value->w);
161 else if (fieldType == TypeDatabase::getType<glm::dvec2>()) {
162 const glm::dvec2* value = field->
getPtr<glm::dvec2>(component);
163 sprintf(buffer,
"%f,%f", value->x, value->y);
166 else if (fieldType == TypeDatabase::getType<glm::dvec3>()) {
167 const glm::dvec3* value = field->
getPtr<glm::dvec3>(component);
168 sprintf(buffer,
"%f,%f,%f", value->x, value->y, value->z);
171 else if (fieldType == TypeDatabase::getType<glm::dvec4>()) {
172 const glm::dvec4* value = field->
getPtr<glm::dvec4>(component);
173 sprintf(buffer,
"%f,%f,%f,%f", value->x, value->y, value->z, value->w);
176 else if (fieldType == TypeDatabase::getType<glm::ivec2>()) {
177 const glm::ivec2* value = field->
getPtr<glm::ivec2>(component);
178 sprintf(buffer,
"%d,%d", value->x, value->y);
181 else if (fieldType == TypeDatabase::getType<glm::ivec3>()) {
182 const glm::ivec3* value = field->
getPtr<glm::ivec3>(component);
183 sprintf(buffer,
"%d,%d,%d", value->x, value->y, value->z);
186 else if (fieldType == TypeDatabase::getType<glm::ivec4>()) {
187 const glm::ivec4* value = field->
getPtr<glm::ivec4>(component);
188 sprintf(buffer,
"%d,%d,%d,%d", value->x, value->y, value->z, value->w);
191 else if (fieldType == TypeDatabase::getType<glm::uvec2>()) {
192 const glm::uvec2* value = field->
getPtr<glm::uvec2>(component);
193 sprintf(buffer,
"%u,%u", value->x, value->y);
196 else if (fieldType == TypeDatabase::getType<glm::uvec3>()) {
197 const glm::uvec3* value = field->
getPtr<glm::uvec3>(component);
198 sprintf(buffer,
"%u,%u,%u", value->x, value->y, value->z);
201 else if (fieldType == TypeDatabase::getType<glm::uvec4>()) {
202 const glm::uvec4* value = field->
getPtr<glm::uvec4>(component);
203 sprintf(buffer,
"%d,%d,%d,%d", value->x, value->y, value->z, value->w);
206 else if (fieldType == TypeDatabase::getType<glm::mat4>()) {
207 const float* values = glm::value_ptr(*field->
getPtr<glm::mat4>(component));
208 sprintf(buffer,
"%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f", values[0], values[1], values[2], values[3], values[4], values[5], values[6], values[7], values[8], values[9], values[10], values[11], values[12], values[13], values[14], values[15]);
211 else if (fieldType == TypeDatabase::getType<glm::quat>()) {
212 const glm::quat* value = field->
getPtr<glm::quat>(component);
213 sprintf(buffer,
"%f,%f,%f,%f", value->x, value->y, value->z, value->w);
217 sprintf(buffer,
"0x%08X", *field->
getPtr<uint32_t>(component));
220 else if (fieldType.
isEnum()) {
221 uint32_t value = *field->
getPtr<uint32_t>(component);
223 for (
size_t idx = 0, enumCount = fieldType.
getNumEnumerators(); idx < enumCount; ++idx) {
231 dest.resize(dest.size() - name.size() - 3);
233 const std::vector<EntityPtr>* childEntities = field->
getPtr<std::vector<EntityPtr>>(component);
235 if (!childEntities->empty()) {
236 children.reserve(1048576);
240 for (
const EntityPtr& child : *childEntities) {
241 exportEntity(context, child.get(), children);
249 else if (fieldType == TypeDatabase::getType<std::string>()) {
250 dest += *field->
getPtr<std::string>(component);
253 const std::vector<std::string>* values = field->
getPtr<std::vector<std::string>>(component);
255 if (!values->empty()) {
256 for (
const std::string& str : *values) {
260 dest.resize(dest.size() - 1);
264 dest +=
"UNSUPPORTED";
270 if (children.empty()) {
276 dest +=
"</component>";
284void Cogs::Core::showCollapsableEntityInspector(
Cogs::Core::Context* context,
const ComponentModel::Entity* entity, std::string_view entityNamePattern, std::string_view componentNamePattern,
bool showBorder)
287 std::array<char, 128> header = {};
288 std::snprintf(header.data(), header.size(),
"%s Id: %zu", entity->
getName().c_str(), entity->
getId());
290 ImGui::PushID(entity);
292 if (ImGui::TreeNodeEx(header.data(), ImGuiTreeNodeFlags_NoAutoOpenOnLog | (showBorder ? ImGuiTreeNodeFlags_Framed : 0))) {
294 showEntityInspector(context, entity, entityNamePattern, componentNamePattern, showBorder);
303void Cogs::Core::showEntities(Context * context, std::span<const EntityPtr> entities, std::string_view entityNamePattern, std::string_view componentNamePattern)
305 for (
const EntityPtr & e : entities) {
306 showCollapsableEntityInspector(context, e.get(), entityNamePattern, componentNamePattern);
310void Cogs::Core::showEntityInspector(Context* context,
const ComponentModel::Entity* entity, std::string_view entityNamePattern, std::string_view componentNamePattern,
bool showBorder)
312 ImGui::Text(
"Id: %zd", entity->
getId());
314 const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
315 static std::array<char, 65> buffer;
316 ImGui::SameLine(0.0f, spacing);
317 constexpr int widthInputText = 120;
318 ImGui::PushItemWidth(widthInputText);
319 ImGui::Text(
"Filter: ");
320 ImGui::SameLine(0.0f, spacing);
321 if (ImGui::InputText(
" ", buffer.data(), buffer.size(), ImGuiInputTextFlags_None)) {
322 ImguiRenderer* guiRenderer = context->renderer->getGuiRenderer();
324 guiRenderer->addTextToGlyphBuilder(buffer.data());
327 ImGui::PopItemWidth();
329 std::string_view findPattern = buffer.data();
334 bool showComponent = (bool)component;
335 if(showComponent && !findPattern.empty()) {
336 showComponent = containsInvariantCase(component->
getType().
getName().
c_str(), findPattern);
340 showComponentInspector(context, component, entityNamePattern, componentNamePattern, showBorder);
345void Cogs::Core::showComponentInspector(Context* context,
ComponentModel::Component* component, std::string_view entityNamePattern, std::string_view componentNamePattern,
bool showBorder)
349 if (ImGui::TreeNodeEx(componentType->
getName().
getName().c_str(), ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog | (showBorder ? ImGuiTreeNodeFlags_Framed : 0))) {
350 ImGui::PushID(component);
352 const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
353 static std::array<char, 65> buffer;
354 ImGui::SameLine(0.0f, spacing);
355 constexpr int widthInputText = 120;
356 ImGui::PushItemWidth(widthInputText);
357 ImGui::Text(
"Filter: ");
358 ImGui::SameLine(0.0f, spacing);
359 if (ImGui::InputText(
" ", buffer.data(), buffer.size(), ImGuiInputTextFlags_None)) {
360 ImguiRenderer* guiRenderer = context->renderer->getGuiRenderer();
362 guiRenderer->addTextToGlyphBuilder(buffer.data());
365 ImGui::PopItemWidth();
366 auto updateGui = componentType->
getMethod(
"updateGui");
368 updateGui->
call(component);
373 std::string_view findPattern = buffer.data();
376 ScopedIndent si_type;
379 for (FieldId fieldId = 0; fieldId < numFields; ++fieldId) {
380 bool showField =
true;
381 if(!findPattern.empty()) {
382 showField = containsInvariantCase(componentType->
getField(fieldId)->
getName().
c_str(), findPattern);
386 showFieldInspector(context, component, fieldId, entityNamePattern, componentNamePattern, showBorder);
394void Cogs::Core::showFieldInspector(Context* context,
ComponentModel::Component* component, FieldId fieldId, std::string_view entityNamePattern, std::string_view componentNamePattern,
bool showBorder)
401 const std::string & fieldHeader = fieldName.
getName();
405 if (fieldType == TypeDatabase::getType<int32_t>()) {
406 auto fieldValue = field->
getPtr<int32_t>(component);
409 const int32_t min = std::min(range->getMin(), *fieldValue);
410 const int32_t max = std::max(range->getMax(), *fieldValue);
411 if (ImGui::SliderInt(fieldHeader.c_str(), fieldValue, min, max)) {
416 if (ImGui::DragInt(fieldHeader.c_str(), fieldValue)) {
421 else if (fieldType == TypeDatabase::getType<float>()) {
422 auto fieldValue = field->
getPtr<
float>(component);
426 const float min = std::min(range ? range->getMin() : 0.0f, *fieldValue);
427 const float max = std::max(range ? range->getMax() : 100.0f, *fieldValue);
428 const float stepValue = (max - min) / 100.f;
430 if (ImGui::DragFloat(fieldHeader.c_str(), fieldValue, stepValue, min, max)) {
435 if (ImGui::DragFloat(fieldHeader.c_str(), fieldValue)) {
440 else if (fieldType == TypeDatabase::getType<glm::vec2>()) {
441 auto fieldValue = field->
getPtr<glm::vec2>(component);
443 if (ImGui::DragFloat2(fieldHeader.c_str(), glm::value_ptr(*fieldValue))) {
447 else if (fieldType == TypeDatabase::getType<glm::vec3>()) {
448 auto fieldValue = field->
getPtr<glm::vec3>(component);
450 if (ImGui::DragFloat3(fieldHeader.c_str(), glm::value_ptr(*fieldValue))) {
454 else if (fieldType == TypeDatabase::getType<glm::vec4>()) {
455 auto fieldValue = field->
getPtr<glm::vec4>(component);
459 if (ca || (fieldName.
getName().find(
"olor") != std::string::npos)) {
460 if (ImGui::ColorEdit4(fieldHeader.c_str(), glm::value_ptr(*fieldValue))) {
464 if (ImGui::DragFloat4(fieldHeader.c_str(), glm::value_ptr(*fieldValue))) {
469 else if (fieldType == TypeDatabase::getType<glm::ivec2>()) {
470 auto fieldValue = field->
getPtr<glm::ivec2>(component);
471 if (ImGui::DragInt2(fieldHeader.c_str(), glm::value_ptr(*fieldValue))) {
475 else if (fieldType == TypeDatabase::getType<glm::ivec3>()) {
476 auto fieldValue = field->
getPtr<glm::ivec3>(component);
477 if (ImGui::DragInt3(fieldHeader.c_str(), glm::value_ptr(*fieldValue))) {
481 else if (fieldType == TypeDatabase::getType<glm::ivec4>()) {
482 auto fieldValue = field->
getPtr<glm::ivec4>(component);
483 if (ImGui::DragInt4(fieldHeader.c_str(), glm::value_ptr(*fieldValue))) {
487 else if (fieldType == TypeDatabase::getType<glm::uvec2>()) {
488 auto fieldValue = field->
getPtr<glm::uvec2>(component);
489 glm::ivec2 tmp = *fieldValue;
490 if (ImGui::DragInt2(fieldHeader.c_str(), glm::value_ptr(tmp))) {
495 else if (fieldType == TypeDatabase::getType<glm::uvec3>()) {
496 auto fieldValue = field->
getPtr<glm::uvec3>(component);
497 glm::ivec3 tmp = *fieldValue;
498 if (ImGui::DragInt3(fieldHeader.c_str(), glm::value_ptr(tmp))) {
503 else if (fieldType == TypeDatabase::getType<glm::uvec4>()) {
504 auto fieldValue = field->
getPtr<glm::uvec4>(component);
505 glm::ivec4 tmp = *fieldValue;
506 if (ImGui::DragInt4(fieldHeader.c_str(), glm::value_ptr(tmp))) {
511 else if (fieldType == TypeDatabase::getType<glm::dvec2>()) {
512 auto fieldValue = field->
getPtr<glm::dvec2>(component);
514 glm::vec2 fValues(*fieldValue);
516 if (ImGui::DragFloat2(fieldHeader.c_str(), glm::value_ptr(fValues))) {
517 *fieldValue = glm::dvec2(fValues);
521 else if (fieldType == TypeDatabase::getType<glm::dvec3>()) {
522 auto fieldValue = field->
getPtr<glm::dvec3>(component);
524 glm::vec3 fValues(*fieldValue);
526 if (ImGui::DragFloat3(fieldHeader.c_str(), glm::value_ptr(fValues))) {
527 *fieldValue = glm::dvec3(fValues);
531 else if (fieldType == TypeDatabase::getType<glm::quat>()) {
532 auto fieldValue = field->
getPtr<glm::quat>(component);
534 glm::vec3 euler = glm::eulerAngles(*fieldValue);
535 if (ImGui::DragFloat3(
"Euler", glm::value_ptr(euler), 0.01f, -3.14f, 3.14f)) {
536 float eps = 0.00001f;
537 if (euler.y >= glm::pi<float>() / 2.0f - eps)
538 euler.y = glm::pi<float>() / 2.0f - eps;
539 else if (euler.y <= -glm::pi<float>() / 2.0f + eps)
540 euler.y = -glm::pi<float>() / 2.0f + eps;
541 *fieldValue = glm::quat(euler);
546 if (ImGui::DragFloat4(fieldHeader.c_str(), glm::value_ptr(*fieldValue), 0.01f, 0, 1)) {
550 else if (fieldType == TypeDatabase::getType<glm::mat4>()) {
551 auto fieldValue = field->
getPtr<glm::mat4>(component);
553 ImGui::PushID(field);
555 if (showMatrix(fieldHeader, *fieldValue)) {
560 else if (fieldType == TypeDatabase::getType<bool>()) {
561 auto fieldValue = field->
getPtr<
bool>(component);
563 if (ImGui::Checkbox(fieldHeader.c_str(), fieldValue)) {
567 else if (fieldType == TypeDatabase::getType<uint32_t>()) {
568 auto fieldValue = field->
getPtr<uint32_t>(component);
569 ImGui::Text(
"%s: 0x%08x", fieldHeader.c_str(), *fieldValue);
571 int tmp =
static_cast<int>(*fieldValue);
574 const int min = std::min(tmp,
static_cast<int>(range->getMin()));
575 const int max = std::max(tmp,
static_cast<int>(range->getMax()));
576 if (ImGui::SliderInt(fieldHeader.c_str(), &tmp, min, max)) {
577 *fieldValue =
static_cast<uint32_t
>(tmp);
582 if (ImGui::DragInt(fieldHeader.c_str(), &tmp)) {
583 *fieldValue =
static_cast<uint32_t
>(tmp);
588 else if (fieldType.
isEnum()) {
589 auto fieldValue = field->
getPtr<uint32_t>(component);
590 auto value = *fieldValue;
593 ImGui::Text(
"%s (%d = 0x%08X):", fieldHeader.c_str(), value, value);
596 ImGui::PushID(field);
600 for (
size_t i = 0; i < numEnums; ++i) {
602 auto enumeratorValue = enumerator->
getValue();
604 if (std::popcount(
static_cast<uint32_t
>(enumeratorValue)) != 1)
continue;
606 if (ImGui::CheckboxFlags(enumerator->getName().c_str(), &value, enumeratorValue)) {
616 std::vector<const char *> enumNames(enums);
617 std::vector<int> enumValues(enums);
619 for (
size_t i = 0; i < enums; ++i) {
622 if (enumValues[i] ==
static_cast<int>(*fieldValue)) index =
static_cast<int>(i);
625 if (ImGui::Combo(fieldHeader.c_str(), &index, enumNames.data(),
static_cast<int>(enumNames.size()))) {
626 *fieldValue = enumValues[index];
632 auto fieldValue = field->
getPtr<std::vector<EntityPtr>>(component);
633 showEntities(context, *fieldValue, entityNamePattern, componentNamePattern);
635 else if (fieldType == TypeDatabase::getType<MeshHandle>()) {
636 auto & fieldValue = *field->
getPtr<MeshHandle>(component);
639 showMesh(context, fieldValue.resolve(), fieldHeader);
644 else if (fieldType == TypeDatabase::getType<TextureHandle>()) {
647 auto editor = context->engine->getEditor();
648 if (editor && editor->isActive()) {
649 if (editor->showTexture(field->
getName().
c_str(), *fieldValue)) {
655 if (ImGui::CollapsingHeader(field->
getName().
c_str())) {
656 Texture* texture = fieldValue->resolve();
658 showTexture(context, renderer, texture);
666 else if (fieldType == TypeDatabase::getType<WeakEntityPtr>()) {
668 if (
auto spt = fieldValue->lock())
670 showEntityInspector(context, &(*spt), entityNamePattern, componentNamePattern, showBorder);
675 else if (fieldType == TypeDatabase::getType<std::string>()) {
676 auto fieldValue = field->
getPtr<std::string>(component);
677 std::string buffer = *fieldValue;
679 if (ImGui::InputText(field->
getName().
c_str(), &buffer[0], buffer.size())) {
680 for (
size_t i = 0; i < buffer.size(); i++) {
681 if (buffer[i] ==
'\0') {
687 ImguiRenderer* guiRenderer = context->renderer->getGuiRenderer();
689 guiRenderer->addTextToGlyphBuilder(buffer.c_str());
692 *fieldValue = std::move(buffer);
696 auto fieldValue = field->
getPtr<std::vector<std::string>>(component);
697 if (fieldValue->empty())
703 if (ImGui::CollapsingHeader(std::string(fieldHeader +
" [size=" + std::to_string(fieldValue->size()) +
"]").c_str()))
706 for (
auto& s : *fieldValue) {
707 auto label = std::to_string(i++);
708 std::string buffer = s;
710 if (ImGui::InputText(label.c_str(), &buffer[0], buffer.size())) {
712 ImguiRenderer* guiRenderer = context->renderer->getGuiRenderer();
714 guiRenderer->addTextToGlyphBuilder(buffer.c_str());
724 auto fieldValue = field->
getPtr<std::vector<int32_t>>(component);
730 auto fieldValue = field->
getPtr<std::vector<uint32_t>>(component);
736 auto fieldValue = field->
getPtr<std::vector<float>>(component);
742 auto fieldValue = field->
getPtr<std::vector<glm::vec3>>(component);
743 if (showArray3D(fieldHeader, *fieldValue)) {
748 auto fieldValue = field->
getPtr<std::vector<glm::vec2>>(component);
749 if (fieldValue->empty())
753 else if (ImGui::CollapsingHeader(fieldHeader.c_str())) {
756 for (
auto& v : *fieldValue) {
757 auto label = std::to_string(i++);
758 if (ImGui::DragFloat2(label.c_str(), glm::value_ptr(v))) {
765 auto fieldValue = field->
getPtr<std::vector<glm::vec4>>(component);
766 if (fieldValue->empty()) {
769 else if (ImGui::CollapsingHeader(fieldHeader.c_str())) {
772 for (
auto& v : *fieldValue) {
773 auto label = std::to_string(i++);
774 if (ImGui::DragFloat4(label.c_str(), glm::value_ptr(v))) {
780 else if (fieldType == TypeDatabase::getType<MaterialInstanceHandle>()) {
781 auto fieldValue = field->
getPtr<MaterialInstanceHandle>(component);
783 auto * material = fieldValue->resolve();
785 showMaterialInstance(context, material, header);
788 ImGui::Text(
"%s: NULL", header.c_str());
792 auto fieldValue = field->
getPtr<std::vector<MaterialInstanceHandle>>(component);
793 if (fieldValue->empty()) {
796 else if (ImGui::CollapsingHeader(fieldHeader.c_str())) {
799 for (
auto& v : *fieldValue) {
800 auto* material = v.resolve();
802 auto label =
"Mat: " + std::to_string(i++);
804 showMaterialInstance(context, material, label);
807 ImGui::Text(
"%s: NULL", label.c_str());
812 else if (fieldType == TypeDatabase::getType<EntityPtr>()) {
814 if (fieldValue->get()) {
815 showEntityInspector(context, fieldValue->get(), entityNamePattern, componentNamePattern, showBorder);
821 else if (fieldType == TypeDatabase::getType<Cogs::Core::FontHandle>()) {
823 if (fieldValue->get()) {
826 ImGui::Text(
"%d", fieldValue->getId());
832 else if (fieldType == TypeDatabase::getType<ModelHandle>()) {
833 auto fieldValue = field->
getPtr<ModelHandle>(component);
835 Model * model = fieldValue->resolve();
837 auto header = (!model->getName().empty() ? model->getName() :
"Model");
838 showModel(context, model, std::string(header));
843 else if (fieldType == TypeDatabase::getType<PropertyStore>()) {
844 PropertyStore* propStore = field->
getPtr<PropertyStore>(component);
845 assert(propStore !=
nullptr);
848 const std::string propName(propStore->getKey(header));
850 switch(header.type) {
851 case Cogs::Core::PropertyType::Bool: {
852 ImGui::Text(
"%s: %s", propName.c_str(), header.boolValue ?
"true" :
"false");
855 case Cogs::Core::PropertyType::Integer: {
856 ImGui::Text(
"%s: %d", propName.c_str(), header.intValue);
859 case Cogs::Core::PropertyType::Int2: {
860 ImGui::Text(
"%s: (%d, %d)", propName.c_str(), header.int2Value[0], header.int2Value[1]);
863 case Cogs::Core::PropertyType::UnsignedInteger: {
864 ImGui::Text(
"%s: %u", propName.c_str(), header.uintValue);
867 case Cogs::Core::PropertyType::UInt2: {
868 ImGui::Text(
"%s: (%u, %u)", propName.c_str(), header.uint2Value[0], header.uint2Value[1]);
871 case Cogs::Core::PropertyType::Float: {
872 ImGui::Text(
"%s: %f", propName.c_str(), header.floatValue);
875 case Cogs::Core::PropertyType::Float2: {
876 ImGui::Text(
"%s: (%f, %f)", propName.c_str(), header.float2Value[0], header.float2Value[1]);
879 case Cogs::Core::PropertyType::Double: {
880 ImGui::Text(
"%s: %f", propName.c_str(), header.doubleValue);
883 case Cogs::Core::PropertyType::StringRef: {
884 ImGui::Text(
"%s: %s", propName.c_str(), Cogs::Core::Strings::getC(header.stringRefValue));
887 case Cogs::Core::PropertyType::String: {
888 ImGui::Text(
"%s: %.*s", propName.c_str(), StringViewFormat(propStore->getString(header)));
891 case Cogs::Core::PropertyType::FloatArray: {
892 showArray1D(propName, propStore->getFloatArray(header));
895 case Cogs::Core::PropertyType::IntArray: {
896 showArray1D(propName, propStore->getIntArray(header));
899 case Cogs::Core::PropertyType::UIntArray: {
900 showArray1D(propName, propStore->getUIntArray(header));
903 case Cogs::Core::PropertyType::DoubleArray: {
904 showArray1D(propName, propStore->getDoubleArray(header));
908 assert(
false &&
"Unsupported PropertyType");
918void Cogs::Core::entityInspector(Context * context,
bool * show)
921 ImGui::SetNextWindowSize(ImVec2(400, 1000), ImGuiCond_Once);
923 guiBegin(
"Entities", show);
925 const std::unordered_map<EntityId, EntityPtr>& entities = context->store->getEntities();
927#if defined(ENABLE_XML_EXPORT)
928 static char filename[1024];
931 if (ImGui::Button(
"Export XML to >")) {
935 dest.reserve(1048576);
936 dest =
"<?xml version='1.0'?><entities>";
937 for (
const auto& [
id, entity] : entities) {
939 exportEntity(context, entity.get(), dest);
942 dest +=
"</entities>";
943 IO::writeBinaryFile(filename, dest.data(), dest.size());
947 ImGui::InputText(
"Filename", filename,
sizeof(filename));
951 static bool onlyRootEntities =
true;
952 size_t numEntities = 0;
953 if (onlyRootEntities) {
954 for (
const auto& [
id, entity] : entities) {
955 if (context->store->getEntityParent(entity.get()) ==
nullptr) {
961 numEntities = entities.size();
964 ImGui::Text(
"Entities: %zu", numEntities);
966 const float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
967 ImGui::SameLine(0.0f, spacing);
969 ImGui::SameLine(0.0f, spacing);
970 if (ImGui::RadioButton(
"Root Entities", onlyRootEntities ==
true)) { onlyRootEntities =
true; }
971 ImGui::SameLine(0.0f, spacing);
972 if (ImGui::RadioButton(
"All User", onlyRootEntities ==
false)) { onlyRootEntities =
false; }
975 std::string_view entityNamePattern;
977 static std::array<char, 33> nameFilterBuffer;
978 constexpr int widthInputText = 120;
979 ImGui::PushItemWidth(widthInputText);
980 ImGui::Text(
"Name:");
981 ImGui::SameLine(0.0f, spacing);
982 if (ImGui::InputText(
" ", nameFilterBuffer.data(), nameFilterBuffer.size(), ImGuiInputTextFlags_None)) {
983 ImguiRenderer* guiRenderer = context->renderer->getGuiRenderer();
985 guiRenderer->addTextToGlyphBuilder(nameFilterBuffer.data());
988 entityNamePattern = nameFilterBuffer.data();
991 std::string_view componentNamePattern;
993 static std::array<char, 33> componentFilterBuffer;
994 ImGui::SameLine(0.0f, spacing);
995 ImGui::Text(
"Componen:");
996 ImGui::SameLine(0.0f, spacing);
997 if (ImGui::InputText(
" ", componentFilterBuffer.data(), componentFilterBuffer.size(), ImGuiInputTextFlags_None)) {
998 ImguiRenderer* guiRenderer = context->renderer->getGuiRenderer();
1000 guiRenderer->addTextToGlyphBuilder(componentFilterBuffer.data());
1003 componentNamePattern = componentFilterBuffer.data();
1006 ImGui::PopItemWidth();
1010 bool showOnlyMultiRefs =
false;
1011 if (!entityNamePattern.empty() && entityNamePattern[0] ==
'+') {
1012 showOnlyMultiRefs =
true;
1013 entityNamePattern = entityNamePattern.substr(1);
1017 ImGui::BeginChild(
"Child");
1018 for (
const auto& [
id, entity] : entities) {
1019 bool showEntity = entity.operator bool();
1020 if (showOnlyMultiRefs) {
1021 showEntity = entity.use_count() > 1;
1024 if (showEntity && (!entityNamePattern.empty() || !componentNamePattern.empty())) {
1028 if (showEntity && onlyRootEntities) {
1029 showEntity = context->store->getEntityParent(entity.get()) ==
nullptr;
1033 showCollapsableEntityInspector(context, entity.get(), entityNamePattern, componentNamePattern);
Base class for Component instances.
void setFieldChanged(const Reflection::FieldId fieldId)
Sets the component to the ComponentFlags::Changed state without carry.
COGSFOUNDATION_API const Reflection::Type & getType() const
Get the full Reflection::Type of the component.
Container for components, providing composition of dynamic entities.
constexpr size_t getId() const noexcept
Get the unique identifier of this entity.
void getComponents(ComponentCollection< T > &collection) const
Get all the components implementing the templated type.
const std::string & getName() const noexcept
Get the name of this entity.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Field definition describing a single data member of a data structure.
const Name & getName() const
Get the name of the field.
const T * get() const
Retrieve an attribute of the given type from storage, if present.
TypeId getTypeId() const
Get the type id of the field.
FieldValueType * getPtr(void *container) const
Get a pointer to this field on the given container.
void call(Class *object, Arg... arg) const
Call the method named name on the given object, with the given arguments.
static const Type & getType()
Get the Type of the given template argument.
Represents a discrete type definition, describing a native type class.
const Type * getBase() const
Get the base type.
size_t getNumFields() const
Get the number of fields in the type.
const Enumerator * getEnumerator(const Name &name) const
Get a pointer to the enumerator with the given name.
const Method * getMethod(const Name &name) const
Get a pointer to the method with the given name.
bool isEnum() const
Get if the type is an enumeration type.
constexpr const Name & getName() const
Get the unique name of the type.
bool isEnumFlags() const
Get if the type is a flag enumeration type.
size_t getNumHierarchyFields() const
Get the number of fields in the type + types in all base types.
size_t getNumEnumerators() const
Get the number of enumerators in the type.
const Field * getField(const Name &name) const
Get a pointer to the field info of the field with the given name.
constexpr TypeId getTypeId() const
Get the unique Reflection::TypeId of this instance.
Provides a weakly referenced view over the contents of a string.
constexpr bool empty() const noexcept
Check if the string is empty.
std::string to_string() const
String conversion method.
Contains code for composing and managing entities built from components.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
bool findHierarchyWithMatch(const Cogs::ComponentModel::Entity &entity, std::string_view entityNamePattern, std::string_view componentNamePattern)
std::shared_ptr< ComponentModel::Entity > EntityPtr
Smart pointer for Entity access.
std::weak_ptr< ComponentModel::Entity > WeakEntityPtr
Weak Smart pointer for Entity access.
bool showArray1D(const std::string &header, std::span< T > array)
Contains reflection support.
Tags an object as being able to represent a color.
Handle to a Component instance.
Adds range information to an object.
const Name & getName() const
Get the name of the enumerator.
int getValue() const
Get the value of the enumerator.
Represents an unique name.
const char * c_str() const
Gets the name as a null-terminated string.
const std::string & getName() const
Get the string name. This can be empty, even in valid instances of Name.