Skip to content

Upgrade editor / inspectors, make Node Ids concurrent and never reset #56

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Nov 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions lib/engine/include/facade/engine/editor/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class TreeNode : public Openable {
public:
explicit TreeNode(char const* label, int flags = {});
~TreeNode();

static bool leaf(char const* label, int flags = {});
};

///
Expand Down
24 changes: 17 additions & 7 deletions lib/engine/include/facade/engine/editor/inspector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
#include <facade/engine/editor/common.hpp>
#include <facade/scene/material.hpp>
#include <facade/scene/node.hpp>
#include <facade/util/nvec3.hpp>
#include <facade/util/rgb.hpp>
#include <limits>

namespace facade {
struct Mesh;
struct Lights;
class Scene;

namespace editor {
Expand All @@ -22,30 +25,37 @@ class Inspector {
///
/// Inspectors don't do anything on construction, constructors exist to enforce invariants instance-wide.
/// For all Inspectors, an existing Window target is required, Inspector instances will not create any
/// Note: target must be open
///
Inspector(Window const& target);
Inspector(NotClosed<Window>) {}

bool inspect(char const* label, glm::vec2& out_vec2, float speed = 1.0f, float lo = min_v, float hi = max_v) const;
bool inspect(char const* label, glm::vec3& out_vec3, float speed = 1.0f, float lo = min_v, float hi = max_v) const;
bool inspect(char const* label, glm::vec4& out_vec4, float speed = 1.0f, float lo = min_v, float hi = max_v) const;
bool inspect(char const* label, nvec3& out_vec3, float speed = 0.01f) const;
bool inspect(char const* label, glm::quat& out_quat) const;
bool inspect_rgb(char const* label, glm::vec3& out_rgb) const;
bool inspect(char const* label, Rgb& out_rgb) const;
bool inspect(Transform& out_transform, Bool& out_unified_scaling) const;
bool inspect(std::span<Transform> out_instances, Bool unfied_scaling) const;
bool inspect(Lights& out_lights) const;

private:
bool do_inspect(Transform& out_transform, Bool& out_unified_scaling, Bool scaling_toggle) const;
};

class SceneInspector : public Inspector {
public:
using Inspector::inspect;

SceneInspector(Window const& target, Scene& scene);
SceneInspector(NotClosed<Window> target, Scene& scene);

bool inspect(TreeNode const& node, UnlitMaterial& out_material) const;
bool inspect(TreeNode const& node, LitMaterial& out_material) const;
bool inspect(NotClosed<TreeNode>, UnlitMaterial& out_material) const;
bool inspect(NotClosed<TreeNode> node, LitMaterial& out_material) const;
bool inspect(Id<Material> material_id) const;
bool inspect(Id<Node> node_id, Bool& out_unified_scaling) const;

bool inspect(Id<Mesh> mesh) const;

bool inspect(Id<Node> node_id, Bool& out_unified_scaling) const;

private:
Scene& m_scene;
};
Expand Down
4 changes: 2 additions & 2 deletions lib/engine/include/facade/engine/editor/scene_tree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace editor {
///
/// \brief Target Node to inspect (driven by SceneTree)
///
struct Inspectee {
struct InspectNode {
FixedString<128> name{"[Node]###Node"};
Id<Node> id{};

Expand All @@ -30,7 +30,7 @@ class SceneTree : public Pinned {
/// \param inout Used to highlight matching Node, and set to clicked Node, if any
/// \returns true if inout changed during tree walk
///
bool render(NotClosed<Window>, Inspectee& inout) const;
bool render(NotClosed<Window>, InspectNode& inout) const;

private:
Scene& m_scene;
Expand Down
5 changes: 5 additions & 0 deletions lib/engine/src/editor/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ TreeNode::~TreeNode() {
if (m_open) { ImGui::TreePop(); }
}

bool TreeNode::leaf(char const* label, int flags) {
if (TreeNode{label, flags | ImGuiTreeNodeFlags_Leaf}) { return true; }
return false;
}

Window::Menu::Menu(NotClosed<Window>) : MenuBar(ImGui::BeginMenuBar()) {}

Window::Menu::~Menu() {
Expand Down
153 changes: 123 additions & 30 deletions lib/engine/src/editor/inspector.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <imgui.h>
#include <facade/engine/editor/inspector.hpp>
#include <facade/scene/scene.hpp>
#include <facade/util/enumerate.hpp>
#include <facade/util/fixed_string.hpp>
#include <cassert>

Expand All @@ -19,8 +20,6 @@ struct Modified {
};
} // namespace

Inspector::Inspector([[maybe_unused]] Window const& target) { assert(target.is_open()); }

bool Inspector::inspect(char const* label, glm::vec2& out_vec2, float speed, float lo, float hi) const {
float arr[2] = {out_vec2.x, out_vec2.y};
ImGui::DragFloat2(label, arr, speed, lo, hi);
Expand Down Expand Up @@ -51,6 +50,15 @@ bool Inspector::inspect(char const* label, glm::vec4& out_vec4, float speed, flo
return false;
}

bool Inspector::inspect(char const* label, nvec3& out_vec3, float speed) const {
auto vec3 = out_vec3.value();
if (inspect(label, vec3, speed, -1.0f, 1.0f)) {
out_vec3 = vec3;
return true;
}
return false;
}

bool Inspector::inspect(char const* label, glm::quat& out_quat) const {
auto euler = to_degree(glm::eulerAngles(out_quat));
auto const org = euler;
Expand All @@ -63,39 +71,124 @@ bool Inspector::inspect(char const* label, glm::quat& out_quat) const {
return false;
}

bool Inspector::inspect_rgb(char const* label, glm::vec3& out_rgb) const {
float arr[3] = {out_rgb.x, out_rgb.y, out_rgb.z};
if (ImGui::ColorEdit3(label, arr)) {
out_rgb = {arr[0], arr[1], arr[2]};
return true;
}
return false;
}

bool Inspector::inspect(char const* label, Rgb& out_rgb) const {
auto ret = Modified{};
if (auto tn = TreeNode{label}) {
auto vec3 = Rgb{.channels = out_rgb.channels, .intensity = 1.0f}.to_vec3();
if (inspect_rgb("RGB", vec3)) {
out_rgb = Rgb::make(vec3, out_rgb.intensity);
ret.value = true;
}
ret(ImGui::DragFloat("Intensity", &out_rgb.intensity, 0.05f, 0.1f, 1000.0f));
}
return ret.value;
}

bool Inspector::inspect(Transform& out_transform, Bool& out_unified_scaling) const {
if (ImGui::CollapsingHeader("Transform", ImGuiTreeNodeFlags_DefaultOpen)) { return do_inspect(out_transform, out_unified_scaling, {true}); }
return false;
}

bool Inspector::inspect(std::span<Transform> out_instances, Bool unified_scaling) const {
if (out_instances.empty()) { return false; }
auto ret = Modified{};
if (ImGui::CollapsingHeader("Instances")) {
for (auto [transform, index] : enumerate(out_instances)) {
if (auto tn = TreeNode{FixedString{"Instance [{}]", index}.c_str()}) { ret(do_inspect(transform, unified_scaling, {false})); }
}
}
return ret.value;
}

bool Inspector::inspect(Lights& out_lights) const {
if (out_lights.dir_lights.empty()) { return false; }
auto ret = Modified{};
if (ImGui::CollapsingHeader("Transform", ImGuiTreeNodeFlags_DefaultOpen)) {
auto vec3 = out_transform.position();
if (ret(inspect("Position", vec3))) { out_transform.set_position(vec3); }
auto quat = out_transform.orientation();
if (ret(inspect("Orientation", quat))) { out_transform.set_orientation(quat); }
vec3 = out_transform.scale();
if (out_unified_scaling) {
if (ret(ImGui::DragFloat("Scale", &vec3.x, 0.1f))) { out_transform.set_scale({vec3.x, vec3.x, vec3.x}); }
} else {
if (ret(inspect("Scale", vec3, 0.1f))) { out_transform.set_scale(vec3); }
auto to_remove = std::optional<std::size_t>{};
bool allow_removal = out_lights.dir_lights.size() > 1;
auto inspect_dir_light = [&](DirLight& out_light, std::size_t index) {
auto tn = TreeNode{FixedString{"[{}]", index}.c_str()};
if (allow_removal) {
ImGui::SameLine(ImGui::GetWindowContentRegionWidth() - 10.0f);
static constexpr auto colour_v = ImVec4{0.8f, 0.0f, 0.1f, 1.0f};
ImGui::PushStyleColor(ImGuiCol_Button, colour_v);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, colour_v);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, colour_v);
if (ImGui::SmallButton("x")) { to_remove = index; }
ImGui::PopStyleColor(3);
}
if (tn) {
ret(inspect("Direction", out_light.direction));
ret(inspect("Albedo", out_light.rgb));
}
};
if (ImGui::CollapsingHeader("DirLights")) {
for (auto [light, index] : enumerate(out_lights.dir_lights.span())) { inspect_dir_light(light, index); }
}
if (to_remove) {
auto replace = decltype(out_lights.dir_lights){};
for (auto const [light, index] : enumerate(out_lights.dir_lights.span())) {
if (index == *to_remove) { continue; }
replace.insert(light);
}
out_lights.dir_lights = std::move(replace);
}
if (out_lights.dir_lights.size() < Lights::max_lights_v && ImGui::Button("[+]")) { out_lights.dir_lights.insert(DirLight{}); }
return ret.value;
}

bool Inspector::do_inspect(Transform& out_transform, Bool& out_unified_scaling, Bool scaling_toggle) const {
auto ret = Modified{};
auto vec3 = out_transform.position();
if (ret(inspect("Position", vec3))) { out_transform.set_position(vec3); }
auto quat = out_transform.orientation();
if (ret(inspect("Orientation", quat))) { out_transform.set_orientation(quat); }
vec3 = out_transform.scale();
if (out_unified_scaling) {
if (ret(ImGui::DragFloat("Scale", &vec3.x, 0.1f))) { out_transform.set_scale({vec3.x, vec3.x, vec3.x}); }
} else {
if (ret(inspect("Scale", vec3, 0.1f))) { out_transform.set_scale(vec3); }
}
if (scaling_toggle) {
ImGui::SameLine();
ImGui::Checkbox("Unified", &out_unified_scaling.value);
}
return ret.value;
}

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

bool SceneInspector::inspect([[maybe_unused]] TreeNode const& node, UnlitMaterial& out_material) const {
assert(node.is_open());
bool SceneInspector::inspect(NotClosed<TreeNode>, UnlitMaterial& out_material) const {
auto ret = Modified{};
ret(inspect("Tint", out_material.tint, 0.01f, 0.0f, 1.0f));
return ret.value;
}

bool SceneInspector::inspect([[maybe_unused]] TreeNode const& node, LitMaterial& out_material) const {
assert(node.is_open());
bool SceneInspector::inspect(NotClosed<TreeNode>, LitMaterial& out_material) const {
auto ret = Modified{};
ret(ImGui::SliderFloat("Metallic", &out_material.metallic, 0.0f, 1.0f));
ret(ImGui::SliderFloat("Roughness", &out_material.roughness, 0.0f, 1.0f));
ret(inspect_rgb("Albedo", out_material.albedo));
if (out_material.base_colour || out_material.roughness_metallic) {
if (auto tn = TreeNode{"Textures"}) {
if (out_material.base_colour) {
auto const* tex = m_scene.find(*out_material.base_colour);
TreeNode::leaf(FixedString{"Albedo: {} ({})", tex->name, *out_material.base_colour}.c_str());
}
if (out_material.roughness_metallic) {
auto const* tex = m_scene.find(*out_material.roughness_metallic);
TreeNode::leaf(FixedString{"Roughness-Metallic: {} ({})", tex->name, *out_material.roughness_metallic}.c_str());
}
}
}
return ret.value;
}

Expand All @@ -112,28 +205,28 @@ bool SceneInspector::inspect(Id<Material> material_id) const {
return false;
}

bool SceneInspector::inspect(Id<Node> node_id, Bool& out_unified_scaling) const {
auto ret = Modified{};
auto* node = m_scene.find(node_id);
if (!node) { return false; }
ret(inspect(node->transform, out_unified_scaling));
if (auto const* mesh_id = node->find<Id<Mesh>>()) { ret(inspect(*mesh_id)); }
return ret.value;
}

bool SceneInspector::inspect(Id<Mesh> mesh_id) const {
auto ret = Modified{};
auto* mesh = m_scene.find(mesh_id);
if (!mesh) { return ret.value; }
if (ImGui::CollapsingHeader(FixedString{"Mesh ({})###Mesh", mesh_id}.c_str())) {
for (std::size_t i = 0; i < mesh->primitives.size(); ++i) {
if (auto tn = TreeNode{FixedString{"Primitive {}", i}.c_str()}) {
auto const& primitive = mesh->primitives[i];
ImGui::Text("%s", FixedString{"Static Mesh ({})", primitive.static_mesh}.c_str());
for (auto [primitive, index] : enumerate(mesh->primitives)) {
if (auto tn = TreeNode{FixedString{"Primitive [{}]", index}.c_str()}) {
TreeNode::leaf(FixedString{"Static Mesh ({})", primitive.static_mesh}.c_str());
if (primitive.material) { ret(inspect(*primitive.material)); }
}
}
}
return ret.value;
}

bool SceneInspector::inspect(Id<Node> node_id, Bool& out_unified_scaling) const {
auto ret = Modified{};
auto* node = m_scene.find(node_id);
if (!node) { return false; }
ret(inspect(node->transform, out_unified_scaling));
ret(inspect(node->instances, out_unified_scaling));
if (auto const* mesh_id = node->find<Id<Mesh>>()) { ret(inspect(*mesh_id)); }
return ret.value;
}
} // namespace facade::editor
8 changes: 4 additions & 4 deletions lib/engine/src/editor/scene_tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ FixedString<128> node_name(Node const& node) {
return ret;
}

Inspectee inspect(Node const& node) {
auto ret = Inspectee{};
InspectNode inspect(Node const& node) {
auto ret = InspectNode{};
ret.id = node.id();
ret.name = node_name(node);
ret.name += FixedString{"###Node"};
return ret;
}

void walk(Node& node, Inspectee& inout) {
void walk(Node& node, InspectNode& inout) {
auto flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_SpanAvailWidth;
if (node.id() == inout.id) { flags |= ImGuiTreeNodeFlags_Selected; }
if (node.children().empty()) { flags |= ImGuiTreeNodeFlags_Leaf; }
Expand All @@ -35,7 +35,7 @@ void walk(Node& node, Inspectee& inout) {
}
} // namespace

bool SceneTree::render(NotClosed<Window>, Inspectee& inout) const {
bool SceneTree::render(NotClosed<Window>, InspectNode& inout) const {
auto const in = inout.id;
if (!m_scene.find(in)) { inout = {}; }
for (auto& root : m_scene.roots()) { walk(root, inout); }
Expand Down
17 changes: 16 additions & 1 deletion lib/engine/src/scene_renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ struct Img1x1 {
};
}
};

struct DirLightSSBO {
alignas(16) glm::vec3 direction{front_v};
alignas(16) glm::vec3 ambient{0.04f};
alignas(16) glm::vec3 diffuse{1.0f};

static DirLightSSBO make(DirLight const& light) {
return {
.direction = light.direction.value(),
.diffuse = light.rgb.to_vec4(),
};
}
};
} // namespace

SceneRenderer::SceneRenderer(Gfx const& gfx)
Expand Down Expand Up @@ -51,7 +64,9 @@ void SceneRenderer::write_view(glm::vec2 const extent) {
.pos_v = {cam_node.transform.position(), 1.0f},
};
m_view_proj.write(&vp, sizeof(vp));
m_dir_lights.write(m_scene->dir_lights.data(), m_scene->dir_lights.size() * sizeof(DirLight));
auto dir_lights = FlexArray<DirLightSSBO, 4>{};
for (auto const& light : m_scene->lights.dir_lights.span()) { dir_lights.insert(DirLightSSBO::make(light)); }
m_dir_lights.write(dir_lights.span().data(), dir_lights.span().size_bytes());
}

void SceneRenderer::update_view(Pipeline& out_pipeline) const {
Expand Down
2 changes: 1 addition & 1 deletion lib/render/src/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ bool Renderer::next_frame(std::span<vk::CommandBuffer> out) {
m_impl->render_target = m_impl->render_pass.refresh(acquired);

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

// begin recording commands
auto const cbii = vk::CommandBufferInheritanceInfo{m_impl->render_pass.render_pass(), 0, m_impl->framebuffer.framebuffer};
Expand Down
1 change: 1 addition & 0 deletions lib/scene/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ target_sources(${PROJECT_NAME} PRIVATE
include/${target_prefix}/scene/lights.hpp
include/${target_prefix}/scene/load_status.hpp
include/${target_prefix}/scene/material.hpp
include/${target_prefix}/scene/mesh.hpp
include/${target_prefix}/scene/node_data.hpp
include/${target_prefix}/scene/node.hpp
include/${target_prefix}/scene/scene.hpp
Expand Down
Loading