add index of font inside of collection to FontProp(font property) + serialization/deserialization (3mf + appConfig)

separate glyph cache from FontFile
This commit is contained in:
Filip Sykala 2022-02-28 18:32:50 +01:00
parent 8022c64209
commit 18d269506a
13 changed files with 189 additions and 136 deletions

View file

@ -21,8 +21,6 @@ class Private
{ {
public: public:
Private() = delete; Private() = delete;
static std::optional<stbtt_fontinfo> load_font_info(const Emboss::FontFile &font);
static std::optional<stbtt_fontinfo> load_font_info(const unsigned char *data, unsigned int index = 0); static std::optional<stbtt_fontinfo> load_font_info(const unsigned char *data, unsigned int index = 0);
static std::optional<Emboss::Glyph> get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness); static std::optional<Emboss::Glyph> get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness);
static std::optional<Emboss::Glyph> get_glyph(int unicode, const Emboss::FontFile &font, const FontProp &font_prop, static std::optional<Emboss::Glyph> get_glyph(int unicode, const Emboss::FontFile &font, const FontProp &font_prop,
@ -42,11 +40,6 @@ public:
static Point to_point(const stbtt__point &point); static Point to_point(const stbtt__point &point);
}; };
std::optional<stbtt_fontinfo> Private::load_font_info(const Emboss::FontFile &font)
{
return load_font_info(font.buffer.data(), font.index);
}
std::optional<stbtt_fontinfo> Private::load_font_info( std::optional<stbtt_fontinfo> Private::load_font_info(
const unsigned char *data, unsigned int index) const unsigned char *data, unsigned int index)
{ {
@ -137,7 +130,10 @@ std::optional<Emboss::Glyph> Private::get_glyph(
return glyph_item->second; return glyph_item->second;
if (!font_info_opt.has_value()) { if (!font_info_opt.has_value()) {
font_info_opt = Private::load_font_info(font); int font_index = font_prop.collection_number.has_value()?
*font_prop.collection_number : 0;
if (font_index >= font.count) return {};
font_info_opt = Private::load_font_info(font.data->data(), font_index);
// can load font info? // can load font info?
if (!font_info_opt.has_value()) return {}; if (!font_info_opt.has_value()) return {};
} }
@ -466,16 +462,16 @@ std::optional<std::wstring> Emboss::get_font_path(const std::wstring &font_face_
} }
#endif #endif
std::unique_ptr<Emboss::FontFile> Emboss::load_font( std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(
std::vector<unsigned char> &&data) std::unique_ptr<std::vector<unsigned char>> data)
{ {
int collection_size = stbtt_GetNumberOfFonts(data.data()); int collection_size = stbtt_GetNumberOfFonts(data->data());
// at least one font must be inside collection // at least one font must be inside collection
if (collection_size < 1) { if (collection_size < 1) {
std::cerr << "There is no font collection inside data." << std::endl; std::cerr << "There is no font collection inside data." << std::endl;
return nullptr; return nullptr;
} }
auto font_info = Private::load_font_info(data.data()); auto font_info = Private::load_font_info(data->data());
if (!font_info.has_value()) return nullptr; if (!font_info.has_value()) return nullptr;
const stbtt_fontinfo *info = &(*font_info); const stbtt_fontinfo *info = &(*font_info);
@ -490,7 +486,7 @@ std::unique_ptr<Emboss::FontFile> Emboss::load_font(
std::move(data), collection_size, ascent, descent, linegap, units_per_em); std::move(data), collection_size, ascent, descent, linegap, units_per_em);
} }
std::unique_ptr<Emboss::FontFile> Emboss::load_font(const char *file_path) std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(const char *file_path)
{ {
FILE *file = fopen(file_path, "rb"); FILE *file = fopen(file_path, "rb");
if (file == nullptr) { if (file == nullptr) {
@ -509,14 +505,13 @@ std::unique_ptr<Emboss::FontFile> Emboss::load_font(const char *file_path)
return nullptr; return nullptr;
} }
rewind(file); rewind(file);
auto buffer = std::make_unique<std::vector<unsigned char>>(size);
std::vector<unsigned char> buffer(size); size_t count_loaded_bytes = fread((void *) &buffer->front(), 1, size, file);
size_t count_loaded_bytes = fread((void *) &buffer.front(), 1, size, file);
if (count_loaded_bytes != size) { if (count_loaded_bytes != size) {
std::cerr << "Different loaded(from file) data size." << std::endl; std::cerr << "Different loaded(from file) data size." << std::endl;
return nullptr; return nullptr;
} }
return load_font(std::move(buffer)); return create_font_file(std::move(buffer));
} }
@ -557,7 +552,7 @@ void * Emboss::can_load(HFONT hfont)
return hfont; return hfont;
} }
std::unique_ptr<Emboss::FontFile> Emboss::load_font(HFONT hfont) std::unique_ptr<Emboss::FontFile> Emboss::create_font_file(HFONT hfont)
{ {
HDC hdc = ::CreateCompatibleDC(NULL); HDC hdc = ::CreateCompatibleDC(NULL);
if (hdc == NULL) { if (hdc == NULL) {
@ -571,16 +566,14 @@ std::unique_ptr<Emboss::FontFile> Emboss::load_font(HFONT hfont)
::DeleteDC(hdc); ::DeleteDC(hdc);
return nullptr; return nullptr;
} }
auto buffer = std::make_unique<std::vector<unsigned char>>(size);
std::vector<unsigned char> buffer(size); size_t loaded_size = ::GetFontData(hdc, dwTable, dwOffset, buffer->data(), size);
size_t loaded_size = ::GetFontData(hdc, dwTable, dwOffset, buffer.data(), size);
::DeleteDC(hdc); ::DeleteDC(hdc);
if (size != loaded_size) { if (size != loaded_size) {
std::cerr << "Different loaded(from HFONT) data size." << std::endl; std::cerr << "Different loaded(from HFONT) data size." << std::endl;
return nullptr; return nullptr;
} }
return create_font_file(std::move(buffer));
return load_font(std::move(buffer));
} }
#endif // _WIN32 #endif // _WIN32
@ -588,20 +581,22 @@ std::optional<Emboss::Glyph> Emboss::letter2glyph(const FontFile &font,
int letter, int letter,
float flatness) float flatness)
{ {
auto font_info_opt = Private::load_font_info(font); auto font_info_opt = Private::load_font_info(font.data->data(), 0);
if (!font_info_opt.has_value()) return {}; if (!font_info_opt.has_value()) return {};
return Private::get_glyph(*font_info_opt, letter, flatness); return Private::get_glyph(*font_info_opt, letter, flatness);
} }
ExPolygons Emboss::text2shapes(FontFile & font, ExPolygons Emboss::text2shapes(FontFileWithCache &font_with_cache,
const char * text, const char * text,
const FontProp &font_prop) const FontProp &font_prop)
{ {
std::optional<stbtt_fontinfo> font_info_opt; assert(font_with_cache.has_value());
std::optional<stbtt_fontinfo> font_info_opt;
Point cursor(0, 0); Point cursor(0, 0);
ExPolygons result; ExPolygons result;
const FontFile& font = *font_with_cache.font_file;
Emboss::Glyphs& cache = *font_with_cache.cache;
std::wstring ws = boost::nowide::widen(text); std::wstring ws = boost::nowide::widen(text);
for (wchar_t wc: ws){ for (wchar_t wc: ws){
if (wc == '\n') { if (wc == '\n') {
@ -617,14 +612,14 @@ ExPolygons Emboss::text2shapes(FontFile & font,
if (wc == '\t') { if (wc == '\t') {
// '\t' = 4*space => same as imgui // '\t' = 4*space => same as imgui
const int count_spaces = 4; const int count_spaces = 4;
std::optional<Glyph> space_opt = Private::get_glyph(int(' '), font, font_prop, font.cache, font_info_opt); std::optional<Glyph> space_opt = Private::get_glyph(int(' '), font, font_prop, cache, font_info_opt);
if (!space_opt.has_value()) continue; if (!space_opt.has_value()) continue;
cursor.x() += count_spaces * space_opt->advance_width; cursor.x() += count_spaces * space_opt->advance_width;
continue; continue;
} }
int unicode = static_cast<int>(wc); int unicode = static_cast<int>(wc);
std::optional<Glyph> glyph_opt = Private::get_glyph(unicode, font, font_prop, font.cache, font_info_opt); std::optional<Glyph> glyph_opt = Private::get_glyph(unicode, font, font_prop, cache, font_info_opt);
if (!glyph_opt.has_value()) continue; if (!glyph_opt.has_value()) continue;
// move glyph to cursor position // move glyph to cursor position
@ -652,9 +647,10 @@ void Emboss::apply_transformation(const FontProp &font_prop,
} }
} }
bool Emboss::is_italic(FontFile &font) { bool Emboss::is_italic(FontFile &font, int font_index)
std::optional<stbtt_fontinfo> font_info_opt = {
Private::load_font_info(font); if (font_index >= font.count) return false;
std::optional<stbtt_fontinfo> font_info_opt = Private::load_font_info(font.data->data(), font_index);
if (!font_info_opt.has_value()) return false; if (!font_info_opt.has_value()) return false;
stbtt_fontinfo *info = &(*font_info_opt); stbtt_fontinfo *info = &(*font_info_opt);

View file

@ -59,44 +59,62 @@ public:
/// keep information from file about font /// keep information from file about font
/// (store file data itself) /// (store file data itself)
/// + cache data readed from buffer /// + cache data readed from buffer
/// + cache shape of glyphs (optionaly modified)
/// </summary> /// </summary>
struct FontFile struct FontFile
{ {
// loaded data from font file // loaded data from font file
const std::vector<unsigned char> buffer; // must store data size for imgui rasterization
// To not store data on heap and To prevent unneccesary copy
// data are stored inside unique_ptr
std::unique_ptr<std::vector<unsigned char>> data;
unsigned int index; // index of actual file info in collection // count of fonts when data are collection of fonts
const unsigned int count; // count of fonts in file collection unsigned int count;
// vertical position is "scale*(ascent - descent + lineGap)" // vertical position is "scale*(ascent - descent + lineGap)"
const int ascent, descent, linegap; int ascent, descent, linegap;
// for convert font units to pixel // for convert font units to pixel
int unit_per_em; int unit_per_em;
Emboss::Glyphs cache; // cache of glyphs FontFile(std::unique_ptr<std::vector<unsigned char>> data,
unsigned int count,
FontFile(std::vector<unsigned char> &&buffer, int ascent,
unsigned int count, int descent,
int ascent, int linegap,
int descent, int unit_per_em)
int linegap, : data(std::move(data))
int unit_per_em
)
: buffer(std::move(buffer))
, index(0) // select default font on index 0
, count(count) , count(count)
, ascent(ascent) , ascent(ascent)
, descent(descent) , descent(descent)
, linegap(linegap) , linegap(linegap)
, unit_per_em(unit_per_em) , unit_per_em(unit_per_em)
{} {
bool operator==(const FontFile &other) const { assert(this->data != nullptr);
return index == other.index &&
buffer.size() == other.buffer.size() &&
buffer == other.buffer;
} }
bool operator==(const FontFile &other) const {
return count == other.count && ascent == other.ascent &&
descent == other.descent && linegap == other.linegap &&
data->size() == other.data->size();
//&& *data == *other.data;
}
};
/// <summary>
/// Add caching for shape of glyphs
/// </summary>
struct FontFileWithCache
{
std::shared_ptr<FontFile> font_file;
// cache for glyph shape
std::shared_ptr<Emboss::Glyphs> cache;
FontFileWithCache() : font_file(nullptr), cache(nullptr) {}
FontFileWithCache(std::unique_ptr<FontFile> font_file)
: font_file(std::move(font_file))
, cache(std::make_shared<Emboss::Glyphs>())
{}
bool has_value() const { return font_file != nullptr && cache != nullptr; }
}; };
/// <summary> /// <summary>
@ -104,14 +122,14 @@ public:
/// </summary> /// </summary>
/// <param name="file_path">Location of .ttf or .ttc font file</param> /// <param name="file_path">Location of .ttf or .ttc font file</param>
/// <returns>Font object when loaded.</returns> /// <returns>Font object when loaded.</returns>
static std::unique_ptr<FontFile> load_font(const char *file_path); static std::unique_ptr<FontFile> create_font_file(const char *file_path);
// data = raw file data // data = raw file data
static std::unique_ptr<FontFile> load_font(std::vector<unsigned char>&& data); static std::unique_ptr<FontFile> create_font_file(std::unique_ptr<std::vector<unsigned char>> data);
#ifdef _WIN32 #ifdef _WIN32
// fix for unknown pointer HFONT // fix for unknown pointer HFONT
using HFONT = void*; using HFONT = void*;
static void * can_load(HFONT hfont); static void * can_load(HFONT hfont);
static std::unique_ptr<FontFile> load_font(HFONT hfont); static std::unique_ptr<FontFile> create_font_file(HFONT hfont);
#endif // _WIN32 #endif // _WIN32
/// <summary> /// <summary>
@ -130,7 +148,7 @@ public:
/// <param name="text">Characters to convert</param> /// <param name="text">Characters to convert</param>
/// <param name="font_prop">User defined property of the font</param> /// <param name="font_prop">User defined property of the font</param>
/// <returns>Inner polygon cw(outer ccw)</returns> /// <returns>Inner polygon cw(outer ccw)</returns>
static ExPolygons text2shapes(FontFile & font, static ExPolygons text2shapes(FontFileWithCache &font,
const char * text, const char * text,
const FontProp &font_prop); const FontProp &font_prop);
@ -148,8 +166,9 @@ public:
/// search for italic (or oblique), bold italic (or bold oblique) /// search for italic (or oblique), bold italic (or bold oblique)
/// </summary> /// </summary>
/// <param name="font">Selector of font</param> /// <param name="font">Selector of font</param>
/// <param name="font_index">Index of font in collection</param>
/// <returns>True when the font description contains italic/obligue otherwise False</returns> /// <returns>True when the font description contains italic/obligue otherwise False</returns>
static bool is_italic(FontFile &font); static bool is_italic(FontFile &font, int font_index = 0);
/// <summary> /// <summary>
/// Project 2d point into space /// Project 2d point into space

View file

@ -163,6 +163,7 @@ static constexpr const char *BOLDNESS_ATTR = "boldness";
static constexpr const char *SKEW_ATTR = "skew"; static constexpr const char *SKEW_ATTR = "skew";
static constexpr const char *DISTANCE_ATTR = "distance"; static constexpr const char *DISTANCE_ATTR = "distance";
static constexpr const char *ANGLE_ATTR = "angle"; static constexpr const char *ANGLE_ATTR = "angle";
static constexpr const char *COLLECTION_NUMBER_ATTR = "collection";
static constexpr const char *FONT_FAMILY_ATTR = "family"; static constexpr const char *FONT_FAMILY_ATTR = "family";
static constexpr const char *FONT_FACE_NAME_ATTR = "face_name"; static constexpr const char *FONT_FACE_NAME_ATTR = "face_name";
@ -3329,7 +3330,8 @@ void TextConfigurationSerialization::to_xml(std::stringstream &stream, const Tex
stream << DISTANCE_ATTR << "=\"" << *fp.distance << "\" "; stream << DISTANCE_ATTR << "=\"" << *fp.distance << "\" ";
if (fp.angle.has_value()) if (fp.angle.has_value())
stream << ANGLE_ATTR << "=\"" << *fp.angle << "\" "; stream << ANGLE_ATTR << "=\"" << *fp.angle << "\" ";
if (fp.collection_number.has_value())
stream << COLLECTION_NUMBER_ATTR << "=\"" << *fp.collection_number << "\" ";
// font descriptor // font descriptor
if (fp.family.has_value()) if (fp.family.has_value())
stream << FONT_FAMILY_ATTR << "=\"" << *fp.family << "\" "; stream << FONT_FAMILY_ATTR << "=\"" << *fp.family << "\" ";
@ -3361,6 +3363,8 @@ std::optional<TextConfiguration> TextConfigurationSerialization::read(const char
float angle = get_attribute_value_float(attributes, num_attributes, ANGLE_ATTR); float angle = get_attribute_value_float(attributes, num_attributes, ANGLE_ATTR);
if (std::fabs(angle) > std::numeric_limits<float>::epsilon()) if (std::fabs(angle) > std::numeric_limits<float>::epsilon())
fp.angle = angle; fp.angle = angle;
int collection_number = get_attribute_value_int(attributes, num_attributes, COLLECTION_NUMBER_ATTR);
if (collection_number > 0) fp.collection_number = collection_number;
fp.size_in_mm = get_attribute_value_float(attributes, num_attributes, LINE_HEIGHT_ATTR); fp.size_in_mm = get_attribute_value_float(attributes, num_attributes, LINE_HEIGHT_ATTR);
fp.emboss = get_attribute_value_float(attributes, num_attributes, DEPTH_ATTR); fp.emboss = get_attribute_value_float(attributes, num_attributes, DEPTH_ATTR);

View file

@ -43,6 +43,10 @@ struct FontProp
// When not set value is zero and is not stored // When not set value is zero and is not stored
std::optional<float> angle; // [in radians] std::optional<float> angle; // [in radians]
// Parameter for True Type Font collections
// Select index of font in collection
std::optional<int> collection_number;
//enum class Align { //enum class Align {
// left, // left,
// right, // right,

View file

@ -78,7 +78,7 @@ GLGizmoEmboss::GLGizmoEmboss(GLCanvas3D &parent)
void GLGizmoEmboss::set_fine_position() void GLGizmoEmboss::set_fine_position()
{ {
const Selection & selection = m_parent.get_selection(); const Selection &selection = m_parent.get_selection();
const Selection::IndicesList indices = selection.get_volume_idxs(); const Selection::IndicesList indices = selection.get_volume_idxs();
// no selected volume // no selected volume
if (indices.empty()) return; if (indices.empty()) return;
@ -157,7 +157,7 @@ void GLGizmoEmboss::create_volume(ModelVolumeType volume_type, const Vec2d& mous
Plater* plater = wxGetApp().plater(); Plater* plater = wxGetApp().plater();
const Camera &camera = plater->get_camera(); const Camera &camera = plater->get_camera();
auto data = std::make_unique<EmbossDataCreate>( auto data = std::make_unique<EmbossDataCreate>(
m_font_manager.get_font_file(), m_font_manager.get_font().font_file_with_cache,
create_configuration(), create_configuration(),
create_volume_name(), volume_type, screen_coor, object_idx, create_volume_name(), volume_type, screen_coor, object_idx,
hit_vol_tr, camera, hit_vol_tr, camera,
@ -662,9 +662,9 @@ bool GLGizmoEmboss::process()
if (m_volume == nullptr) return false; if (m_volume == nullptr) return false;
// exist loaded font? // exist loaded font?
std::shared_ptr<Emboss::FontFile>& font_file = m_font_manager.get_font_file(); Emboss::FontFileWithCache font = m_font_manager.get_font().font_file_with_cache;
if (font_file == nullptr) return false; if (!font.has_value()) return false;
auto data = std::make_unique<EmbossDataUpdate>(font_file, auto data = std::make_unique<EmbossDataUpdate>(font,
create_configuration(), create_configuration(),
create_volume_name(), m_volume); create_volume_name(), m_volume);
@ -1401,6 +1401,7 @@ void GLGizmoEmboss::draw_style_edit() {
if (exist_change) { if (exist_change) {
m_font_manager.free_style_images(); m_font_manager.free_style_images();
m_font_manager.clear_glyphs_cache();
process(); process();
} }
@ -1581,21 +1582,27 @@ void GLGizmoEmboss::draw_advanced()
ImGui::Text("%s", _u8L("Advanced font options could be change only for corect font.\nStart with select correct font.").c_str()); ImGui::Text("%s", _u8L("Advanced font options could be change only for corect font.\nStart with select correct font.").c_str());
return; return;
} }
FontProp &font_prop = m_font_manager.get_font_item().prop;
#ifdef SHOW_FONT_FILE_PROPERTY #ifdef SHOW_FONT_FILE_PROPERTY
ImGui::SameLine(); ImGui::SameLine();
auto& ff = m_font_manager.get_font().font_file_with_cache;
int cache_size = ff.has_value()? (int)ff.cache->size() : 0;
std::string ff_property = std::string ff_property =
"ascent=" + std::to_string(font_file->ascent) + "ascent=" + std::to_string(font_file->ascent) +
", descent=" + std::to_string(font_file->descent) + ", descent=" + std::to_string(font_file->descent) +
", lineGap=" + std::to_string(font_file->linegap) + ", lineGap=" + std::to_string(font_file->linegap) +
", unitPerEm=" + std::to_string(font_file->unit_per_em) + ", unitPerEm=" + std::to_string(font_file->unit_per_em) +
", cache(" + std::to_string(font_file->cache.size()) + " glyphs)"; ", cache(" + std::to_string(cache_size) + " glyphs)";
if (font_file->count > 1) ff_property += if (font_file->count > 1) {
", collect=" + std::to_string(font_file->index + 1) + "/" + std::to_string(font_file->count); int collection = font_prop.collection_number.has_value() ?
*font_prop.collection_number : 0;
ff_property += ", collect=" + std::to_string(collection+1) + "/" + std::to_string(font_file->count);
}
m_imgui->text_colored(ImGuiWrapper::COL_GREY_DARK, ff_property); m_imgui->text_colored(ImGuiWrapper::COL_GREY_DARK, ff_property);
#endif // SHOW_FONT_FILE_PROPERTY #endif // SHOW_FONT_FILE_PROPERTY
FontProp &font_prop = m_font_manager.get_font_item().prop;
bool exist_change = false; bool exist_change = false;
auto &tr = m_gui_cfg->translations; auto &tr = m_gui_cfg->translations;
@ -1693,12 +1700,15 @@ void GLGizmoEmboss::draw_advanced()
ImGui::Text("%s", tr.collection.c_str()); ImGui::Text("%s", tr.collection.c_str());
ImGui::SameLine(m_gui_cfg->advanced_input_offset); ImGui::SameLine(m_gui_cfg->advanced_input_offset);
ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width); ImGui::SetNextItemWidth(m_gui_cfg->advanced_input_width);
if (ImGui::BeginCombo("## Font collection", std::to_string(font_file->index).c_str())) { unsigned int selected = font_prop.collection_number.has_value() ?
*font_prop.collection_number : 0;
if (ImGui::BeginCombo("## Font collection", std::to_string(selected).c_str())) {
for (unsigned int i = 0; i < font_file->count; ++i) { for (unsigned int i = 0; i < font_file->count; ++i) {
ImGui::PushID(1 << (10 + i)); ImGui::PushID(1 << (10 + i));
bool is_selected = i == font_file->index; bool is_selected = (i == selected);
if (ImGui::Selectable(std::to_string(i).c_str(), is_selected)) { if (ImGui::Selectable(std::to_string(i).c_str(), is_selected)) {
font_file->index = i; if (i == 0) font_prop.collection_number.reset();
else font_prop.collection_number = i;
exist_change = true; exist_change = true;
} }
ImGui::PopID(); ImGui::PopID();
@ -1711,6 +1721,7 @@ void GLGizmoEmboss::draw_advanced()
if (exist_change) { if (exist_change) {
m_font_manager.free_style_images(); m_font_manager.free_style_images();
m_font_manager.clear_glyphs_cache();
process(); process();
} }
#ifdef ALLOW_DEBUG_MODE #ifdef ALLOW_DEBUG_MODE

View file

@ -22,11 +22,11 @@ using namespace GUI;
void EmbossUpdateJob::process(Ctl &ctl) void EmbossUpdateJob::process(Ctl &ctl)
{ {
// check if exist valid font // check if exist valid font
if (m_input->font_file == nullptr) return; if (!m_input->font_file.has_value()) return;
const TextConfiguration &cfg = m_input->text_configuration; const TextConfiguration &cfg = m_input->text_configuration;
m_result = EmbossCreateJob::create_mesh( m_result = EmbossCreateJob::create_mesh(
cfg.text.c_str(), *m_input->font_file, cfg.font_item.prop, ctl); cfg.text.c_str(), m_input->font_file, cfg.font_item.prop, ctl);
if (m_result.its.empty()) return; if (m_result.its.empty()) return;
if (ctl.was_canceled()) return; if (ctl.was_canceled()) return;
@ -98,11 +98,11 @@ void EmbossUpdateJob::finalize(bool canceled, std::exception_ptr &)
void EmbossCreateJob::process(Ctl &ctl) { void EmbossCreateJob::process(Ctl &ctl) {
// It is neccessary to create some shape // It is neccessary to create some shape
// Emboss text window is opened by creation new emboss text object // Emboss text window is opened by creation new emboss text object
m_result = (m_input->font_file == nullptr) ? const char *text = m_input->text_configuration.text.c_str();
create_default_mesh() : FontProp &prop = m_input->text_configuration.font_item.prop;
create_mesh(m_input->text_configuration.text.c_str(), m_result = (m_input->font_file.has_value()) ?
*m_input->font_file, create_mesh(text, m_input->font_file, prop, ctl):
m_input->text_configuration.font_item.prop, ctl); create_default_mesh();
if (m_result.its.empty()) m_result = create_default_mesh(); if (m_result.its.empty()) m_result = create_default_mesh();
if (ctl.was_canceled()) return; if (ctl.was_canceled()) return;
@ -240,16 +240,20 @@ TriangleMesh EmbossCreateJob::create_default_mesh()
return triangle_mesh; return triangle_mesh;
} }
TriangleMesh EmbossCreateJob::create_mesh(const char * text, TriangleMesh EmbossCreateJob::create_mesh(const char *text,
Emboss::FontFile &font, Emboss::FontFileWithCache &font,
const FontProp & font_prop, const FontProp &font_prop,
Ctl & ctl) Ctl &ctl)
{ {
assert(font.has_value());
if (!font.has_value()) return {};
ExPolygons shapes = Emboss::text2shapes(font, text, font_prop); ExPolygons shapes = Emboss::text2shapes(font, text, font_prop);
if (shapes.empty()) return {}; if (shapes.empty()) return {};
if (ctl.was_canceled()) return {}; if (ctl.was_canceled()) return {};
float scale = font_prop.size_in_mm / font.unit_per_em; int unit_per_em = font.font_file->unit_per_em;
float scale = font_prop.size_in_mm / unit_per_em;
float depth = font_prop.emboss / scale; float depth = font_prop.emboss / scale;
auto projectZ = std::make_unique<Emboss::ProjectZ>(depth); auto projectZ = std::make_unique<Emboss::ProjectZ>(depth);
Emboss::ProjectScale project(std::move(projectZ), scale); Emboss::ProjectScale project(std::move(projectZ), scale);

View file

@ -47,7 +47,7 @@ public:
/// <param name="ctl">Control for job, check of cancelation</param> /// <param name="ctl">Control for job, check of cancelation</param>
/// <returns>Triangle mesh model</returns> /// <returns>Triangle mesh model</returns>
static TriangleMesh create_mesh(const char * text, static TriangleMesh create_mesh(const char * text,
Emboss::FontFile &font, Emboss::FontFileWithCache &font,
const FontProp & font_prop, const FontProp & font_prop,
Ctl & ctl); Ctl & ctl);
@ -61,16 +61,16 @@ private:
/// </summary> /// </summary>
struct EmbossDataBase struct EmbossDataBase
{ {
// Pointer on Data of font (glyph shapes) // Keep pointer on Data of font (glyph shapes)
std::shared_ptr<Emboss::FontFile> font_file; Emboss::FontFileWithCache font_file;
// font item is not used for create object // font item is not used for create object
TextConfiguration text_configuration; TextConfiguration text_configuration;
// new volume name created from text // new volume name created from text
std::string volume_name; std::string volume_name;
EmbossDataBase(std::shared_ptr<Emboss::FontFile> font_file, EmbossDataBase(Emboss::FontFileWithCache font_file,
TextConfiguration text_configuration, TextConfiguration text_configuration,
std::string volume_name) std::string volume_name)
: font_file(std::move(font_file)) : font_file(font_file)
, text_configuration(text_configuration) , text_configuration(text_configuration)
, volume_name(volume_name) , volume_name(volume_name)
{} {}
@ -88,11 +88,11 @@ struct EmbossDataUpdate : public EmbossDataBase
// unique identifier of volume to change // unique identifier of volume to change
// Change of volume change id, last change could disapear // Change of volume change id, last change could disapear
// ObjectID volume_id; // ObjectID volume_id;
EmbossDataUpdate(std::shared_ptr<Emboss::FontFile> font_file, EmbossDataUpdate(Emboss::FontFileWithCache font_file,
TextConfiguration text_configuration, TextConfiguration text_configuration,
std::string volume_name, std::string volume_name,
ModelVolume * volume) ModelVolume *volume)
: EmbossDataBase(std::move(font_file), text_configuration, volume_name) : EmbossDataBase(font_file, text_configuration, volume_name)
, volume(volume) , volume(volume)
{} {}
}; };
@ -125,7 +125,7 @@ struct EmbossDataCreate: public EmbossDataBase
// It is inside of GLGizmoEmboss object, // It is inside of GLGizmoEmboss object,
// so I hope it will survive // so I hope it will survive
EmbossDataCreate(std::shared_ptr<Emboss::FontFile> font_file, EmbossDataCreate(Emboss::FontFileWithCache font_file,
const TextConfiguration & text_configuration, const TextConfiguration & text_configuration,
const std::string & volume_name, const std::string & volume_name,
ModelVolumeType volume_type, ModelVolumeType volume_type,
@ -135,7 +135,7 @@ struct EmbossDataCreate: public EmbossDataBase
const Camera& camera, const Camera& camera,
const std::vector<Vec2d> & bed_shape, const std::vector<Vec2d> & bed_shape,
RaycastManager * raycast_manager) RaycastManager * raycast_manager)
: EmbossDataBase(std::move(font_file), text_configuration, volume_name) : EmbossDataBase(font_file, text_configuration, volume_name)
, volume_type(volume_type) , volume_type(volume_type)
, screen_coor(screen_coor) , screen_coor(screen_coor)
, object_idx(object_idx) , object_idx(object_idx)

View file

@ -14,6 +14,7 @@ const std::string FontListSerializable::APP_CONFIG_FONT_BOLDNESS = "boldness"
const std::string FontListSerializable::APP_CONFIG_FONT_SKEW = "skew"; const std::string FontListSerializable::APP_CONFIG_FONT_SKEW = "skew";
const std::string FontListSerializable::APP_CONFIG_FONT_DISTANCE = "distance"; const std::string FontListSerializable::APP_CONFIG_FONT_DISTANCE = "distance";
const std::string FontListSerializable::APP_CONFIG_FONT_ANGLE = "angle"; const std::string FontListSerializable::APP_CONFIG_FONT_ANGLE = "angle";
const std::string FontListSerializable::APP_CONFIG_FONT_COLLECTION = "collection";
const std::string FontListSerializable::APP_CONFIG_FONT_CHAR_GAP = "char_gap"; const std::string FontListSerializable::APP_CONFIG_FONT_CHAR_GAP = "char_gap";
const std::string FontListSerializable::APP_CONFIG_FONT_LINE_GAP = "line_gap"; const std::string FontListSerializable::APP_CONFIG_FONT_LINE_GAP = "line_gap";
@ -83,6 +84,7 @@ std::optional<FontItem> FontListSerializable::load_font_item(
read(app_cfg_section, APP_CONFIG_FONT_SKEW, fp.skew); read(app_cfg_section, APP_CONFIG_FONT_SKEW, fp.skew);
read(app_cfg_section, APP_CONFIG_FONT_DISTANCE, fp.distance); read(app_cfg_section, APP_CONFIG_FONT_DISTANCE, fp.distance);
read(app_cfg_section, APP_CONFIG_FONT_ANGLE, fp.angle); read(app_cfg_section, APP_CONFIG_FONT_ANGLE, fp.angle);
read(app_cfg_section, APP_CONFIG_FONT_COLLECTION, fp.collection_number);
read(app_cfg_section, APP_CONFIG_FONT_CHAR_GAP, fp.char_gap); read(app_cfg_section, APP_CONFIG_FONT_CHAR_GAP, fp.char_gap);
read(app_cfg_section, APP_CONFIG_FONT_LINE_GAP, fp.line_gap); read(app_cfg_section, APP_CONFIG_FONT_LINE_GAP, fp.line_gap);
@ -109,6 +111,8 @@ void FontListSerializable::store_font_item(AppConfig & cfg,
cfg.set(section_name, APP_CONFIG_FONT_DISTANCE, std::to_string(*fp.distance)); cfg.set(section_name, APP_CONFIG_FONT_DISTANCE, std::to_string(*fp.distance));
if (fp.angle.has_value()) if (fp.angle.has_value())
cfg.set(section_name, APP_CONFIG_FONT_ANGLE, std::to_string(*fp.angle)); cfg.set(section_name, APP_CONFIG_FONT_ANGLE, std::to_string(*fp.angle));
if (fp.collection_number.has_value())
cfg.set(section_name, APP_CONFIG_FONT_COLLECTION, std::to_string(*fp.collection_number));
if (fp.char_gap.has_value()) if (fp.char_gap.has_value())
cfg.set(section_name, APP_CONFIG_FONT_CHAR_GAP, std::to_string(*fp.char_gap)); cfg.set(section_name, APP_CONFIG_FONT_CHAR_GAP, std::to_string(*fp.char_gap));
if (fp.line_gap.has_value()) if (fp.line_gap.has_value())

View file

@ -25,6 +25,7 @@ class FontListSerializable
static const std::string APP_CONFIG_FONT_SKEW; static const std::string APP_CONFIG_FONT_SKEW;
static const std::string APP_CONFIG_FONT_DISTANCE; static const std::string APP_CONFIG_FONT_DISTANCE;
static const std::string APP_CONFIG_FONT_ANGLE; static const std::string APP_CONFIG_FONT_ANGLE;
static const std::string APP_CONFIG_FONT_COLLECTION;
static const std::string APP_CONFIG_FONT_CHAR_GAP; static const std::string APP_CONFIG_FONT_CHAR_GAP;
static const std::string APP_CONFIG_FONT_LINE_GAP; static const std::string APP_CONFIG_FONT_LINE_GAP;
public: public:

View file

@ -72,13 +72,12 @@ bool FontManager::wx_font_changed(std::unique_ptr<Emboss::FontFile> font_file)
if (!wx_font.has_value()) return false; if (!wx_font.has_value()) return false;
if (font_file == nullptr) { if (font_file == nullptr) {
auto new_font_file = WxFontUtils::create_font_file(*wx_font); font_file = WxFontUtils::create_font_file(*wx_font);
if (new_font_file == nullptr) return false; if (font_file == nullptr) return false;
m_font_list[m_font_selected].font_file = std::move(new_font_file);
} else {
m_font_list[m_font_selected].font_file = std::move(font_file);
} }
m_font_list[m_font_selected].font_file_with_cache =
Emboss::FontFileWithCache(std::move(font_file));
auto &fi = get_font_item(); auto &fi = get_font_item();
fi.type = WxFontUtils::get_actual_type(); fi.type = WxFontUtils::get_actual_type();
fi.path = WxFontUtils::store_wxFont(*wx_font); fi.path = WxFontUtils::store_wxFont(*wx_font);
@ -150,7 +149,7 @@ std::shared_ptr<Emboss::FontFile> &FontManager::get_font_file()
{ {
// TODO: fix not selected font // TODO: fix not selected font
//if (!is_activ_font()) return nullptr; //if (!is_activ_font()) return nullptr;
return m_font_list[m_font_selected].font_file; return m_font_list[m_font_selected].font_file_with_cache.font_file;
} }
const FontItem &FontManager::get_font_item() const const FontItem &FontManager::get_font_item() const
@ -209,8 +208,17 @@ const std::optional<wxFont> &FontManager::get_wx_font() const
return m_font_list[m_font_selected].wx_font; return m_font_list[m_font_selected].wx_font;
} }
void FontManager::clear_glyphs_cache()
{
if (!is_activ_font()) return;
Emboss::FontFileWithCache &ff = m_font_list[m_font_selected].font_file_with_cache;
if (!ff.has_value()) return;
ff.cache = std::make_shared<Emboss::Glyphs>();
}
void FontManager::clear_imgui_font() { void FontManager::clear_imgui_font() {
// TODO: improove to clear only actual font // TODO: improove to clear only actual font
if (!is_activ_font()) return;
free_imgui_fonts(); free_imgui_fonts();
return; return;
ImFont *imgui_font = get_imgui_font(m_font_selected); ImFont *imgui_font = get_imgui_font(m_font_selected);
@ -255,7 +263,7 @@ void FontManager::free_except_active_font() {
const Item &act_item = m_font_list[m_font_selected]; const Item &act_item = m_font_list[m_font_selected];
for (auto &item : m_font_list) { for (auto &item : m_font_list) {
if (&item == &act_item) continue; // keep alive actual font file if (&item == &act_item) continue; // keep alive actual font file
item.font_file = nullptr; item.font_file_with_cache = {};
} }
} }
@ -301,10 +309,11 @@ bool FontManager::set_up_font_file(size_t item_index)
if (fi.type == FontItem::Type::file_path) { if (fi.type == FontItem::Type::file_path) {
// fill font name after load from .3mf // fill font name after load from .3mf
if (fi.name.empty()) fi.name = get_file_name(fi.path); if (fi.name.empty()) fi.name = get_file_name(fi.path);
std::unique_ptr<Emboss::FontFile> font_ptr = Emboss::load_font( std::unique_ptr<Emboss::FontFile> font_ptr =
fi.path.c_str()); Emboss::create_font_file(fi.path.c_str());
if (font_ptr == nullptr) return false; if (font_ptr == nullptr) return false;
item.font_file = std::move(font_ptr); item.font_file_with_cache =
Emboss::FontFileWithCache(std::move(font_ptr));
return true; return true;
} }
if (fi.type != WxFontUtils::get_actual_type()) return false; if (fi.type != WxFontUtils::get_actual_type()) return false;
@ -366,10 +375,12 @@ void FontManager::create_texture(size_t index, const std::string &text, GLuint&
{ {
if (index >= m_font_list.size()) return; if (index >= m_font_list.size()) return;
Item &item = m_font_list[index]; Item &item = m_font_list[index];
if (!item.font_file_with_cache.has_value() && !set_up_font_file(index))
return;
const FontProp &font_prop = item.font_item.prop; const FontProp &font_prop = item.font_item.prop;
std::shared_ptr<Emboss::FontFile> &font_file = item.font_file; ExPolygons shapes = Emboss::text2shapes(item.font_file_with_cache,
if (font_file == nullptr && !set_up_font_file(index)) return; text.c_str(), font_prop);
ExPolygons shapes = Emboss::text2shapes(*font_file, text.c_str(), font_prop);
BoundingBox bb; BoundingBox bb;
for (ExPolygon &shape : shapes) bb.merge(BoundingBox(shape.contour.points)); for (ExPolygon &shape : shapes) bb.merge(BoundingBox(shape.contour.points));
@ -415,13 +426,12 @@ void FontManager::init_style_images(int max_width) {
for (Item &item : m_font_list) { for (Item &item : m_font_list) {
FontItem & font_item = item.font_item; FontItem & font_item = item.font_item;
const FontProp & font_prop = font_item.prop; const FontProp & font_prop = font_item.prop;
std::shared_ptr<Emboss::FontFile> &font_file = item.font_file;
size_t index = &item - &m_font_list.front(); size_t index = &item - &m_font_list.front();
if (font_file == nullptr && !set_up_font_file(index)) continue; if (!item.font_file_with_cache.has_value() && !set_up_font_file(index))
if (font_file == nullptr) continue; continue;
ExPolygons &shapes = name_shapes[index]; ExPolygons &shapes = name_shapes[index];
shapes = Emboss::text2shapes(*font_file, font_item.name.c_str(), font_prop); shapes = Emboss::text2shapes(item.font_file_with_cache, font_item.name.c_str(), font_prop);
// create image description // create image description
item.image = StyleImage(); item.image = StyleImage();
@ -437,7 +447,8 @@ void FontManager::init_style_images(int max_width) {
// dot per inch for monitor // dot per inch for monitor
int dpi = get_dpi_for_window(mf); int dpi = get_dpi_for_window(mf);
double ppm = dpi / 25.4; // pixel per milimeter double ppm = dpi / 25.4; // pixel per milimeter
double scale = font_prop.size_in_mm / font_file->unit_per_em * Emboss::SHAPE_SCALE * ppm; 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; scales[index] = scale;
//double scale = font_prop.size_in_mm * SCALING_FACTOR; //double scale = font_prop.size_in_mm * SCALING_FACTOR;
@ -520,11 +531,6 @@ void FontManager::init_style_images(int max_width) {
void FontManager::free_style_images() { void FontManager::free_style_images() {
if (!is_activ_font()) return; if (!is_activ_font()) return;
std::shared_ptr<Emboss::FontFile> &font_file =
m_font_list[m_font_selected].font_file;
if(font_file != nullptr)
font_file->cache.clear();
if (!m_exist_style_images) return; if (!m_exist_style_images) return;
GLuint tex_id = (GLuint) (intptr_t) m_font_list.front().image->texture_id; GLuint tex_id = (GLuint) (intptr_t) m_font_list.front().image->texture_id;
for (Item &it : m_font_list) it.image.reset(); for (Item &it : m_font_list) it.image.reset();
@ -560,8 +566,8 @@ ImFont * FontManager::load_imgui_font(size_t index, const std::string &text)
if (index >= m_font_list.size()) return nullptr; if (index >= m_font_list.size()) return nullptr;
Item &item = m_font_list[index]; Item &item = m_font_list[index];
if (item.font_file == nullptr) return nullptr; if (!item.font_file_with_cache.has_value()) return nullptr;
const Emboss::FontFile &font_file = *item.font_file; const Emboss::FontFile &font_file = *item.font_file_with_cache.font_file;
// TODO: Create glyph range // TODO: Create glyph range
ImFontGlyphRangesBuilder builder; ImFontGlyphRangesBuilder builder;
@ -596,7 +602,7 @@ ImFont * FontManager::load_imgui_font(size_t index, const std::string &text)
font_config.FontDataOwnedByAtlas = false; font_config.FontDataOwnedByAtlas = false;
const std::vector<unsigned char> &buffer = font_file.buffer; const std::vector<unsigned char> &buffer = *font_file.data;
m_imgui_font_atlas.AddFontFromMemoryTTF( m_imgui_font_atlas.AddFontFromMemoryTTF(
(void *) buffer.data(), buffer.size(), font_size, &font_config, item.font_ranges.Data); (void *) buffer.data(), buffer.size(), font_size, &font_config, item.font_ranges.Data);
@ -633,9 +639,10 @@ bool FontManager::set_wx_font(size_t item_index, const wxFont &wx_font) {
WxFontUtils::create_font_file(wx_font); WxFontUtils::create_font_file(wx_font);
if (font_file == nullptr) return false; if (font_file == nullptr) return false;
Item &item = m_font_list[item_index]; Item &item = m_font_list[item_index];
item.font_file = std::move(font_file); item.font_file_with_cache =
item.wx_font = wx_font; Emboss::FontFileWithCache(std::move(font_file));
item.wx_font = wx_font;
FontItem &fi = item.font_item; FontItem &fi = item.font_item;
fi.type = WxFontUtils::get_actual_type(); fi.type = WxFontUtils::get_actual_type();

View file

@ -59,6 +59,9 @@ public:
// fastering load font on index by wxFont, ignore type and descriptor // fastering load font on index by wxFont, ignore type and descriptor
bool load_font(size_t font_index, const wxFont &font); bool load_font(size_t font_index, const wxFont &font);
// clear actual selected glyphs cache
void clear_glyphs_cache();
// remove cached imgui font for actual selected font // remove cached imgui font for actual selected font
void clear_imgui_font(); void clear_imgui_font();
@ -137,7 +140,7 @@ public:
std::string truncated_name; std::string truncated_name;
// share font file data with emboss job thread // share font file data with emboss job thread
std::shared_ptr<Emboss::FontFile> font_file = nullptr; Emboss::FontFileWithCache font_file_with_cache;
std::optional<size_t> imgui_font_index; std::optional<size_t> imgui_font_index;

View file

@ -45,7 +45,7 @@ bool WxFontUtils::can_load(const wxFont &font)
std::unique_ptr<Emboss::FontFile> WxFontUtils::create_font_file(const wxFont &font) std::unique_ptr<Emboss::FontFile> WxFontUtils::create_font_file(const wxFont &font)
{ {
#ifdef _WIN32 #ifdef _WIN32
return Emboss::load_font(font.GetHFONT()); return Emboss::create_font_file(font.GetHFONT());
#elif defined(__APPLE__) #elif defined(__APPLE__)
// use file path // use file path
const wxNativeFontInfo *info = font.GetNativeFontInfo(); const wxNativeFontInfo *info = font.GetNativeFontInfo();
@ -61,12 +61,12 @@ std::unique_ptr<Emboss::FontFile> WxFontUtils::create_font_file(const wxFont &fo
size_t start = std::string("file://").size(); size_t start = std::string("file://").size();
if (file_path.empty() || file_path.size() <= start) return nullptr; if (file_path.empty() || file_path.size() <= start) return nullptr;
file_path = file_path.substr(start, file_path.size() - start); file_path = file_path.substr(start, file_path.size() - start);
return Emboss::load_font(file_path.c_str()); return Emboss::create_font_file(file_path.c_str());
#elif defined(__linux__) #elif defined(__linux__)
static FontConfigHelp help; static FontConfigHelp help;
std::string font_path = help.get_font_path(font); std::string font_path = help.get_font_path(font);
if (font_path.empty()) return nullptr; if (font_path.empty()) return nullptr;
return Emboss::load_font(font_path.c_str()); return Emboss::create_font_file(font_path.c_str());
#else #else
// HERE is place to add implementation for another platform // HERE is place to add implementation for another platform
// to convert wxFont to font data as windows or font file path as linux // to convert wxFont to font data as windows or font file path as linux

View file

@ -130,7 +130,7 @@ TEST_CASE("Emboss text", "[Emboss]")
char letter = '%'; char letter = '%';
float flatness = 2.; float flatness = 2.;
auto font = Emboss::load_font(font_path.c_str()); auto font = Emboss::create_font_file(font_path.c_str());
REQUIRE(font != nullptr); REQUIRE(font != nullptr);
std::optional<Emboss::Glyph> glyph = Emboss::letter2glyph(*font, letter, flatness); std::optional<Emboss::Glyph> glyph = Emboss::letter2glyph(*font, letter, flatness);
@ -237,7 +237,7 @@ TEST_CASE("Italic check", "[]")
[](unsigned char c) { return std::tolower(c); }); [](unsigned char c) { return std::tolower(c); });
if (ext != ".ttf") continue; if (ext != ".ttf") continue;
std::string path_str = act_path.u8string(); std::string path_str = act_path.u8string();
auto font_opt = Emboss::load_font(path_str.c_str()); auto font_opt = Emboss::create_font_file(path_str.c_str());
if (font_opt == nullptr) continue; if (font_opt == nullptr) continue;
if (Emboss::is_italic(*font_opt)) if (Emboss::is_italic(*font_opt))
exist_italic = true; exist_italic = true;