11#include < imgui.h>
22#include < facade/engine/editor/inspector.hpp>
33#include < facade/scene/scene.hpp>
4+ #include < facade/util/enumerate.hpp>
45#include < facade/util/fixed_string.hpp>
56#include < cassert>
67
@@ -19,8 +20,6 @@ struct Modified {
1920};
2021} // namespace
2122
22- Inspector::Inspector ([[maybe_unused]] Window const & target) { assert (target.is_open ()); }
23-
2423bool Inspector::inspect (char const * label, glm::vec2& out_vec2, float speed, float lo, float hi) const {
2524 float arr[2 ] = {out_vec2.x , out_vec2.y };
2625 ImGui::DragFloat2 (label, arr, speed, lo, hi);
@@ -51,6 +50,15 @@ bool Inspector::inspect(char const* label, glm::vec4& out_vec4, float speed, flo
5150 return false ;
5251}
5352
53+ bool Inspector::inspect (char const * label, nvec3& out_vec3, float speed) const {
54+ auto vec3 = out_vec3.value ();
55+ if (inspect (label, vec3, speed, -1 .0f , 1 .0f )) {
56+ out_vec3 = vec3;
57+ return true ;
58+ }
59+ return false ;
60+ }
61+
5462bool Inspector::inspect (char const * label, glm::quat& out_quat) const {
5563 auto euler = to_degree (glm::eulerAngles (out_quat));
5664 auto const org = euler;
@@ -63,39 +71,124 @@ bool Inspector::inspect(char const* label, glm::quat& out_quat) const {
6371 return false ;
6472}
6573
74+ bool Inspector::inspect_rgb (char const * label, glm::vec3& out_rgb) const {
75+ float arr[3 ] = {out_rgb.x , out_rgb.y , out_rgb.z };
76+ if (ImGui::ColorEdit3 (label, arr)) {
77+ out_rgb = {arr[0 ], arr[1 ], arr[2 ]};
78+ return true ;
79+ }
80+ return false ;
81+ }
82+
83+ bool Inspector::inspect (char const * label, Rgb& out_rgb) const {
84+ auto ret = Modified{};
85+ if (auto tn = TreeNode{label}) {
86+ auto vec3 = Rgb{.channels = out_rgb.channels , .intensity = 1 .0f }.to_vec3 ();
87+ if (inspect_rgb (" RGB" , vec3)) {
88+ out_rgb = Rgb::make (vec3, out_rgb.intensity );
89+ ret.value = true ;
90+ }
91+ ret (ImGui::DragFloat (" Intensity" , &out_rgb.intensity , 0 .05f , 0 .1f , 1000 .0f ));
92+ }
93+ return ret.value ;
94+ }
95+
6696bool Inspector::inspect (Transform& out_transform, Bool& out_unified_scaling) const {
97+ if (ImGui::CollapsingHeader (" Transform" , ImGuiTreeNodeFlags_DefaultOpen)) { return do_inspect (out_transform, out_unified_scaling, {true }); }
98+ return false ;
99+ }
100+
101+ bool Inspector::inspect (std::span<Transform> out_instances, Bool unified_scaling) const {
102+ if (out_instances.empty ()) { return false ; }
103+ auto ret = Modified{};
104+ if (ImGui::CollapsingHeader (" Instances" )) {
105+ for (auto [transform, index] : enumerate(out_instances)) {
106+ if (auto tn = TreeNode{FixedString{" Instance [{}]" , index}.c_str ()}) { ret (do_inspect (transform, unified_scaling, {false })); }
107+ }
108+ }
109+ return ret.value ;
110+ }
111+
112+ bool Inspector::inspect (Lights& out_lights) const {
113+ if (out_lights.dir_lights .empty ()) { return false ; }
67114 auto ret = Modified{};
68- if (ImGui::CollapsingHeader (" Transform" , ImGuiTreeNodeFlags_DefaultOpen)) {
69- auto vec3 = out_transform.position ();
70- if (ret (inspect (" Position" , vec3))) { out_transform.set_position (vec3); }
71- auto quat = out_transform.orientation ();
72- if (ret (inspect (" Orientation" , quat))) { out_transform.set_orientation (quat); }
73- vec3 = out_transform.scale ();
74- if (out_unified_scaling) {
75- if (ret (ImGui::DragFloat (" Scale" , &vec3.x , 0 .1f ))) { out_transform.set_scale ({vec3.x , vec3.x , vec3.x }); }
76- } else {
77- if (ret (inspect (" Scale" , vec3, 0 .1f ))) { out_transform.set_scale (vec3); }
115+ auto to_remove = std::optional<std::size_t >{};
116+ bool allow_removal = out_lights.dir_lights .size () > 1 ;
117+ auto inspect_dir_light = [&](DirLight& out_light, std::size_t index) {
118+ auto tn = TreeNode{FixedString{" [{}]" , index}.c_str ()};
119+ if (allow_removal) {
120+ ImGui::SameLine (ImGui::GetWindowContentRegionWidth () - 10 .0f );
121+ static constexpr auto colour_v = ImVec4{0 .8f , 0 .0f , 0 .1f , 1 .0f };
122+ ImGui::PushStyleColor (ImGuiCol_Button, colour_v);
123+ ImGui::PushStyleColor (ImGuiCol_ButtonHovered, colour_v);
124+ ImGui::PushStyleColor (ImGuiCol_ButtonActive, colour_v);
125+ if (ImGui::SmallButton (" x" )) { to_remove = index; }
126+ ImGui::PopStyleColor (3 );
127+ }
128+ if (tn) {
129+ ret (inspect (" Direction" , out_light.direction ));
130+ ret (inspect (" Albedo" , out_light.rgb ));
131+ }
132+ };
133+ if (ImGui::CollapsingHeader (" DirLights" )) {
134+ for (auto [light, index] : enumerate(out_lights.dir_lights .span ())) { inspect_dir_light (light, index); }
135+ }
136+ if (to_remove) {
137+ auto replace = decltype (out_lights.dir_lights ){};
138+ for (auto const [light, index] : enumerate(out_lights.dir_lights .span ())) {
139+ if (index == *to_remove) { continue ; }
140+ replace.insert (light);
78141 }
142+ out_lights.dir_lights = std::move (replace);
143+ }
144+ if (out_lights.dir_lights .size () < Lights::max_lights_v && ImGui::Button (" [+]" )) { out_lights.dir_lights .insert (DirLight{}); }
145+ return ret.value ;
146+ }
147+
148+ bool Inspector::do_inspect (Transform& out_transform, Bool& out_unified_scaling, Bool scaling_toggle) const {
149+ auto ret = Modified{};
150+ auto vec3 = out_transform.position ();
151+ if (ret (inspect (" Position" , vec3))) { out_transform.set_position (vec3); }
152+ auto quat = out_transform.orientation ();
153+ if (ret (inspect (" Orientation" , quat))) { out_transform.set_orientation (quat); }
154+ vec3 = out_transform.scale ();
155+ if (out_unified_scaling) {
156+ if (ret (ImGui::DragFloat (" Scale" , &vec3.x , 0 .1f ))) { out_transform.set_scale ({vec3.x , vec3.x , vec3.x }); }
157+ } else {
158+ if (ret (inspect (" Scale" , vec3, 0 .1f ))) { out_transform.set_scale (vec3); }
159+ }
160+ if (scaling_toggle) {
79161 ImGui::SameLine ();
80162 ImGui::Checkbox (" Unified" , &out_unified_scaling.value );
81163 }
82164 return ret.value ;
83165}
84166
85- SceneInspector::SceneInspector ([[maybe_unused]] Window const & target, Scene& scene) : Inspector(target), m_scene(scene) { assert (target. is_open ()); }
167+ SceneInspector::SceneInspector (NotClosed< Window> target, Scene& scene) : Inspector(target), m_scene(scene) {}
86168
87- bool SceneInspector::inspect ([[maybe_unused]] TreeNode const & node, UnlitMaterial& out_material) const {
88- assert (node.is_open ());
169+ bool SceneInspector::inspect (NotClosed<TreeNode>, UnlitMaterial& out_material) const {
89170 auto ret = Modified{};
90171 ret (inspect (" Tint" , out_material.tint , 0 .01f , 0 .0f , 1 .0f ));
91172 return ret.value ;
92173}
93174
94- bool SceneInspector::inspect ([[maybe_unused]] TreeNode const & node, LitMaterial& out_material) const {
95- assert (node.is_open ());
175+ bool SceneInspector::inspect (NotClosed<TreeNode>, LitMaterial& out_material) const {
96176 auto ret = Modified{};
97177 ret (ImGui::SliderFloat (" Metallic" , &out_material.metallic , 0 .0f , 1 .0f ));
98178 ret (ImGui::SliderFloat (" Roughness" , &out_material.roughness , 0 .0f , 1 .0f ));
179+ ret (inspect_rgb (" Albedo" , out_material.albedo ));
180+ if (out_material.base_colour || out_material.roughness_metallic ) {
181+ if (auto tn = TreeNode{" Textures" }) {
182+ if (out_material.base_colour ) {
183+ auto const * tex = m_scene.find (*out_material.base_colour );
184+ TreeNode::leaf (FixedString{" Albedo: {} ({})" , tex->name , *out_material.base_colour }.c_str ());
185+ }
186+ if (out_material.roughness_metallic ) {
187+ auto const * tex = m_scene.find (*out_material.roughness_metallic );
188+ TreeNode::leaf (FixedString{" Roughness-Metallic: {} ({})" , tex->name , *out_material.roughness_metallic }.c_str ());
189+ }
190+ }
191+ }
99192 return ret.value ;
100193}
101194
@@ -112,28 +205,28 @@ bool SceneInspector::inspect(Id<Material> material_id) const {
112205 return false ;
113206}
114207
115- bool SceneInspector::inspect (Id<Node> node_id, Bool& out_unified_scaling) const {
116- auto ret = Modified{};
117- auto * node = m_scene.find (node_id);
118- if (!node) { return false ; }
119- ret (inspect (node->transform , out_unified_scaling));
120- if (auto const * mesh_id = node->find <Id<Mesh>>()) { ret (inspect (*mesh_id)); }
121- return ret.value ;
122- }
123-
124208bool SceneInspector::inspect (Id<Mesh> mesh_id) const {
125209 auto ret = Modified{};
126210 auto * mesh = m_scene.find (mesh_id);
127211 if (!mesh) { return ret.value ; }
128212 if (ImGui::CollapsingHeader (FixedString{" Mesh ({})###Mesh" , mesh_id}.c_str ())) {
129- for (std::size_t i = 0 ; i < mesh->primitives .size (); ++i) {
130- if (auto tn = TreeNode{FixedString{" Primitive {}" , i}.c_str ()}) {
131- auto const & primitive = mesh->primitives [i];
132- ImGui::Text (" %s" , FixedString{" Static Mesh ({})" , primitive.static_mesh }.c_str ());
213+ for (auto [primitive, index] : enumerate(mesh->primitives )) {
214+ if (auto tn = TreeNode{FixedString{" Primitive [{}]" , index}.c_str ()}) {
215+ TreeNode::leaf (FixedString{" Static Mesh ({})" , primitive.static_mesh }.c_str ());
133216 if (primitive.material ) { ret (inspect (*primitive.material )); }
134217 }
135218 }
136219 }
137220 return ret.value ;
138221}
222+
223+ bool SceneInspector::inspect (Id<Node> node_id, Bool& out_unified_scaling) const {
224+ auto ret = Modified{};
225+ auto * node = m_scene.find (node_id);
226+ if (!node) { return false ; }
227+ ret (inspect (node->transform , out_unified_scaling));
228+ ret (inspect (node->instances , out_unified_scaling));
229+ if (auto const * mesh_id = node->find <Id<Mesh>>()) { ret (inspect (*mesh_id)); }
230+ return ret.value ;
231+ }
139232} // namespace facade::editor
0 commit comments