From 501f6f021f2ec14bb8b1cb0833f499ee1387c331 Mon Sep 17 00:00:00 2001 From: Filip Sykala Date: Tue, 22 Mar 2022 21:38:07 +0100 Subject: [PATCH] Initialize font style images in job --- src/libslic3r/Emboss.hpp | 6 +- src/slic3r/CMakeLists.txt | 2 + .../GUI/Jobs/CreateFontStyleImagesJob.cpp | 145 +++++++++++++++ .../GUI/Jobs/CreateFontStyleImagesJob.hpp | 60 ++++++ src/slic3r/Utils/FontManager.cpp | 175 +++--------------- src/slic3r/Utils/FontManager.hpp | 8 +- 6 files changed, 239 insertions(+), 157 deletions(-) create mode 100644 src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp create mode 100644 src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp diff --git a/src/libslic3r/Emboss.hpp b/src/libslic3r/Emboss.hpp index 0e57f54c80..4449bfa466 100644 --- a/src/libslic3r/Emboss.hpp +++ b/src/libslic3r/Emboss.hpp @@ -105,8 +105,12 @@ public: /// struct FontFileWithCache { + // Pointer on data of the font file std::shared_ptr font_file; - // cache for glyph shape + + // Cache for glyph shape + // IMPORTANT: accessible only in plater job thread !!! + // main thread only clear cache by set to another shared_ptr std::shared_ptr cache; FontFileWithCache() : font_file(nullptr), cache(nullptr) {} diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 86178e0051..d6bd8118e0 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -184,6 +184,8 @@ set(SLIC3R_GUI_SOURCES GUI/Jobs/PlaterWorker.hpp GUI/Jobs/ArrangeJob.hpp GUI/Jobs/ArrangeJob.cpp + GUI/Jobs/CreateFontStyleImagesJob.cpp + GUI/Jobs/CreateFontStyleImagesJob.hpp GUI/Jobs/EmbossJob.cpp GUI/Jobs/EmbossJob.hpp GUI/Jobs/RotoptimizeJob.hpp diff --git a/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp b/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp new file mode 100644 index 0000000000..9d95818da9 --- /dev/null +++ b/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.cpp @@ -0,0 +1,145 @@ +#include "CreateFontStyleImagesJob.hpp" + +// rasterization of ExPoly +#include "libslic3r/SLA/AGGRaster.hpp" + +// for get DPI +#include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/MainFrame.hpp" + +#include "slic3r/GUI/3DScene.hpp" // ::glsafe + +using namespace Slic3r; +using namespace Slic3r::GUI; + + +CreateFontStyleImagesJob::CreateFontStyleImagesJob(StyleImagesData &&input) + : m_input(std::move(input)) +{} + +void CreateFontStyleImagesJob::process(Ctl &ctl) +{ + // create shapes and calc size (bounding boxes) + std::vector name_shapes(m_input.styles.size()); + std::vector scales(m_input.styles.size()); + images = std::vector(m_input.styles.size()); + + for (StyleImagesData::Item &item : m_input.styles) { + size_t index = &item - &m_input.styles.front(); + ExPolygons &shapes = name_shapes[index]; + shapes = Emboss::text2shapes(item.font, item.text.c_str(), item.prop); + + // create image description + FontManager::StyleImage &image = images[index]; + BoundingBox &bounding_box = image.bounding_box; + for (ExPolygon &shape : shapes) + bounding_box.merge(BoundingBox(shape.contour.points)); + for (ExPolygon &shape : shapes) shape.translate(-bounding_box.min); + + // calculate conversion from FontPoint to screen pixels by size of font + auto mf = wxGetApp().mainframe; + // dot per inch for monitor + int dpi = get_dpi_for_window(mf); + double ppm = dpi / 25.4; // pixel per milimeter + double unit_per_em = item.font.font_file->unit_per_em; + double scale = item.prop.size_in_mm / unit_per_em * Emboss::SHAPE_SCALE * ppm; + scales[index] = scale; + + //double scale = font_prop.size_in_mm * SCALING_FACTOR; + BoundingBoxf bb2(bounding_box.min.cast(), + bounding_box.max.cast()); + bb2.scale(scale); + image.tex_size.x = std::ceil(bb2.max.x() - bb2.min.x()); + image.tex_size.y = std::ceil(bb2.max.y() - bb2.min.y()); + + // crop image width + if (image.tex_size.x > m_input.max_width) + image.tex_size.x = m_input.max_width; + } + + // arrange bounding boxes + int offset_y = 0; + width = 0; + for (FontManager::StyleImage &image : images) { + image.offset.y() = offset_y; + offset_y += image.tex_size.y+1; + if (width < image.tex_size.x) + width = image.tex_size.x; + } + height = offset_y; + for (FontManager::StyleImage &image : images) { + const Point &o = image.offset; + const ImVec2 &s = image.tex_size; + image.uv0 = ImVec2(o.x() / (double) width, + o.y() / (double) height); + image.uv1 = ImVec2((o.x() + s.x) / (double) width, + (o.y() + s.y) / (double) height); + } + + // Set up result + pixels = std::vector(width * height, {0}); + + // upload sub textures + for (FontManager::StyleImage &image : images) { + sla::Resolution resolution(image.tex_size.x, image.tex_size.y); + size_t index = &image - &images.front(); + double pixel_dim = SCALING_FACTOR / scales[index]; + sla::PixelDim dim(pixel_dim, pixel_dim); + double gamma = 1.; + std::unique_ptr r = + sla::create_raster_grayscale_aa(resolution, dim, gamma); + for (const ExPolygon &shape : name_shapes[index]) r->draw(shape); + + // copy rastered data to pixels + sla::RasterEncoder encoder = [&offset = image.offset, &pix = pixels, w=width,h=height] + (const void *ptr, size_t width, size_t height, size_t num_components) { + assert((offset.x() + width) <= w); + assert((offset.y() + height) <= h); + const unsigned char *ptr2 = (const unsigned char *) ptr; + for (int x=0; x < width; ++x) + for (int y = 0; y < height; ++y) { + size_t index = (offset.y() + y)*w + offset.x() + x; + assert(index < w * h); + pix[index] = ptr2[y * width + x]; + } + return sla::EncodedRaster(); + }; + r->encode(encoder); + } +} + +void CreateFontStyleImagesJob::finalize(bool canceled, std::exception_ptr &) +{ + // upload texture on GPU + GLuint tex_id; + GLenum target = GL_TEXTURE_2D, format = GL_ALPHA, type = GL_UNSIGNED_BYTE; + GLint level = 0, border = 0; + glsafe(::glGenTextures(1, &tex_id)); + glsafe(::glBindTexture(target, tex_id)); + glsafe(::glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); + glsafe(::glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); + GLint w = width, h=height; + glsafe(::glTexImage2D(target, level, GL_ALPHA, w, h, border, format, type, + (const void *) pixels.data())); + + // set up texture id + void *texture_id = (void *) (intptr_t) tex_id; + for (FontManager::StyleImage &image : images) { + image.texture_id = texture_id; + size_t index = &image - &images.front(); + StyleImagesData::Item &style = m_input.styles[index]; + + // find manager image and copy to it + for (auto& it: m_input.mng->m_font_list) { + if (it.font_item.name != style.text || + !(it.font_item.prop == style.prop)) + continue; + it.image = image; + break; + } + } + + // bind default texture + GLuint no_texture_id = 0; + glsafe(::glBindTexture(target, no_texture_id)); +} \ No newline at end of file diff --git a/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp b/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp new file mode 100644 index 0000000000..ad9dffd73d --- /dev/null +++ b/src/slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp @@ -0,0 +1,60 @@ +#ifndef slic3r_CreateFontStyleImagesJob_hpp_ +#define slic3r_CreateFontStyleImagesJob_hpp_ + +#include +#include +#include +#include "slic3r/Utils/FontManager.hpp" +#include "Job.hpp" + +namespace Slic3r::GUI { + +/// +/// Data needed to create Font Style Images +/// +struct StyleImagesData +{ + struct Item + { + Emboss::FontFileWithCache font; + std::string text; + FontProp prop; + }; + using Items = std::vector; + + // Keep styles to render + Items styles; + + // maximal width in pixels of image + int max_width; + + // is used in finalize to set result + // and I Can't proof of alive + FontManager *mng; +}; + +/// +/// Create texture with name of styles written by its style +/// NOTE: Access to glyph cache is possible only from job +/// +class CreateFontStyleImagesJob : public Job +{ + StyleImagesData m_input; + + // Output data + // texture size + int width, height; + // texture data + std::vector pixels; + // descriptors of sub textures + std::vector images; + +public: + CreateFontStyleImagesJob(StyleImagesData &&input); + void process(Ctl &ctl) override; + void finalize(bool canceled, std::exception_ptr &) override; +}; + +} // namespace Slic3r::GUI + +#endif // slic3r_EmbossJob_hpp_ diff --git a/src/slic3r/Utils/FontManager.cpp b/src/slic3r/Utils/FontManager.cpp index 47ca3dbb88..3814a382c3 100644 --- a/src/slic3r/Utils/FontManager.cpp +++ b/src/slic3r/Utils/FontManager.cpp @@ -4,7 +4,9 @@ #include // ImTextCharFromUtf8 #include "WxFontUtils.hpp" #include "libslic3r/Utils.hpp" // ScopeGuard + #include "slic3r/GUI/3DScene.hpp" // ::glsafe +#include "slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp" using namespace Slic3r; using namespace Slic3r::GUI; @@ -370,166 +372,32 @@ ImFont* FontManager::extend_imgui_font_range(size_t index, const std::string& te return load_imgui_font(index, text); } -#include "libslic3r/SLA/AGGRaster.hpp" -void FontManager::create_texture(size_t index, const std::string &text, GLuint& tex_id, ImVec2& tex_size) -{ - if (index >= m_font_list.size()) return; - Item &item = m_font_list[index]; - if (!item.font_file_with_cache.has_value() && !set_up_font_file(index)) - return; +#include "slic3r/GUI/Jobs/CreateFontStyleImagesJob.hpp" - const FontProp &font_prop = item.font_item.prop; - ExPolygons shapes = Emboss::text2shapes(item.font_file_with_cache, - text.c_str(), font_prop); - - BoundingBox bb; - for (ExPolygon &shape : shapes) bb.merge(BoundingBox(shape.contour.points)); - for (ExPolygon &shape : shapes) shape.translate(-bb.min); - - double scale = font_prop.size_in_mm; - BoundingBoxf bb2 = unscaled(bb); - bb2.scale(scale); - tex_size.x = bb2.max.x() - bb2.min.x(); - tex_size.y = bb2.max.y() - bb2.min.y(); - sla::Resolution resolution(tex_size.x,tex_size.y); - sla::PixelDim dim(1/scale, 1/scale); - const double no_gamma = 1.; - std::unique_ptr r = - sla::create_raster_grayscale_aa(resolution, dim, no_gamma); - for (const ExPolygon &shape : shapes) r->draw(shape); - // reserve texture on GPU - glGenTextures(1, &tex_id); - glBindTexture(GL_TEXTURE_2D, tex_id); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - sla::RasterEncoder encoder = [](const void *ptr, size_t w, size_t h, size_t num_components) -> sla::EncodedRaster { - GLsizei width = w, height = h; - GLint border = 0; - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, border, GL_ALPHA, GL_UNSIGNED_BYTE, ptr); - return sla::EncodedRaster(); - }; - r->encode(encoder); - glBindTexture(GL_TEXTURE_2D, 0); -} - -// for get DPI +// for access to worker #include "slic3r/GUI/GUI_App.hpp" -#include "slic3r/GUI/MainFrame.hpp" +#include "slic3r/GUI/Plater.hpp" void FontManager::init_style_images(int max_width) { // check already initialized if (m_exist_style_images) return; - // create shapes and calc size (bounding boxes) - std::vector name_shapes(m_font_list.size()); - std::vector scales(m_font_list.size()); + StyleImagesData::Items styles; + styles.reserve(m_font_list.size()); for (Item &item : m_font_list) { - FontItem & font_item = item.font_item; - const FontProp & font_prop = font_item.prop; size_t index = &item - &m_font_list.front(); if (!item.font_file_with_cache.has_value() && !set_up_font_file(index)) continue; - - ExPolygons &shapes = name_shapes[index]; - shapes = Emboss::text2shapes(item.font_file_with_cache, font_item.name.c_str(), font_prop); - - // create image description - item.image = StyleImage(); - StyleImage &image = *item.image; - - BoundingBox &bounding_box = image.bounding_box; - for (ExPolygon &shape : shapes) - bounding_box.merge(BoundingBox(shape.contour.points)); - for (ExPolygon &shape : shapes) shape.translate(-bounding_box.min); - - // calculate conversion from FontPoint to screen pixels by size of font - auto mf = wxGetApp().mainframe; - // dot per inch for monitor - int dpi = get_dpi_for_window(mf); - double ppm = dpi / 25.4; // pixel per milimeter - double unit_per_em = item.font_file_with_cache.font_file->unit_per_em; - double scale = font_prop.size_in_mm / unit_per_em * Emboss::SHAPE_SCALE * ppm; - scales[index] = scale; - - //double scale = font_prop.size_in_mm * SCALING_FACTOR; - BoundingBoxf bb2(bounding_box.min.cast(), - bounding_box.max.cast()); - bb2.scale(scale); - image.tex_size.x = std::ceil(bb2.max.x() - bb2.min.x()); - image.tex_size.y = std::ceil(bb2.max.y() - bb2.min.y()); - // crop image width - if (image.tex_size.x > max_width) - image.tex_size.x = max_width; + styles.push_back({ + item.font_file_with_cache, + item.font_item.name, + item.font_item.prop + }); } - // arrange bounding boxes - int offset_y = 0; - int width = 0; - for (Item &item : m_font_list) { - if (!item.image.has_value()) continue; - StyleImage &image = *item.image; - image.offset.y() = offset_y; - offset_y += image.tex_size.y+1; - if (width < image.tex_size.x) - width = image.tex_size.x; - } - int height = offset_y; - for (Item &item : m_font_list) { - if (!item.image.has_value()) continue; - StyleImage &image = *item.image; - const Point &o = image.offset; - const ImVec2 &s = image.tex_size; - image.uv0 = ImVec2(o.x() / (double) width, - o.y() / (double) height); - image.uv1 = ImVec2((o.x() + s.x) / (double) width, - (o.y() + s.y) / (double) height); - } - - // reserve texture on GPU - GLuint tex_id; - GLenum target = GL_TEXTURE_2D, format = GL_ALPHA, type = GL_UNSIGNED_BYTE; - GLint level = 0, border = 0; - glsafe(::glGenTextures(1, &tex_id)); - glsafe(::glBindTexture(target, tex_id)); - glsafe(::glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); - glsafe(::glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); - // texture size - GLint w = width, h = height; - glsafe(::glTexImage2D(target, level, GL_ALPHA, w, h, border, format, type, nullptr)); - - // set up texture id - void *texture_id = (void *)(intptr_t) tex_id; - for (Item &item : m_font_list) - if (item.image.has_value()) - item.image->texture_id = texture_id; - - // upload sub textures - for (Item &item : m_font_list) { - if (!item.image.has_value()) continue; - StyleImage &image = *item.image; - sla::Resolution resolution(image.tex_size.x, image.tex_size.y); - - size_t index = &item - &m_font_list.front(); - double pixel_dim = SCALING_FACTOR / scales[index]; - sla::PixelDim dim(pixel_dim, pixel_dim); - double gamma = 1.; - std::unique_ptr r = sla::create_raster_grayscale_aa(resolution, dim, gamma); - for (const ExPolygon &shape : name_shapes[index]) r->draw(shape); - const Point& offset = image.offset; - sla::RasterEncoder encoder = - [offset, target, level, format, type] - (const void *ptr, size_t w, size_t h, size_t num_components) { - GLint sub_w = w, sub_h = h, xoffset = offset.x(), yoffset = offset.y(); - glsafe(::glTexSubImage2D(target, level, xoffset, yoffset, sub_w, sub_h, format, type, ptr)); - return sla::EncodedRaster(); - }; - // upload texture data to GPU - r->encode(encoder); - } - - // bind default texture - GLuint no_texture_id = 0; - glsafe(::glBindTexture(target, no_texture_id)); + auto &worker = wxGetApp().plater()->get_ui_job_worker(); + StyleImagesData data{styles, max_width, this}; + queue_job(worker, std::make_unique(std::move(data))); m_exist_style_images = true; } @@ -537,14 +405,19 @@ void FontManager::init_style_images(int max_width) { void FontManager::free_style_images() { if (!is_activ_font()) return; if (!m_exist_style_images) return; - GLuint tex_id = (GLuint) (intptr_t) m_font_list.front().image->texture_id; - for (Item &it : m_font_list) it.image.reset(); - glsafe(::glDeleteTextures(1, &tex_id)); + GLuint tex_id = 0; + + for (Item &it : m_font_list) { + if (tex_id == 0 && it.image.has_value()) + tex_id = (GLuint)(intptr_t) it.image->texture_id; + it.image.reset(); + } + if (tex_id != 0) + glsafe(::glDeleteTextures(1, &tex_id)); m_exist_style_images = false; } - void FontManager::free_imgui_fonts() { for (auto &item : m_font_list) diff --git a/src/slic3r/Utils/FontManager.hpp b/src/slic3r/Utils/FontManager.hpp index eb95d66632..ce66864853 100644 --- a/src/slic3r/Utils/FontManager.hpp +++ b/src/slic3r/Utils/FontManager.hpp @@ -4,12 +4,11 @@ #include #include #include -#include "libslic3r/Emboss.hpp" +#include class wxFont; namespace Slic3r::GUI { - /// /// GUI list of loaded fonts /// Keep pointer to ImGui font pointers @@ -18,6 +17,8 @@ namespace Slic3r::GUI { /// class FontManager { + friend class CreateFontStyleImagesJob; + public: FontManager(const ImWchar *language_glyph_range); ~FontManager(); @@ -109,8 +110,6 @@ public: void init_style_images(int max_width); void free_style_images(); - void create_texture(size_t font_index, const std::string &text, GLuint& tex_id, ImVec2& tex_size); - struct Item; // access to all managed fonts const std::vector &get_fonts() const; @@ -187,7 +186,6 @@ private: static bool is_text_in_ranges(const ImWchar *ranges, const std::string &text); static bool is_char_in_ranges(const ImWchar *ranges, unsigned int letter); - bool check_imgui_font_range(ImFont *font, const std::string &text); void free_imgui_fonts(); bool set_up_font_file(size_t item_index);