支持多字体加载

This commit is contained in:
Nanako 2024-12-25 22:07:06 +08:00
parent b6c5bdae77
commit 0937bb8a60
4 changed files with 132 additions and 65 deletions

View File

@ -112,7 +112,7 @@ void dx_window::begin_frame() {
// context.draw_line( { 600, 600 }, { mouse_x, mouse_y }, { 1, 0, 1, 1 }, thickness); // context.draw_line( { 600, 600 }, { mouse_x, mouse_y }, { 1, 0, 1, 1 }, thickness);
// if (test_texture) context.draw_texture({ 0.f, 0.f }, test_texture->size().cast<float>(), test_texture); // if (test_texture) context.draw_texture({ 0.f, 0.f }, test_texture->size().cast<float>(), test_texture);
context.draw_string({0, 0}, U"你好,世界!全是水群大师\n测试换行\n测试Unicode: 😀\nТест по русскому языку\nテスト日本語", 32); context.draw_string({0, 0}, U"你好,世界!全是水群大师\n测试换行\n测试Unicode: 😀\nТест по русскому языку\nテスト日本語", 32, {0, 0, 0, 1});
context.flush(); context.flush();

View File

@ -6,8 +6,10 @@
aorii_text* text = nullptr; aorii_text* text = nullptr;
void renderer_context::init() { void renderer_context::init() {
text = new aorii_text(2048); text = new aorii_text();
text->initialize(LR"(C:\Windows\Fonts\msyh.ttc)", 64); // D:\Projects\aorii\JetBrainsMono-Regular.ttf
text->initialize(LR"(HarmonyOS_Sans_SC_Regular.ttf)", 64);
text->add_font(LR"(C:\Windows\Fonts\seguiemj.ttf)");
// text->precache_common_characters(); // text->precache_common_characters();
} }

View File

@ -25,19 +25,20 @@ const std::u32string aorii_text::COMMON_PUNCTUATION =
const std::u32string aorii_text::COMMON_NUMBERS = const std::u32string aorii_text::COMMON_NUMBERS =
U"0123456789"; U"0123456789";
aorii_text::aorii_text(const uint32_t in_texture_size) : font(nullptr), texture_array(nullptr), font_pixel_size(0), aorii_text::font_data::~font_data() {
space_width(0), delete info;
ascent(0), descent(0),
line_gap(0),
scale(0),
texture_size(in_texture_size), current_x(0), current_y(0),
current_texture_index(0) {
} }
aorii_text::~aorii_text() { aorii_text::aorii_text() : texture_array(nullptr), font_pixel_size(0),
delete font; space_width(0),
ascent(0), descent(0),
line_gap(0),
current_x(0), current_y(0),
current_texture_index(0) {
} }
aorii_text::~aorii_text() {}
bool aorii_text::init_freetype() { bool aorii_text::init_freetype() {
return true; return true;
} }
@ -45,47 +46,84 @@ bool aorii_text::init_freetype() {
void aorii_text::destroy_freetype() { void aorii_text::destroy_freetype() {
} }
bool aorii_text::initialize(const wchar_t* in_font_path, const float in_font_pixel_size) { bool aorii_text::initialize(const std::wstring& in_font_path, const float in_font_pixel_size) {
const std::string font_path_a(in_font_path, in_font_path + wcslen(in_font_path));
font = new stbtt_fontinfo();
font_pixel_size = in_font_pixel_size; font_pixel_size = in_font_pixel_size;
font_file.map_file(in_font_path);
auto font_buffer = (uint8_t*)font_file.get_data(); // 预计需要的纹理数量(8张纹理几乎可以容纳所有字符)
if (!stbtt_InitFont(font, font_buffer, stbtt_GetFontOffsetForIndex(font_buffer, 0))) { constexpr uint32_t expected_textures = 8;
spdlog::error("Failed to initialize font"); texture_array = aorii::get_renderer_raw()->create_texture_array(2048, 2048, expected_textures, texture_format::R8_UNORM, device_memory_type::gpu);
font_file.unmap(); if (!texture_array) {
delete font; spdlog::error("无法创建字符缓冲纹理");
font = nullptr;
return false; return false;
} }
scale = stbtt_ScaleForPixelHeight(font, in_font_pixel_size); if (!add_font(in_font_path)) {
spdlog::error("添加主要字体失败");
return false;
}
// 获取字体的垂直度量 // 获取主字体的度量信息
stbtt_GetFontVMetrics(font, &ascent, &descent, &line_gap); const auto& primary_font = fonts[0];
stbtt_GetCodepointHMetrics(font, ' ', &space_width, nullptr); stbtt_GetFontVMetrics(primary_font.info, &ascent, &descent, &line_gap);
ascent *= scale; stbtt_GetCodepointHMetrics(primary_font.info, ' ', &space_width, nullptr);
descent *= scale; stbtt_GetCodepointHMetrics(primary_font.info, '\t', &tab_width, nullptr);
line_gap *= scale;
space_width *= scale;
spdlog::info("Font vertical metrics:\n 上升距离: {}, 下降距离: {}, 行间距: {}", ascent, descent, line_gap);
// Create initial texture atlas ascent *= primary_font.scale;
return create_new_texture_atlas(); descent *= primary_font.scale;
line_gap *= primary_font.scale;
space_width *= primary_font.scale;
tab_width *= primary_font.scale;
spdlog::info("主字体度量信息:\n 上升距离: {}, 下降距离: {}, 行间距: {}", ascent, descent, line_gap);
return true;
} }
float aorii_text::get_kerning(char32_t ch1, char32_t ch2) const { float aorii_text::get_kerning(char32_t ch1, char32_t ch2) const {
// 获取字距调整 font_data const* left_ch_font = nullptr;
return stbtt_GetCodepointKernAdvance(font, ch1, ch2) * scale; int g1 = 0, g2 = 0;
// 在所有字体中查找字符对的字距调整
for (const auto& font : fonts) {
g1 = stbtt_FindGlyphIndex(font.info, ch1);
g2 = stbtt_FindGlyphIndex(font.info, ch2);
if (g1 != 0) {
left_ch_font = &font;
}
if (g1 != 0 && g2 != 0) {
return stbtt_GetGlyphKernAdvance(font.info, g1, g2) * font.scale;
}
}
if (!left_ch_font)
return 0.0f;
int x0, x1;
stbtt_GetGlyphBox(left_ch_font->info, g1, &x0, nullptr, &x1, nullptr);
return (x1 - x0) * left_ch_font->scale;
} }
bool aorii_text::create_new_texture_atlas() { bool aorii_text::add_font(const std::wstring& font_path) {
// 预计需要的纹理数量(8张纹理几乎可以容纳所有字符) font_data new_font{};
constexpr uint32_t expected_textures = 8; new_font.info = new stbtt_fontinfo();
texture_array = aorii::get_renderer_raw()->create_texture_array(texture_size, texture_size, expected_textures, texture_format::R8_UNORM, device_memory_type::gpu);
return texture_array != nullptr; // 映射字体文件
if (!new_font.file.map_file(font_path)) {
delete new_font.info;
spdlog::error("Failed to map font file");
return false;
}
const auto* font_buffer = static_cast<uint8_t*>(new_font.file.get_data());
if (!stbtt_InitFont(new_font.info, font_buffer, stbtt_GetFontOffsetForIndex(font_buffer, 0))) {
new_font.file.unmap();
delete new_font.info;
spdlog::error("Failed to initialize font");
return false;
}
new_font.scale = stbtt_ScaleForPixelHeight(new_font.info, font_pixel_size);
fonts.emplace_back(std::move(new_font));
return true;
} }
character_info* aorii_text::get_or_create_character(const char32_t ch) { character_info* aorii_text::get_or_create_character(const char32_t ch) {
@ -97,11 +135,6 @@ character_info* aorii_text::get_or_create_character(const char32_t ch) {
} }
bool aorii_text::precache_characters(const std::u32string& characters) { bool aorii_text::precache_characters(const std::u32string& characters) {
if (!font) {
spdlog::error("Font not initialized");
return false;
}
// 创建进度通知回调的函数指针类型 // 创建进度通知回调的函数指针类型
using ProgressCallback = std::function<void(float progress, const wchar_t currentChar)>; using ProgressCallback = std::function<void(float progress, const wchar_t currentChar)>;
@ -142,10 +175,33 @@ bool aorii_text::precache_common_characters() {
return precache_characters(all_common_chars); return precache_characters(all_common_chars);
} }
uint32_t aorii_text::get_font_char_count() const { return font->numGlyphs; } uint32_t aorii_text::get_font_char_count() const {
uint32_t result = 0;
for (const auto& font : fonts) {
result += font.info->numGlyphs;
}
return result;
}
uint32_t aorii_text::get_texture_size() const {
return texture_array->size().x();
}
character_info* aorii_text::add_character_to_atlas(const char32_t ch) { character_info* aorii_text::add_character_to_atlas(const char32_t ch) {
int glyph_index = stbtt_FindGlyphIndex(font, ch); font_data const* current_font = nullptr;
int glyph_index = 0;
for (const auto& font : fonts) {
if (glyph_index = stbtt_FindGlyphIndex(font.info, ch)) {
current_font = &font;
break;
}
}
if (!current_font) {
return nullptr;
}
const auto font = current_font->info;
const uint32_t texture_size = get_texture_size();
// 获取SDF尺寸和位图 // 获取SDF尺寸和位图
int32_t width, height, x_offset, y_offset; int32_t width, height, x_offset, y_offset;
constexpr int padding = 8; constexpr int padding = 8;
@ -154,7 +210,7 @@ character_info* aorii_text::add_character_to_atlas(const char32_t ch) {
auto* sdf_bitmap = stbtt_GetGlyphSDF( auto* sdf_bitmap = stbtt_GetGlyphSDF(
font, font,
scale, current_font->scale,
glyph_index, glyph_index,
padding, padding,
on_edge_value, on_edge_value,
@ -204,7 +260,7 @@ character_info* aorii_text::add_character_to_atlas(const char32_t ch) {
character_info info; character_info info;
info.tex_u = current_x / static_cast<float>(texture_size); info.tex_u = current_x / static_cast<float>(texture_size);
info.tex_v = current_y / static_cast<float>(texture_size); info.tex_v = current_y / static_cast<float>(texture_size);
info.advance = advance_width * scale; info.advance = advance_width * current_font->scale;
info.tex_z = static_cast<float>(current_texture_index); info.tex_z = static_cast<float>(current_texture_index);
info.width = width; info.width = width;
info.height = height; info.height = height;
@ -217,4 +273,3 @@ character_info* aorii_text::add_character_to_atlas(const char32_t ch) {
return &(character_map[ch] = info); return &(character_map[ch] = info);
} }

View File

@ -22,25 +22,37 @@ struct character_info {
}; };
class aorii_text { class aorii_text {
struct font_data {
font_data() = default;
font_data(font_data&& other) {
file = std::move(other.file);
info = other.info;
scale = other.scale;
other.info = nullptr;
other.scale = 0;
}
~font_data();
stbtt_fontinfo* info;
mapped_file file;
float scale;
};
public: public:
aorii_text(uint32_t in_texture_size = 2048); aorii_text();
~aorii_text(); ~aorii_text();
static bool init_freetype(); static bool init_freetype();
static void destroy_freetype(); static void destroy_freetype();
bool initialize(const wchar_t* in_font_path, float in_font_pixel_size); bool initialize(const std::wstring& in_font_path, float in_font_pixel_size);
bool add_font(const std::wstring& font_path);
character_info* get_or_create_character(char32_t ch); character_info* get_or_create_character(char32_t ch);
// 空格宽度
[[nodiscard]] int32_t get_space_width() const { return space_width; } [[nodiscard]] int32_t get_space_width() const { return space_width; }
// 上升距离
[[nodiscard]] int32_t get_ascent() const { return ascent; } [[nodiscard]] int32_t get_ascent() const { return ascent; }
// 下降距离
[[nodiscard]] int32_t get_descent() const { return descent; } [[nodiscard]] int32_t get_descent() const { return descent; }
// 行间距
[[nodiscard]] int32_t get_line_gap() const { return line_gap; } [[nodiscard]] int32_t get_line_gap() const { return line_gap; }
// 纹理尺寸
[[nodiscard]] uint32_t get_texture_size() const { return texture_size; }
// 字体像素大小 // 字体像素大小
[[nodiscard]] float get_font_pixel_size() const { return font_pixel_size; } [[nodiscard]] float get_font_pixel_size() const { return font_pixel_size; }
@ -57,20 +69,18 @@ public:
[[nodiscard]] uint32_t get_font_char_count() const; [[nodiscard]] uint32_t get_font_char_count() const;
[[nodiscard]] renderer_texture_array* get_texture_array() const { return texture_array; } [[nodiscard]] renderer_texture_array* get_texture_array() const { return texture_array; }
[[nodiscard]] uint32_t get_texture_size() const;
[[nodiscard]] float get_kerning(char32_t ch1, char32_t ch2) const; [[nodiscard]] float get_kerning(char32_t ch1, char32_t ch2) const;
private: private:
bool create_new_texture_atlas();
character_info* add_character_to_atlas(char32_t ch); character_info* add_character_to_atlas(char32_t ch);
stbtt_fontinfo* font;
mapped_file font_file; std::vector<font_data> fonts;
renderer_texture_array* texture_array; renderer_texture_array* texture_array;
float font_pixel_size; float font_pixel_size;
int32_t space_width, ascent, descent, line_gap; int32_t space_width, tab_width, ascent, descent, line_gap;
float scale;
const uint32_t texture_size;
uint32_t current_x; uint32_t current_x;
uint32_t current_y; uint32_t current_y;
uint32_t next_row_y = 0; // 跟踪当前行的最大高度 uint32_t next_row_y = 0; // 跟踪当前行的最大高度