Render texture of svg

This commit is contained in:
Filip Sykala - NTB T15p 2023-06-09 17:49:48 +02:00
parent 87517c5c68
commit 1c80d4358a
5 changed files with 141 additions and 29 deletions

View File

@ -678,7 +678,7 @@ void GLGizmoEmboss::on_render() {
if (m_text_lines.is_init()) { if (m_text_lines.is_init()) {
const Transform3d& tr = gl_volume_ptr->world_matrix(); const Transform3d& tr = gl_volume_ptr->world_matrix();
const auto &fix = m_volume->text_configuration->fix_3mf_tr; const auto &fix = m_volume->emboss_shape->fix_3mf_tr;
if (fix.has_value()) if (fix.has_value())
m_text_lines.render(tr * fix->inverse()); m_text_lines.render(tr * fix->inverse());
else else
@ -1096,6 +1096,11 @@ void init_text_lines(TextLinesModel &text_lines, const Selection& selection, /*
if (mv.is_the_only_one_part()) if (mv.is_the_only_one_part())
return; return;
const std::optional<EmbossShape> &es_opt = mv.emboss_shape;
if (!es_opt.has_value())
return;
const EmbossShape &es = *es_opt;
const std::optional<TextConfiguration> &tc_opt = mv.text_configuration; const std::optional<TextConfiguration> &tc_opt = mv.text_configuration;
if (!tc_opt.has_value()) if (!tc_opt.has_value())
return; return;
@ -1125,8 +1130,8 @@ void init_text_lines(TextLinesModel &text_lines, const Selection& selection, /*
// For interactivity during drag over surface it must be from gl_volume not volume. // For interactivity during drag over surface it must be from gl_volume not volume.
Transform3d mv_trafo = gl_volume.get_volume_transformation().get_matrix(); Transform3d mv_trafo = gl_volume.get_volume_transformation().get_matrix();
if (tc.fix_3mf_tr.has_value()) if (es.fix_3mf_tr.has_value())
mv_trafo = mv_trafo * (tc.fix_3mf_tr->inverse()); mv_trafo = mv_trafo * (es.fix_3mf_tr->inverse());
FontProp::VerticalAlign align = style_manager.get_font_prop().align.second; FontProp::VerticalAlign align = style_manager.get_font_prop().align.second;
double line_height_mm, line_offset_mm; double line_height_mm, line_offset_mm;
if (!get_line_height_offset(style_manager, line_height_mm, line_offset_mm)) if (!get_line_height_offset(style_manager, line_height_mm, line_offset_mm))
@ -1357,13 +1362,18 @@ bool GLGizmoEmboss::process()
if (sources.empty()) if (sources.empty())
return false; return false;
const std::optional<EmbossShape> &es_opt = m_volume->emboss_shape;
if (!es_opt.has_value())
return false;
const EmbossShape &es = *es_opt;
Transform3d text_tr = m_volume->get_matrix(); Transform3d text_tr = m_volume->get_matrix();
auto& fix_3mf = m_volume->text_configuration->fix_3mf_tr; auto& fix_3mf = es.fix_3mf_tr;
if (fix_3mf.has_value()) if (fix_3mf.has_value())
text_tr = text_tr * fix_3mf->inverse(); text_tr = text_tr * fix_3mf->inverse();
// when it is new applying of use surface than move origin onto surfaca // when it is new applying of use surface than move origin onto surfaca
if (!m_volume->text_configuration->style.prop.use_surface) { if (!es.projection.use_surface) {
auto offset = calc_surface_offset(m_parent.get_selection(), m_raycast_manager); auto offset = calc_surface_offset(m_parent.get_selection(), m_raycast_manager);
if (offset.has_value()) if (offset.has_value())
text_tr *= Eigen::Translation<double, 3>(*offset); text_tr *= Eigen::Translation<double, 3>(*offset);
@ -3377,9 +3387,11 @@ std::unique_ptr<DataBase> create_emboss_data_base(const std::string
cancel->store(true); cancel->store(true);
// create new shared ptr to cancel new job // create new shared ptr to cancel new job
cancel = std::make_shared<std::atomic<bool>>(false); cancel = std::make_shared<std::atomic<bool>>(false);
DataBase base(volume_name, cancel); DataBase base(volume_name, cancel);
base.is_outside = is_outside; base.is_outside = is_outside;
base.text_lines = text_lines.get_lines(); base.text_lines = text_lines.get_lines();
base.from_surface = style.distance;
FontFileWithCache &font = style_manager.get_font_file_with_cache(); FontFileWithCache &font = style_manager.get_font_file_with_cache();
TextConfiguration tc{static_cast<EmbossStyle>(style), text}; TextConfiguration tc{static_cast<EmbossStyle>(style), text};

View File

@ -147,6 +147,16 @@ GuiCfg create_gui_configuration();
// use private definition // use private definition
struct GLGizmoSVG::GuiCfg: public ::GuiCfg{}; struct GLGizmoSVG::GuiCfg: public ::GuiCfg{};
namespace Slic3r {
BoundingBox get_extents(const ExPolygonsWithIds &expoly_ids)
{
BoundingBox result;
for (const ExPolygonsWithId &expoly_id : expoly_ids)
result.merge(get_extents(expoly_id.expoly));
return result;
}
} // namespace Slic3r
bool GLGizmoSVG::create_volume(ModelVolumeType volume_type, const Vec2d &mouse_pos) bool GLGizmoSVG::create_volume(ModelVolumeType volume_type, const Vec2d &mouse_pos)
{ {
CreateVolumeParams input = create_input(m_parent, m_raycast_manager, volume_type); CreateVolumeParams input = create_input(m_parent, m_raycast_manager, volume_type);
@ -433,6 +443,79 @@ void GLGizmoSVG::on_stop_dragging()
} }
void GLGizmoSVG::on_dragging(const UpdateData &data) { m_rotate_gizmo.dragging(data); } void GLGizmoSVG::on_dragging(const UpdateData &data) { m_rotate_gizmo.dragging(data); }
#include "slic3r/GUI/BitmapCache.hpp"
#include "nanosvg/nanosvgrast.h"
namespace{
bool init_texture(Texture &texture, const ModelVolume &mv) {
if (!mv.emboss_shape.has_value())
return false;
const EmbossShape &es = *mv.emboss_shape;
const std::string &filepath = es.svg_file_path;
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, {});
if (image == nullptr)
return false;
ScopeGuard sg_image([image]() { nsvgDelete(image); });
// NOTE: Can not use es.shape --> it is aligned and one need offset in svg
ExPolygons shape = to_expolygons(image);
if (shape.empty())
return false;
BoundingBox bb = get_extents(shape);
Point bb_size = bb.size();
double bb_width = bb_size.x(); // [in mm]
double bb_height = bb_size.y(); // [in mm]
bool is_widder = bb_size.x() > bb_size.y();
float scale = 0.f;
if (is_widder){
scale = static_cast<float>(max_size_px / bb_width);
texture.width = max_size_px;
texture.height = static_cast<unsigned>(std::ceil(bb_height * scale));
} else {
scale = static_cast<float>(max_size_px / bb_height);
texture.width = static_cast<unsigned>(std::ceil(bb_width * scale));
texture.height = max_size_px;
}
const int n_pixels = texture.width * texture.height;
if (n_pixels <= 0)
return false;
NSVGrasterizer* rast = nsvgCreateRasterizer();
if (rast == nullptr)
return false;
ScopeGuard sg_rast([rast]() { nsvgDeleteRasterizer(rast); });
int channels_count = 4;
std::vector<unsigned char> data(n_pixels * channels_count, 0);
float tx = static_cast<float>(-bb.min.x() * scale);
float ty = static_cast<float>(bb.max.y() * scale); // Reverse direction of y
int stride = texture.width * channels_count;
nsvgRasterizeXY(rast, image, tx, ty, scale, scale, data.data(), texture.width, texture.height, stride);
// sends data to gpu
glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
glsafe(::glGenTextures(1, &texture.id));
glsafe(::glBindTexture(GL_TEXTURE_2D, texture.id));
glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei) texture.width, (GLsizei) texture.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const void *) data.data()));
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));
GLuint NO_TEXTURE_ID = 0;
glsafe(::glBindTexture(GL_TEXTURE_2D, NO_TEXTURE_ID));
return true;
}
}
void GLGizmoSVG::set_volume_by_selection() void GLGizmoSVG::set_volume_by_selection()
{ {
const Selection &selection = m_parent.get_selection(); const Selection &selection = m_parent.get_selection();
@ -471,7 +554,7 @@ void GLGizmoSVG::set_volume_by_selection()
// Calculate current angle of up vector // Calculate current angle of up vector
m_angle = calc_up(gl_volume->world_matrix(), Slic3r::GUI::up_limit); m_angle = calc_up(gl_volume->world_matrix(), Slic3r::GUI::up_limit);
m_distance = calc_distance(*gl_volume, m_raycast_manager, m_parent); 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 for height and depth inside of scaled object instance
calculate_scale(); calculate_scale();
} }
@ -484,6 +567,9 @@ void GLGizmoSVG::reset_volume()
m_volume = nullptr; m_volume = nullptr;
m_volume_id.id = 0; m_volume_id.id = 0;
m_volume_shape.shapes_with_ids.clear(); m_volume_shape.shapes_with_ids.clear();
if (m_texture.id != 0)
glsafe(::glDeleteTextures(1, &m_texture.id));
} }
void GLGizmoSVG::calculate_scale() { void GLGizmoSVG::calculate_scale() {
@ -553,10 +639,17 @@ void GLGizmoSVG::draw_window()
if (m_volume->emboss_shape.has_value()) if (m_volume->emboss_shape.has_value())
ImGui::Text("SVG file path is %s", m_volume->emboss_shape->svg_file_path.c_str()); 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::Indent(m_gui_cfg->icon_width); ImGui::Indent(m_gui_cfg->icon_width);
draw_depth(); draw_depth();
draw_size(); draw_size();
draw_use_surface(); draw_use_surface();
draw_distance(); draw_distance();
draw_rotation(); draw_rotation();
ImGui::Unindent(m_gui_cfg->icon_width); ImGui::Unindent(m_gui_cfg->icon_width);
@ -597,16 +690,6 @@ void GLGizmoSVG::draw_depth()
ImGui::SetTooltip("%s", _u8L("Size in emboss direction.").c_str()); ImGui::SetTooltip("%s", _u8L("Size in emboss direction.").c_str());
} }
namespace Slic3r {
BoundingBox get_extents(const ExPolygonsWithIds &expoly_ids)
{
BoundingBox result;
for (const ExPolygonsWithId &expoly_id : expoly_ids)
result.merge(get_extents(expoly_id.expoly));
return result;
}
} // namespace Slic3r
void GLGizmoSVG::draw_size() void GLGizmoSVG::draw_size()
{ {
ImGuiWrapper::text(m_gui_cfg->translations.size); ImGuiWrapper::text(m_gui_cfg->translations.size);
@ -859,7 +942,7 @@ void GLGizmoSVG::draw_model_type()
m_volume->set_type(*new_type); m_volume->set_type(*new_type);
// Update volume position when switch from part or into part // Update volume position when switch from part or into part
if (m_volume->text_configuration->style.prop.use_surface) { if (m_volume->emboss_shape->projection.use_surface) {
// move inside // move inside
bool is_volume_move_inside = (type == part); bool is_volume_move_inside = (type == part);
bool is_volume_move_outside = (*new_type == part); bool is_volume_move_outside = (*new_type == part);

View File

@ -6,6 +6,7 @@
#include "GLGizmoBase.hpp" #include "GLGizmoBase.hpp"
#include "GLGizmoRotate.hpp" #include "GLGizmoRotate.hpp"
#include "slic3r/GUI/SurfaceDrag.hpp" #include "slic3r/GUI/SurfaceDrag.hpp"
#include "slic3r/GUI/GLTexture.hpp"
#include "slic3r/Utils/RaycastManager.hpp" #include "slic3r/Utils/RaycastManager.hpp"
#include <optional> #include <optional>
@ -20,13 +21,20 @@
#include <GL/glew.h> #include <GL/glew.h>
namespace Slic3r{ namespace Slic3r{
//class AppConfig; //class AppConfig;
class GLVolume; class GLVolume;
class ModelVolume; class ModelVolume;
enum class ModelVolumeType : int; enum class ModelVolumeType : int;
} }
namespace Slic3r::GUI { namespace Slic3r::GUI {
struct Texture{
unsigned id{0};
unsigned width{0};
unsigned height{0};
};
class GLGizmoSVG : public GLGizmoBase class GLGizmoSVG : public GLGizmoBase
{ {
public: public:
@ -151,10 +159,13 @@ private:
std::optional<float> m_scale_depth; std::optional<float> m_scale_depth;
void calculate_scale(); void calculate_scale();
// keep SVG data rendered on GPU
Texture m_texture;
// only temporary solution // only temporary solution
static const std::string M_ICON_FILENAME; static const std::string M_ICON_FILENAME;
}; };
} // namespace Slic3r::GUI } // namespace Slic3r::GUI
#endif // slic3r_GLGizmoSVG_hpp_ #endif // slic3r_GLGizmoSVG_hpp_

View File

@ -859,9 +859,8 @@ template<typename Fnc> TriangleMesh create_mesh_per_glyph(DataBase &input, Fnc w
Vec2d to_zero_vec = letter_bb.center().cast<double>() * shape.scale; // [in mm] Vec2d to_zero_vec = letter_bb.center().cast<double>() * shape.scale; // [in mm]
float surface_offset = input.is_outside ? -SAFE_SURFACE_OFFSET : (-shape.projection.depth + SAFE_SURFACE_OFFSET); float surface_offset = input.is_outside ? -SAFE_SURFACE_OFFSET : (-shape.projection.depth + SAFE_SURFACE_OFFSET);
// TODO: fix it if (input.from_surface.has_value())
//if (prop.distance.has_value()) surface_offset += *input.from_surface;
// surface_offset += *prop.distance;
Eigen::Translation<double, 3> to_zero(-to_zero_vec.x(), 0., static_cast<double>(surface_offset)); Eigen::Translation<double, 3> to_zero(-to_zero_vec.x(), 0., static_cast<double>(surface_offset));
@ -931,6 +930,8 @@ TriangleMesh try_create_mesh(DataBase &input, const Fnc& was_canceled)
double depth = input.shape.projection.depth / scale; double depth = input.shape.projection.depth / scale;
auto projectZ = std::make_unique<ProjectZ>(depth); auto projectZ = std::make_unique<ProjectZ>(depth);
float offset = input.is_outside ? -SAFE_SURFACE_OFFSET : (SAFE_SURFACE_OFFSET - input.shape.projection.depth); float offset = input.is_outside ? -SAFE_SURFACE_OFFSET : (SAFE_SURFACE_OFFSET - input.shape.projection.depth);
if (input.from_surface.has_value())
offset += *input.from_surface;
Transform3d tr = Eigen::Translation<double, 3>(0., 0.,static_cast<double>(offset)) * Eigen::Scaling(scale); Transform3d tr = Eigen::Translation<double, 3>(0., 0.,static_cast<double>(offset)) * Eigen::Scaling(scale);
ProjectTransform project(std::move(projectZ), tr); ProjectTransform project(std::move(projectZ), tr);
if (was_canceled()) return {}; if (was_canceled()) return {};

View File

@ -57,13 +57,18 @@ public:
virtual void write(ModelVolume &volume) const; virtual void write(ModelVolume &volume) const;
// Define projection move // Define projection move
// True (raised) .. move outside from surface // True (raised) .. move outside from surface (MODEL_PART)
// False (engraved).. move into object // False (engraved).. move into object (NEGATIVE_VOLUME)
bool is_outside; bool is_outside = true;
// Define per letter projection on one text line // Define per letter projection on one text line
// [optional] It is not used when empty // [optional] It is not used when empty
Slic3r::Emboss::TextLines text_lines; Slic3r::Emboss::TextLines text_lines = {};
// [optional] Define distance for surface
// It is used only for flat surface (not cutted)
// Position of Zero(not set value) differ for MODEL_PART and NEGATIVE_VOLUME
std::optional<float> from_surface;
// new volume name // new volume name
std::string volume_name; std::string volume_name;