mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 09:46:05 +08:00
Load white/gray icons by icon manager
This commit is contained in:
parent
9ee86599d5
commit
3a6c85ef58
@ -112,6 +112,20 @@ std::string volume_name(const EmbossShape& shape);
|
||||
/// <returns>Params</returns>
|
||||
CreateVolumeParams create_input(GLCanvas3D &canvas, RaycastManager &raycaster, ModelVolumeType volume_type);
|
||||
|
||||
enum class IconType : unsigned {
|
||||
reset_value,
|
||||
reset_value_hover,
|
||||
lock,
|
||||
lock_hover,
|
||||
unlock,
|
||||
unlock_hover,
|
||||
// automatic calc of icon's count
|
||||
_count
|
||||
};
|
||||
|
||||
const IconManager::Icon &get_icon(const IconManager::Icons &icons, IconType type) {
|
||||
return *icons[static_cast<unsigned>(type)]; }
|
||||
|
||||
// This configs holds GUI layout size given by translated texts.
|
||||
// etc. When language changes, GUI is recreated and this class constructed again,
|
||||
// so the change takes effect. (info by GLGizmoFdmSupports.hpp)
|
||||
@ -121,6 +135,9 @@ struct GuiCfg
|
||||
double screen_scale;
|
||||
float main_toolbar_height;
|
||||
|
||||
// Define bigger size(width or height)
|
||||
unsigned texture_max_size_px = 64;
|
||||
|
||||
// Zero means it is calculated in init function
|
||||
ImVec2 minimal_window_size = ImVec2(0, 0);
|
||||
|
||||
@ -337,6 +354,55 @@ void GLGizmoSVG::on_unregister_raycasters_for_picking(){
|
||||
m_rotate_gizmo.unregister_raycasters_for_picking();
|
||||
}
|
||||
|
||||
namespace{
|
||||
IconManager::Icons init_icons(IconManager &mng, const GuiCfg &cfg)
|
||||
{
|
||||
mng.release();
|
||||
|
||||
ImVec2 size(cfg.icon_width, cfg.icon_width);
|
||||
// icon order has to match the enum IconType
|
||||
IconManager::InitTypes init_types{
|
||||
{"undo.svg", size, IconManager::RasterType::white_only_data}, // undo
|
||||
{"undo.svg", size, IconManager::RasterType::color}, // undo_hovered
|
||||
{"lock_closed.svg", size, IconManager::RasterType::white_only_data}, // lock,
|
||||
{"lock_closed_f.svg",size, IconManager::RasterType::white_only_data}, // lock_hovered,
|
||||
{"lock_open.svg", size, IconManager::RasterType::white_only_data}, // unlock,
|
||||
{"lock_open_f.svg", size, IconManager::RasterType::white_only_data} // unlock_hovered
|
||||
};
|
||||
|
||||
assert(init_types.size() == static_cast<size_t>(IconType::_count));
|
||||
std::string path = resources_dir() + "/icons/";
|
||||
for (IconManager::InitType &init_type : init_types)
|
||||
init_type.filepath = path + init_type.filepath;
|
||||
|
||||
return mng.init(init_types);
|
||||
|
||||
//IconManager::VIcons vicons = mng.init(init_types);
|
||||
//
|
||||
//// flatten icons
|
||||
//IconManager::Icons icons;
|
||||
//icons.reserve(vicons.size());
|
||||
//for (IconManager::Icons &i : vicons)
|
||||
// icons.push_back(i.front());
|
||||
//return icons;
|
||||
}
|
||||
|
||||
bool reset_button(const IconManager::Icons &icons)
|
||||
{
|
||||
float reset_offset = ImGui::GetStyle().FramePadding.x;
|
||||
ImGui::SameLine(reset_offset);
|
||||
|
||||
// from GLGizmoCut
|
||||
//std::string label_id = "neco";
|
||||
//std::string btn_label;
|
||||
//btn_label += ImGui::RevertButton;
|
||||
//return ImGui::Button((btn_label + "##" + label_id).c_str());
|
||||
|
||||
return clickable(get_icon(icons, IconType::reset_value), get_icon(icons, IconType::reset_value_hover));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void GLGizmoSVG::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
set_volume_by_selection();
|
||||
@ -358,6 +424,8 @@ void GLGizmoSVG::on_render_input_window(float x, float y, float bottom_limit)
|
||||
|
||||
// set position near toolbar
|
||||
m_set_window_offset = ImVec2(-1.f, -1.f);
|
||||
|
||||
m_icons = init_icons(m_icon_manager, *m_gui_cfg); // need regeneration when change resolution(move between monitors)
|
||||
}
|
||||
|
||||
const ImVec2 &min_window_size = m_gui_cfg->minimal_window_size;
|
||||
@ -399,8 +467,8 @@ void GLGizmoSVG::on_render_input_window(float x, float y, float bottom_limit)
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
if (!is_opened)
|
||||
close();
|
||||
//if (!is_opened)
|
||||
// close();
|
||||
}
|
||||
|
||||
void GLGizmoSVG::on_set_state()
|
||||
@ -455,7 +523,8 @@ void GLGizmoSVG::on_dragging(const UpdateData &data) { m_rotate_gizmo.dragging(d
|
||||
#include "slic3r/GUI/BitmapCache.hpp"
|
||||
#include "nanosvg/nanosvgrast.h"
|
||||
namespace{
|
||||
bool init_texture(Texture &texture, const ModelVolume &mv) {
|
||||
bool init_texture(Texture &texture, const ModelVolume &mv, unsigned max_size_px)
|
||||
{
|
||||
if (!mv.emboss_shape.has_value())
|
||||
return false;
|
||||
|
||||
@ -464,7 +533,6 @@ bool init_texture(Texture &texture, const ModelVolume &mv) {
|
||||
if (filepath.empty())
|
||||
return false;
|
||||
|
||||
unsigned max_size_px = 256;
|
||||
// inspired by:
|
||||
// GLTexture::load_from_svg_file(filepath, false, false, false, max_size_px);
|
||||
NSVGimage *image = BitmapCache::nsvgParseFromFileWithReplace(filepath.c_str(), "px", 96.0f, {});
|
||||
@ -563,7 +631,7 @@ void GLGizmoSVG::set_volume_by_selection()
|
||||
// Calculate current angle of up vector
|
||||
m_angle = calc_up(gl_volume->world_matrix(), Slic3r::GUI::up_limit);
|
||||
m_distance = calc_distance(*gl_volume, m_raycast_manager, m_parent);
|
||||
init_texture(m_texture, *m_volume);
|
||||
|
||||
// calculate scale for height and depth inside of scaled object instance
|
||||
calculate_scale();
|
||||
}
|
||||
@ -644,15 +712,9 @@ void GLGizmoSVG::draw_window()
|
||||
ImGui::Text("Not valid state please report reproduction steps on github");
|
||||
return;
|
||||
}
|
||||
draw_preview();
|
||||
|
||||
if (m_volume->emboss_shape.has_value())
|
||||
ImGui::Text("SVG file path is %s", m_volume->emboss_shape->svg_file_path.c_str());
|
||||
|
||||
if (m_texture.id != 0) {
|
||||
ImTextureID id = (void *) static_cast<intptr_t>(m_texture.id);
|
||||
ImVec2 s(m_texture.width, m_texture.height);
|
||||
ImGui::Image(id, s);
|
||||
}
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Indent(m_gui_cfg->icon_width);
|
||||
draw_depth();
|
||||
@ -663,19 +725,46 @@ void GLGizmoSVG::draw_window()
|
||||
draw_rotation();
|
||||
ImGui::Unindent(m_gui_cfg->icon_width);
|
||||
|
||||
if (ImGui::Button("change file")) {
|
||||
m_volume_shape.shapes_with_ids = select_shape().shapes_with_ids;
|
||||
init_texture(m_texture, *m_volume);
|
||||
// TODO: use setted scale
|
||||
process();
|
||||
}
|
||||
|
||||
if (!m_volume->is_the_only_one_part()) {
|
||||
ImGui::Separator();
|
||||
draw_model_type();
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoSVG::draw_preview(){
|
||||
|
||||
if (m_volume->emboss_shape.has_value())
|
||||
ImGui::Text("SVG file path is %s", m_volume->emboss_shape->svg_file_path.c_str());
|
||||
|
||||
if (m_texture.id == 0)
|
||||
init_texture(m_texture, *m_volume, m_gui_cfg->texture_max_size_px);
|
||||
|
||||
if (m_texture.id != 0) {
|
||||
ImTextureID id = (void *) static_cast<intptr_t>(m_texture.id);
|
||||
ImVec2 s(m_texture.width, m_texture.height);
|
||||
ImGui::Image(id, s);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("change file")) {
|
||||
m_volume_shape.shapes_with_ids = select_shape().shapes_with_ids;
|
||||
init_texture(m_texture, *m_volume, m_gui_cfg->texture_max_size_px);
|
||||
process();
|
||||
}
|
||||
|
||||
// Re-Load button
|
||||
bool can_reload = !m_volume_shape.svg_file_path.empty();
|
||||
if (can_reload) {
|
||||
ImGui::SameLine();
|
||||
if (clickable(get_icon(m_icons, IconType::reset_value), get_icon(m_icons, IconType::reset_value_hover))) {
|
||||
m_volume_shape.shapes_with_ids = select_shape(m_volume_shape.svg_file_path).shapes_with_ids;
|
||||
init_texture(m_texture, *m_volume, m_gui_cfg->texture_max_size_px);
|
||||
process();
|
||||
} else if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", _u8L("Re-load SVG file from disk.").c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoSVG::draw_depth()
|
||||
{
|
||||
ImGuiWrapper::text(m_gui_cfg->translations.depth);
|
||||
@ -746,17 +835,14 @@ void GLGizmoSVG::draw_size()
|
||||
ImGui::SetTooltip("%s", _u8L("Height of SVG.").c_str());
|
||||
|
||||
bool can_reset = !is_approx(m_volume_shape.scale, DEFAULT_SCALE);
|
||||
m_imgui->disabled_begin(!can_reset);
|
||||
ScopeGuard sc([imgui = m_imgui]() { imgui->disabled_end(); });
|
||||
|
||||
float reset_offset = ImGui::GetStyle().FramePadding.x;
|
||||
ImGui::SameLine(reset_offset);
|
||||
if (ImGui::Button("R##size_reset")) {
|
||||
if (can_reset) {
|
||||
if (reset_button(m_icons)) {
|
||||
m_volume_shape.scale = DEFAULT_SCALE;
|
||||
process();
|
||||
} else if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", _u8L("Reset scale to loaded one from the SVG").c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoSVG::draw_use_surface()
|
||||
{
|
||||
@ -810,16 +896,14 @@ void GLGizmoSVG::draw_distance()
|
||||
is_moved = true;
|
||||
}
|
||||
|
||||
m_imgui->disabled_begin(!m_distance.has_value() && allowe_surface_distance);
|
||||
ScopeGuard sg2([imgui = m_imgui]() { imgui->disabled_end(); });
|
||||
|
||||
float reset_offset = ImGui::GetStyle().FramePadding.x;
|
||||
ImGui::SameLine(reset_offset);
|
||||
if (ImGui::Button("R##distance_reset")){
|
||||
bool can_reset = m_distance.has_value();
|
||||
if (can_reset) {
|
||||
if (reset_button(m_icons)) {
|
||||
m_distance.reset();
|
||||
is_moved = true;
|
||||
} else if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", _u8L("Reset distance to zero value").c_str());
|
||||
}
|
||||
|
||||
if (is_moved)
|
||||
do_local_z_move(m_parent, m_distance.value_or(.0f) - prev_distance);
|
||||
@ -837,7 +921,7 @@ void GLGizmoSVG::draw_rotation()
|
||||
// minus create clock-wise roation from CCW
|
||||
float angle = m_angle.value_or(0.f);
|
||||
float angle_deg = static_cast<float>(-angle * 180 / M_PI);
|
||||
if (m_imgui->slider_float("##angle", &angle_deg, limits.angle.min, limits.angle.max, u8"%.2f DEG", 1.f, false, _L("Rotate text Clock-wise."))){
|
||||
if (m_imgui->slider_float("##angle", &angle_deg, limits.angle.min, limits.angle.max, u8"%.2f °", 1.f, false, _L("Rotate text Clock-wise."))){
|
||||
// convert back to radians and CCW
|
||||
double angle_rad = -angle_deg * M_PI / 180.0;
|
||||
Geometry::to_range_pi_pi(angle_rad);
|
||||
@ -854,24 +938,9 @@ void GLGizmoSVG::draw_rotation()
|
||||
process();
|
||||
}
|
||||
|
||||
if (!m_volume->is_the_only_one_part()) {
|
||||
// Keep up - lock button icon
|
||||
ImGui::SameLine(m_gui_cfg->lock_offset);
|
||||
ImGui::Checkbox("##Lock_up_vector", &m_keep_up);
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", (m_keep_up ?
|
||||
_u8L("Unlock the rotation when moving volume along the object's surface.") :
|
||||
_u8L("Lock the rotation when moving volume along the object's surface."))
|
||||
.c_str());
|
||||
}
|
||||
|
||||
// Reset button
|
||||
m_imgui->disabled_begin(!m_angle.has_value());
|
||||
ScopeGuard sg([imgui = m_imgui]() { imgui->disabled_end(); });
|
||||
|
||||
float reset_offset = ImGui::GetStyle().FramePadding.x;
|
||||
ImGui::SameLine(reset_offset);
|
||||
if (ImGui::Button("R##angle_reset")) {
|
||||
if (m_angle.has_value()) {
|
||||
if (reset_button(m_icons)) {
|
||||
do_local_z_rotate(m_parent, -(*m_angle));
|
||||
m_angle.reset();
|
||||
|
||||
@ -880,19 +949,21 @@ void GLGizmoSVG::draw_rotation()
|
||||
process();
|
||||
} else if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", _u8L("Reset rotation to zero value").c_str());
|
||||
}
|
||||
|
||||
// Keep up - lock button icon
|
||||
//ImGui::SameLine(m_gui_cfg->lock_offset);
|
||||
//const IconManager::Icon &icon = get_icon(m_icons, m_keep_up ? IconType::lock : IconType::unlock, IconState::activable);
|
||||
//const IconManager::Icon &icon_hover = get_icon(m_icons, m_keep_up ? IconType::lock_bold : IconType::unlock_bold, IconState::activable);
|
||||
//const IconManager::Icon &icon_disable = get_icon(m_icons, m_keep_up ? IconType::lock : IconType::unlock, IconState::disabled);
|
||||
//if (button(icon, icon_hover, icon_disable))
|
||||
// m_keep_up = !m_keep_up;
|
||||
//if (ImGui::IsItemHovered())
|
||||
// ImGui::SetTooltip("%s", (m_keep_up?
|
||||
// _u8L("Unlock the text's rotation when moving text along the object's surface."):
|
||||
// _u8L("Lock the text's rotation when moving text along the object's surface.")
|
||||
// ).c_str());
|
||||
if (!m_volume->is_the_only_one_part()) {
|
||||
ImGui::SameLine(m_gui_cfg->lock_offset);
|
||||
const IconManager::Icon &icon = get_icon(m_icons,m_keep_up ? IconType::lock : IconType::unlock);
|
||||
const IconManager::Icon &icon_hover = get_icon(m_icons, m_keep_up ? IconType::lock_hover : IconType::unlock_hover);
|
||||
if (button(icon, icon_hover, icon))
|
||||
m_keep_up = !m_keep_up;
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", (m_keep_up?
|
||||
_u8L("Free angle when dragging above the object's surface."):
|
||||
_u8L("Keep same rotation angle when dragging above the object's surface.")
|
||||
).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoSVG::draw_model_type()
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "slic3r/GUI/SurfaceDrag.hpp"
|
||||
#include "slic3r/GUI/GLTexture.hpp"
|
||||
#include "slic3r/Utils/RaycastManager.hpp"
|
||||
#include "slic3r/GUI/IconManager.hpp"
|
||||
|
||||
#include <optional>
|
||||
#include <memory>
|
||||
@ -115,6 +116,7 @@ private:
|
||||
bool process();
|
||||
void close();
|
||||
void draw_window();
|
||||
void draw_preview();
|
||||
void draw_depth();
|
||||
void draw_size();
|
||||
void draw_use_surface();
|
||||
@ -172,6 +174,9 @@ private:
|
||||
|
||||
Texture m_texture;
|
||||
|
||||
IconManager m_icon_manager;
|
||||
IconManager::Icons m_icons;
|
||||
|
||||
// only temporary solution
|
||||
static const std::string M_ICON_FILENAME;
|
||||
};
|
||||
|
@ -1,6 +1,15 @@
|
||||
#include "IconManager.hpp"
|
||||
#include <cmath>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include "nanosvg/nanosvg.h"
|
||||
#include "nanosvg/nanosvgrast.h"
|
||||
#include "libslic3r/Utils.hpp" // ScopeGuard
|
||||
|
||||
#include "3DScene.hpp" // glsafe
|
||||
#include "GL/glew.h"
|
||||
|
||||
#define STB_RECT_PACK_IMPLEMENTATION
|
||||
#include "imgui/imstb_rectpack.h" // distribute rectangles
|
||||
|
||||
using namespace Slic3r::GUI;
|
||||
|
||||
@ -14,12 +23,188 @@ static void draw_transparent_icon(const IconManager::Icon &icon); // only help f
|
||||
IconManager::~IconManager() {
|
||||
priv::clear(m_icons);
|
||||
// release opengl texture is made in ~GLTexture()
|
||||
|
||||
if (m_id != 0)
|
||||
glsafe(::glDeleteTextures(1, &m_id));
|
||||
}
|
||||
|
||||
std::vector<IconManager::Icons> IconManager::init(const InitTypes &input)
|
||||
namespace {
|
||||
NSVGimage *parse_file(const char * filepath) {
|
||||
FILE *fp = boost::nowide::fopen(filepath, "rb");
|
||||
assert(fp != nullptr);
|
||||
if (fp == nullptr)
|
||||
return nullptr;
|
||||
|
||||
Slic3r::ScopeGuard sg([fp]() { fclose(fp); });
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
size_t size = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
// Note: +1 is for null termination
|
||||
auto data_ptr = std::make_unique<char[]>(size+1);
|
||||
data_ptr[size] = '\0'; // Must be null terminated.
|
||||
|
||||
size_t readed_size = fread(data_ptr.get(), 1, size, fp);
|
||||
assert(readed_size == size);
|
||||
if (readed_size != size)
|
||||
return nullptr;
|
||||
|
||||
return nsvgParse(data_ptr.get(), "px", 96.0f);
|
||||
}
|
||||
|
||||
void subdata(unsigned char *data, size_t data_stride, const std::vector<unsigned char> &data2, size_t data2_row) {
|
||||
assert(data_stride >= data2_row);
|
||||
for (size_t data2_offset = 0, data_offset = 0;
|
||||
data2_offset < data2.size();
|
||||
data2_offset += data2_row, data_offset += data_stride)
|
||||
::memcpy((void *)(data + data_offset), (const void *)(data2.data() + data2_offset), data2_row);
|
||||
}
|
||||
}
|
||||
|
||||
IconManager::Icons IconManager::init(const InitTypes &input)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << "Not implemented yet";
|
||||
if (input.empty())
|
||||
return {};
|
||||
|
||||
// TODO: remove in future
|
||||
if (m_id != 0) {
|
||||
glsafe(::glDeleteTextures(1, &m_id));
|
||||
m_id = 0;
|
||||
}
|
||||
|
||||
int total_surface = 0;
|
||||
for (const InitType &i : input)
|
||||
total_surface += i.size.x * i.size.y;
|
||||
const int surface_sqrt = (int)sqrt((float)total_surface) + 1;
|
||||
|
||||
// Start packing
|
||||
// Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
|
||||
const int TEX_HEIGHT_MAX = 1024 * 32;
|
||||
int width = (surface_sqrt >= 4096 * 0.7f) ? 4096 : (surface_sqrt >= 2048 * 0.7f) ? 2048 : (surface_sqrt >= 1024 * 0.7f) ? 1024 : 512;
|
||||
|
||||
int num_nodes = width;
|
||||
std::vector<stbrp_node> nodes(num_nodes);
|
||||
stbrp_context context;
|
||||
stbrp_init_target(&context, width, TEX_HEIGHT_MAX, nodes.data(), num_nodes);
|
||||
|
||||
ImVector<stbrp_rect> pack_rects;
|
||||
pack_rects.resize(input.size());
|
||||
memset(pack_rects.Data, 0, (size_t) pack_rects.size_in_bytes());
|
||||
for (int i = 0; i < input.size(); i++) {
|
||||
const ImVec2 &size = input[i].size;
|
||||
assert(size.x > 1);
|
||||
assert(size.y > 1);
|
||||
pack_rects[i].w = size.x;
|
||||
pack_rects[i].h = size.y;
|
||||
}
|
||||
int pack_rects_res = stbrp_pack_rects(&context, &pack_rects[0], pack_rects.Size);
|
||||
assert(pack_rects_res == 1);
|
||||
if (pack_rects_res != 1)
|
||||
return {};
|
||||
|
||||
ImVec2 tex_size(width, width);
|
||||
for (const stbrp_rect &rect : pack_rects) {
|
||||
float x = rect.x + rect.w;
|
||||
float y = rect.y + rect.h;
|
||||
if(x > tex_size.x) tex_size.x = x;
|
||||
if(y > tex_size.y) tex_size.y = y;
|
||||
}
|
||||
|
||||
Icons result(input.size());
|
||||
for (int i = 0; i < pack_rects.Size; i++) {
|
||||
const stbrp_rect &rect = pack_rects[i];
|
||||
assert(rect.was_packed);
|
||||
if (!rect.was_packed)
|
||||
return {};
|
||||
|
||||
ImVec2 tl(rect.x / tex_size.x, rect.y / tex_size.y);
|
||||
ImVec2 br((rect.x + rect.w) / tex_size.x, (rect.y + rect.h) / tex_size.y);
|
||||
|
||||
assert(input[i].size.x == rect.w);
|
||||
assert(input[i].size.y == rect.h);
|
||||
Icon icon = {input[i].size, tl, br};
|
||||
result[i] = std::make_shared<Icon>(std::move(icon));
|
||||
}
|
||||
|
||||
NSVGrasterizer *rast = nsvgCreateRasterizer();
|
||||
assert(rast != nullptr);
|
||||
if (rast == nullptr)
|
||||
return {};
|
||||
ScopeGuard sg_rast([rast]() { ::nsvgDeleteRasterizer(rast); });
|
||||
|
||||
int channels = 4;
|
||||
int n_pixels = tex_size.x * tex_size.y;
|
||||
// store data for whole texture
|
||||
std::vector<unsigned char> data(n_pixels * channels, {0});
|
||||
|
||||
// initialize original index locations
|
||||
std::vector<size_t> idx(input.size());
|
||||
std::iota(idx.begin(), idx.end(), 0);
|
||||
|
||||
// Group same filename by sort inputs
|
||||
// sort indexes based on comparing values in input
|
||||
std::sort(idx.begin(), idx.end(), [&input](size_t i1, size_t i2) { return input[i1].filepath < input[i2].filepath; });
|
||||
for (size_t j: idx) {
|
||||
const InitType &i = input[j];
|
||||
if (i.filepath.empty())
|
||||
continue; // no file path only reservation of space for texture
|
||||
|
||||
if (!boost::filesystem::exists(i.filepath))
|
||||
continue;
|
||||
if (!boost::algorithm::iends_with(i.filepath, ".svg"))
|
||||
continue;
|
||||
|
||||
NSVGimage *image = parse_file(i.filepath.c_str());
|
||||
assert(image != nullptr);
|
||||
if (image == nullptr)
|
||||
return {};
|
||||
|
||||
ScopeGuard sg_image([image]() { ::nsvgDelete(image); });
|
||||
|
||||
float svg_scale = i.size.y / image->height;
|
||||
// scale should be same in both directions
|
||||
assert(is_approx(svg_scale, i.size.y / image->width));
|
||||
|
||||
const stbrp_rect &rect = pack_rects[j];
|
||||
int n_pixels = rect.w * rect.h;
|
||||
std::vector<unsigned char> icon_data(n_pixels * channels, {0});
|
||||
::nsvgRasterize(rast, image, 0, 0, svg_scale, icon_data.data(), i.size.x, i.size.y, i.size.x * channels);
|
||||
|
||||
// makes white or gray only data in icon
|
||||
if (i.type == RasterType::white_only_data ||
|
||||
i.type == RasterType::gray_only_data) {
|
||||
unsigned char value = (i.type == RasterType::white_only_data) ? 255 : 127;
|
||||
for (size_t k = 0; k < icon_data.size(); k += channels)
|
||||
if (icon_data[k] != 0 || icon_data[k + 1] != 0 || icon_data[k + 2] != 0) {
|
||||
icon_data[k] = value;
|
||||
icon_data[k + 1] = value;
|
||||
icon_data[k + 2] = value;
|
||||
}
|
||||
}
|
||||
|
||||
int start_offset = (rect.y*tex_size.x + rect.x) * channels;
|
||||
int data_stride = tex_size.x * channels;
|
||||
subdata(data.data() + start_offset, data_stride, icon_data, rect.w * channels);
|
||||
}
|
||||
|
||||
if (m_id != 0)
|
||||
glsafe(::glDeleteTextures(1, &m_id));
|
||||
|
||||
glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
|
||||
glsafe(::glGenTextures(1, &m_id));
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint) m_id));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei) tex_size.x, (GLsizei) tex_size.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void*) data.data()));
|
||||
|
||||
// bind no texture
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
||||
|
||||
for (const auto &i : result)
|
||||
i->tex_id = m_id;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<IconManager::Icons> IconManager::init(const std::vector<std::string> &file_paths, const ImVec2 &size, RasterType type)
|
||||
|
@ -70,10 +70,10 @@ public:
|
||||
/// Initialize raster texture on GPU with given images
|
||||
/// NOTE: Have to be called after OpenGL initialization
|
||||
/// </summary>
|
||||
/// <param name="input">Define files and its </param>
|
||||
/// <param name="input">Define files and its size with rasterization</param>
|
||||
/// <returns>Rasterized icons stored on GPU,
|
||||
/// Same size and order as input, each item of vector is set of texture in order by RasterType</returns>
|
||||
VIcons init(const InitTypes &input);
|
||||
Icons init(const InitTypes &input);
|
||||
|
||||
/// <summary>
|
||||
/// Initialize multiple icons with same settings for size and type
|
||||
@ -96,6 +96,11 @@ public:
|
||||
private:
|
||||
// keep data stored on GPU
|
||||
GLTexture m_icons_texture;
|
||||
|
||||
unsigned int m_id{ 0 };
|
||||
int m_width{ 0 };
|
||||
int m_height{ 0 };
|
||||
|
||||
Icons m_icons;
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user