Skip to content

Commit 843d531

Browse files
authored
Inspector refactor (#66)
* Move SceneResources to dedicated header - Make mut and const versions. * WIP: Inspector refactor * WIP: contd * Remove old inspector * Enable adding new materials and meshes * Cleanup * Use typeid::name() for payload type - Add docs. * Split Inspector, add docs - `ResourceInspector`: unframed nodes. - `SceneInspector`: framed nodes. * Enable orientation reset - Fixup default sizes and positions of editor windows.
1 parent 0b62003 commit 843d531

File tree

19 files changed

+662
-406
lines changed

19 files changed

+662
-406
lines changed

lib/engine/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@ target_sources(${PROJECT_NAME} PRIVATE
4242

4343
include/${target_prefix}/engine/editor/browse_file.hpp
4444
include/${target_prefix}/engine/editor/common.hpp
45+
include/${target_prefix}/engine/editor/drag_drop_id.hpp
4546
include/${target_prefix}/engine/editor/inspector.hpp
4647
include/${target_prefix}/engine/editor/log.hpp
48+
include/${target_prefix}/engine/editor/reflector.hpp
4749
include/${target_prefix}/engine/editor/scene_tree.hpp
4850

4951
src/scene_renderer.cpp
@@ -53,5 +55,6 @@ target_sources(${PROJECT_NAME} PRIVATE
5355
src/editor/common.cpp
5456
src/editor/inspector.cpp
5557
src/editor/log.cpp
58+
src/editor/reflector.cpp
5659
src/editor/scene_tree.cpp
5760
)

lib/engine/include/facade/engine/editor/common.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,20 @@ class Engine;
1111
}
1212

1313
namespace facade::editor {
14+
///
15+
/// \brief Obtain the maximum width and height of a number of ImGui Texts.
16+
/// \param strings Array of C strings to compute sizes of
17+
/// \returns Maximum width and height (independent) of all strings
18+
///
19+
glm::vec2 max_size(std::span<char const* const> strings);
20+
21+
///
22+
/// \brief Create a small red button.
23+
/// \param label Label on the button
24+
/// \returns true if clicked
25+
///
26+
bool small_button_red(char const* label);
27+
1428
///
1529
/// \brief Base class for RAII Dear ImGui wrappers whose widgets return a boolean on Begin()
1630
///
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#pragma once
2+
#include <imgui.h>
3+
#include <facade/engine/editor/common.hpp>
4+
#include <facade/scene/node.hpp>
5+
#include <facade/util/fixed_string.hpp>
6+
#include <optional>
7+
#include <typeinfo>
8+
9+
namespace facade::editor {
10+
///
11+
/// \brief Initiate dragging an Id<T> drag-drop payload.
12+
/// \param out Id to store as the drag-drop payload
13+
/// \param label Label to display on drag
14+
/// \returns true if dragging is engaged
15+
///
16+
template <typename T>
17+
bool drag_payload(Id<T> id, char const* label) {
18+
if (ImGui::BeginDragDropSource()) {
19+
ImGui::SetDragDropPayload(typeid(id).name(), &id, sizeof(id));
20+
if (label && *label) { ImGui::Text("%s", label); }
21+
ImGui::EndDragDropSource();
22+
return true;
23+
}
24+
return false;
25+
}
26+
27+
///
28+
/// \brief Accept dropping an Id<T> drag-drop payload.
29+
/// \param out Id to write payload to
30+
/// \returns true if payload accepted
31+
///
32+
template <typename T>
33+
bool accept_drop(Id<T>& out) {
34+
if (ImGui::BeginDragDropTarget()) {
35+
if (ImGuiPayload const* payload = ImGui::AcceptDragDropPayload(typeid(out).name())) {
36+
assert(payload->DataSize == sizeof(out));
37+
out = *reinterpret_cast<Id<T>*>(payload->Data);
38+
return true;
39+
}
40+
ImGui::EndDragDropTarget();
41+
}
42+
return false;
43+
}
44+
45+
///
46+
/// \brief Create a potentially nullable drag-drop Id slot.
47+
/// \param out_id Id to use for drag-drop payload
48+
/// \param label Label to use for the slot
49+
/// \param payload_name Label to use when dragging payload
50+
/// \param removable Whether to allow nulling out out_id
51+
///
52+
template <typename T>
53+
void make_id_slot(std::optional<Id<T>>& out_id, char const* label, char const* payload_name, Bool removable) {
54+
ImGui::Text("%s", label);
55+
if (out_id) {
56+
if (removable) {
57+
ImGui::SameLine();
58+
if (small_button_red(FixedString{"x###remove_{}", label}.c_str())) {
59+
out_id = {};
60+
return;
61+
}
62+
}
63+
ImGui::SameLine();
64+
auto const name = FixedString{"{} ({})", payload_name, *out_id};
65+
ImGui::Selectable(name.c_str());
66+
drag_payload(*out_id, name.c_str());
67+
accept_drop(*out_id);
68+
} else {
69+
ImGui::SameLine();
70+
ImGui::Selectable("[None]");
71+
auto id = Id<T>{};
72+
if (accept_drop(id)) { out_id = id; }
73+
}
74+
}
75+
76+
///
77+
/// \brief Create a drag-drop Id slot.
78+
/// \param out_id Id to use for drag-drop payload
79+
/// \param label Label to use for the slot
80+
/// \param payload_name Label to use when dragging payload
81+
///
82+
template <typename T>
83+
void make_id_slot(Id<T>& out_id, char const* label, char const* payload_name) {
84+
auto id = std::optional<Id<T>>{out_id};
85+
make_id_slot(id, label, payload_name, {false});
86+
out_id = *id;
87+
}
88+
89+
///
90+
/// \brief Create a drag-drop Id slot.
91+
/// \param out_node Node to attach / detach Id<T> drag-drop payloads to / from
92+
/// \param label Label to use for the slot
93+
/// \param payload_name Label to use when dragging payload
94+
///
95+
template <typename T>
96+
void make_id_slot(Node& out_node, char const* label, char const* payload_name) {
97+
auto oid = std::optional<Id<T>>{};
98+
auto* id = out_node.find<Id<T>>();
99+
if (id) { oid = *id; }
100+
make_id_slot(oid, label, payload_name, {true});
101+
if (id) {
102+
if (!oid) {
103+
out_node.detach<Id<T>>();
104+
} else {
105+
*id = *oid;
106+
}
107+
} else {
108+
if (oid) { out_node.attach(*oid); }
109+
}
110+
}
111+
} // namespace facade::editor
Lines changed: 91 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,112 @@
11
#pragma once
22
#include <facade/engine/editor/common.hpp>
3-
#include <facade/scene/material.hpp>
4-
#include <facade/scene/node.hpp>
5-
#include <facade/util/nvec3.hpp>
6-
#include <facade/util/rgb.hpp>
7-
#include <limits>
3+
#include <facade/scene/scene.hpp>
84

9-
namespace facade {
10-
struct Camera;
11-
struct Mesh;
12-
struct Lights;
13-
struct SceneResources;
14-
class Scene;
15-
16-
namespace editor {
5+
namespace facade::editor {
6+
///
7+
/// \brief Base class for Inspectors.
178
///
18-
/// \brief Stateless ImGui helper to inspect / reflect various properties
9+
/// Inspectors are stateless ImGui helpers to view / edit various components, with drag-and-drop support.
1910
///
2011
class Inspector {
21-
public:
22-
static constexpr auto min_v{-std::numeric_limits<float>::max()};
23-
static constexpr auto max_v{std::numeric_limits<float>::max()};
24-
12+
protected:
2513
///
26-
/// \brief Construct an Inspector instance
14+
/// \brief Construct an Inspector instance.
2715
///
2816
/// Inspectors don't do anything on construction, constructors exist to enforce invariants instance-wide.
29-
/// For all Inspectors, an existing Window target is required, Inspector instances will not create any
17+
/// For all Inspectors, an existing Window target is required, Inspector instances will not create any.
3018
///
31-
Inspector(NotClosed<Window>) {}
32-
33-
bool inspect(char const* label, glm::vec2& out_vec2, float speed = 1.0f, float lo = min_v, float hi = max_v) const;
34-
bool inspect(char const* label, glm::vec3& out_vec3, float speed = 1.0f, float lo = min_v, float hi = max_v) const;
35-
bool inspect(char const* label, glm::vec4& out_vec4, float speed = 1.0f, float lo = min_v, float hi = max_v) const;
36-
bool inspect(char const* label, nvec3& out_vec3, float speed = 0.01f) const;
37-
bool inspect(char const* label, glm::quat& out_quat) const;
38-
bool inspect_rgb(char const* label, glm::vec3& out_rgb) const;
39-
bool inspect(char const* label, Rgb& out_rgb) const;
40-
bool inspect(Transform& out_transform, Bool& out_unified_scaling) const;
41-
bool inspect(std::span<Transform> out_instances, Bool unfied_scaling) const;
42-
bool inspect(Lights& out_lights) const;
19+
Inspector(NotClosed<Window> target, Scene& out_scene) : m_target(target), m_scene(out_scene), m_resources(out_scene.resources()) {}
4320

44-
private:
45-
bool do_inspect(Transform& out_transform, Bool& out_unified_scaling, Bool scaling_toggle) const;
21+
NotClosed<Window> m_target;
22+
Scene& m_scene;
23+
SceneResourcesMut m_resources;
4624
};
4725

48-
class SceneInspector : public Inspector {
26+
///
27+
/// \brief Inspector for resources in a Scene.
28+
///
29+
/// Provides drag source (and target) for each resource viewed (and edited).
30+
///
31+
class ResourceInspector : public Inspector {
4932
public:
50-
using Inspector::inspect;
51-
52-
SceneInspector(NotClosed<Window> target, Scene& scene);
33+
ResourceInspector(NotClosed<Window> target, Scene& out_scene) : Inspector(target, out_scene) {}
5334

54-
bool inspect(NotClosed<TreeNode>, UnlitMaterial& out_material) const;
55-
bool inspect(NotClosed<TreeNode> node, LitMaterial& out_material) const;
56-
bool inspect(Id<Material> material_id) const;
57-
bool inspect(Id<Mesh> mesh_id) const;
58-
bool inspect(Id<Camera> camera_id) const;
59-
60-
bool inspect(Id<Node> node_id, Bool& out_unified_scaling) const;
35+
///
36+
/// \brief Inspect a Texture (read-only).
37+
/// \param texture Texture to inspect
38+
/// \param id Id of the Texture being inspected (used to create unique labels and drag payloads)
39+
///
40+
void view(Texture const& texture, Id<Texture> id) const;
41+
///
42+
/// \brief Inspect a StaticMesh (read-only).
43+
/// \param mesh the StaticMesh to inspect
44+
/// \param id Id of the StaticMesh being inspected (used to create unique labels and drag payloads)
45+
///
46+
void view(StaticMesh const& mesh, Id<StaticMesh> id) const;
6147

62-
private:
63-
Scene& m_scene;
64-
NotClosed<Window> m_target;
48+
///
49+
/// \brief Inspect a Material.
50+
/// \param out_material Material to inspect
51+
/// \param id Id of the Material being inspected (used to create unique labels and drag payloads)
52+
///
53+
void edit(Material& out_material, Id<Material> id) const;
54+
///
55+
/// \brief Inspect a Mesh.
56+
/// \param out_mesh Mesh to inspect
57+
/// \param id Id of the Mesh being inspected (used to create unique labels and drag payloads)
58+
///
59+
void edit(Mesh& out_mesh, Id<Mesh> id) const;
6560
};
6661

67-
class ResourceInspector {
62+
///
63+
/// \brief Inspector for Scene and its Nodes.
64+
///
65+
/// Provides drag-and-drop support where applicable.
66+
/// Uses a framed TreeNode for each top level component.
67+
///
68+
class SceneInspector : public Inspector {
6869
public:
69-
ResourceInspector(NotClosed<Window>, SceneResources const& resources);
70-
71-
void display() const;
72-
void display(Camera const& camera, std::size_t index, std::string_view prefix = {}) const;
73-
void display(Texture const& texture, std::size_t index, std::string_view prefix = {}) const;
74-
void display(Material const& material, std::size_t const index, std::string_view prefix = {}) const;
75-
void display(Mesh const& mesh, std::size_t const index, std::string_view prefix = {}) const;
76-
77-
private:
78-
void display(LitMaterial const& lit) const;
79-
void display(UnlitMaterial const& unlit) const;
70+
SceneInspector(NotClosed<Window> target, Scene& out_scene) : Inspector(target, out_scene) {}
8071

81-
SceneResources const& m_resources;
72+
///
73+
/// \brief View/edit all resources.
74+
/// \param out_name_buf Persistent buffer for popups
75+
///
76+
/// Uses ResourceInspector.
77+
///
78+
void resources(std::string& out_name_buf) const;
79+
///
80+
/// \brief Inspect the Scene's camera.
81+
///
82+
void camera() const;
83+
///
84+
/// \brief Inspect the Scene's lights.
85+
///
86+
void lights() const;
87+
///
88+
/// \brief Inspect a Node's Transform.
89+
/// \param out_node Node whose Transform to inspect
90+
/// \param out_unified_scaling Whether to use a single locked control for scale
91+
///
92+
void transform(Node& out_node, Bool& out_unified_scaling) const;
93+
///
94+
/// \brief Inspect a Node's instances.
95+
/// \param out_node Node whose instances to inspect
96+
/// \param unified_scaling Whether to use a single locked control for scale
97+
///
98+
void instances(Node& out_node, Bool unified_scaling) const;
99+
///
100+
/// \brief Inspect a Node's Id<Mesh>.
101+
/// \param out_node Node whose attachment to inspect
102+
///
103+
void mesh(Node& out_node) const;
104+
///
105+
/// \brief Inspect a Node and its attachments.
106+
/// \param node_id Id of Node to inspect
107+
///
108+
/// Inspects Transform, instances, and Id<Mesh>.
109+
///
110+
void node(Id<Node> node_id, Bool& out_unified_scaling) const;
82111
};
83-
} // namespace editor
84-
} // namespace facade
112+
} // namespace facade::editor
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#pragma once
2+
#include <facade/engine/editor/common.hpp>
3+
#include <facade/scene/camera.hpp>
4+
#include <facade/util/nvec3.hpp>
5+
#include <facade/util/rgb.hpp>
6+
#include <facade/util/transform.hpp>
7+
#include <glm/gtc/quaternion.hpp>
8+
9+
namespace facade::editor {
10+
///
11+
/// \brief Stateless ImGui helper to reflect various properties.
12+
///
13+
class Reflector {
14+
public:
15+
struct AsRgb {
16+
glm::vec3& out;
17+
};
18+
19+
static constexpr auto min_v{-std::numeric_limits<float>::max()};
20+
static constexpr auto max_v{std::numeric_limits<float>::max()};
21+
22+
///
23+
/// \brief Construct an Reflector instance.
24+
///
25+
/// Reflectors don't do anything on construction, constructors exist to enforce invariants instance-wide.
26+
/// For all Reflectors, an existing Window target is required, Reflector instances will not create any
27+
///
28+
Reflector(NotClosed<Window>) {}
29+
30+
bool operator()(char const* label, glm::vec2& out_vec2, float speed = 1.0f, float lo = min_v, float hi = max_v) const;
31+
bool operator()(char const* label, glm::vec3& out_vec3, float speed = 1.0f, float lo = min_v, float hi = max_v) const;
32+
bool operator()(char const* label, glm::vec4& out_vec4, float speed = 1.0f, float lo = min_v, float hi = max_v) const;
33+
bool operator()(char const* label, nvec3& out_vec3, float speed = 0.01f) const;
34+
bool operator()(char const* label, glm::quat& out_quat) const;
35+
bool operator()(char const* label, AsRgb out_rgb) const;
36+
bool operator()(Rgb& out_rgb) const;
37+
bool operator()(Transform& out_transform, Bool& out_unified_scaling, Bool scaling_toggle) const;
38+
bool operator()(Camera& out_camera) const;
39+
};
40+
} // namespace facade::editor

lib/engine/src/editor/common.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,26 @@
33
#include <cassert>
44

55
namespace facade::editor {
6+
glm::vec2 max_size(std::span<char const* const> strings) {
7+
auto ret = glm::vec2{};
8+
for (auto const* str : strings) {
9+
auto const size = ImGui::CalcTextSize(str);
10+
ret.x = std::max(ret.x, size.x);
11+
ret.y = std::max(ret.y, size.y);
12+
}
13+
return ret;
14+
}
15+
16+
bool small_button_red(char const* label) {
17+
bool ret = false;
18+
ImGui::PushStyleColor(ImGuiCol_Button, {0.8f, 0.0f, 0.1f, 1.0f});
19+
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, {1.0f, 0.0f, 0.1f, 1.0f});
20+
ImGui::PushStyleColor(ImGuiCol_ButtonActive, {0.6f, 0.0f, 0.1f, 1.0f});
21+
if (ImGui::SmallButton(label)) { ret = true; }
22+
ImGui::PopStyleColor(3);
23+
return ret;
24+
}
25+
626
Openable::Openable(bool is_open) : m_open(is_open) {}
727

828
Window::Window(char const* label, bool* open_if, int flags) : Canvas(ImGui::Begin(label, open_if, flags)) {}

0 commit comments

Comments
 (0)