TODO: 多字体和字体缺失处理
This commit is contained in:
parent
e6a7254598
commit
c1e16b213e
@ -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}, L"你好,世界!全是水群大师\n测试换行\n测试日语: かわいい\n测试俄语: милый", 32);
|
||||
|
||||
context.flush();
|
||||
|
||||
|
@ -54,21 +54,23 @@ void renderer_context::draw_string(const Eigen::Vector2f& in_pos, const std::wst
|
||||
}
|
||||
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;
|
||||
|
@ -25,13 +25,13 @@ const std::wstring aorii_text::COMMON_PUNCTUATION =
|
||||
const std::wstring aorii_text::COMMON_NUMBERS =
|
||||
L"0123456789";
|
||||
|
||||
aorii_text::aorii_text(const uint32_t in_texture_size) : font(nullptr), texture_array(nullptr),
|
||||
aorii_text::aorii_text(const uint32_t in_texture_size) : fonts(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() {
|
||||
delete font;
|
||||
delete fonts;
|
||||
}
|
||||
|
||||
bool aorii_text::init_freetype() {
|
||||
@ -44,7 +44,7 @@ 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();
|
||||
auto font = new stbtt_fontinfo();
|
||||
font_pixel_size = in_font_pixel_size;
|
||||
|
||||
// 加载字体文件
|
||||
@ -67,7 +67,6 @@ bool aorii_text::initialize(const wchar_t* in_font_path, const float in_font_pix
|
||||
spdlog::error("Failed to initialize font");
|
||||
free(font_buffer);
|
||||
delete font;
|
||||
font = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -78,8 +77,9 @@ bool aorii_text::initialize(const wchar_t* in_font_path, const float in_font_pix
|
||||
ascent *= scale;
|
||||
descent *= scale;
|
||||
line_gap *= scale;
|
||||
spdlog::info("Font vertical metrics:\n 上升距离: {}, 下降距离: {}, 行间距: {}", ascent, descent, line_gap);
|
||||
spdlog::info("Font vertical metrics: 上升距离: {}, 下降距离: {}, 行间距: {}", ascent, descent, line_gap);
|
||||
|
||||
fonts.push_back(font);
|
||||
// Create initial texture atlas
|
||||
return create_new_texture_atlas();
|
||||
}
|
||||
@ -96,26 +96,16 @@ 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 wchar_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) {
|
||||
if (!font) {
|
||||
if (!fonts.size()) {
|
||||
spdlog::error("Font not initialized");
|
||||
return false;
|
||||
}
|
||||
@ -138,14 +128,8 @@ bool aorii_text::precache_characters(const std::wstring& characters) {
|
||||
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;
|
||||
@ -166,31 +150,49 @@ 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 char_count = 0;
|
||||
for (auto& font : fonts) {
|
||||
char_count += font->numGlyphs;
|
||||
}
|
||||
return char_count;
|
||||
}
|
||||
|
||||
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 wchar_t ch) {
|
||||
// 获取SDF尺寸和位图
|
||||
int32_t width, height, x_offset, y_offset;
|
||||
constexpr int padding = 8;
|
||||
constexpr uint8_t on_edge_value = 128;
|
||||
constexpr float pixel_dist_scale = 16.f;
|
||||
|
||||
auto* sdf_bitmap = stbtt_GetGlyphSDF(
|
||||
font,
|
||||
scale,
|
||||
glyph_index,
|
||||
padding,
|
||||
on_edge_value,
|
||||
pixel_dist_scale,
|
||||
&width, &height,
|
||||
&x_offset, &y_offset
|
||||
);
|
||||
uint8_t* sdf_bitmap = nullptr;
|
||||
const stbtt_fontinfo* font_info = nullptr;
|
||||
for (const auto f: fonts) {
|
||||
const uint32_t glyph_index = stbtt_FindGlyphIndex(f, ch);
|
||||
if (glyph_index == 0)
|
||||
continue;
|
||||
sdf_bitmap = stbtt_GetGlyphSDF(
|
||||
f,
|
||||
scale,
|
||||
glyph_index,
|
||||
padding,
|
||||
on_edge_value,
|
||||
pixel_dist_scale,
|
||||
&width, &height,
|
||||
&x_offset, &y_offset
|
||||
);
|
||||
if (sdf_bitmap) {
|
||||
font_info = f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sdf_bitmap) {
|
||||
throw std::runtime_error("Failed to generate SDF for glyph");
|
||||
spdlog::error("Failed to generate SDF for glyph {}", ch);
|
||||
return nullptr;
|
||||
}
|
||||
ON_SCOPE_EXIT {
|
||||
stbtt_FreeSDF(sdf_bitmap, font->userdata);
|
||||
stbtt_FreeSDF(sdf_bitmap, font_info->userdata);
|
||||
};
|
||||
|
||||
// 检查当前行是否有足够空间
|
||||
@ -204,7 +206,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;
|
||||
@ -220,7 +223,7 @@ character_info& aorii_text::add_character_to_atlas(int32_t glyph_index, const wc
|
||||
|
||||
// 获取字形度量信息
|
||||
int advance_width, left_side_bearing;
|
||||
stbtt_GetGlyphHMetrics(font, glyph_index, &advance_width, &left_side_bearing);
|
||||
stbtt_GetGlyphHMetrics(font_info, glyph_index, &advance_width, &left_side_bearing);
|
||||
|
||||
// 创建并存储字符信息
|
||||
character_info info;
|
||||
@ -237,6 +240,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);
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ 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(wchar_t ch);
|
||||
// 上升距离
|
||||
[[nodiscard]] int32_t get_ascent() const { return ascent; }
|
||||
// 下降距离
|
||||
@ -57,8 +57,8 @@ public:
|
||||
float get_kerning(wchar_t ch1, wchar_t ch2) const;
|
||||
private:
|
||||
bool create_new_texture_atlas();
|
||||
character_info& add_character_to_atlas(int32_t glyph_index, const wchar_t ch);
|
||||
stbtt_fontinfo* font;
|
||||
character_info* add_character_to_atlas(wchar_t ch);
|
||||
std::vector<stbtt_fontinfo*> fonts;
|
||||
|
||||
renderer_texture_array* texture_array;
|
||||
const uint32_t texture_size;
|
||||
|
Loading…
x
Reference in New Issue
Block a user