mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 01:25:59 +08:00
Render texture of svg
This commit is contained in:
parent
87517c5c68
commit
1c80d4358a
@ -678,7 +678,7 @@ void GLGizmoEmboss::on_render() {
|
||||
|
||||
if (m_text_lines.is_init()) {
|
||||
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())
|
||||
m_text_lines.render(tr * fix->inverse());
|
||||
else
|
||||
@ -1096,6 +1096,11 @@ void init_text_lines(TextLinesModel &text_lines, const Selection& selection, /*
|
||||
if (mv.is_the_only_one_part())
|
||||
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;
|
||||
if (!tc_opt.has_value())
|
||||
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.
|
||||
Transform3d mv_trafo = gl_volume.get_volume_transformation().get_matrix();
|
||||
if (tc.fix_3mf_tr.has_value())
|
||||
mv_trafo = mv_trafo * (tc.fix_3mf_tr->inverse());
|
||||
if (es.fix_3mf_tr.has_value())
|
||||
mv_trafo = mv_trafo * (es.fix_3mf_tr->inverse());
|
||||
FontProp::VerticalAlign align = style_manager.get_font_prop().align.second;
|
||||
double 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())
|
||||
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();
|
||||
auto& fix_3mf = m_volume->text_configuration->fix_3mf_tr;
|
||||
auto& fix_3mf = es.fix_3mf_tr;
|
||||
if (fix_3mf.has_value())
|
||||
text_tr = text_tr * fix_3mf->inverse();
|
||||
|
||||
// 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);
|
||||
if (offset.has_value())
|
||||
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);
|
||||
// create new shared ptr to cancel new job
|
||||
cancel = std::make_shared<std::atomic<bool>>(false);
|
||||
|
||||
DataBase base(volume_name, cancel);
|
||||
base.is_outside = is_outside;
|
||||
base.text_lines = text_lines.get_lines();
|
||||
base.from_surface = style.distance;
|
||||
|
||||
FontFileWithCache &font = style_manager.get_font_file_with_cache();
|
||||
TextConfiguration tc{static_cast<EmbossStyle>(style), text};
|
||||
|
@ -147,6 +147,16 @@ GuiCfg create_gui_configuration();
|
||||
// use private definition
|
||||
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)
|
||||
{
|
||||
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); }
|
||||
|
||||
#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()
|
||||
{
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
@ -471,7 +554,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();
|
||||
}
|
||||
@ -484,6 +567,9 @@ void GLGizmoSVG::reset_volume()
|
||||
m_volume = nullptr;
|
||||
m_volume_id.id = 0;
|
||||
m_volume_shape.shapes_with_ids.clear();
|
||||
|
||||
if (m_texture.id != 0)
|
||||
glsafe(::glDeleteTextures(1, &m_texture.id));
|
||||
}
|
||||
|
||||
void GLGizmoSVG::calculate_scale() {
|
||||
@ -553,10 +639,17 @@ void GLGizmoSVG::draw_window()
|
||||
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::Indent(m_gui_cfg->icon_width);
|
||||
draw_depth();
|
||||
draw_size();
|
||||
draw_use_surface();
|
||||
|
||||
draw_distance();
|
||||
draw_rotation();
|
||||
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());
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
ImGuiWrapper::text(m_gui_cfg->translations.size);
|
||||
@ -859,7 +942,7 @@ void GLGizmoSVG::draw_model_type()
|
||||
m_volume->set_type(*new_type);
|
||||
|
||||
// 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
|
||||
bool is_volume_move_inside = (type == part);
|
||||
bool is_volume_move_outside = (*new_type == part);
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "GLGizmoBase.hpp"
|
||||
#include "GLGizmoRotate.hpp"
|
||||
#include "slic3r/GUI/SurfaceDrag.hpp"
|
||||
#include "slic3r/GUI/GLTexture.hpp"
|
||||
#include "slic3r/Utils/RaycastManager.hpp"
|
||||
|
||||
#include <optional>
|
||||
@ -27,6 +28,13 @@ namespace Slic3r{
|
||||
}
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
struct Texture{
|
||||
unsigned id{0};
|
||||
unsigned width{0};
|
||||
unsigned height{0};
|
||||
};
|
||||
|
||||
class GLGizmoSVG : public GLGizmoBase
|
||||
{
|
||||
public:
|
||||
@ -151,10 +159,13 @@ private:
|
||||
std::optional<float> m_scale_depth;
|
||||
void calculate_scale();
|
||||
|
||||
// keep SVG data rendered on GPU
|
||||
|
||||
Texture m_texture;
|
||||
|
||||
// only temporary solution
|
||||
static const std::string M_ICON_FILENAME;
|
||||
};
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
|
||||
#endif // slic3r_GLGizmoSVG_hpp_
|
||||
|
@ -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]
|
||||
float surface_offset = input.is_outside ? -SAFE_SURFACE_OFFSET : (-shape.projection.depth + SAFE_SURFACE_OFFSET);
|
||||
|
||||
// TODO: fix it
|
||||
//if (prop.distance.has_value())
|
||||
// surface_offset += *prop.distance;
|
||||
if (input.from_surface.has_value())
|
||||
surface_offset += *input.from_surface;
|
||||
|
||||
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;
|
||||
auto projectZ = std::make_unique<ProjectZ>(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);
|
||||
ProjectTransform project(std::move(projectZ), tr);
|
||||
if (was_canceled()) return {};
|
||||
|
@ -57,13 +57,18 @@ public:
|
||||
virtual void write(ModelVolume &volume) const;
|
||||
|
||||
// Define projection move
|
||||
// True (raised) .. move outside from surface
|
||||
// False (engraved).. move into object
|
||||
bool is_outside;
|
||||
// True (raised) .. move outside from surface (MODEL_PART)
|
||||
// False (engraved).. move into object (NEGATIVE_VOLUME)
|
||||
bool is_outside = true;
|
||||
|
||||
// Define per letter projection on one text line
|
||||
// [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
|
||||
std::string volume_name;
|
||||
|
Loading…
x
Reference in New Issue
Block a user