Skip to content

Commit ad87774

Browse files
committed
Concurrent node Ids, more inspection
- Use atomic static incrementing Id for nodes in scenes: unique across all scenes. - Inspect instance transforms, if present. - Display textures in use, if any. - Add shortcut for leaf nodes: `TreeNode::leaf`. - Add enumerate. - Add cylinder, cone, arrow, manipulator geometries. - Move `Mesh` into dedicated header. - Add `Scene::Resources` as immutable view of all storage.
1 parent 6171e99 commit ad87774

File tree

18 files changed

+358
-69
lines changed

18 files changed

+358
-69
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ class TreeNode : public Openable {
4949
public:
5050
explicit TreeNode(char const* label, int flags = {});
5151
~TreeNode();
52+
53+
static void leaf(char const* label, int flags = {});
5254
};
5355

5456
///

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,25 @@ class Inspector {
2222
///
2323
/// Inspectors don't do anything on construction, constructors exist to enforce invariants instance-wide.
2424
/// For all Inspectors, an existing Window target is required, Inspector instances will not create any
25-
/// Note: target must be open
2625
///
27-
Inspector(Window const& target);
26+
Inspector(NotClosed<Window>) {}
2827

2928
bool inspect(char const* label, glm::vec2& out_vec2, float speed = 1.0f, float lo = min_v, float hi = max_v) const;
3029
bool inspect(char const* label, glm::vec3& out_vec3, float speed = 1.0f, float lo = min_v, float hi = max_v) const;
3130
bool inspect(char const* label, glm::vec4& out_vec4, float speed = 1.0f, float lo = min_v, float hi = max_v) const;
3231
bool inspect(char const* label, glm::quat& out_quat) const;
3332
bool inspect(Transform& out_transform, Bool& out_unified_scaling) const;
33+
bool inspect(std::span<Transform> out_instances, Bool unfied_scaling) const;
34+
35+
private:
36+
bool do_inspect(Transform& out_transform, Bool& out_unified_scaling, Bool scaling_toggle) const;
3437
};
3538

3639
class SceneInspector : public Inspector {
3740
public:
3841
using Inspector::inspect;
3942

40-
SceneInspector(Window const& target, Scene& scene);
43+
SceneInspector(NotClosed<Window> target, Scene& scene);
4144

4245
bool inspect(TreeNode const& node, UnlitMaterial& out_material) const;
4346
bool inspect(TreeNode const& node, LitMaterial& out_material) const;

lib/engine/src/editor/common.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ TreeNode::~TreeNode() {
2525
if (m_open) { ImGui::TreePop(); }
2626
}
2727

28+
void TreeNode::leaf(char const* label, int flags) {
29+
if (auto tn = TreeNode{label, flags | ImGuiTreeNodeFlags_Leaf}) {}
30+
}
31+
2832
Window::Menu::Menu(NotClosed<Window>) : MenuBar(ImGui::BeginMenuBar()) {}
2933

3034
Window::Menu::~Menu() {

lib/engine/src/editor/inspector.cpp

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
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-
2423
bool 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);
@@ -64,25 +63,41 @@ bool Inspector::inspect(char const* label, glm::quat& out_quat) const {
6463
}
6564

6665
bool Inspector::inspect(Transform& out_transform, Bool& out_unified_scaling) const {
66+
if (ImGui::CollapsingHeader("Transform", ImGuiTreeNodeFlags_DefaultOpen)) { return do_inspect(out_transform, out_unified_scaling, {true}); }
67+
return false;
68+
}
69+
70+
bool Inspector::inspect(std::span<Transform> out_instances, Bool unified_scaling) const {
71+
if (out_instances.empty()) { return false; }
6772
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); }
73+
if (ImGui::CollapsingHeader("Instances")) {
74+
for (auto [transform, index] : enumerate(out_instances)) {
75+
if (auto tn = TreeNode{FixedString{"Instance [{}]", index}.c_str()}) { ret(do_inspect(transform, unified_scaling, {false})); }
7876
}
77+
}
78+
return ret.value;
79+
}
80+
81+
bool Inspector::do_inspect(Transform& out_transform, Bool& out_unified_scaling, Bool scaling_toggle) const {
82+
auto ret = Modified{};
83+
auto vec3 = out_transform.position();
84+
if (ret(inspect("Position", vec3))) { out_transform.set_position(vec3); }
85+
auto quat = out_transform.orientation();
86+
if (ret(inspect("Orientation", quat))) { out_transform.set_orientation(quat); }
87+
vec3 = out_transform.scale();
88+
if (out_unified_scaling) {
89+
if (ret(ImGui::DragFloat("Scale", &vec3.x, 0.1f))) { out_transform.set_scale({vec3.x, vec3.x, vec3.x}); }
90+
} else {
91+
if (ret(inspect("Scale", vec3, 0.1f))) { out_transform.set_scale(vec3); }
92+
}
93+
if (scaling_toggle) {
7994
ImGui::SameLine();
8095
ImGui::Checkbox("Unified", &out_unified_scaling.value);
8196
}
8297
return ret.value;
8398
}
8499

