Choose font by wxWidgetDialog
This commit is contained in:
parent
578abe4cce
commit
9d52ceee44
6 changed files with 317 additions and 109 deletions
|
@ -25,13 +25,7 @@ public:
|
|||
Privat() = delete;
|
||||
|
||||
static std::optional<stbtt_fontinfo> load_font_info(const Emboss::Font &font);
|
||||
|
||||
struct Glyph
|
||||
{
|
||||
Polygons polygons;
|
||||
int advance_width, left_side_bearing;
|
||||
};
|
||||
static std::optional<Glyph> get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness = 2.f);
|
||||
static std::optional<Emboss::Glyph> get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness = 2.f);
|
||||
};
|
||||
|
||||
std::optional<stbtt_fontinfo> Privat::load_font_info(const Emboss::Font &font)
|
||||
|
@ -49,7 +43,7 @@ std::optional<stbtt_fontinfo> Privat::load_font_info(const Emboss::Font &font)
|
|||
return font_info;
|
||||
}
|
||||
|
||||
std::optional<Privat::Glyph> Privat::get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness)
|
||||
std::optional<Emboss::Glyph> Privat::get_glyph(stbtt_fontinfo &font_info, int unicode_letter, float flatness)
|
||||
{
|
||||
int glyph_index = stbtt_FindGlyphIndex(&font_info, unicode_letter);
|
||||
if (glyph_index == 0) {
|
||||
|
@ -58,7 +52,7 @@ std::optional<Privat::Glyph> Privat::get_glyph(stbtt_fontinfo &font_info, int un
|
|||
return {};
|
||||
}
|
||||
|
||||
Privat::Glyph glyph;
|
||||
Emboss::Glyph glyph;
|
||||
stbtt_GetGlyphHMetrics(&font_info, glyph_index, &glyph.advance_width, &glyph.left_side_bearing);
|
||||
|
||||
stbtt_vertex *vertices;
|
||||
|
@ -96,16 +90,15 @@ std::optional<Privat::Glyph> Privat::get_glyph(stbtt_fontinfo &font_info, int un
|
|||
|
||||
// change outer cw to ccw and inner ccw to cw order
|
||||
std::reverse(pts.begin(), pts.end());
|
||||
|
||||
glyph.polygons.emplace_back(pts);
|
||||
}
|
||||
|
||||
// fix for bad defined fonts
|
||||
glyph.polygons = union_(glyph.polygons);
|
||||
// inner cw - hole
|
||||
// outer ccw - contour
|
||||
return glyph;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <wingdi.h>
|
||||
|
@ -210,23 +203,46 @@ void choose_font_dlg() {
|
|||
|
||||
void get_OS_font()
|
||||
{
|
||||
HGDIOBJ g_hfFont = GetStockObject(DEFAULT_GUI_FONT);
|
||||
LOGFONT lf;
|
||||
HGDIOBJ g_hfFont = GetStockObject(DEFAULT_GUI_FONT);
|
||||
GetObject(g_hfFont, sizeof(LOGFONT), &lf);
|
||||
std::wcout << "Default WIN font is " << (std::wstring) lf.lfFaceName
|
||||
<< std::endl;
|
||||
std::wcout << "DEFAULT_GUI_FONT is " << (std::wstring) lf.lfFaceName << std::endl;
|
||||
|
||||
g_hfFont = GetStockObject(OEM_FIXED_FONT);
|
||||
GetObject(g_hfFont, sizeof(LOGFONT), &lf);
|
||||
std::wcout << "OEM_FIXED_FONT is " << (std::wstring) lf.lfFaceName << std::endl;
|
||||
|
||||
g_hfFont = GetStockObject(ANSI_FIXED_FONT);
|
||||
GetObject(g_hfFont, sizeof(LOGFONT), &lf);
|
||||
std::wcout << "ANSI_FIXED_FONT is " << (std::wstring) lf.lfFaceName << std::endl;
|
||||
|
||||
g_hfFont = GetStockObject(ANSI_VAR_FONT);
|
||||
GetObject(g_hfFont, sizeof(LOGFONT), &lf);
|
||||
std::wcout << "ANSI_VAR_FONT is " << (std::wstring) lf.lfFaceName << std::endl;
|
||||
|
||||
g_hfFont = GetStockObject(SYSTEM_FONT);
|
||||
GetObject(g_hfFont, sizeof(LOGFONT), &lf);
|
||||
std::wcout << "SYSTEM_FONT is " << (std::wstring) lf.lfFaceName << std::endl;
|
||||
|
||||
g_hfFont = GetStockObject(DEVICE_DEFAULT_FONT);
|
||||
GetObject(g_hfFont, sizeof(LOGFONT), &lf);
|
||||
std::wcout << "DEVICE_DEFAULT_FONT is " << (std::wstring) lf.lfFaceName << std::endl;
|
||||
|
||||
g_hfFont = GetStockObject(SYSTEM_FIXED_FONT);
|
||||
GetObject(g_hfFont, sizeof(LOGFONT), &lf);
|
||||
std::wcout << "SYSTEM_FIXED_FONT is " << (std::wstring) lf.lfFaceName << std::endl;
|
||||
}
|
||||
|
||||
//#include <wx/fontdlg.h>
|
||||
|
||||
Emboss::FontList Emboss::get_font_list()
|
||||
{
|
||||
//auto a = get_font_path(L"none");
|
||||
//get_OS_font();
|
||||
get_OS_font();
|
||||
//choose_font_dlg();
|
||||
//FontList list1 = get_font_list_by_enumeration();
|
||||
//FontList list2 = get_font_list_by_register();
|
||||
//FontList list3 = get_font_list_by_folder();
|
||||
//FontList list3 = get_font_list_by_folder();
|
||||
|
||||
return get_font_list_by_register();
|
||||
}
|
||||
|
||||
|
@ -337,9 +353,11 @@ Emboss::FontList Emboss::get_font_list_by_folder() {
|
|||
std::wstring search_dir = std::wstring(winDir, winDir_size) + L"\\Fonts\\";
|
||||
WIN32_FIND_DATA fd;
|
||||
HANDLE hFind;
|
||||
auto iterate_files = [&hFind, &fd, &search_dir, &result]() {
|
||||
if (hFind == INVALID_HANDLE_VALUE) return;
|
||||
// read all (real) files in current folder
|
||||
// By https://en.wikipedia.org/wiki/TrueType has also suffix .tte
|
||||
std::vector<std::wstring> suffixes = {L"*.ttf", L"*.ttc", L"*.tte"};
|
||||
for (const std::wstring &suffix : suffixes) {
|
||||
hFind = ::FindFirstFile((search_dir + suffix).c_str(), &fd);
|
||||
if (hFind == INVALID_HANDLE_VALUE) continue;
|
||||
do {
|
||||
// skip folder . and ..
|
||||
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
|
||||
|
@ -347,13 +365,8 @@ Emboss::FontList Emboss::get_font_list_by_folder() {
|
|||
// TODO: find font name instead of filename
|
||||
result.emplace_back(file_name, search_dir + file_name);
|
||||
} while (::FindNextFile(hFind, &fd));
|
||||
::FindClose(hFind);
|
||||
};
|
||||
|
||||
hFind = ::FindFirstFile((search_dir + L"*.ttf").c_str(), &fd);
|
||||
iterate_files();
|
||||
hFind = ::FindFirstFile((search_dir + L"*.ttc").c_str(), &fd);
|
||||
iterate_files();
|
||||
::FindClose(hFind);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -366,6 +379,34 @@ std::optional<std::wstring> Emboss::get_font_path(const std::wstring &font_face_
|
|||
}
|
||||
#endif
|
||||
|
||||
std::optional<Emboss::Font> Emboss::load_font(std::vector<unsigned char> data)
|
||||
{
|
||||
Font res;
|
||||
res.buffer = std::move(data);
|
||||
|
||||
unsigned int index = 0;
|
||||
int font_offset = 0;
|
||||
while (font_offset >= 0) {
|
||||
font_offset = stbtt_GetFontOffsetForIndex(res.buffer.data(), index++);
|
||||
}
|
||||
// at least one font must be inside collection
|
||||
if (index < 1) {
|
||||
std::cerr << "There is no font collection inside file.";
|
||||
return {};
|
||||
}
|
||||
// select default font on index 0
|
||||
res.index = 0;
|
||||
res.count = index;
|
||||
|
||||
auto font_info = Privat::load_font_info(res);
|
||||
if (!font_info.has_value()) return {};
|
||||
|
||||
// load information about line gap
|
||||
stbtt_GetFontVMetrics(&(*font_info), &res.ascent, &res.descent,
|
||||
&res.linegap);
|
||||
return res;
|
||||
}
|
||||
|
||||
std::optional<Emboss::Font> Emboss::load_font(const char *file_path)
|
||||
{
|
||||
FILE *file = fopen(file_path, "rb");
|
||||
|
@ -386,52 +427,63 @@ std::optional<Emboss::Font> Emboss::load_font(const char *file_path)
|
|||
}
|
||||
rewind(file);
|
||||
|
||||
Font res;
|
||||
res.buffer = std::vector<unsigned char>(size);
|
||||
size_t count_loaded_bytes = fread((void *) &res.buffer.front(), 1, size, file);
|
||||
|
||||
unsigned int index = 0;
|
||||
int font_offset = 0;
|
||||
while (font_offset >= 0) {
|
||||
font_offset = stbtt_GetFontOffsetForIndex(res.buffer.data(), index++);
|
||||
std::vector<unsigned char> buffer(size);
|
||||
size_t count_loaded_bytes = fread((void *) &buffer.front(), 1, size, file);
|
||||
if (count_loaded_bytes != size) {
|
||||
std::cerr << "Different loaded(from file) data size.";
|
||||
return {};
|
||||
}
|
||||
// at least one font must be inside collection
|
||||
if (index < 1) {
|
||||
std::cerr << "There is no font collection inside file.";
|
||||
return {};
|
||||
}
|
||||
// select default font on index 0
|
||||
res.index = 0;
|
||||
res.count = index;
|
||||
|
||||
auto font_info = Privat::load_font_info(res);
|
||||
if (!font_info.has_value()) return {};
|
||||
|
||||
// load information about line gap
|
||||
stbtt_GetFontVMetrics(&(*font_info), &res.ascent, &res.descent, &res.linegap);
|
||||
return res;
|
||||
return load_font(std::move(buffer));
|
||||
}
|
||||
|
||||
Polygons Emboss::letter2polygons(const Font &font, char letter, float flatness)
|
||||
|
||||
#ifdef _WIN32
|
||||
std::optional<Emboss::Font> Emboss::load_font(HFONT hfont)
|
||||
{
|
||||
HDC hdc = ::CreateCompatibleDC(NULL);
|
||||
if (hdc == NULL) {
|
||||
std::cerr << "Can't create HDC by CreateCompatibleDC(NULL).";
|
||||
return {};
|
||||
}
|
||||
|
||||
::SelectObject(hdc, hfont);
|
||||
size_t size = ::GetFontData(hdc, 0, 0, NULL, 0);
|
||||
if (size == 0) {
|
||||
std::cerr << "HFONT doesn't have size.";
|
||||
::DeleteDC(hdc);
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<unsigned char> buffer(size);
|
||||
size_t loaded_size = ::GetFontData(hdc, 0, 0, buffer.data(), size);
|
||||
::DeleteDC(hdc);
|
||||
|
||||
if (size != loaded_size) {
|
||||
std::cerr << "Different loaded(from HFONT) data size.";
|
||||
return {};
|
||||
}
|
||||
|
||||
return load_font(std::move(buffer));
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
std::optional<Emboss::Glyph> Emboss::letter2glyph(const Font &font,
|
||||
int letter,
|
||||
float flatness)
|
||||
{
|
||||
auto font_info_opt = Privat::load_font_info(font);
|
||||
if (!font_info_opt.has_value()) return Polygons();
|
||||
if (!font_info_opt.has_value()) return {};
|
||||
stbtt_fontinfo *font_info = &(*font_info_opt);
|
||||
|
||||
auto glyph_opt = Privat::get_glyph(*font_info_opt, (int) letter, flatness);
|
||||
if (!glyph_opt.has_value()) return Polygons();
|
||||
|
||||
return union_(glyph_opt->polygons);
|
||||
return Privat::get_glyph(*font_info_opt, (int) letter, flatness);
|
||||
}
|
||||
|
||||
Polygons Emboss::text2polygons(const Font & font,
|
||||
const char * text,
|
||||
const FontProp &font_prop)
|
||||
const FontProp &font_prop,
|
||||
Glyphs & cache)
|
||||
{
|
||||
auto font_info_opt = Privat::load_font_info(font);
|
||||
if (!font_info_opt.has_value()) return Polygons();
|
||||
stbtt_fontinfo *font_info = &(*font_info_opt);
|
||||
|
||||
std::optional<stbtt_fontinfo> font_info_opt;
|
||||
|
||||
Point cursor(0, 0);
|
||||
Polygons result;
|
||||
|
||||
|
@ -443,16 +495,27 @@ Polygons Emboss::text2polygons(const Font & font,
|
|||
continue;
|
||||
}
|
||||
int unicode = static_cast<int>(wc);
|
||||
auto glyph_opt = Privat::get_glyph(*font_info_opt, unicode, font_prop.flatness);
|
||||
if (!glyph_opt.has_value()) continue;
|
||||
|
||||
std::optional<Glyph> glyph_opt;
|
||||
auto glyph_item = cache.find(unicode);
|
||||
if (glyph_item != cache.end()) glyph_opt = glyph_item->second;
|
||||
else {
|
||||
if (!font_info_opt.has_value()) {
|
||||
font_info_opt = Privat::load_font_info(font);
|
||||
// can load font info?
|
||||
if (!font_info_opt.has_value()) return Polygons();
|
||||
}
|
||||
glyph_opt = Privat::get_glyph(*font_info_opt, unicode,
|
||||
font_prop.flatness);
|
||||
// has definition inside of font?
|
||||
if (!glyph_opt.has_value()) continue;
|
||||
cache[unicode] = *glyph_opt;
|
||||
}
|
||||
|
||||
// move glyph to cursor position
|
||||
Polygons polygons = glyph_opt->polygons; // copy
|
||||
for (Polygon &polygon : polygons)
|
||||
for (Point &p : polygon.points) p += cursor;
|
||||
|
||||
polygon.translate(cursor);
|
||||
cursor.x() += glyph_opt->advance_width + font_prop.char_gap;
|
||||
|
||||
polygons_append(result, polygons);
|
||||
}
|
||||
return union_(result);
|
||||
|
|
|
@ -75,30 +75,49 @@ public:
|
|||
FontProp() = default;
|
||||
};
|
||||
|
||||
// description of one letter
|
||||
struct Glyph
|
||||
{
|
||||
Polygons polygons;
|
||||
int advance_width, left_side_bearing;
|
||||
};
|
||||
// cache for glyph by unicode
|
||||
using Glyphs = std::map<int, Glyph>;
|
||||
|
||||
/// <summary>
|
||||
/// Load font file into buffer
|
||||
/// </summary>
|
||||
/// <param name="file_path">Location of .ttf or .ttc font file</param>
|
||||
/// <returns>Font object when loaded.</returns>
|
||||
static std::optional<Font> load_font(const char *file_path);
|
||||
static std::optional<Font> load_font(std::vector<unsigned char> data);
|
||||
#ifdef _WIN32
|
||||
// fix for unknown pointer HFONT
|
||||
using HFONT = void*;
|
||||
static std::optional<Font> load_font(HFONT hfont);
|
||||
#endif // _WIN32
|
||||
|
||||
/// <summary>
|
||||
/// convert letter into polygons
|
||||
/// </summary>
|
||||
/// <param name="font">Define fonts</param>
|
||||
/// <param name="letter">One character to convert</param>
|
||||
/// <param name="letter">One character defined by unicode codepoint</param>
|
||||
/// <param name="flatness">Precision of lettter outline curve in conversion to lines</param>
|
||||
/// <returns>inner polygon cw(outer ccw)</returns>
|
||||
static Polygons letter2polygons(const Font &font, char letter, float flatness);
|
||||
static std::optional<Glyph> letter2glyph(const Font &font, int letter, float flatness);
|
||||
|
||||
/// <summary>
|
||||
/// Convert text into polygons
|
||||
/// </summary>
|
||||
/// <param name="font">Define fonts</param>
|
||||
/// <param name="text">Characters to convert</param>
|
||||
/// <param name="font_prop">User defined property of font</param>
|
||||
/// <param name="font_prop">User defined property of the font</param>
|
||||
/// <param name="cache">Cache for letter polygons</param>
|
||||
/// <returns>Inner polygon cw(outer ccw)</returns>
|
||||
static Polygons text2polygons(const Font &font, const char *text, const FontProp& font_prop);
|
||||
static Polygons text2polygons(const Font & font,
|
||||
const char * text,
|
||||
const FontProp &font_prop,
|
||||
Glyphs & cache = Glyphs());
|
||||
|
||||
/// <summary>
|
||||
/// Project 2d point into space
|
||||
|
|
|
@ -433,7 +433,7 @@ wxString file_wildcards(FileType file_type, const std::string &custom_extension)
|
|||
/* FT_GCODE */ "G-code files (*.gcode, *.gco, *.g, *.ngc)|*.gcode;*.GCODE;*.gco;*.GCO;*.g;*.G;*.ngc;*.NGC",
|
||||
/* FT_MODEL */ "Known files (*.stl, *.obj, *.amf, *.xml, *.3mf, *.prusa)|*.stl;*.STL;*.obj;*.OBJ;*.amf;*.AMF;*.xml;*.XML;*.3mf;*.3MF;*.prusa;*.PRUSA",
|
||||
/* FT_PROJECT */ "Project files (*.3mf, *.amf)|*.3mf;*.3MF;*.amf;*.AMF",
|
||||
/* FT_FONTS */ "Font files (*.ttf, *.ttc)|*.ttf;*.TTF;*.ttc;*.TTC",
|
||||
/* FT_FONTS */ "Font files (*.ttf, *.tte, *.ttc, *.dfont)|*.ttf;*.tte;*.ttc;*.dfont;*.TTF;*.TTE;*.TTC;*.DFONT",
|
||||
/* FT_GALLERY */ "Known files (*.stl, *.obj)|*.stl;*.STL;*.obj;*.OBJ",
|
||||
|
||||
/* FT_INI */ "INI files (*.ini)|*.ini;*.INI",
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
|
||||
#include "libslic3r/Model.hpp"
|
||||
|
||||
#include <wx/font.h>
|
||||
#include <wx/fontdlg.h>
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
GLGizmoEmboss::GLGizmoEmboss(GLCanvas3D & parent,
|
||||
|
@ -21,7 +24,8 @@ GLGizmoEmboss::GLGizmoEmboss(GLCanvas3D & parent,
|
|||
, m_text_size(255)
|
||||
, m_text(new char[m_text_size])
|
||||
, m_scale(0.01f)
|
||||
, m_emboss(5.f)
|
||||
, m_emboss(5.f)
|
||||
, m_volume(nullptr)
|
||||
{
|
||||
// TODO: suggest to use https://fontawesome.com/
|
||||
// (copy & paste) unicode symbols from web
|
||||
|
@ -63,18 +67,17 @@ void GLGizmoEmboss::on_render_for_picking() {}
|
|||
|
||||
void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
if (!m_gui_cfg.has_value()) m_gui_cfg.emplace(GuiCfg());
|
||||
|
||||
int flag = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoCollapse;
|
||||
m_imgui->begin(on_get_name(), flag);
|
||||
|
||||
size_t max_font_name = 20; // count characters
|
||||
|
||||
auto& current = m_font_list[m_font_selected];
|
||||
if (ImGui::BeginCombo("##font_selector", current.name.c_str())) {
|
||||
for (const Emboss::FontItem &f : m_font_list) {
|
||||
ImGui::PushID((void*)&f.name);
|
||||
std::string name = (f.name.size() < max_font_name) ?
|
||||
f.name : (f.name.substr(0,max_font_name - 3) + " ..");
|
||||
std::string name = (f.name.size() < m_gui_cfg->max_font_name) ?
|
||||
f.name : (f.name.substr(0,m_gui_cfg->max_font_name - 3) + " ..");
|
||||
if (ImGui::Selectable(name.c_str(), &f == ¤t)) {
|
||||
m_font_selected = &f - &m_font_list.front();
|
||||
load_font();
|
||||
|
@ -90,28 +93,52 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
|
|||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
m_imgui->disabled_begin(!m_font.has_value() || m_font->count == 1);
|
||||
if (ImGui::BeginCombo("##font_collection_selector", std::to_string(m_font->index).c_str())) {
|
||||
for (size_t i = 0; i < m_font->count; ++i) {
|
||||
ImGui::PushID(1<<10 + i);
|
||||
if (ImGui::Selectable(std::to_string(i).c_str(), i == m_font->index)) {
|
||||
m_font->index = i;
|
||||
if (m_font.has_value()) {
|
||||
if (ImGui::BeginCombo("##font_collection_selector", std::to_string(m_font->index).c_str())) {
|
||||
for (size_t i = 0; i < m_font->count; ++i) {
|
||||
ImGui::PushID(1 << 10 + i);
|
||||
if (ImGui::Selectable(std::to_string(i).c_str(),
|
||||
i == m_font->index)) {
|
||||
m_font->index = i;
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::PopID();
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
m_imgui->disabled_end();
|
||||
|
||||
static std::string fontName;
|
||||
if (ImGui::Button(_L("choose font").c_str())) {
|
||||
static wxFontData data; // keep last selected font
|
||||
wxFontDialog font_dialog(nullptr, data);
|
||||
font_dialog.SetTitle(_L("Select font FFF"));
|
||||
if (font_dialog.ShowModal() == wxID_OK) {
|
||||
data = font_dialog.GetFontData();
|
||||
wxFont font = data.GetChosenFont();
|
||||
fontName = boost::nowide::narrow(font.GetFaceName());
|
||||
m_font = Emboss::load_font(font.GetHFONT());
|
||||
m_font_glyph_cache.clear();
|
||||
process();
|
||||
}
|
||||
}
|
||||
if (!fontName.empty()) ImGui::Text(fontName.c_str());
|
||||
|
||||
ImGui::SameLine();
|
||||
draw_add_button();
|
||||
|
||||
ImGui::InputFloat("Scale", &m_scale);
|
||||
ImGui::InputFloat("Emboss", &m_emboss);
|
||||
ImGui::InputFloat("Flatness", &m_font_prop.flatness);
|
||||
if (ImGui::InputFloat("Flatness", &m_font_prop.flatness))
|
||||
m_font_glyph_cache.clear();
|
||||
ImGui::InputInt("CharGap", &m_font_prop.char_gap);
|
||||
ImGui::InputInt("LineGap", &m_font_prop.line_gap);
|
||||
|
||||
ImGui::InputFloat3("Origin", m_orientation.origin.data());
|
||||
//if (ImGui::InputFloat3("Normal", m_normal.data())) m_normal.normalize();
|
||||
//if (ImGui::InputFloat3("Up", m_up.data())) m_up.normalize();
|
||||
|
||||
|
||||
|
||||
m_imgui->disabled_begin(!m_font.has_value());
|
||||
if (ImGui::Button("Preview")) process();
|
||||
m_imgui->disabled_end();
|
||||
|
@ -129,12 +156,12 @@ void GLGizmoEmboss::on_render_input_window(float x, float y, float bottom_limit)
|
|||
}
|
||||
|
||||
// change text size
|
||||
int max_text_size = m_text_size;
|
||||
int max_text_size = static_cast<int>(m_text_size);
|
||||
if (ImGui::InputInt("max text size", &max_text_size, 8, 64)) {
|
||||
if (max_text_size < 4) max_text_size = 4;
|
||||
std::unique_ptr<char[]> newData(new char[max_text_size]);
|
||||
size_t index = 0;
|
||||
while (index < max_text_size-1) {
|
||||
while ((index+1) < max_text_size) {
|
||||
if (m_text.get()[index] == '\0') break;
|
||||
newData.get()[index] = m_text.get()[index];
|
||||
++index;
|
||||
|
@ -165,7 +192,7 @@ void GLGizmoEmboss::on_set_state()
|
|||
// Closing gizmo. e.g. selecting another one
|
||||
if (GLGizmoBase::m_state == GLGizmoBase::Off) {
|
||||
|
||||
// refuse outgoing during simlification
|
||||
// refuse outgoing during text preview
|
||||
if (false) {
|
||||
GLGizmoBase::m_state = GLGizmoBase::On;
|
||||
auto notification_manager = wxGetApp().plater()->get_notification_manager();
|
||||
|
@ -175,36 +202,115 @@ void GLGizmoEmboss::on_set_state()
|
|||
_u8L("ERROR: Wait until ends or Cancel process."));
|
||||
return;
|
||||
}
|
||||
|
||||
m_volume = nullptr;
|
||||
} else if (GLGizmoBase::m_state == GLGizmoBase::On) {
|
||||
// when open by hyperlink it needs to show up
|
||||
//request_rerender();
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoEmboss::process() {
|
||||
auto project = std::make_unique<Emboss::ProjectScale>(
|
||||
std::make_unique<Emboss::ProjectZ>(m_emboss/m_scale), m_scale);
|
||||
// IMPROVE: Do not use gizmo_event - especialy smth with prefix SLA,
|
||||
// use Bind into wxGLCanvas?
|
||||
bool GLGizmoEmboss::gizmo_event(SLAGizmoEventType action,
|
||||
const Vec2d & mouse_position,
|
||||
bool shift_down,
|
||||
bool alt_down,
|
||||
bool control_down)
|
||||
{
|
||||
/* if (action == SLAGizmoEventType::LeftUp) {
|
||||
const Camera & camera = wxGetApp().plater()->get_camera();
|
||||
const Selection & selection = m_parent.get_selection();
|
||||
const ModelObject * mo = m_c->selection_info()->model_object();
|
||||
const ModelInstance *mi = mo->instances[selection.get_instance_idx()];
|
||||
const Transform3d & instance_trafo = mi->get_transformation()
|
||||
.get_matrix();
|
||||
|
||||
Polygons polygons = Emboss::text2polygons(*m_font, m_text.get(), m_font_prop);
|
||||
// Precalculate transformations of individual meshes.
|
||||
std::vector<Transform3d> trafo_matrices;
|
||||
for (const ModelVolume *mv : mo->volumes)
|
||||
if (mv->is_model_part())
|
||||
trafo_matrices.emplace_back(instance_trafo * mv->get_matrix());
|
||||
|
||||
Vec3f normal = Vec3f::Zero();
|
||||
Vec3f hit = Vec3f::Zero();
|
||||
size_t facet = 0;
|
||||
Vec3f closest_hit = Vec3f::Zero();
|
||||
double closest_hit_squared_distance =
|
||||
std::numeric_limits<double>::max();
|
||||
size_t closest_facet = 0;
|
||||
int closest_hit_mesh_id = -1;
|
||||
|
||||
// Cast a ray on all meshes, pick the closest hit and save it for the
|
||||
// respective mesh
|
||||
for (int mesh_id = 0; mesh_id < int(trafo_matrices.size());
|
||||
++mesh_id) {
|
||||
if (m_c->raycaster()->raycasters()[mesh_id]->unproject_on_mesh(
|
||||
mouse_position, trafo_matrices[mesh_id], camera, hit,
|
||||
normal, m_c->object_clipper()->get_clipping_plane(),
|
||||
&facet)) {
|
||||
|
||||
// In case this hit is clipped, skip it.
|
||||
|
||||
// Is this hit the closest to the camera so far?
|
||||
double hit_squared_distance = (camera.get_position() -
|
||||
trafo_matrices[mesh_id] *
|
||||
hit.cast<double>())
|
||||
.squaredNorm();
|
||||
if (hit_squared_distance < closest_hit_squared_distance) {
|
||||
closest_hit_squared_distance = hit_squared_distance;
|
||||
closest_facet = facet;
|
||||
closest_hit_mesh_id = mesh_id;
|
||||
closest_hit = hit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get intersection
|
||||
|
||||
}
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLGizmoEmboss::process() {
|
||||
if (!m_font.has_value()) return;
|
||||
|
||||
Polygons polygons = Emboss::text2polygons(*m_font, m_text.get(), m_font_prop, m_font_glyph_cache);
|
||||
if (polygons.empty()) return;
|
||||
|
||||
auto project = std::make_unique<Emboss::ProjectScale>(
|
||||
std::make_unique<Emboss::ProjectZ>(m_emboss/m_scale), m_scale);
|
||||
indexed_triangle_set its = Emboss::polygons2model(polygons, *project);
|
||||
if (its.indices.empty()) return;
|
||||
|
||||
// add object
|
||||
TriangleMesh tm(its);
|
||||
TriangleMesh tm(std::move(its));
|
||||
tm.repair();
|
||||
|
||||
tm.WriteOBJFile("text_preview.obj");
|
||||
//tm.WriteOBJFile("text_preview.obj");
|
||||
|
||||
const Selection &selection = m_parent.get_selection();
|
||||
int object_idx = selection.get_object_idx();
|
||||
ModelObject * obj = wxGetApp().plater()->model().objects[object_idx];
|
||||
ModelVolume * v = obj->volumes.front();
|
||||
v->set_mesh(tm);
|
||||
v->set_new_unique_id();
|
||||
obj->invalidate_bounding_box();
|
||||
|
||||
//if (m_volume != nullptr) {
|
||||
// // TODO: fix index of m_volume
|
||||
// size_t m_volume_index = obj->volumes.size() - 1;
|
||||
// obj->delete_volume(m_volume_index);
|
||||
//}
|
||||
//m_volume = obj->add_volume(std::move(tm), ModelVolumeType::MODEL_PART);
|
||||
|
||||
if (m_volume == nullptr) {
|
||||
m_volume = obj->add_volume(std::move(tm), ModelVolumeType::MODEL_PART);
|
||||
} else {
|
||||
m_volume->set_mesh(std::move(tm));
|
||||
m_volume->set_new_unique_id();
|
||||
m_volume->translate(-m_volume->source.mesh_offset);
|
||||
|
||||
m_volume->center_geometry_after_creation(true);
|
||||
m_volume->calculate_convex_hull();
|
||||
m_volume->get_object()->invalidate_bounding_box();
|
||||
}
|
||||
m_parent.reload_scene(true);
|
||||
}
|
||||
|
||||
|
@ -235,7 +341,7 @@ void GLGizmoEmboss::draw_add_button() {
|
|||
font_list.emplace_back(name, path);
|
||||
}
|
||||
// set last added font as active
|
||||
m_font_selected = m_font_list.size() - 1;
|
||||
m_font_selected = m_font_list.size() + font_list.size() - 1;
|
||||
add_fonts(font_list);
|
||||
load_font();
|
||||
}
|
||||
|
@ -250,6 +356,7 @@ bool GLGizmoEmboss::load_font()
|
|||
{
|
||||
auto font_path = m_font_list[m_font_selected].path.c_str();
|
||||
m_font = Emboss::load_font(font_path);
|
||||
m_font_glyph_cache.clear();
|
||||
return m_font.has_value();
|
||||
}
|
||||
|
||||
|
@ -279,5 +386,4 @@ void GLGizmoEmboss::add_fonts(const Emboss::FontList &font_list) {
|
|||
sort_fonts();
|
||||
}
|
||||
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
|
|
|
@ -4,11 +4,14 @@
|
|||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code,
|
||||
// which overrides our localization "L" macro.
|
||||
#include "GLGizmoBase.hpp"
|
||||
#include "GLGizmosCommon.hpp"
|
||||
|
||||
#include "admesh/stl.h" // indexed_triangle_set
|
||||
#include <optional>
|
||||
#include <memory>
|
||||
|
||||
#include "libslic3r/Emboss.hpp"
|
||||
#include "libslic3r/Point.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
class ModelVolume;
|
||||
|
@ -19,6 +22,8 @@ class GLGizmoEmboss : public GLGizmoBase
|
|||
public:
|
||||
GLGizmoEmboss(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
virtual ~GLGizmoEmboss();
|
||||
// pseudo virtual function, no inheritance
|
||||
virtual bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
|
||||
protected:
|
||||
virtual bool on_init() override;
|
||||
virtual std::string on_get_name() const override;
|
||||
|
@ -27,7 +32,7 @@ protected:
|
|||
virtual void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
virtual bool on_is_activable() const override;
|
||||
virtual bool on_is_selectable() const override { return true; }
|
||||
virtual void on_set_state() override;
|
||||
virtual void on_set_state() override;
|
||||
|
||||
private:
|
||||
void process();
|
||||
|
@ -42,7 +47,8 @@ private:
|
|||
// so the change takes effect. (info by GLGizmoFdmSupports.hpp)
|
||||
struct GuiCfg
|
||||
{
|
||||
|
||||
const size_t max_font_name = 20; // count characters
|
||||
GuiCfg() = default;
|
||||
};
|
||||
std::optional<GuiCfg> m_gui_cfg;
|
||||
|
||||
|
@ -50,14 +56,28 @@ private:
|
|||
size_t m_font_selected;// index to m_font_list
|
||||
|
||||
std::optional<Emboss::Font> m_font;
|
||||
Emboss::Glyphs m_font_glyph_cache;
|
||||
|
||||
size_t m_text_size;
|
||||
std::unique_ptr<char[]> m_text;
|
||||
|
||||
Emboss::FontProp m_font_prop;
|
||||
|
||||
// text position
|
||||
struct Orientation
|
||||
{
|
||||
Vec3f origin = Vec3f(0.f, 0.f, 0.f);
|
||||
Vec3f normal = Vec3f(0.f, 0.f, 1.f);
|
||||
Vec3f up = Vec3f(0.f, 1.f, 0.f);
|
||||
Orientation() = default;
|
||||
};
|
||||
Orientation m_orientation;
|
||||
|
||||
float m_scale;
|
||||
float m_emboss;
|
||||
|
||||
// actual volume
|
||||
ModelVolume *m_volume;
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
|
|
|
@ -54,7 +54,7 @@ TEST_CASE("Add TriangleMeshes", "[MeshBoolean]")
|
|||
Polygons ttf2polygons(const char * font_name, char letter, float flatness = 1.f) {
|
||||
auto font = Emboss::load_font(font_name);
|
||||
if (!font.has_value()) return Polygons();
|
||||
return Emboss::letter2polygons(*font, letter, flatness);
|
||||
return Emboss::letter2glyph(*font, letter, flatness)->polygons;
|
||||
}
|
||||
|
||||
#include "libslic3r/SVG.hpp"
|
||||
|
|
Loading…
Reference in a new issue