Skip to content

Commit b26b623

Browse files
authored
Improve GLTF loading and Inspector (#51)
* Improve GLTF loading - If directory dragged onto window, search for `.gltf` in it. - Improve progres bar: use full-width window at bottom instead of a modal popup. - Add and use `struct Bool` as conversion-resistant alias for `bool`. * Polish up loading bar - Add title bar. - Adjust dimensions. - Make non-movable and non-resizable.
1 parent c02209e commit b26b623

File tree

6 files changed

+71
-23
lines changed

6 files changed

+71
-23
lines changed

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#pragma once
2+
#include <facade/util/bool.hpp>
23
#include <facade/util/pinned.hpp>
34
#include <glm/vec2.hpp>
45
#include <cassert>
@@ -14,7 +15,7 @@ class Openable : public Pinned {
1415
explicit operator bool() const { return is_open(); }
1516

1617
protected:
17-
Openable(bool is_open);
18+
Openable(bool is_open = false);
1819
bool m_open;
1920
};
2021

@@ -34,7 +35,7 @@ class Window : public Openable {
3435
class Menu;
3536

3637
explicit Window(char const* label, bool* open_if = {}, int flags = {});
37-
Window(NotClosed<Window> parent, char const* label, glm::vec2 size = {}, bool border = {}, int flags = {});
38+
Window(NotClosed<Window> parent, char const* label, glm::vec2 size = {}, Bool border = {}, int flags = {});
3839
~Window();
3940

4041
private:
@@ -63,7 +64,7 @@ class MenuBar : public Openable {
6364
///
6465
class Menu : public Openable {
6566
public:
66-
explicit Menu(NotClosed<MenuBar>, char const* label, bool enabled = true);
67+
explicit Menu(NotClosed<MenuBar>, char const* label, Bool enabled = {true});
6768
~Menu();
6869
};
6970

@@ -90,22 +91,22 @@ class MainMenu : public MenuBar {
9091
///
9192
class Popup : public Openable {
9293
public:
93-
explicit Popup(char const* id, int flags = {}) : Popup(id, false, flags) {}
94+
explicit Popup(char const* id, Bool centered = {}, int flags = {}) : Popup(id, {}, centered, flags) {}
9495
~Popup();
9596

9697
static void open(char const* id);
9798
static void close_current();
9899

99100
protected:
100-
explicit Popup(char const* id, bool modal, int flags);
101+
explicit Popup(char const* id, Bool modal, Bool centered, int flags);
101102
};
102103

103104
///
104105
/// \brief RAII Dear ImGui PopupModal
105106
///
106107
class Modal : public Popup {
107108
public:
108-
explicit Modal(char const* id, int flags = {}) : Popup(id, true, flags) {}
109+
explicit Modal(char const* id, Bool centered = {true}, int flags = {}) : Popup(id, {true}, centered, flags) {}
109110
};
110111

111112
///

lib/engine/src/editor/common.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ Openable::Openable(bool is_open) : m_open(is_open) {}
77

88
Window::Window(char const* label, bool* open_if, int flags) : Openable(ImGui::Begin(label, open_if, flags)) {}
99

10-
Window::Window(NotClosed<Window>, char const* label, glm::vec2 size, bool border, int flags)
11-
: Openable(ImGui::BeginChild(label, {size.x, size.y}, border, flags)), m_child(true) {}
10+
Window::Window(NotClosed<Window>, char const* label, glm::vec2 size, Bool border, int flags)
11+
: Openable(ImGui::BeginChild(label, {size.x, size.y}, border.value, flags)), m_child(true) {}
1212

1313
// ImGui windows requires End() even if Begin() returned false
1414
Window::~Window() {
@@ -37,7 +37,17 @@ MainMenu::~MainMenu() {
3737
if (m_open) { ImGui::EndMainMenuBar(); }
3838
}
3939

40-
Popup::Popup(char const* id, bool modal, int flags) : Openable(modal ? ImGui::BeginPopupModal(id, {}, flags) : ImGui::BeginPopup(id, flags)) {}
40+
Popup::Popup(char const* id, Bool modal, Bool centered, int flags) {
41+
if (centered) {
42+
auto const center = ImGui::GetMainViewport()->GetCenter();
43+
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2{0.5f, 0.5f});
44+
}
45+
if (modal) {
46+
m_open = ImGui::BeginPopupModal(id, {}, flags);
47+
} else {
48+
m_open = ImGui::BeginPopup(id, flags);
49+
}
50+
}
4151

4252
Popup::~Popup() {
4353
if (m_open) { ImGui::EndPopup(); }
@@ -47,7 +57,7 @@ void Popup::open(char const* id) { ImGui::OpenPopup(id); }
4757

4858
void Popup::close_current() { ImGui::CloseCurrentPopup(); }
4959

50-
Menu::Menu(NotClosed<MenuBar>, char const* label, bool enabled) : Openable(ImGui::BeginMenu(label, enabled)) {}
60+
Menu::Menu(NotClosed<MenuBar>, char const* label, Bool enabled) : Openable(ImGui::BeginMenu(label, enabled.value)) {}
5161

5262
Menu::~Menu() {
5363
if (m_open) { ImGui::EndMenu(); }

lib/engine/src/editor/inspector.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ bool Inspector::inspect(char const* label, glm::vec4& out_vec4, float speed, flo
5555
bool Inspector::inspect(char const* label, glm::quat& out_quat) const {
5656
auto euler = to_degree(glm::eulerAngles(out_quat));
5757
if (inspect(label, euler, 0.5f, -180.0f, 180.0f)) {
58+
static constexpr auto y_limit_v{90.0f};
59+
if (euler.y < -y_limit_v) { euler.y = y_limit_v; }
60+
if (euler.y > y_limit_v) { euler.y = -y_limit_v; }
5861
out_quat = glm::quat(to_radian(euler));
5962
return true;
6063
}
@@ -63,8 +66,7 @@ bool Inspector::inspect(char const* label, glm::quat& out_quat) const {
6366

6467
bool Inspector::inspect(Transform& out_transform) const {
6568
auto ret = Modified{};
66-
ImGui::Separator();
67-
if (auto tn = TreeNode{"Transform"}) {
69+
if (ImGui::CollapsingHeader("Transform", ImGuiTreeNodeFlags_DefaultOpen)) {
6870
auto vec3 = out_transform.position();
6971
if (ret(inspect("Position", vec3))) { out_transform.set_position(vec3); }
7072
auto quat = out_transform.orientation();
@@ -96,10 +98,10 @@ bool SceneInspector::inspect(Id<Material> material_id) const {
9698
auto* material = m_scene.find(material_id);
9799
if (!material) { return false; }
98100
if (auto* unlit = dynamic_cast<UnlitMaterial*>(material)) {
99-
if (auto tn = TreeNode{FixedString{"Material (Unlit) ({})", material_id}.c_str()}) { return inspect(tn, *unlit); }
101+
if (auto tn = TreeNode{FixedString{"Material (Unlit) ({})###Material", material_id}.c_str()}) { return inspect(tn, *unlit); }
100102
return false;
101103
} else if (auto* lit = dynamic_cast<LitMaterial*>(material)) {
102-
if (auto tn = TreeNode{FixedString{"Material (Lit) ({})", material_id}.c_str()}) { return inspect(tn, *lit); }
104+
if (auto tn = TreeNode{FixedString{"Material (Lit) ({})###Material", material_id}.c_str()}) { return inspect(tn, *lit); }
103105
return false;
104106
}
105107
return false;
@@ -118,15 +120,15 @@ bool SceneInspector::inspect(Id<Mesh> mesh_id) const {
118120
auto ret = Modified{};
119121
auto* mesh = m_scene.find(mesh_id);
120122
if (!mesh) { return ret.value; }
121-
ImGui::Separator();
122-
if (auto tn = TreeNode{FixedString{"Mesh ({})", mesh_id}.c_str()})
123+
if (ImGui::CollapsingHeader(FixedString{"Mesh ({})###Mesh", mesh_id}.c_str())) {
123124
for (std::size_t i = 0; i < mesh->primitives.size(); ++i) {
124125
if (auto tn = TreeNode{FixedString{"Primitive {}", i}.c_str()}) {
125126
auto const& primitive = mesh->primitives[i];
126127
ImGui::Text("%s", FixedString{"Static Mesh ({})", primitive.static_mesh}.c_str());
127128
if (primitive.material) { ret(inspect(*primitive.material)); }
128129
}
129130
}
131+
}
130132
return ret.value;
131133
}
132134
} // namespace facade::editor

lib/util/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ target_compile_definitions(${PROJECT_NAME}
6464

6565
target_sources(${PROJECT_NAME} PRIVATE
6666
include/${target_prefix}/util/async_queue.hpp
67+
include/${target_prefix}/util/bool.hpp
6768
include/${target_prefix}/util/byte_buffer.hpp
6869
include/${target_prefix}/util/colour_space.hpp
6970
include/${target_prefix}/util/data_provider.hpp

lib/util/include/facade/util/bool.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#pragma once
2+
#include <cstdint>
3+
4+
namespace facade {
5+
///
6+
/// \brief Strongly typed alias for booleans (no implicit conversions)
7+
///
8+
struct Bool {
9+
bool value{};
10+
11+
explicit constexpr operator bool() const { return value; }
12+
};
13+
} // namespace facade

src/main.cpp

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@
1919

2020
#include <bin/shaders.hpp>
2121

22+
#include <filesystem>
2223
#include <iostream>
2324

2425
#include <imgui.h>
2526

2627
using namespace facade;
2728

2829
namespace {
30+
namespace fs = std::filesystem;
31+
2932
static constexpr auto test_json_v = R"(
3033
{
3134
"scene": 0,
@@ -206,6 +209,16 @@ void log_prologue() {
206209
logger::info("facade v{}.{}.{} | {} |", 0, 0, 0, buf);
207210
}
208211

212+
fs::path find_gltf(fs::path root) {
213+
if (root.extension() == ".gltf") { return root; }
214+
for (auto const& it : fs::directory_iterator{root}) {
215+
if (!it.is_regular_file()) { continue; }
216+
auto path = it.path();
217+
if (path.extension() == ".gltf") { return path; }
218+
}
219+
return {};
220+
}
221+
209222
void run() {
210223
auto engine = std::optional<Engine>{};
211224

@@ -267,17 +280,25 @@ void run() {
267280
if (input.keyboard.pressed(GLFW_KEY_ESCAPE)) { engine->request_stop(); }
268281
glfwSetInputMode(engine->window(), GLFW_CURSOR, mouse_look ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL);
269282

270-
if (!state.file_drops.empty()) {
271-
engine->load_async(state.file_drops.front(), [&] { post_scene_load(engine->scene()); });
272-
loading.title = fmt::format("Loading {}...", state.to_filename(state.file_drops.front()));
273-
editor::Popup::open(loading.title.c_str());
283+
if (!state.file_drops.empty() && engine->load_status() == LoadStatus::eNone) {
284+
auto path = find_gltf(state.file_drops.front());
285+
if (!fs::is_regular_file(path)) {
286+
logger::error("Failed to locate .gltf in path: [{}]", state.file_drops.front());
287+
} else {
288+
if (engine->load_async(path.generic_string(), [&] { post_scene_load(engine->scene()); })) {
289+
loading.title = fmt::format("Loading {}...", path.filename().generic_string());
290+
}
291+
}
274292
}
275293
loading.status = engine->load_status();
276294

277-
if (auto popup = editor::Modal{loading.title.c_str()}) {
295+
if (loading.status > LoadStatus::eNone) {
296+
auto const* main_viewport = ImGui::GetMainViewport();
297+
ImGui::SetNextWindowPos({0.0f, main_viewport->WorkPos.y + main_viewport->Size.y - 100.0f});
298+
ImGui::SetNextWindowSize({main_viewport->Size.x, 100.0f});
299+
auto window = editor::Window{loading.title.c_str(), nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize};
278300
ImGui::Text("%s", load_status_str[loading.status].data());
279-
ImGui::ProgressBar(load_progress(loading.status), ImVec2{400.0f, 0}, load_status_str[loading.status].data());
280-
if (loading.status == LoadStatus::eNone) { editor::Popup::close_current(); }
301+
ImGui::ProgressBar(load_progress(loading.status), ImVec2{-1.0f, 0.0f}, load_status_str[loading.status].data());
281302
}
282303

283304
auto& camera = engine->scene().camera();

0 commit comments

Comments
 (0)