85-
SceneInspector::SceneInspector([[maybe_unused]] Window const& target, Scene& scene) : Inspector(target), m_scene(scene) { assert(target.is_open()); }
100+
SceneInspector::SceneInspector(NotClosed<Window> target, Scene& scene) : Inspector(target), m_scene(scene) {}
86101

87102
bool SceneInspector::inspect([[maybe_unused]] TreeNode const& node, UnlitMaterial& out_material) const {
88103
assert(node.is_open());
@@ -96,6 +111,18 @@ bool SceneInspector::inspect([[maybe_unused]] TreeNode const& node, LitMaterial&
96111
auto ret = Modified{};
97112
ret(ImGui::SliderFloat("Metallic", &out_material.metallic, 0.0f, 1.0f));
98113
ret(ImGui::SliderFloat("Roughness", &out_material.roughness, 0.0f, 1.0f));
114+
if (out_material.base_colour || out_material.roughness_metallic) {
115+
if (auto tn = TreeNode{"Textures"}) {
116+
if (out_material.base_colour) {
117+
auto const* tex = m_scene.find(*out_material.base_colour);
118+
TreeNode::leaf(FixedString{"Albedo: {} ({})", tex->name, *out_material.base_colour}.c_str());
119+
}
120+
if (out_material.roughness_metallic) {
121+
auto const* tex = m_scene.find(*out_material.roughness_metallic);
122+
TreeNode::leaf(FixedString{"Roughness-Metallic: {} ({})", tex->name, *out_material.roughness_metallic}.c_str());
123+
}
124+
}
125+
}
99126
return ret.value;
100127
}
101128

@@ -117,6 +144,7 @@ bool SceneInspector::inspect(Id<Node> node_id, Bool& out_unified_scaling) const
117144
auto* node = m_scene.find(node_id);
118145
if (!node) { return false; }
119146
ret(inspect(node->transform, out_unified_scaling));
147+
ret(inspect(node->instances, out_unified_scaling));
120148
if (auto const* mesh_id = node->find<Id<Mesh>>()) { ret(inspect(*mesh_id)); }
121149
return ret.value;
122150
}
@@ -127,9 +155,9 @@ bool SceneInspector::inspect(Id<Mesh> mesh_id) const {
127155
if (!mesh) { return ret.value; }
128156
if (ImGui::CollapsingHeader(FixedString{"Mesh ({})###Mesh", mesh_id}.c_str())) {
129157
for (std::size_t i = 0; i < mesh->primitives.size(); ++i) {
130-
if (auto tn = TreeNode{FixedString{"Primitive {}", i}.c_str()}) {
158+
if (auto tn = TreeNode{FixedString{"Primitive [{}]", i}.c_str()}) {
131159
auto const& primitive = mesh->primitives[i];
132-
ImGui::Text("%s", FixedString{"Static Mesh ({})", primitive.static_mesh}.c_str());
160+
TreeNode::leaf(FixedString{"Static Mesh ({})", primitive.static_mesh}.c_str());
133161
if (primitive.material) { ret(inspect(*primitive.material)); }
134162
}
135163
}

lib/render/src/renderer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ bool Renderer::next_frame(std::span<vk::CommandBuffer> out) {
187187
m_impl->render_target = m_impl->render_pass.refresh(acquired);
188188

189189
// refresh framebuffer
190-
m_impl->framebuffer = frame.refresh(m_impl->render_pass.render_pass(), *m_impl->render_target);
190+
m_impl->framebuffer = frame.refresh(m_impl->gfx.device, m_impl->render_pass.render_pass(), *m_impl->render_target);
191191

192192
// begin recording commands
193193
auto const cbii = vk::CommandBufferInheritanceInfo{m_impl->render_pass.render_pass(), 0, m_impl->framebuffer.framebuffer};

lib/scene/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ target_sources(${PROJECT_NAME} PRIVATE
3939
include/${target_prefix}/scene/lights.hpp
4040
include/${target_prefix}/scene/load_status.hpp
4141
include/${target_prefix}/scene/material.hpp
42+
include/${target_prefix}/scene/mesh.hpp
4243
include/${target_prefix}/scene/node_data.hpp
4344
include/${target_prefix}/scene/node.hpp
4445
include/${target_prefix}/scene/scene.hpp

lib/scene/include/facade/scene/material.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ class Material {
6464
/// \param store Texture lookup store
6565
///
6666
virtual void write_sets(Pipeline& pipeline, TextureStore const& store) const = 0;
67+
68+
std::string name{"(Unnamed)"};
6769
};
6870

6971
///
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#pragma once
2+
#include <facade/scene/id.hpp>
3+
#include <optional>
4+
5+
namespace facade {
6+
class StaticMesh;
7+
class Material;
8+
9+
///
10+
/// \brief Represents a Mesh in a Scene.
11+
///
12+
struct Mesh {
13+
///
14+
/// \brief Represents a primitive in a mesh
15+
///
16+
struct Primitive {
17+
///
18+
/// \brief Id of the StaticMesh this primitive uses.
19+
///
20+
Id<StaticMesh> static_mesh{};
21+
///
22+
/// \brief Id of the Material this primitive uses.
23+
///
24+
std::optional<Id<Material>> material{};
25+
};
26+
27+
///
28+
/// \brief List of primitives in this mesh.
29+
///
30+
std::vector<Primitive> primitives{};
31+
};
32+
} // namespace facade

lib/scene/include/facade/scene/scene.hpp

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <facade/scene/lights.hpp>
55
#include <facade/scene/load_status.hpp>
66
#include <facade/scene/material.hpp>
7+
#include <facade/scene/mesh.hpp>
78
#include <facade/scene/node.hpp>
89
#include <facade/scene/node_data.hpp>
910
#include <facade/util/enum_array.hpp>
@@ -41,30 +42,6 @@ struct AtomicLoadStatus {
4142
}
4243
};
4344

44-
///
45-
/// \brief Represents a Mesh in a Scene.
46-
///
47-
struct Mesh {
48-
///
49-
/// \brief Represents a primitive in a mesh
50-
///
51-
struct Primitive {
52-
///
53-
/// \brief Id of the StaticMesh this primitive uses.
54-
///
55-
Id<StaticMesh> static_mesh{};
56-
///
57-
/// \brief Id of the Material this primitive uses.
58-
///
59-
std::optional<Id<Material>> material{};
60-
};
61-
62-
///
63-
/// \brief List of primitives in this mesh.
64-
///
65-
std::vector<Primitive> primitives{};
66-
};
67-
6845
///
6946
/// \brief Models a 3D scene.
7047
///
@@ -78,6 +55,18 @@ class Scene {
7855
///
7956
struct Tree {};
8057

58+
///
59+
/// \brief Immutable view of the resources stored in the scene.
60+
///
61+
struct Resources {
62+
std::span<Camera const> cameras{};
63+
std::span<Sampler const> samplers{};
64+
std::span<std::unique_ptr<Material> const> materials{};
65+
std::span<StaticMesh const> static_meshes{};
66+
std::span<Texture const> textures{};
67+
std::span<Mesh const> meshes{};
68+
};
69+
8170
///
8271
/// \brief "Null" Id for a Node: refers to no Node.
8372
///
@@ -247,6 +236,12 @@ class Scene {
247236
///
248237
Texture make_texture(Image::View image) const;
249238

239+
///
240+
/// \brief Obtain a view into the stored resources.
241+
/// \returns A Resources object
242+
///
243+
Resources resources() const { return m_storage.resources(); }
244+
250245
///
251246
/// \brief All the directional lights in the scene.
252247
///
@@ -279,7 +274,8 @@ class Scene {
279274
std::vector<Mesh> meshes{};
280275

281276
Data data{};
282-
Id<Node> next_node{};
277+
278+
Resources resources() const { return {cameras, samplers, materials, static_meshes, textures, meshes}; }
283279
};
284280

285281
void add_default_camera();
@@ -291,6 +287,8 @@ class Scene {
291287
void check(Mesh const& mesh) const noexcept(false);
292288
void check(Node const& node) const noexcept(false);
293289

290+
inline static std::atomic<Id<Node>::id_type> s_next_node{};
291+
294292
Gfx m_gfx;
295293
Sampler m_sampler;
296294
Storage m_storage{};

lib/scene/src/detail/gltf.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ struct Data {
288288

289289
void buffer(dj::Json const& json) {
290290
auto& b = storage.buffers.emplace_back();
291-
b.name = json["name"].as_string();
291+
b.name = json["name"].as_string("(Unnamed)");
292292
auto const uri = json["uri"].as_string();
293293
// TODO
294294
assert(!uri.empty());
@@ -319,7 +319,7 @@ struct Data {
319319
if (auto const& bv = json["bufferView"]) { a.buffer_view = bv.as<std::size_t>(); }
320320
a.byte_offset = json["byteOffset"].as<std::size_t>(0U);
321321
a.normalized = json["normalized"].as_bool(dj::Boolean{false}).value;
322-
a.name = json["name"].as_string();
322+
a.name = json["name"].as_string("(Unnamed)");
323323
// TODO range
324324
}
325325

@@ -346,7 +346,7 @@ struct Data {
346346
void camera(dj::Json const& json) {
347347
auto& c = storage.cameras.emplace_back();
348348
assert(json.contains("type"));
349-
c.name = json["name"].as_string();
349+
c.name = json["name"].as_string("(Unnamed)");
350350
c.type = json["type"].as_string() == "orthographic" ? Camera::Type::eOrthographic : Camera::Type::ePerspective;
351351
if (c.type == Camera::Type::eOrthographic) {
352352
assert(json.contains("orthographic"));
@@ -359,7 +359,7 @@ struct Data {
359359

360360
void sampler(dj::Json const& json) {
361361
auto& s = storage.samplers.emplace_back();
362-
s.name = json["name"].as<std::string>();
362+
s.name = json["name"].as<std::string>("(Unnamed)");
363363
if (auto const& min = json["minFilter"]) { s.min_filter = static_cast<Filter>(min.as<int>()); }
364364
if (auto const& mag = json["magFilter"]) { s.mag_filter = static_cast<Filter>(mag.as<int>()); }
365365
s.wrap_s = static_cast<Wrap>(json["wrapS"].as<int>(static_cast<int>(s.wrap_s)));
@@ -377,14 +377,14 @@ struct Data {
377377

378378
void mesh(dj::Json const& json) {
379379
auto& m = storage.meshes.emplace_back();
380-
m.name = json["name"].as_string();
380+
m.name = json["name"].as_string("(Unnamed)");
381381
for (auto const& j : json["primitives"].array_view()) { m.primitives.push_back(primitive(j)); }
382382
}
383383

384384
void image(dj::Json const& json) {
385385
auto& i = storage.images.emplace_back();
386386
auto const uri = json["uri"].as_string();
387-
auto name = std::string{json["name"].as_string()};
387+
auto name = std::string{json["name"].as_string("(Unnamed)")};
388388
if (auto const it = get_base64_start(uri); it != std::string_view::npos) {
389389
i = Image{base64_decode(uri.substr(it)), std::move(name)};
390390
} else {
@@ -394,7 +394,7 @@ struct Data {
394394

395395
void texture(dj::Json const& json) {
396396
auto& t = storage.textures.emplace_back();
397-
t.name = json["name"].as<std::string>();
397+
t.name = json["name"].as<std::string>("(Unnamed)");
398398
if (auto const& sampler = json["sampler"]) { t.sampler = sampler.as<std::size_t>(); }
399399
assert(json.contains("source"));
400400
t.source = json["source"].as<std::size_t>();
@@ -455,7 +455,7 @@ struct Data {
455455

456456
void material(dj::Json const& json) {
457457
auto& m = storage.materials.emplace_back();
458-
m.name = std::string{json["name"].as_string()};
458+
m.name = std::string{json["name"].as_string("(Unnamed)")};
459459
m.pbr = pbr_metallic_roughness(json["pbrMetallicRoughness"]);
460460
m.emissive_factor = get_vec<float, 3>(json["emissiveFactor"]);
461461
if (auto const& nt = json["normalTexture"]) { m.normal_texture = get_normal_texture_info(nt); }

0 commit comments

Comments
 (0)