将wchar_t改为char32_t以支持多语言,同时处理空格和获取字形失败的情况

This commit is contained in:
Nanako 2024-12-25 12:53:41 +08:00
parent 6ea4ee9a78
commit af1002d8a6
5 changed files with 66 additions and 66 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);
// if (test_texture) context.draw_texture({ 0.f, 0.f }, test_texture->size().cast<float>(), test_texture);
context.draw_string({0, 0}, L"你好,世界!全是水群大师\n测试换行", 32);
context.draw_string({0, 0}, U"你好,世界!全是水群大师\n测试换行\n测试Unicode: 😀\nТест по русскому языку\nテスト日本語", 32);
context.flush();

View File

@ -39,7 +39,7 @@ void renderer_context::draw_texture(const Eigen::Vector2f& in_pos, const Eigen::
flush();
}
void renderer_context::draw_string(const Eigen::Vector2f& in_pos, const std::wstring& in_str, float in_height, const linear_color& in_color) {
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();
@ -47,28 +47,33 @@ void renderer_context::draw_string(const Eigen::Vector2f& in_pos, const std::wst
const float scale = in_height / text->get_font_pixel_size();
wchar_t last_char = 0;
for (const auto c : in_str) {
if (c == '\n') {
if (c == U'\n') {
cursor_x = in_pos.x();
cursor_y += text->get_ascent() * scale;
continue;
}
if (c == U' ') {
cursor_x += text->get_space_width() * scale;
continue;
}
cursor_x += last_char ? text->get_kerning(last_char, c) : 0;
character_info info{};
text->get_or_create_character(c, info);
const character_info* info = text->get_or_create_character(c);
if (!info)
continue;
// 根据in_height缩放字符大小
const float y_offset = (info.y_offset + text->get_ascent()) * scale;
const Eigen::Vector2f size { info.width * scale, info.height * scale };
const Eigen::Vector2f pos { cursor_x + info.x_offset * scale, cursor_y + y_offset };
cursor_x += info.advance * scale;
const float y_offset = (info->y_offset + text->get_ascent()) * scale;
const Eigen::Vector2f size { info->width * scale, info->height * scale };
const Eigen::Vector2f pos { cursor_x + info->x_offset * scale, cursor_y + y_offset };
cursor_x += info->advance * scale;
aorii_vertex_param param{};
param.param_a1 = info.tex_u;
param.param_a2 = info.tex_v;
param.param_a3 = info.tex_z;
param.param_b1 = info.width / (float)text->get_texture_size();
param.param_b2 = info.height / (float)text->get_texture_size();
param.param_a1 = info->tex_u;
param.param_a2 = info->tex_v;
param.param_a3 = info->tex_z;
param.param_b1 = info->width / (float)text->get_texture_size();
param.param_b2 = info->height / (float)text->get_texture_size();
make_rect(pos, size, in_color, 0, param);
last_char = c;

View File

@ -60,7 +60,7 @@ public:
*/
void draw_texture(const Eigen::Vector2f& in_pos, const Eigen::Vector2f& in_size, renderer_texture* in_texture, const linear_color& in_color = linear_color::white);
void draw_string(const Eigen::Vector2f& in_pos, const std::wstring& in_str, float in_height, const linear_color& in_color = linear_color::white);
void draw_string(const Eigen::Vector2f& in_pos, const std::u32string& in_str, float in_height, const linear_color& in_color = linear_color::white);
void clear() {
vertices.clear();

View File

@ -13,21 +13,25 @@
#include "misc/scope_exit.h"
// 在SDFFontCache.cpp中添加实现
const std::wstring aorii_text::COMMON_ASCII =
L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
const std::u32string aorii_text::COMMON_ASCII =
U"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
const std::wstring aorii_text::COMMON_CHINESE =
L"的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着等部度家电力里如水化高自二理起小物现实加量都两体制机当使点从业本去把性好应开它合还因由其些然前外天政四日那社义事平形相全表间样与关各重新线内数正心反你明看原又么利比或但质气第向道命此变条只没结解问意建月公无系军很情者最立代想已通并提直题党程展五果料象员革位入常文总次品式活设及管特件长求老头基资边流路级少图山统接知较将组见计别她手角期根论运农指几九区强放决西被干做必战先回则任取据处队南给色光门即保治北造百规热领七海口东导器压志世金增争济阶油思术极交受联什认六共权收证改清己美再采转更单风切打白教速花带安场身车例真务具万每目至达走积示议声报斗完类八离华名确才科张信马节话米整空元况今集温传土许步群广石记需段研界拉林律叫且究观越织装影算低持音众书布复容儿须际商非验连断深难近矿千周委素技备半办青省列习响约支般史感劳便团往酸历市克何除消构府称太准精值号率族维划选标写存候毛亲快效斯院查江型眼王按格养易置派层片始却专状育厂京识适属圆包火住调满县局照参红细引听该铁价严";
const std::u32string aorii_text::COMMON_CHINESE =
U"的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着等部度家电力里如水化高自二理起小物现实加量都两体制机当使点从业本去把性好应开它合还因由其些然前外天政四日那社义事平形相全表间样与关各重新线内数正心反你明看原又么利比或但质气第向道命此变条只没结解问意建月公无系军很情者最立代想已通并提直题党程展五果料象员革位入常文总次品式活设及管特件长求老头基资边流路级少图山统接知较将组见计别她手角期根论运农指几九区强放决西被干做必战先回则任取据处队南给色光门即保治北造百规热领七海口东导器压志世金增争济阶油思术极交受联什认六共权收证改清己美再采转更单风切打白教速花带安场身车例真务具万每目至达走积示议声报斗完类八离华名确才科张信马节话米整空元况今集温传土许步群广石记需段研界拉林律叫且究观越织装影算低持音众书布复容儿须际商非验连断深难近矿千周委素技备半办青省列习响约支般史感劳便团往酸历市克何除消构府称太准精值号率族维划选标写存候毛亲快效斯院查江型眼王按格养易置派层片始却专状育厂京识适属圆包火住调满县局照参红细引听该铁价严";
const std::wstring aorii_text::COMMON_PUNCTUATION =
L",。!?:;''""《》【】()、";
const std::u32string aorii_text::COMMON_PUNCTUATION =
U",。!?:;''""《》【】()、";
const std::wstring aorii_text::COMMON_NUMBERS =
L"0123456789";
const std::u32string aorii_text::COMMON_NUMBERS =
U"0123456789";
aorii_text::aorii_text(const uint32_t in_texture_size) : font(nullptr), texture_array(nullptr),
texture_size(in_texture_size),
current_x(0), current_y(0), current_texture_index(0), scale(0) {
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::~aorii_text() {
@ -61,16 +65,18 @@ bool aorii_text::initialize(const wchar_t* in_font_path, const float in_font_pix
// 获取字体的垂直度量
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);
// Create initial texture atlas
return create_new_texture_atlas();
}
float aorii_text::get_kerning(wchar_t ch1, wchar_t ch2) const {
float aorii_text::get_kerning(char32_t ch1, char32_t ch2) const {
// 获取字距调整
return stbtt_GetCodepointKernAdvance(font, ch1, ch2) * scale;
}
@ -82,25 +88,15 @@ bool aorii_text::create_new_texture_atlas() {
return texture_array != nullptr;
}
bool aorii_text::get_or_create_character(const wchar_t ch, character_info& out_info) {
character_info* aorii_text::get_or_create_character(const char32_t ch) {
if (const auto it = character_map.find(ch); it != character_map.end()) {
out_info = it->second;
return true;
return &it->second;
}
// 加载目标字符(以 'A' 为例)
int glyph_index = stbtt_FindGlyphIndex(font, ch);
if (glyph_index == 0) {
printf("Failed to find glyph for character\n");
return false;
}
// Try to add to current atlas
out_info = add_character_to_atlas(glyph_index, ch);
return true;
return add_character_to_atlas(ch);
}
bool aorii_text::precache_characters(const std::wstring& characters) {
bool aorii_text::precache_characters(const std::u32string& characters) {
if (!font) {
spdlog::error("Font not initialized");
return false;
@ -117,28 +113,22 @@ bool aorii_text::precache_characters(const std::wstring& characters) {
std::mutex map_mutex;
for (size_t i = 0; i < characters.length(); i++) {
wchar_t ch = characters[i];
auto ch = characters[i];
// 检查字符是否已经缓存
if (character_map.contains(ch)) {
continue;
}
// 加载目标字符(以 'A' 为例)
int glyph_index = stbtt_FindGlyphIndex(font, ch);
if (glyph_index == 0) {
continue;
}
// 生成SDF数据
add_character_to_atlas(glyph_index, ch);
add_character_to_atlas(ch);
}
return success;
}
bool aorii_text::precache_common_characters() {
std::wstring all_common_chars;
std::u32string all_common_chars;
all_common_chars.reserve(COMMON_ASCII.length() +
COMMON_CHINESE.length() +
COMMON_PUNCTUATION.length() +
@ -154,7 +144,8 @@ bool aorii_text::precache_common_characters() {
uint32_t aorii_text::get_font_char_count() const { return font->numGlyphs; }
character_info& aorii_text::add_character_to_atlas(int32_t glyph_index, const wchar_t ch) {
character_info* aorii_text::add_character_to_atlas(const char32_t ch) {
int glyph_index = stbtt_FindGlyphIndex(font, ch);
// 获取SDF尺寸和位图
int32_t width, height, x_offset, y_offset;
constexpr int padding = 8;
@ -173,7 +164,7 @@ character_info& aorii_text::add_character_to_atlas(int32_t glyph_index, const wc
);
if (!sdf_bitmap) {
throw std::runtime_error("Failed to generate SDF for glyph");
return nullptr;
}
ON_SCOPE_EXIT {
stbtt_FreeSDF(sdf_bitmap, font->userdata);
@ -190,7 +181,8 @@ character_info& aorii_text::add_character_to_atlas(int32_t glyph_index, const wc
if (current_y + height > texture_size) {
current_texture_index++;
if (current_texture_index >= texture_array->get_count()) {
throw std::runtime_error("Texture array capacity exceeded");
spdlog::error("Texture array capacity exceeded");
return nullptr;
}
current_x = 0;
current_y = 0;
@ -223,6 +215,6 @@ character_info& aorii_text::add_character_to_atlas(int32_t glyph_index, const wc
current_x += width;
next_row_y = std::max(next_row_y, current_y + height);
return character_map[ch] = info;
return &(character_map[ch] = info);
}

View File

@ -30,7 +30,9 @@ public:
static void destroy_freetype();
bool initialize(const wchar_t* in_font_path, float in_font_pixel_size);
bool get_or_create_character(wchar_t ch, character_info& out_info);
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; }
// 下降距离
@ -43,7 +45,7 @@ public:
[[nodiscard]] float get_font_pixel_size() const { return font_pixel_size; }
// 预缓存一组字符
bool precache_characters(const std::wstring& characters);
bool precache_characters(const std::u32string& characters);
// 预缓存常用字符集
bool precache_common_characters();
@ -56,28 +58,29 @@ public:
[[nodiscard]] renderer_texture_array* get_texture_array() const { return texture_array; }
float get_kerning(wchar_t ch1, wchar_t ch2) const;
[[nodiscard]] float get_kerning(char32_t ch1, char32_t ch2) const;
private:
bool create_new_texture_atlas();
character_info& add_character_to_atlas(int32_t glyph_index, const wchar_t ch);
character_info* add_character_to_atlas(char32_t ch);
stbtt_fontinfo* font;
mapped_file font_file;
renderer_texture_array* texture_array;
const uint32_t texture_size;
float font_pixel_size;
int32_t space_width, ascent, descent, line_gap;
float scale;
const uint32_t texture_size;
uint32_t current_x;
uint32_t current_y;
uint32_t next_row_y = 0; // 跟踪当前行的最大高度
uint8_t current_texture_index;
int32_t ascent, descent, line_gap;
float scale;
std::unordered_map<wchar_t, character_info> character_map;
std::unordered_map<char32_t, character_info> character_map;
// 常用字符集定义
static const std::wstring COMMON_ASCII; // ASCII字符
static const std::wstring COMMON_CHINESE; // 常用汉字
static const std::wstring COMMON_PUNCTUATION; // 常用标点符号
static const std::wstring COMMON_NUMBERS; // 数字
static const std::u32string COMMON_ASCII; // ASCII字符
static const std::u32string COMMON_CHINESE; // 常用汉字
static const std::u32string COMMON_PUNCTUATION; // 常用标点符号
static const std::u32string COMMON_NUMBERS; // 数字
};