From 0937bb8a60bf0a4215332a1303b85f582c15e863 Mon Sep 17 00:00:00 2001 From: Nanako <469449812@qq.com> Date: Wed, 25 Dec 2024 22:07:06 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=A4=9A=E5=AD=97=E4=BD=93?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/renderer/backend/dx/dx_window.cpp | 2 +- .../core/renderer/renderer_context.cpp | 6 +- src/renderer/core/renderer/renderer_text.cpp | 151 ++++++++++++------ src/renderer/core/renderer/renderer_text.h | 38 +++-- 4 files changed, 132 insertions(+), 65 deletions(-) diff --git a/src/renderer/backend/dx/dx_window.cpp b/src/renderer/backend/dx/dx_window.cpp index c23a13a..23de93a 100644 --- a/src/renderer/backend/dx/dx_window.cpp +++ b/src/renderer/backend/dx/dx_window.cpp @@ -112,7 +112,7 @@ void dx_window::begin_frame() { // 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(), 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(); diff --git a/src/renderer/core/renderer/renderer_context.cpp b/src/renderer/core/renderer/renderer_context.cpp index aeb0b60..bf5cbf5 100644 --- a/src/renderer/core/renderer/renderer_context.cpp +++ b/src/renderer/core/renderer/renderer_context.cpp @@ -6,8 +6,10 @@ aorii_text* text = nullptr; void renderer_context::init() { - text = new aorii_text(2048); - text->initialize(LR"(C:\Windows\Fonts\msyh.ttc)", 64); + text = new aorii_text(); + // 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(); } diff --git a/src/renderer/core/renderer/renderer_text.cpp b/src/renderer/core/renderer/renderer_text.cpp index 0a84e22..bf5257f 100644 --- a/src/renderer/core/renderer/renderer_text.cpp +++ b/src/renderer/core/renderer/renderer_text.cpp @@ -25,19 +25,20 @@ const std::u32string aorii_text::COMMON_PUNCTUATION = const std::u32string aorii_text::COMMON_NUMBERS = U"0123456789"; -aorii_text::aorii_text(const uint32_t in_texture_size) : font(nullptr), texture_array(nullptr), font_pixel_size(0), - space_width(0), - 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::font_data::~font_data() { + delete info; } -aorii_text::~aorii_text() { - delete font; +aorii_text::aorii_text() : texture_array(nullptr), font_pixel_size(0), + 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() { return true; } @@ -45,47 +46,84 @@ bool aorii_text::init_freetype() { void aorii_text::destroy_freetype() { } -bool aorii_text::initialize(const wchar_t* 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(); +bool aorii_text::initialize(const std::wstring& in_font_path, const float 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(); - if (!stbtt_InitFont(font, font_buffer, stbtt_GetFontOffsetForIndex(font_buffer, 0))) { - spdlog::error("Failed to initialize font"); - font_file.unmap(); - delete font; - font = nullptr; + // 预计需要的纹理数量(8张纹理几乎可以容纳所有字符) + constexpr uint32_t expected_textures = 8; + texture_array = aorii::get_renderer_raw()->create_texture_array(2048, 2048, expected_textures, texture_format::R8_UNORM, device_memory_type::gpu); + if (!texture_array) { + spdlog::error("无法创建字符缓冲纹理"); 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); - stbtt_GetCodepointHMetrics(font, ' ', &space_width, nullptr); - ascent *= scale; - descent *= scale; - line_gap *= scale; - space_width *= scale; - spdlog::info("Font vertical metrics:\n 上升距离: {}, 下降距离: {}, 行间距: {}", ascent, descent, line_gap); + // 获取主字体的度量信息 + const auto& primary_font = fonts[0]; + stbtt_GetFontVMetrics(primary_font.info, &ascent, &descent, &line_gap); + stbtt_GetCodepointHMetrics(primary_font.info, ' ', &space_width, nullptr); + stbtt_GetCodepointHMetrics(primary_font.info, '\t', &tab_width, nullptr); - // Create initial texture atlas - return create_new_texture_atlas(); + ascent *= primary_font.scale; + 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 { - // 获取字距调整 - return stbtt_GetCodepointKernAdvance(font, ch1, ch2) * scale; + font_data const* left_ch_font = nullptr; + 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() { - // 预计需要的纹理数量(8张纹理几乎可以容纳所有字符) - constexpr uint32_t expected_textures = 8; - 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; +bool aorii_text::add_font(const std::wstring& font_path) { + font_data new_font{}; + new_font.info = new stbtt_fontinfo(); + + // 映射字体文件 + 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(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) { @@ -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) { - if (!font) { - spdlog::error("Font not initialized"); - return false; - } - // 创建进度通知回调的函数指针类型 using ProgressCallback = std::function; @@ -142,10 +175,33 @@ bool aorii_text::precache_common_characters() { 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) { - 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尺寸和位图 int32_t width, height, x_offset, y_offset; 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( font, - scale, + current_font->scale, glyph_index, padding, on_edge_value, @@ -204,7 +260,7 @@ character_info* aorii_text::add_character_to_atlas(const char32_t ch) { character_info info; info.tex_u = current_x / static_cast(texture_size); info.tex_v = current_y / static_cast(texture_size); - info.advance = advance_width * scale; + info.advance = advance_width * current_font->scale; info.tex_z = static_cast(current_texture_index); info.width = width; info.height = height; @@ -217,4 +273,3 @@ character_info* aorii_text::add_character_to_atlas(const char32_t ch) { return &(character_map[ch] = info); } - diff --git a/src/renderer/core/renderer/renderer_text.h b/src/renderer/core/renderer/renderer_text.h index cc74c39..f8d3b89 100644 --- a/src/renderer/core/renderer/renderer_text.h +++ b/src/renderer/core/renderer/renderer_text.h @@ -22,25 +22,37 @@ struct character_info { }; 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: - aorii_text(uint32_t in_texture_size = 2048); + aorii_text(); ~aorii_text(); static bool init_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); - // 空格宽度 [[nodiscard]] int32_t get_space_width() const { return space_width; } - // 上升距离 [[nodiscard]] int32_t get_ascent() const { return ascent; } - // 下降距离 [[nodiscard]] int32_t get_descent() const { return descent; } - // 行间距 [[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; } @@ -57,20 +69,18 @@ public: [[nodiscard]] uint32_t get_font_char_count() const; [[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; private: - bool create_new_texture_atlas(); character_info* add_character_to_atlas(char32_t ch); - stbtt_fontinfo* font; - mapped_file font_file; + + std::vector fonts; renderer_texture_array* texture_array; float font_pixel_size; - int32_t space_width, ascent, descent, line_gap; - float scale; + int32_t space_width, tab_width, ascent, descent, line_gap; - const uint32_t texture_size; uint32_t current_x; uint32_t current_y; uint32_t next_row_y = 0; // 跟踪当前行的最大高度