From b50d7e46a7cee2791dcec468e5420ebaf4c4ad07 Mon Sep 17 00:00:00 2001 From: Nanako <469449812@qq.com> Date: Fri, 27 Dec 2024 19:45:20 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B5=8B=E8=AF=95=E7=94=A8?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/renderer/backend/dx/dx_window.cpp | 3 +- .../core/renderer/renderer_context.cpp | 13 +- src/renderer/core/renderer/renderer_text.cpp | 114 ++++++++++++------ src/renderer/core/renderer/renderer_text.h | 3 +- 4 files changed, 82 insertions(+), 51 deletions(-) diff --git a/src/renderer/backend/dx/dx_window.cpp b/src/renderer/backend/dx/dx_window.cpp index 764190f..5f4216b 100644 --- a/src/renderer/backend/dx/dx_window.cpp +++ b/src/renderer/backend/dx/dx_window.cpp @@ -113,8 +113,9 @@ void dx_window::begin_frame() { // 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, {0, 0, 0, 1}); - context.draw_string({0, 100}, U"Тест по русскому языку", 32, {0, 0, 0, 1}); + context.draw_string({0, 100}, U"你好,世界!\nТест по русскому языку\nテスト", 32, {0, 0, 0, 1}); context.draw_rectangle({ 0, 100 }, { 2048, 1 }, { 1, 0, 1, 1 }); + context.draw_rectangle({ 0, 132 }, { 2048, 1 }, { 1, 0, 1, 1 }); context.flush(); diff --git a/src/renderer/core/renderer/renderer_context.cpp b/src/renderer/core/renderer/renderer_context.cpp index 5499828..e85d77e 100644 --- a/src/renderer/core/renderer/renderer_context.cpp +++ b/src/renderer/core/renderer/renderer_context.cpp @@ -44,22 +44,14 @@ void renderer_context::draw_texture(const Eigen::Vector2f& in_pos, const Eigen:: void renderer_context::draw_string(const Eigen::Vector2f& in_pos, const std::u32string& in_str, float in_height, const linear_color& in_color) { to_text_pipeline(in_color); - float cursor_x = in_pos.x(); - float cursor_y = in_pos.y(); - Eigen::Vector2f cursor(cursor_x, cursor_y); const auto& measure = text->measure_text(in_str, in_height); for (const auto& mch: measure) { const auto info = mch.item; if (!info) continue; - // 使用整形坐标, 避免出现模糊 - Eigen::Vector2f pos{ info->left, info->right }; - pos += cursor; - Eigen::Vector2f size{ info->get_width(), info->get_height() }; - - // const Eigen::Vector2f pos { cursor_x + mch.x_offset, cursor_y + mch.y_offset }; - // const Eigen::Vector2f size { info->get_width() * mch.size_scale, info->get_height() * mch.size_scale }; + const Eigen::Vector2f pos = mch.offset + in_pos; + const Eigen::Vector2f size = Eigen::Vector2f{ info->get_width(), info->get_height() } * mch.size_scale; aorii_vertex_param param{}; param.param_a1 = info->tex_u; @@ -69,7 +61,6 @@ void renderer_context::draw_string(const Eigen::Vector2f& in_pos, const std::u32 param.param_b2 = info->v_size; make_rect(pos, size, in_color, 0, param); - cursor.x() += size.x(); } } diff --git a/src/renderer/core/renderer/renderer_text.cpp b/src/renderer/core/renderer/renderer_text.cpp index dcb6c81..d13a64a 100644 --- a/src/renderer/core/renderer/renderer_text.cpp +++ b/src/renderer/core/renderer/renderer_text.cpp @@ -183,52 +183,92 @@ std::vector aorii_text::measure_text(const std::u32string& text, fl // 基线和行高信息 const int32_t ascent = primary_font.ascent; const int32_t descent = primary_font.descent; - const int32_t line_gap = primary_font.line_gap * scale; + const float line_gap = primary_font.line_gap * scale; const int32_t line_height = height; const float space_width = primary_font.space_width * scale; const float tab_width = primary_font.tab_width * scale; + struct line_data { + std::u32string text; + int32_t max_top{}; + int32_t min_top{}; + int32_t max_bottom{}; + int32_t min_bottom{}; + }; + std::vector lines; + // 按照\n分割文本 + std::u32string text_copy = text; + for (size_t i = 0; i < text_copy.length(); i++) { + if (text_copy[i] == U'\n') { + lines.emplace_back(text_copy.substr(0, i)); + text_copy = text_copy.substr(i + 1); + i = 0; + } + } + if (!text_copy.empty()) + lines.emplace_back(text_copy); + + for (auto& data: lines) { + int32_t max_top = 0; + int32_t min_top = 0; + int32_t max_bottom = 0; + int32_t min_bottom = 0; + for (const auto& ch: data.text) { + const auto item = get_atlas_item(ch); + if (!item) + continue; + max_top = std::max(max_top, item->top); + min_top = std::min(min_top, item->top); + max_bottom = std::max(max_bottom, item->bottom); + min_bottom = std::min(min_bottom, item->bottom); + } + data.max_top = max_top; + data.min_top = min_top; + data.max_bottom = max_bottom; + data.min_bottom = min_bottom; + } + std::vector result; - float x = 0; - float y = 0; + Eigen::Vector2f pos{0, 0}; - char32_t prev_char = 0; - for (const auto& ch : text) { - if (ch == U' ') { - x += space_width; - continue; - } - if (ch == U'\t') { - x += tab_width; - continue; - } - if (ch == U'\n') { - x = 0; - y += line_height; - y += line_gap; - y -= scale_padding * 2; - continue; - } - - const auto item = get_atlas_item(ch); - measured_ch mch{}; - mch.item = item; - mch.x_offset = x; - mch.y_offset = y; - mch.size_scale = scale; - if (item) { - // 如果字符高度大于行高, 则缩放 - const float item_height = item->get_height() * scale; - if (item_height > line_height) { - mch.size_scale = line_height / item_height * scale; + for (const auto& line : lines) { + for (const auto& ch : line.text) { + if (ch == U' ') { + pos.x() += space_width; + continue; + } + if (ch == U'\t') { + pos.x() += tab_width; + continue; } - float test = line_height - item->get_height() * mch.size_scale; - mch.y_offset += test; - x += item->get_width() * mch.size_scale; - prev_char = ch; + const auto item = get_atlas_item(ch); + measured_ch mch{}; + mch.item = item; + mch.offset = pos; + mch.size_scale = scale; + if (item) { + // 如果字符高度大于行高, 则缩放 + const float item_height = item->get_height() * scale; + if (item_height > line_height) { + mch.size_scale = line_height / item_height * scale; + } + // 注意字符坐标系的原点在左下角 + + // 如果字符的顶部高于行的顶部,则将其对齐到min_top + if (item->top < 0) { + mch.offset.y() += (line.min_top - item->top) * mch.size_scale; + } + + pos.x() += (item->right - item->left) * mch.size_scale; + } + result.push_back(mch); } - result.push_back(mch); + + pos.x() = 0; + pos.y() += line_height; + pos.y() += line_gap; + pos.y() -= scale_padding * 2; } return result; } diff --git a/src/renderer/core/renderer/renderer_text.h b/src/renderer/core/renderer/renderer_text.h index 9a59d13..783163f 100644 --- a/src/renderer/core/renderer/renderer_text.h +++ b/src/renderer/core/renderer/renderer_text.h @@ -29,8 +29,7 @@ struct ch_atlas_item { struct measured_ch { ch_atlas_item const* item; - float x_offset; - float y_offset; + Eigen::Vector2f offset; float size_scale; };