From e5f303714b9ea9d39af5e3bc367b45f327e54dc0 Mon Sep 17 00:00:00 2001 From: "k.koide" Date: Sun, 21 Apr 2024 17:49:03 +0900 Subject: [PATCH 1/4] has_model_matrix() --- include/guik/viewer/shader_setting.hpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/include/guik/viewer/shader_setting.hpp b/include/guik/viewer/shader_setting.hpp index 25c7be17..8b4fc557 100644 --- a/include/guik/viewer/shader_setting.hpp +++ b/include/guik/viewer/shader_setting.hpp @@ -119,7 +119,7 @@ struct ShaderSetting { } template - boost::optional get(const std::string& name) { + boost::optional get(const std::string& name) const { for (const auto& param : params) { if (param->name != name) { continue; @@ -137,7 +137,7 @@ struct ShaderSetting { } template - const T& cast(const std::string& name) { + const T& cast(const std::string& name) const { for (const auto& param : params) { if (param->name != name) { continue; @@ -160,6 +160,11 @@ struct ShaderSetting { } } + int color_mode() const { + auto p = static_cast*>(params[0].get()); + return p->value; + } + // Point size and scale float point_scale() const { auto p = static_cast*>(params[1].get()); @@ -191,6 +196,10 @@ struct ShaderSetting { return *this; } + bool has_model_matrix() const { + return params[2] != nullptr; + } + Eigen::Matrix4f model_matrix() const { auto p = static_cast*>(params[2].get()); return p->value; From bb18faf41436043fdbc80c5a2f4b58a93a946f64 Mon Sep 17 00:00:00 2001 From: "k.koide" Date: Sun, 21 Apr 2024 17:50:43 +0900 Subject: [PATCH 2/4] DrawableTree (WIP) --- include/guik/drawable_tree.hpp | 120 +++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 include/guik/drawable_tree.hpp diff --git a/include/guik/drawable_tree.hpp b/include/guik/drawable_tree.hpp new file mode 100644 index 00000000..86a159cc --- /dev/null +++ b/include/guik/drawable_tree.hpp @@ -0,0 +1,120 @@ +#pragma once + +#include +#include + +namespace guik +{ + +class DrawableTree : public glk::Drawable { +public: + using Ptr = std::shared_ptr; + using ConstPtr = std::shared_ptr; + + DrawableTree() : name("root") {} + DrawableTree(const std::string& name) : name(name) {} + + void update_drawable(const std::string& name, glk::Drawable::ConstPtr drawable, const guik::ShaderSetting& setting) { + const auto names = split_path(name); + update_drawable(names.data(), names.data() + names.size(), drawable, setting); + } + + void update_setting(const std::string& name, const guik::ShaderSetting& setting) { + const auto names = split_path(name); + update_drawable(names.data(), names.data() + names.size(), nullptr, setting); + } + + virtual void draw(glk::GLSLShader& shader) const override { draw(shader, Eigen::Matrix4f::Identity()); } + + void print_tree(int depth = 0, const Eigen::Matrix4f& parent_model_matrix = Eigen::Matrix4f::Identity()) const { + Eigen::Matrix4f model_matrix = setting.has_model_matrix() ? parent_model_matrix * setting.model_matrix() : parent_model_matrix; + + for (int i = 0; i < depth; i++) { + std::cout << " "; + } + + Eigen::Quaternionf quat(model_matrix.block<3, 3>(0, 0)); + Eigen::Vector3f trans(model_matrix.block<3, 1>(0, 3)); + + std::cout << name << " : trans=(" << trans.x() << "," << trans.y() << "," << trans.z() << ") quat=(" << quat.x() << "," << quat.y() << "," << quat.z() << "," << quat.w() << ")" + << (drawable ? " D" : "") << std::endl; + + for (const auto& child : children) { + child.second->print_tree(depth + 1, model_matrix); + } + } + +private: + void update_drawable(const std::string* first, const std::string* last, glk::Drawable::ConstPtr drawable, const guik::ShaderSetting& setting) { + if (first == last) { + this->setting = setting; + if (drawable) { + this->drawable = drawable; + } + return; + } + + auto found = children.find(*first); + if (found == children.end()) { + auto child = std::make_shared(*first); + found = children.emplace_hint(found, *first, child); + } + + found->second->update_drawable(first + 1, last, drawable, setting); + } + + void draw(glk::GLSLShader& shader, const Eigen::Matrix4f& parent_model_matrix) const { + Eigen::Matrix4f model_matrix = parent_model_matrix; + if (setting.has_model_matrix()) { + model_matrix = model_matrix * setting.model_matrix(); + } + + if (drawable) { + setting.set(shader); + shader.set_uniform("model_matrix", model_matrix); + drawable->draw(shader); + } + + for (const auto& child : children) { + setting.set(shader); + child.second->draw(shader, model_matrix); + } + } + +private: + std::vector split_path(const std::string& path) { + if (path.empty()) { + std::cerr << "warning: empty path" << std::endl; + return {}; + } + + std::vector names; + int cursor = path.find_first_not_of('/'); + while (cursor < path.size()) { + int next = path.find('/', cursor); + if (next == cursor) { + std::cout << "warning: skip empty name : " << path.substr(0, cursor) << "()" << path.substr(cursor) << std::endl; + cursor++; + continue; + } + + if (next == std::string::npos) { + names.push_back(path.substr(cursor)); + break; + } + names.push_back(path.substr(cursor, next - cursor)); + cursor = next + 1; + } + + return names; + } + +private: + const std::string name; + guik::ShaderSetting setting; + + glk::Drawable::ConstPtr drawable; + std::unordered_map children; +}; + +} // namespace guik From e8957a13556d167f3df4d8defaa777b4f1fce5f7 Mon Sep 17 00:00:00 2001 From: "k.koide" Date: Sun, 9 Jun 2024 17:05:12 +0900 Subject: [PATCH 3/4] add DrawableTree::remove and update_tree_setting --- CMakeLists.txt | 2 + include/guik/drawable_tree.hpp | 118 +++++++++------------------- src/guik/drawable_tree.cpp | 137 +++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+), 82 deletions(-) create mode 100644 src/guik/drawable_tree.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a8f5e69..cd8f813b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,6 +121,7 @@ add_library(iridescence SHARED src/guik/imgui_application.cpp src/guik/screen_capture.cpp src/guik/recent_files.cpp + src/guik/drawable_tree.cpp src/guik/camera/camera_control.cpp src/guik/camera/orbit_camera_control_xy.cpp src/guik/camera/orbit_camera_control_xz.cpp @@ -196,6 +197,7 @@ if(BUILD_EXAMPLES) ${example_src} ) target_link_libraries(${example_name} + fmt iridescence ) endforeach() diff --git a/include/guik/drawable_tree.hpp b/include/guik/drawable_tree.hpp index 86a159cc..6217e4c9 100644 --- a/include/guik/drawable_tree.hpp +++ b/include/guik/drawable_tree.hpp @@ -1,113 +1,65 @@ -#pragma once +#ifndef GUIK_DRAWABLE_TREE_HPP +#define GUIK_DRAWABLE_TREE_HPP #include #include -namespace guik -{ +namespace guik { +/// @brief Hierarchical drawable tree class DrawableTree : public glk::Drawable { public: using Ptr = std::shared_ptr; using ConstPtr = std::shared_ptr; - DrawableTree() : name("root") {} - DrawableTree(const std::string& name) : name(name) {} + DrawableTree(); - void update_drawable(const std::string& name, glk::Drawable::ConstPtr drawable, const guik::ShaderSetting& setting) { - const auto names = split_path(name); - update_drawable(names.data(), names.data() + names.size(), drawable, setting); - } + void update_drawable(const std::string& name, glk::Drawable::ConstPtr drawable, const guik::ShaderSetting& setting); + void update_setting(const std::string& name, const guik::ShaderSetting& setting); - void update_setting(const std::string& name, const guik::ShaderSetting& setting) { + template + void update_tree_setting(const std::string& name, const std::string& param_name, const T& val) { const auto names = split_path(name); - update_drawable(names.data(), names.data() + names.size(), nullptr, setting); + update_tree_setting(names.data(), names.data() + names.size(), param_name, val); } - virtual void draw(glk::GLSLShader& shader) const override { draw(shader, Eigen::Matrix4f::Identity()); } + void update_tree_color_mode(const std::string& name, guik::ColorMode::MODE color_mode); + void update_tree_color(const std::string& name, const Eigen::Vector4f& color); - void print_tree(int depth = 0, const Eigen::Matrix4f& parent_model_matrix = Eigen::Matrix4f::Identity()) const { - Eigen::Matrix4f model_matrix = setting.has_model_matrix() ? parent_model_matrix * setting.model_matrix() : parent_model_matrix; + bool remove(const std::string& name); - for (int i = 0; i < depth; i++) { - std::cout << " "; - } + void print_tree(int depth = 0, const Eigen::Matrix4f& parent_model_matrix = Eigen::Matrix4f::Identity()) const; - Eigen::Quaternionf quat(model_matrix.block<3, 3>(0, 0)); - Eigen::Vector3f trans(model_matrix.block<3, 1>(0, 3)); + virtual void draw(glk::GLSLShader& shader) const override; - std::cout << name << " : trans=(" << trans.x() << "," << trans.y() << "," << trans.z() << ") quat=(" << quat.x() << "," << quat.y() << "," << quat.z() << "," << quat.w() << ")" - << (drawable ? " D" : "") << std::endl; +private: + DrawableTree(const std::string& name); - for (const auto& child : children) { - child.second->print_tree(depth + 1, model_matrix); - } - } + void update_drawable(const std::string* first, const std::string* last, glk::Drawable::ConstPtr drawable, const guik::ShaderSetting& setting); -private: - void update_drawable(const std::string* first, const std::string* last, glk::Drawable::ConstPtr drawable, const guik::ShaderSetting& setting) { + bool remove(const std::string* first, const std::string* last); + + template + void update_tree_setting(const std::string* first, const std::string* last, const std::string& param_name, const T& val) { if (first == last) { - this->setting = setting; - if (drawable) { - this->drawable = drawable; + setting.add(param_name, val); + for (auto child : children) { + child.second->update_tree_setting(first, last, param_name, val); + } + } else { + auto found = children.find(*first); + if (found == children.end()) { + return; } - return; - } - auto found = children.find(*first); - if (found == children.end()) { - auto child = std::make_shared(*first); - found = children.emplace_hint(found, *first, child); + found->second->update_tree_setting(first + 1, last, param_name, val); } - - found->second->update_drawable(first + 1, last, drawable, setting); } - void draw(glk::GLSLShader& shader, const Eigen::Matrix4f& parent_model_matrix) const { - Eigen::Matrix4f model_matrix = parent_model_matrix; - if (setting.has_model_matrix()) { - model_matrix = model_matrix * setting.model_matrix(); - } - - if (drawable) { - setting.set(shader); - shader.set_uniform("model_matrix", model_matrix); - drawable->draw(shader); - } - - for (const auto& child : children) { - setting.set(shader); - child.second->draw(shader, model_matrix); - } - } + void draw(glk::GLSLShader& shader, const Eigen::Matrix4f& parent_model_matrix) const; private: - std::vector split_path(const std::string& path) { - if (path.empty()) { - std::cerr << "warning: empty path" << std::endl; - return {}; - } - - std::vector names; - int cursor = path.find_first_not_of('/'); - while (cursor < path.size()) { - int next = path.find('/', cursor); - if (next == cursor) { - std::cout << "warning: skip empty name : " << path.substr(0, cursor) << "()" << path.substr(cursor) << std::endl; - cursor++; - continue; - } - - if (next == std::string::npos) { - names.push_back(path.substr(cursor)); - break; - } - names.push_back(path.substr(cursor, next - cursor)); - cursor = next + 1; - } - - return names; - } + std::vector split_path(const std::string& path); private: const std::string name; @@ -117,4 +69,6 @@ class DrawableTree : public glk::Drawable { std::unordered_map children; }; -} // namespace guik +} // namespace guik + +#endif \ No newline at end of file diff --git a/src/guik/drawable_tree.cpp b/src/guik/drawable_tree.cpp new file mode 100644 index 00000000..937f3f46 --- /dev/null +++ b/src/guik/drawable_tree.cpp @@ -0,0 +1,137 @@ +#include + +namespace guik { + +DrawableTree::DrawableTree() : name("root") {} + +DrawableTree::DrawableTree(const std::string& name) : name(name) {} + +void DrawableTree::update_drawable(const std::string& name, glk::Drawable::ConstPtr drawable, const guik::ShaderSetting& setting) { + const auto names = split_path(name); + update_drawable(names.data(), names.data() + names.size(), drawable, setting); +} + +void DrawableTree::update_setting(const std::string& name, const guik::ShaderSetting& setting) { + const auto names = split_path(name); + update_drawable(names.data(), names.data() + names.size(), nullptr, setting); +} + +void DrawableTree::update_tree_color_mode(const std::string& name, guik::ColorMode::MODE color_mode) { + update_tree_setting(name, "color_mode", color_mode); +} +void DrawableTree::update_tree_color(const std::string& name, const Eigen::Vector4f& color) { + update_tree_setting(name, "material_color", color); +} + +bool DrawableTree::remove(const std::string& name) { + const auto names = split_path(name); + if (!remove(names.data(), names.data() + names.size())) { + std::cerr << "warning: failed to remove subtree : " << name << std::endl; + return false; + } + return true; +} + +void DrawableTree::draw(glk::GLSLShader& shader) const { + draw(shader, Eigen::Matrix4f::Identity()); +} + +void DrawableTree::print_tree(int depth, const Eigen::Matrix4f& parent_model_matrix) const { + Eigen::Matrix4f model_matrix = setting.has_model_matrix() ? parent_model_matrix * setting.model_matrix() : parent_model_matrix; + + for (int i = 0; i < depth; i++) { + std::cout << " "; + } + + Eigen::Quaternionf quat(model_matrix.block<3, 3>(0, 0)); + Eigen::Vector3f trans(model_matrix.block<3, 1>(0, 3)); + + std::cout << name << " : trans=(" << trans.x() << "," << trans.y() << "," << trans.z() << ") quat=(" << quat.x() << "," << quat.y() << "," << quat.z() << "," << quat.w() << ")" + << (drawable ? " D" : "") << std::endl; + + for (const auto& child : children) { + child.second->print_tree(depth + 1, model_matrix); + } +} + +void DrawableTree::update_drawable(const std::string* first, const std::string* last, glk::Drawable::ConstPtr drawable, const guik::ShaderSetting& setting) { + if (first == last) { + this->setting = setting; + if (drawable) { + this->drawable = drawable; + } + return; + } + + auto found = children.find(*first); + if (found == children.end()) { + auto child = DrawableTree::Ptr(new DrawableTree(*first)); + found = children.emplace_hint(found, *first, child); + } + + found->second->update_drawable(first + 1, last, drawable, setting); +} + +bool DrawableTree::remove(const std::string* first, const std::string* last) { + if (first == last) { + return false; + } + + auto found = children.find(*first); + if (found == children.end()) { + return false; + } + + if (first + 1 == last) { + children.erase(found); + return true; + } + + return found->second->remove(first + 1, last); +} + +void DrawableTree::draw(glk::GLSLShader& shader, const Eigen::Matrix4f& parent_model_matrix) const { + Eigen::Matrix4f model_matrix = parent_model_matrix; + if (setting.has_model_matrix()) { + model_matrix = model_matrix * setting.model_matrix(); + } + + if (drawable) { + setting.set(shader); + shader.set_uniform("model_matrix", model_matrix); + drawable->draw(shader); + } + + for (const auto& child : children) { + setting.set(shader); + child.second->draw(shader, model_matrix); + } +} + +std::vector DrawableTree::split_path(const std::string& path) { + if (path.empty()) { + std::cerr << "warning: empty path" << std::endl; + return {}; + } + + std::vector names; + int cursor = path.find_first_not_of('/'); + while (cursor < path.size()) { + int next = path.find('/', cursor); + if (next == cursor) { + std::cout << "warning: skip empty name : " << path.substr(0, cursor) << "()" << path.substr(cursor) << std::endl; + cursor++; + continue; + } + + if (next == std::string::npos) { + names.push_back(path.substr(cursor)); + break; + } + names.push_back(path.substr(cursor, next - cursor)); + cursor = next + 1; + } + + return names; +} +} // namespace guik From 9175cc4ea912a8be1962d5a205e6a98f51716f64 Mon Sep 17 00:00:00 2001 From: "k.koide" Date: Thu, 20 Jun 2024 22:55:22 +0900 Subject: [PATCH 4/4] doc --- include/guik/drawable_tree.hpp | 48 +++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/include/guik/drawable_tree.hpp b/include/guik/drawable_tree.hpp index 6217e4c9..064b411c 100644 --- a/include/guik/drawable_tree.hpp +++ b/include/guik/drawable_tree.hpp @@ -6,7 +6,31 @@ namespace guik { -/// @brief Hierarchical drawable tree +/** +@brief Hierarchical drawable tree. + Drawables are managed with slash-separated path names (e.g., "tree/child/grandchild/obj1"). + The model matrix of a node is hierarchically applied to its children. + For example, for a tree "A/B/C", the model matrix of "C" becomes "A * B * C". +@example + auto tree = std::make_shared(); + // Register drawables to the tree. + tree->update_drawable("parent/child/node1", drawable1, guik::VertexColor(node1_matrix)); + tree->update_drawable("parent/child/node2", drawable2, guik::VertexColor(node2_matrix)); + // Update shader settings. This matrix is applied to both "node1" and "node2". + tree->update_setting("parent/child", guik::ShaderSetting(child_matrix)); + + // Overwrite the color settings of all children of "parent/child". + tree->update_tree_color_mode("parent/child", guik::ColorMode::FLAT_COLOR); + tree->update_tree_color("parent/child", Eigen::Vector4f(0.0f, 0.0f, 1.0f, 1.0f)); + + // Overwrite the point scale of all children of "parent/child". + tree->update_tree_setting("parent/child", "point_scale", 2.0f); + + // Output the tree structure to stdout for debugging. + tree->print_tree(); + + viewer->update_drawable("tree", tree); +*/ class DrawableTree : public glk::Drawable { public: using Ptr = std::shared_ptr; @@ -14,22 +38,35 @@ class DrawableTree : public glk::Drawable { DrawableTree(); + /// @brief Update drawable at a tree node. + /// @param name Slash-separated path name (e.g., "parent/child/node1") + /// @param drawable Drawable object + /// @param setting Shader setting void update_drawable(const std::string& name, glk::Drawable::ConstPtr drawable, const guik::ShaderSetting& setting); + + /// @brief Update shader setting of a node. void update_setting(const std::string& name, const guik::ShaderSetting& setting); + /// @brief Update shader setting of all children of a node. template void update_tree_setting(const std::string& name, const std::string& param_name, const T& val) { const auto names = split_path(name); update_tree_setting(names.data(), names.data() + names.size(), param_name, val); } + /// @brief Update color mode of all children of a node. void update_tree_color_mode(const std::string& name, guik::ColorMode::MODE color_mode); + + /// @brief Update color of all children of a node. void update_tree_color(const std::string& name, const Eigen::Vector4f& color); + /// @brief Remove a subtree. bool remove(const std::string& name); + /// @brief Print the tree structure to stdout. void print_tree(int depth = 0, const Eigen::Matrix4f& parent_model_matrix = Eigen::Matrix4f::Identity()) const; + /// @brief Draw the tree. virtual void draw(glk::GLSLShader& shader) const override; private: @@ -62,11 +99,10 @@ class DrawableTree : public glk::Drawable { std::vector split_path(const std::string& path); private: - const std::string name; - guik::ShaderSetting setting; - - glk::Drawable::ConstPtr drawable; - std::unordered_map children; + const std::string name; // Node name + guik::ShaderSetting setting; // Shader setting associated with the node + glk::Drawable::ConstPtr drawable; // Drawable object associated with the node + std::unordered_map children; // Child nodes }; } // namespace guik