From 9d8883036593143c4e9453f5ffca80553796c3a3 Mon Sep 17 00:00:00 2001 From: Filip Sykala - NTB T15p Date: Fri, 24 Feb 2023 13:31:20 +0100 Subject: [PATCH] Separate icon manager. Create well public interface for future work and improve --- src/slic3r/CMakeLists.txt | 2 + src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 72 ++++-------- src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp | 10 +- src/slic3r/GUI/IconManager.cpp | 150 ++++++++++++++++++++++++ src/slic3r/GUI/IconManager.hpp | 110 +++++++++++++++++ 5 files changed, 287 insertions(+), 57 deletions(-) create mode 100644 src/slic3r/GUI/IconManager.cpp create mode 100644 src/slic3r/GUI/IconManager.hpp diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 453d7eeb5..299705ce8 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -97,6 +97,8 @@ set(SLIC3R_GUI_SOURCES GUI/GUI_Geometry.hpp GUI/I18N.cpp GUI/I18N.hpp + GUI/IconManager.cpp + GUI/IconManager.hpp GUI/MainFrame.cpp GUI/MainFrame.hpp GUI/Plater.cpp diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index b12aeea66..f6b49d1cb 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -3795,23 +3795,9 @@ void GLGizmoEmboss::init_icons() std::string path = resources_dir() + "/icons/"; for (std::string &filename : filenames) filename = path + filename; - // state order has to match the enum IconState - std::vector> states; - states.push_back(std::make_pair(1, false)); // Activable - states.push_back(std::make_pair(0, false)); // Hovered - states.push_back(std::make_pair(2, false)); // Disabled - - bool compress = false; - bool is_loaded = m_icons_texture.load_from_svg_files_as_sprites_array( - filenames, states, m_gui_cfg->icon_width, compress); - - if (!is_loaded || - (size_t)m_icons_texture.get_width() < (states.size() * m_gui_cfg->icon_width) || - (size_t)m_icons_texture.get_height() < (filenames.size() * m_gui_cfg->icon_width)) { - // bad load of icons, but all usage of m_icons_texture check that texture is initialized - assert(false); - m_icons_texture.reset(); - } + ImVec2 size(m_gui_cfg->icon_width, m_gui_cfg->icon_width); + auto type = IconManager::RasterType::color_wite_gray; + m_icons = m_icon_manager.init(filenames, size, type); } void GLGizmoEmboss::draw_icon(IconType icon, IconState state, ImVec2 size) @@ -3820,48 +3806,32 @@ void GLGizmoEmboss::draw_icon(IconType icon, IconState state, ImVec2 size) assert(icon != IconType::_count); if (icon == IconType::_count) return; - unsigned int icons_texture_id = m_icons_texture.get_id(); - int tex_width = m_icons_texture.get_width(); - int tex_height = m_icons_texture.get_height(); - // is icon loaded - if ((icons_texture_id == 0) || (tex_width <= 1) || (tex_height <= 1)){ - ImGui::Text("▮"); - return; - } - - int icon_width = m_gui_cfg->icon_width; - ImTextureID tex_id = (void *) (intptr_t) (GLuint) icons_texture_id; - int start_x = static_cast(state) * (icon_width + 1) + 1, - start_y = static_cast(icon) * (icon_width + 1) + 1; - - ImVec2 uv0(start_x / (float) tex_width, - start_y / (float) tex_height); - ImVec2 uv1((start_x + icon_width) / (float) tex_width, - (start_y + icon_width) / (float) tex_height); - - if (size.x < 1 || size.y < 1) - size = ImVec2(m_gui_cfg->icon_width, m_gui_cfg->icon_width); - - ImGui::Image(tex_id, size, uv0, uv1); + const auto &i = *m_icons[static_cast(icon)][static_cast(state)]; + IconManager::draw(i); } void GLGizmoEmboss::draw_transparent_icon() { - unsigned int icons_texture_id = m_icons_texture.get_id(); - int tex_width = m_icons_texture.get_width(); - int tex_height = m_icons_texture.get_height(); - // is icon loaded - if ((icons_texture_id == 0) || (tex_width <= 1) || (tex_height <= 1)) { + // use top left corner of first icon + IconManager::Icon icon = *m_icons.front().front(); // copy + + if (!icon.is_valid()) { ImGui::Text("▯"); return; } - ImTextureID tex_id = (void *) (intptr_t) (GLuint) icons_texture_id; - int icon_width = m_gui_cfg->icon_width; - ImVec2 icon_size(icon_width, icon_width); - ImVec2 pixel_size(1.f / tex_width, 1.f / tex_height); - // zero pixel is transparent in texture - ImGui::Image(tex_id, icon_size, ImVec2(0, 0), pixel_size); + // size UV texture coors [in texture ratio] + ImVec2 size_uv( + icon.br.x-icon.tl.x, + icon.br.y-icon.tl.y); + ImVec2 one_px( + size_uv.x/icon.size.x, + size_uv.y/icon.size.y); + // reduce uv coors to one pixel + icon.br = ImVec2( + icon.tl.x + one_px.x, + icon.tl.y + one_px.y); + IconManager::draw(icon); } bool GLGizmoEmboss::draw_clickable( diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index f17293074..76d870726 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -5,15 +5,12 @@ // which overrides our localization "L" macro. #include "GLGizmoBase.hpp" #include "GLGizmoRotate.hpp" -#include "slic3r/GUI/GLTexture.hpp" +#include "slic3r/GUI/IconManager.hpp" #include "slic3r/Utils/RaycastManager.hpp" #include "slic3r/Utils/EmbossStyleManager.hpp" -#include "admesh/stl.h" // indexed_triangle_set #include #include -#include -#include #include #include "libslic3r/Emboss.hpp" @@ -33,7 +30,6 @@ namespace Slic3r{ } namespace Slic3r::GUI { -class MeshRaycaster; class GLGizmoEmboss : public GLGizmoBase { public: @@ -346,7 +342,9 @@ private: void calculate_scale(); // drawing icons - GLTexture m_icons_texture; + IconManager m_icon_manager; + std::vector m_icons; + void init_icons(); enum class IconType : unsigned { rename = 0, diff --git a/src/slic3r/GUI/IconManager.cpp b/src/slic3r/GUI/IconManager.cpp new file mode 100644 index 000000000..0cde271d0 --- /dev/null +++ b/src/slic3r/GUI/IconManager.cpp @@ -0,0 +1,150 @@ +#include "IconManager.hpp" + +#include + +using namespace Slic3r::GUI; + +namespace priv { +// set shared pointer to point on bad texture +static void clear(IconManager::Icons &icons); +static const std::vector>& get_states(IconManager::RasterType type); +} + +IconManager::~IconManager() { + priv::clear(m_icons); + // release opengl texture is made in ~GLTexture() +} + +std::vector IconManager::init(const InitTypes &input) +{ + BOOST_LOG_TRIVIAL(error) << "Not implemented yet"; + return {}; +} + +std::vector IconManager::init(const std::vector &file_paths, const ImVec2 &size, RasterType type) +{ + // TODO: remove in future + if (!m_icons.empty()) { + // not first initialization + priv::clear(m_icons); + m_icons.clear(); + m_icons_texture.reset(); + } + + // only rectangle are supported + assert(size.x == size.y); + // no subpixel supported + unsigned int width = static_cast(std::fabs(std::round(size.x))); + assert(size.x == static_cast(width)); + + // state order has to match the enum IconState + const auto& states = priv::get_states(type); + + bool compress = false; + bool is_loaded = m_icons_texture.load_from_svg_files_as_sprites_array(file_paths, states, width, compress); + if (!is_loaded || (size_t) m_icons_texture.get_width() < (states.size() * width) || + (size_t) m_icons_texture.get_height() < (file_paths.size() * width)) { + // bad load of icons, but all usage of m_icons_texture check that texture is initialized + assert(false); + m_icons_texture.reset(); + return {}; + } + + unsigned count_files = file_paths.size(); + // count icons per file + unsigned count = states.size(); + // create result + std::vector result; + result.reserve(count_files); + + Icon def_icon; + def_icon.tex_id = m_icons_texture.get_id(); + def_icon.size = size; + + // float beacouse of dividing + float tex_height = static_cast(m_icons_texture.get_height()); + float tex_width = static_cast(m_icons_texture.get_width()); + + //for (const auto &f: file_paths) { + for (unsigned f = 0; f < count_files; ++f) { + // NOTE: there are space between icons + unsigned start_y = static_cast(f) * (width + 1) + 1; + float y1 = start_y / tex_height; + float y2 = (start_y + width) / tex_height; + Icons file_icons; + file_icons.reserve(count); + //for (const auto &s : states) { + for (unsigned j = 0; j < count; ++j) { + auto icon = std::make_shared(def_icon); + // NOTE: there are space between icons + unsigned start_x = static_cast(j) * (width + 1) + 1; + float x1 = start_x / tex_width; + float x2 = (start_x + width) / tex_width; + icon->tl = ImVec2(x1, y1); + icon->br = ImVec2(x2, y2); + file_icons.push_back(icon); + m_icons.push_back(std::move(icon)); + } + result.emplace_back(std::move(file_icons)); + } + return result; +} + +void IconManager::release() { + BOOST_LOG_TRIVIAL(error) << "Not implemented yet"; +} + +void IconManager::draw(const Icon &icon, const ImVec2 &size, const ImVec4 &tint_col, const ImVec4 &border_col) +{ + // is icon loaded + if (!icon.is_valid()) { + ImGui::Text("?"); + return; + } + + ImTextureID id = (void *) icon.tex_id; + const ImVec2 &s = (size.x < 1 || size.y < 1) ? icon.size : size; + ImGui::Image(id, s, icon.tl, icon.br, tint_col, border_col); +} + +void priv::clear(IconManager::Icons &icons) { + std::string message; + for (auto &icon : icons) { + // Exist more than this instance of shared ptr? + long count = icon.use_count(); + if (count != 1) { + // in existing icon change texture to non existing one + icon->tex_id = 0; + + std::string descr = + ((count > 2) ? (std::to_string(count - 1) + "x") : "") + // count + std::to_string(icon->size.x) + "x" + std::to_string(icon->size.y); // resolution + if (message.empty()) + message = descr; + else + message += ", " + descr; + } + } + + if (!message.empty()) + BOOST_LOG_TRIVIAL(warning) << "There is still used icons(" << message << ")."; +} + +const std::vector> &priv::get_states(IconManager::RasterType type) { + static std::vector> color = {std::make_pair(0, false)}; + static std::vector> white = {std::make_pair(1, false)}; + static std::vector> gray = {std::make_pair(2, false)}; + static std::vector> color_wite_gray = { + std::make_pair(1, false), // Activable + std::make_pair(0, false), // Hovered + std::make_pair(2, false) // Disabled + }; + + switch (type) { + case IconManager::RasterType::color: return color; + case IconManager::RasterType::white_only_data: return white; + case IconManager::RasterType::gray_only_data: return gray; + case IconManager::RasterType::color_wite_gray: return color_wite_gray; + default: return color; + } +} diff --git a/src/slic3r/GUI/IconManager.hpp b/src/slic3r/GUI/IconManager.hpp new file mode 100644 index 000000000..91177fe8a --- /dev/null +++ b/src/slic3r/GUI/IconManager.hpp @@ -0,0 +1,110 @@ +#ifndef slic3r_IconManager_hpp_ +#define slic3r_IconManager_hpp_ + +#include +#include +#include "imgui/imgui.h" // ImVec2 +#include "slic3r/GUI/GLTexture.hpp" // texture storage + +namespace Slic3r::GUI { + +/// +/// Keep texture with icons for UI +/// Manage texture live -> create and destruct texture +/// by live of icon shared pointers. +/// +class IconManager +{ +public: + /// + /// Release texture + /// Set shared pointers to invalid texture + /// + ~IconManager(); + + /// + /// Define way to convert svg data to raster + /// + enum class RasterType: int{ + color = 1 << 1, + white_only_data = 1 << 2, + gray_only_data = 1 << 3, + color_wite_gray = color | white_only_data | gray_only_data + // TODO: add type with backgrounds + }; + + struct InitType { + // path to file with image .. svg + std::string filepath; + + // resolution of stored rasterized icon + ImVec2 size; // float will be rounded + + // could contain more than one type + RasterType type = RasterType::color; + // together color, white and gray = color | white_only_data | gray_only_data + }; + using InitTypes = std::vector; + + /// + /// Data for render texture with icon + /// + struct Icon { + // stored texture size + ImVec2 size = ImVec2(-1, -1); // [in px] --> unsigned int values stored as float + + // SubTexture UV coordinate in range from 0. to 1. + ImVec2 tl; // top left -> uv0 + ImVec2 br; // bottom right -> uv1 + + // OpenGL texture id + unsigned int tex_id = 0; + bool is_valid() const { return tex_id != 0;} + // && size.x > 0 && size.y > 0 && tl.x != br.x && tl.y != br.y; + }; + using Icons = std::vector >; + + /// + /// Initialize raster texture on GPU with given images + /// NOTE: Have to be called after OpenGL initialization + /// + /// Define files and its + /// Rasterized icons stored on GPU, + /// Same size and order as input, each item of vector is set of texture in order by RasterType + std::vector init(const InitTypes &input); + + /// + /// Initialize multiple icons with same settings for size and type + /// NOTE: Have to be called after OpenGL initialization + /// + /// Define files with icon + /// Size of stored texture[in px], float will be rounded + /// Define way to rasterize icon, + /// together color, white and gray = RasterType::color | RasterType::white_only_data | RasterType::gray_only_data + /// Rasterized icons stored on GPU, + /// Same size and order as file_paths, each item of vector is set of texture in order by RasterType + std::vector init(const std::vector &file_paths, const ImVec2 &size, RasterType type = RasterType::color); + + /// + /// Release icons which are hold only by this manager + /// May change texture and position of icons. + /// + void release(); + + /// + /// Draw imgui image with icon + /// + /// Place in texture + /// [optional]Size of image, wen zero than use same size as stored texture + /// viz ImGui::Image + /// viz ImGui::Image + static void draw(const Icon &icon, const ImVec2 &size = ImVec2(0, 0), const ImVec4& tint_col = ImVec4(1,1,1,1), const ImVec4& border_col = ImVec4(0,0,0,0)); + +private: + // keep data stored on GPU + GLTexture m_icons_texture; + Icons m_icons; +}; + +} // namespace Slic3r::GUI +#endif // slic3r_IconManager_hpp_ \ No newline at end of file