mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-25 11:52:05 +00:00
Port Emboss & SVG gizmo from PrusaSlicer (#2819)
* Rework UI jobs to make them more understandable and flexible. * Update Orca specific jobs * Fix progress issue * Fix dark mode and window radius * Update cereal version from 1.2.2 to 1.3.0 (cherry picked from commit prusa3d/PrusaSlicer@057232a275) * Initial port of Emboss gizmo * Bump up CGAL version to 5.4 (cherry picked from commit prusa3d/PrusaSlicer@1bf9dee3e7) * Fix text rotation * Fix test dragging * Add text gizmo to right click menu * Initial port of SVG gizmo * Fix text rotation * Fix Linux build * Fix "from surface" * Fix -90 rotation * Fix icon path * Fix loading font with non-ascii name * Fix storing non-utf8 font descriptor in 3mf file * Fix filtering with non-utf8 characters * Emboss: Use Orca style input dialog * Fix build on macOS * Fix tooltip color in light mode * InputText: fixed incorrect padding when FrameBorder > 0. (ocornut/imgui#4794, ocornut/imgui#3781) InputTextMultiline: fixed vertical tracking with large values of FramePadding.y. (ocornut/imgui#3781, ocornut/imgui#4794) (cherry picked from commit ocornut/imgui@072caa4a90) (cherry picked from commit ocornut/imgui@bdd2a94315) * SVG: Use Orca style input dialog * Fix job progress update * Fix crash when select editing text in preview screen * Use Orca checkbox style * Fix issue that toolbar icons are kept regenerated * Emboss: Fix text & icon alignment * SVG: Fix text & icon alignment * Emboss: fix toolbar icon mouse hover state * Add a simple subtle outline effect by drawing back faces using wireframe mode * Disable selection outlines * Show outline in white if the model color is too dark * Make the outline algorithm more reliable * Enable cull face, which fix render on Linux * Fix `disable_cullface` * Post merge fix * Optimize selection rendering * Fix scale gizmo * Emboss: Fix text rotation if base object is scaled * Fix volume synchronize * Fix emboss rotation * Emboss: Fix advance toggle * Fix text position after reopened the project * Make font style preview darker * Make font style preview selector height shorter --------- Co-authored-by: tamasmeszaros <meszaros.q@gmail.com> Co-authored-by: ocornut <omarcornut@gmail.com> Co-authored-by: SoftFever <softfeverever@gmail.com>
This commit is contained in:
170
src/slic3r/GUI/Jobs/CreateFontNameImageJob.cpp
Normal file
170
src/slic3r/GUI/Jobs/CreateFontNameImageJob.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
///|/ Copyright (c) Prusa Research 2022 Filip Sykala @Jony01
|
||||
///|/
|
||||
///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher
|
||||
///|/
|
||||
#include "CreateFontNameImageJob.hpp"
|
||||
|
||||
#include "libslic3r/Emboss.hpp"
|
||||
// rasterization of ExPoly
|
||||
#include "libslic3r/SLA/AGGRaster.hpp"
|
||||
|
||||
#include "slic3r/Utils/WxFontUtils.hpp"
|
||||
#include "slic3r/GUI/3DScene.hpp" // ::glsafe
|
||||
|
||||
// ability to request new frame after finish rendering
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
|
||||
#include "wx/fontenum.h"
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
using namespace Slic3r;
|
||||
using namespace Slic3r::GUI;
|
||||
|
||||
const std::string CreateFontImageJob::default_text = "AaBbCc 123";
|
||||
|
||||
CreateFontImageJob::CreateFontImageJob(FontImageData &&input)
|
||||
: m_input(std::move(input))
|
||||
{
|
||||
assert(wxFontEnumerator::IsValidFacename(m_input.font_name));
|
||||
assert(m_input.gray_level > 0 && m_input.gray_level < 255);
|
||||
assert(m_input.texture_id != 0);
|
||||
}
|
||||
|
||||
void CreateFontImageJob::process(Ctl &ctl)
|
||||
{
|
||||
if (!wxFontEnumerator::IsValidFacename(m_input.font_name)) return;
|
||||
// Select font
|
||||
wxFont wx_font(
|
||||
wxFontInfo().FaceName(m_input.font_name).Encoding(m_input.encoding));
|
||||
if (!wx_font.IsOk()) return;
|
||||
|
||||
std::unique_ptr<Emboss::FontFile> font_file =
|
||||
WxFontUtils::create_font_file(wx_font);
|
||||
if (font_file == nullptr) return;
|
||||
|
||||
Emboss::FontFileWithCache font_file_with_cache(std::move(font_file));
|
||||
// use only first line of text
|
||||
std::string& text = m_input.text;
|
||||
if (text.empty())
|
||||
text = default_text; // copy
|
||||
|
||||
size_t enter_pos = text.find('\n');
|
||||
if (enter_pos < text.size()) {
|
||||
// text start with enter
|
||||
if (enter_pos == 0) return;
|
||||
// exist enter, soo delete all after enter
|
||||
text = text.substr(0, enter_pos);
|
||||
}
|
||||
|
||||
std::function<bool()> was_canceled = [&ctl, cancel = m_input.cancel]() -> bool {
|
||||
if (ctl.was_canceled()) return true;
|
||||
if (cancel->load()) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
FontProp fp; // create default font parameters
|
||||
ExPolygons shapes = Emboss::text2shapes(font_file_with_cache, text.c_str(), fp, was_canceled);
|
||||
|
||||
// select some character from font e.g. default text
|
||||
if (shapes.empty())
|
||||
shapes = Emboss::text2shapes(font_file_with_cache, default_text.c_str(), fp, was_canceled);
|
||||
if (shapes.empty()) {
|
||||
m_input.cancel->store(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// normalize height of font
|
||||
BoundingBox bounding_box;
|
||||
for (const ExPolygon &shape : shapes)
|
||||
bounding_box.merge(BoundingBox(shape.contour.points));
|
||||
if (bounding_box.size().x() < 1 || bounding_box.size().y() < 1) {
|
||||
m_input.cancel->store(true);
|
||||
return;
|
||||
}
|
||||
double scale = m_input.size.y() / (double) bounding_box.size().y();
|
||||
BoundingBoxf bb2(bounding_box.min.cast<double>(),
|
||||
bounding_box.max.cast<double>());
|
||||
bb2.scale(scale);
|
||||
Vec2d size_f = bb2.size();
|
||||
m_tex_size = Point(std::ceil(size_f.x()), std::ceil(size_f.y()));
|
||||
// crop image width
|
||||
if (m_tex_size.x() > m_input.size.x()) m_tex_size.x() = m_input.size.x();
|
||||
if (m_tex_size.y() > m_input.size.y()) m_tex_size.y() = m_input.size.y();
|
||||
|
||||
// Set up result
|
||||
unsigned bit_count = 4; // RGBA
|
||||
m_result = std::vector<unsigned char>(m_tex_size.x() * m_tex_size.y() * bit_count, {255});
|
||||
|
||||
sla::Resolution resolution(m_tex_size.x(), m_tex_size.y());
|
||||
double pixel_dim = SCALING_FACTOR / scale;
|
||||
sla::PixelDim dim(pixel_dim, pixel_dim);
|
||||
double gamma = 1.;
|
||||
std::unique_ptr<sla::RasterBase> r =
|
||||
sla::create_raster_grayscale_aa(resolution, dim, gamma);
|
||||
for (ExPolygon &shape : shapes) shape.translate(-bounding_box.min);
|
||||
for (const ExPolygon &shape : shapes) r->draw(shape);
|
||||
|
||||
// copy rastered data to pixels
|
||||
sla::RasterEncoder encoder =
|
||||
[&pix = m_result, w = m_tex_size.x(), h = m_tex_size.y(),
|
||||
gray_level = m_input.gray_level]
|
||||
(const void *ptr, size_t width, size_t height, size_t num_components) {
|
||||
size_t size {static_cast<size_t>(w*h)};
|
||||
const unsigned char *ptr2 = (const unsigned char *) ptr;
|
||||
for (size_t x = 0; x < width; ++x)
|
||||
for (size_t y = 0; y < height; ++y) {
|
||||
size_t index = y*w + x;
|
||||
assert(index < size);
|
||||
if (index >= size) continue;
|
||||
pix[3+4*index] = ptr2[y * width + x] / gray_level;
|
||||
}
|
||||
return sla::EncodedRaster();
|
||||
};
|
||||
r->encode(encoder);
|
||||
}
|
||||
|
||||
void CreateFontImageJob::finalize(bool canceled, std::exception_ptr &)
|
||||
{
|
||||
if (m_input.count_opened_font_files)
|
||||
--(*m_input.count_opened_font_files);
|
||||
if (canceled || m_input.cancel->load()) return;
|
||||
|
||||
*m_input.is_created = true;
|
||||
|
||||
// Exist result bitmap with preview?
|
||||
// (not valid input. e.g. not loadable font)
|
||||
if (m_result.empty()) {
|
||||
// TODO: write text cannot load into texture
|
||||
m_result = std::vector<unsigned char>(m_tex_size.x() * m_tex_size.y() * 4, {255});
|
||||
}
|
||||
|
||||
// upload texture on GPU
|
||||
const GLenum target = GL_TEXTURE_2D;
|
||||
glsafe(::glBindTexture(target, m_input.texture_id));
|
||||
|
||||
GLsizei w = m_tex_size.x(), h = m_tex_size.y();
|
||||
GLint xoffset = m_input.size.x() - m_tex_size.x(), // arrange right
|
||||
yoffset = m_input.size.y() * m_input.index;
|
||||
glsafe(::glTexSubImage2D(target, m_input.level, xoffset, yoffset, w, h,
|
||||
m_input.format, m_input.type, m_result.data()));
|
||||
|
||||
// clear rest of texture
|
||||
std::vector<unsigned char> empty_data(xoffset * h * 4, {0});
|
||||
glsafe(::glTexSubImage2D(target, m_input.level, 0, yoffset, xoffset, h,
|
||||
m_input.format, m_input.type, empty_data.data()));
|
||||
|
||||
// bind default texture
|
||||
GLuint no_texture_id = 0;
|
||||
glsafe(::glBindTexture(target, no_texture_id));
|
||||
|
||||
// show rendered texture
|
||||
wxGetApp().plater()->canvas3D()->schedule_extra_frame(0);
|
||||
|
||||
BOOST_LOG_TRIVIAL(info)
|
||||
<< "Generate Preview font('" << m_input.font_name << "' id:" << m_input.index << ") "
|
||||
<< "with text: '" << m_input.text << "' "
|
||||
<< "texture_size " << m_input.size.x() << " x " << m_input.size.y();
|
||||
}
|
||||
Reference in New Issue
Block a user