diff --git a/CMakeLists.txt b/CMakeLists.txt index e7bc828..604275e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,7 +48,6 @@ else () add_definitions(-DDEBUG=0) endif () -add_subdirectory(third_party/harfbuzz) add_subdirectory(src/sokol) add_subdirectory(src/mirage_render) add_subdirectory(src/mirage_image) diff --git a/example/src/main.cpp b/example/src/main.cpp index cca6384..f5b26ce 100644 --- a/example/src/main.cpp +++ b/example/src/main.cpp @@ -1,21 +1,18 @@ #include "mirage.h" #include "window/mwindow.h" -#include "widget/panel_widget/mbox.h" -#include "font/font_atlas_system.h" -#include "font/font_face.h" #include "font/font_system.h" #include "widget/widget_new.h" -#include "widget/leaf_widget/mimage.h" #include "widget/leaf_widget/mtext_block.h" int main(int argc, char* argv[]) { mirage_app::get().init(); auto& manager = font_manager::instance(); + manager.add_font(L"C:/Users/46944/AppData/Local/Microsoft/Windows/Fonts/MapleMono-NF-CN-Regular.ttf"); manager.add_font(L"C:/Windows/Fonts/msyh.ttc"); auto text_block = std::make_shared(); - text_block->set_text("Hello, World!"); + text_block->set_text(U"Hello, World! 你好,世界!😀"); const auto& window = mwindow::create({ 1024, 1024 }, L"Hello, World!"); window->set_content(text_block); diff --git a/src/mirage_render/font/font_atlas_system.h b/src/mirage_render/font/font_atlas_system.h index 1072c50..37cb4c7 100644 --- a/src/mirage_render/font/font_atlas_system.h +++ b/src/mirage_render/font/font_atlas_system.h @@ -71,35 +71,13 @@ public: return result; } - // 获取字形度量 - // const auto& glyph_metrics = in_font.get_glyph_by_index(in_glygh_index, in_font_size); - - // 计算MTSDF尺寸(添加4px内边距) - // const int padding = 4; - // int width = static_cast(glyph_metrics->size.x()) + padding * 2; - // int height = static_cast(glyph_metrics->size.y()) + padding * 2; - - // 确保最小尺寸 - // width = std::max(width, 8); - // height = std::max(height, 8); - - - // 生成MTSDF - // const auto& mtsdf_data = mtsdf_generator::generate_mtsdf( - // glyph_shape.data(), - // glyph_shape.size(), - // width, - // height, - // 3.0f // 范围值 - // ); - - // 使用stb_truetype生成MTSDF + // 使用stb_truetype生成位图 float scale = in_font.get_scale_for_pixel_height(in_font_size); int width, height, xoff, yoff; auto bitmap = stbtt_GetGlyphBitmap(&in_font.get_font_info(), scale, scale, in_glygh_index, &width, &height, &xoff, &yoff); // 从图集分配空间 - auto region = atlas_->allocate_region({width, height}); + auto region = atlas_->allocate_region({ width, height }, { 2, 2 }); if (!region) { result.reason = glyph_atlas_reason_t::atlas_full; return result; @@ -197,7 +175,7 @@ public: const auto& bitmap = *bitmap_opt; // 从图集分配空间 - const auto& region = atlas_->allocate_region({bitmap.width, bitmap.height}); + const auto& region = atlas_->allocate_region({ bitmap.width, bitmap.height }, { 2, 2 }); if (!region) { return std::nullopt; } diff --git a/src/mirage_render/font/font_face.cpp b/src/mirage_render/font/font_face.cpp index a1ae997..3b0425e 100644 --- a/src/mirage_render/font/font_face.cpp +++ b/src/mirage_render/font/font_face.cpp @@ -53,7 +53,11 @@ std::optional font_face_t::get_glyph_by_index(int32_t in_glyph_index, f // 获取垂直度量 int ascent, descent, line_gap; - stbtt_GetFontVMetrics(&font_info_, &ascent, &descent, &line_gap); + // 尝试使用OS2表中的度量 + if (!stbtt_GetFontVMetricsOS2(&font_info_, &ascent, &descent, &line_gap)) { + // 如果失败使用默认的VMetrics + stbtt_GetFontVMetrics(&font_info_, &ascent, &descent, &line_gap); + } // 获取字形边界 int x0, y0, x1, y1; diff --git a/src/mirage_render/font/font_face.h b/src/mirage_render/font/font_face.h index 2546cc0..e9fb9ad 100644 --- a/src/mirage_render/font/font_face.h +++ b/src/mirage_render/font/font_face.h @@ -47,6 +47,10 @@ public: return stbtt_FindGlyphIndex(&font_info_, in_code_point); } + float get_glyph_advance(int32_t in_glyph_index1, int32_t in_glyph_index2) const { + return stbtt_GetGlyphKernAdvance(&font_info_, in_glyph_index1, in_glyph_index2); + } + /** * @brief 检查字体是否包含指定字形 * @param in_code_point Unicode码点 diff --git a/src/mirage_render/font/font_system.cpp b/src/mirage_render/font/font_system.cpp index 1a629f7..dca3880 100644 --- a/src/mirage_render/font/font_system.cpp +++ b/src/mirage_render/font/font_system.cpp @@ -1,11 +1,11 @@ #include "font_system.h" -text_layout_t font_manager::layout_text(const std::string& text, - const std::shared_ptr& in_font, float font_size, - float max_width, - float line_spacing) { +text_layout_t font_manager::layout_text(const std::u32string& text, + const std::shared_ptr& in_font, float font_size, + float max_width, + float line_spacing) { text_layout_t layout; - float scale = in_font->get_scale_for_pixel_height(font_size); + const float scale = in_font->get_scale_for_pixel_height(font_size); // 布局变量 float cursor_x = 0.0f; @@ -14,6 +14,9 @@ text_layout_t font_manager::layout_text(const std::string& text const float ascent = in_font->get_ascent() * scale; float baseline = cursor_y + ascent; + int32_t last_index = 0; + float min_y = std::numeric_limits::max(); + // 处理每个字形 for (const auto& c : text) { const auto glyph_index = in_font->find_glyph_index(c); @@ -40,7 +43,7 @@ text_layout_t font_manager::layout_text(const std::string& text // **计算最终位置** float glyph_x = cursor_x + glyph_metrics->bearing.x(); - float glyph_y = ascent - glyph_metrics->descent + glyph_metrics->line_gap + glyph_metrics->bearing.y(); + float glyph_y = glyph_metrics->ascent - glyph_metrics->descent + glyph_metrics->line_gap + glyph_metrics->bearing.y(); auto& glyph_position = layout.glyphs.emplace_back(); glyph_position.glyph_index = glyph_index; @@ -51,6 +54,20 @@ text_layout_t font_manager::layout_text(const std::string& text // 前进光标 cursor_x += glyph_metrics->advance; cursor_y += 0; // 通常为0,除非是垂直文本 + + if (last_index > 0) { + const float kern_advance = in_font->get_glyph_advance(last_index, glyph_index) * scale; + cursor_x += kern_advance; + } + last_index = glyph_index; + + // 更新行的最小和最大Y坐标 + min_y = std::min(min_y, glyph_y); + } + + // 根据最小和最大Y坐标更新行的高度 + for (auto& line : layout.glyphs) { + line.position.y() -= min_y; } // 设置布局总体尺寸 diff --git a/src/mirage_render/font/font_system.h b/src/mirage_render/font/font_system.h index 025a603..fa3954c 100644 --- a/src/mirage_render/font/font_system.h +++ b/src/mirage_render/font/font_system.h @@ -116,7 +116,7 @@ public: } text_layout_t layout_text( - const std::string& text, + const std::u32string& text, const std::shared_ptr& in_font, float font_size, float max_width = 0.0f, diff --git a/src/mirage_render/texture/atlas/texture2d_atlas.cpp b/src/mirage_render/texture/atlas/texture2d_atlas.cpp index b7690dc..1170dbb 100644 --- a/src/mirage_render/texture/atlas/texture2d_atlas.cpp +++ b/src/mirage_render/texture/atlas/texture2d_atlas.cpp @@ -36,25 +36,38 @@ std::optional> texture2d_atlas::allocate(const Eigen::Vector2i& return std::nullopt; } -std::optional texture2d_atlas::allocate_region(const Eigen::Vector2i& size) { - if (!allocator_) { - return std::nullopt; - } +std::optional texture2d_atlas::allocate_region(const Eigen::Vector2i& size, const Eigen::Vector2i& padding) { + if (!allocator_) { + return std::nullopt; + } - // 使用分配器分配区域 - auto rect_opt = allocator_->allocate(size); - if (!rect_opt) { - return std::nullopt; // 分配失败 - } + // 计算包含padding的总尺寸 + const Eigen::Vector2i& padded_size = size + padding * 2; // 每边加上padding - // 分配成功,创建区域信息 - const int region_id = next_region_id_++; - atlas_region_t region(region_id, *rect_opt, texture_, calculate_uv_rect(*rect_opt)); + // 使用分配器分配包含padding的区域 + const auto& rect_opt = allocator_->allocate(padded_size); + if (!rect_opt) { + return std::nullopt; // 分配失败 + } - // 存储区域信息 - allocated_regions_[region.id] = region; + // 分配成功,创建区域信息 + const int region_id = next_region_id_++; - return region; + // 获取分配的带padding的矩形 + const auto& padded_rect = *rect_opt; + + const Eigen::Vector2i& content_position = padded_rect.top_left() + padding; + + // 计算内部有效区域(不含padding) + rect_t content_rect{ content_position, size }; + + // 创建region对象,使用内容区域的UV坐标 + atlas_region_t region(region_id, content_rect, texture_, calculate_uv_rect(content_rect)); + + // 存储区域信息 + allocated_regions_[region.id] = region; + + return region; } bool texture2d_atlas::free(const rect_t& rect) { diff --git a/src/mirage_render/texture/atlas/texture2d_atlas.h b/src/mirage_render/texture/atlas/texture2d_atlas.h index e1ca218..6f6fcc8 100644 --- a/src/mirage_render/texture/atlas/texture2d_atlas.h +++ b/src/mirage_render/texture/atlas/texture2d_atlas.h @@ -44,7 +44,7 @@ public: * @param size 要分配的区域大小 * @return 分配的区域信息,失败返回std::nullopt */ - std::optional allocate_region(const Eigen::Vector2i& size); + std::optional allocate_region(const Eigen::Vector2i& size, const Eigen::Vector2i& padding = {0, 0}); /** * @brief 释放之前分配的纹理区域 diff --git a/src/mirage_widget/widget/leaf_widget/mtext_block.h b/src/mirage_widget/widget/leaf_widget/mtext_block.h index ce53bf2..6d90045 100644 --- a/src/mirage_widget/widget/leaf_widget/mtext_block.h +++ b/src/mirage_widget/widget/leaf_widget/mtext_block.h @@ -6,7 +6,7 @@ class mtext_block : public mleaf_widget { public: void on_paint(mirage_paint_context& in_context) override; - void set_text(const std::string& in_text) { + void set_text(const std::u32string& in_text) { text_ = in_text; update_layout(); } @@ -41,7 +41,7 @@ public: private: void update_layout(); - std::string text_; + std::u32string text_; text_layout_t layout_; float font_size_ = 24.0f * 1.5f; float line_spacing_ = 1.2f;