ImGui
Using the ImGui integration plugin and the DataInspector resource.
The ImGui plugin allows you to integrate the Dear ImGui library with Cubos, making it quick, straightforward, and effortless to create user interfaces and interactive debugging tools within your applications.
First, let's start by including the header files we need.
#include <iostream> #include <map> #include <vector> #include <imgui.h> #include <cubos/core/reflection/external/map.hpp> #include <cubos/core/reflection/external/primitives.hpp> #include <cubos/core/reflection/external/string.hpp> #include <cubos/core/reflection/external/vector.hpp> #include <cubos/core/reflection/reflect.hpp> #include <cubos/core/reflection/traits/constructible.hpp> #include <cubos/core/reflection/traits/fields.hpp> #include <cubos/core/reflection/traits/nullable.hpp> #include <cubos/engine/imgui/data_inspector.hpp> #include <cubos/engine/imgui/plugin.hpp> #include <cubos/engine/render/target/plugin.hpp> #include <cubos/engine/settings/plugin.hpp> #include <cubos/engine/window/plugin.hpp>
Then, make sure to add the plugin.
cubos.plugin(settingsPlugin); cubos.plugin(windowPlugin); cubos.plugin(renderTargetPlugin); cubos.plugin(imguiPlugin);
When you're using ImGui directly in an application or a library, you must also make sure to initialize the ImGui context on it. To do so, you can add a startup system just like the one below:
cubos.startupSystem("set ImGui context").after(imguiInitTag).call([](ImGuiContextHolder& holder) { ImGui::SetCurrentContext(holder.context); });
You can read more about this in the documentation of cubos::
cubos.system("show ImGui demo").tagged(imguiTag).call([]() { ImGui::Begin("Dear ImGui + Cubos"); ImGui::Text("Hello world!"); ImGui::End(); ImGui::ShowDemoWindow(); });
Ensure that you add your system with the cubos.imgui
tag; otherwise, the ImGui elements from that system won't be be visible.
Pretty simple right? You're now equipped to craft and utilize ImGui's functions to design your cool user interface.
Now, we'll also show you how you can use the cubos::
To start off, we'll need to have some sort of dummy data shared across our application, so we can inspect/modify later. Let's create a DummyResource
with some fields and fill it with random data.
struct Person { CUBOS_REFLECT; std::string name; int32_t age; float weight; bool dead; }; CUBOS_REFLECT_IMPL(Person) { return Type::create("Person") .with(FieldsTrait() .withField("name", &Person::name) .withField("age", &Person::age) .withField("weight", &Person::weight) .withField("dead", &Person::dead)) .with(NullableTrait{[](const void* instance) { const auto* person = static_cast<const Person*>(instance); return person->dead; }, [](void* instance) { auto* person = static_cast<Person*>(instance); person->dead = true; }}) .with(ConstructibleTrait::typed<Person>().withDefaultConstructor().build()); } struct DummyResource { CUBOS_REFLECT; int integer; Person person; std::vector<Person> persons; std::vector<int32_t> vec; std::map<int32_t, int32_t> map; }; CUBOS_REFLECT_IMPL(DummyResource) { return Type::create("DummyResource") .with(FieldsTrait() .withField("integer", &DummyResource::integer) .withField("person", &DummyResource::person) .withField("persons", &DummyResource::persons) .withField("vec", &DummyResource::vec) .withField("v", &DummyResource::map)) .with(ConstructibleTrait::typed<DummyResource>().withDefaultConstructor().build()); }
cubos.resource<DummyResource>( DummyResource{.integer = 1337, .person = Person{"roby", 1337, 666.5F, false}, .persons{Person{"roby", 1337, 666.5F, false}, Person{"riscado", 123, 321.0F, false}}, .vec = {12, 59, 25}, .map = { {1, 2}, {2, 4}, {3, 6}, {4, 8}, }});
Well now, using the cubos::DataInspector::edit
and DataInspector::edit
.
cubos.system("data inspector example").tagged(imguiTag).call([](DataInspector& inspector, DummyResource& data) { ImGui::Begin("Data Inspector"); inspector.edit(data); ImGui::End(); });
You can find more about how to use Dear ImGui stuff here.