TODO: 布局代码
This commit is contained in:
parent
0937bb8a60
commit
5abdc2fc1d
@ -9,14 +9,14 @@ bool dx_sdf_text_pipeline::init() {
|
|||||||
const auto d3d_device = aorii::get_renderer<dx_renderer>()->get_d3d_device();
|
const auto d3d_device = aorii::get_renderer<dx_renderer>()->get_d3d_device();
|
||||||
|
|
||||||
D3D11_SAMPLER_DESC sampler_desc = {};
|
D3D11_SAMPLER_DESC sampler_desc = {};
|
||||||
sampler_desc.Filter = D3D11_FILTER_ANISOTROPIC;
|
sampler_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
|
||||||
sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
sampler_desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||||
sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
sampler_desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||||
sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
sampler_desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||||
sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
|
sampler_desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
|
||||||
sampler_desc.MinLOD = 0;
|
sampler_desc.MinLOD = 0;
|
||||||
sampler_desc.MaxLOD = 1;
|
sampler_desc.MaxLOD = D3D11_FLOAT32_MAX;
|
||||||
sampler_desc.MaxAnisotropy = 4;
|
sampler_desc.MaxAnisotropy = 1;
|
||||||
d3d_device->CreateSamplerState(&sampler_desc, &sampler_state);
|
d3d_device->CreateSamplerState(&sampler_desc, &sampler_state);
|
||||||
|
|
||||||
loader.load("aorii_sdf_text_vertex_main", "aorii_sdf_text_pixel_main");
|
loader.load("aorii_sdf_text_vertex_main", "aorii_sdf_text_pixel_main");
|
||||||
|
@ -8,7 +8,7 @@ aorii_text* text = nullptr;
|
|||||||
void renderer_context::init() {
|
void renderer_context::init() {
|
||||||
text = new aorii_text();
|
text = new aorii_text();
|
||||||
// D:\Projects\aorii\JetBrainsMono-Regular.ttf
|
// D:\Projects\aorii\JetBrainsMono-Regular.ttf
|
||||||
text->initialize(LR"(HarmonyOS_Sans_SC_Regular.ttf)", 64);
|
text->initialize(LR"(C:\Windows\Fonts\simhei.ttf)");
|
||||||
text->add_font(LR"(C:\Windows\Fonts\seguiemj.ttf)");
|
text->add_font(LR"(C:\Windows\Fonts\seguiemj.ttf)");
|
||||||
// text->precache_common_characters();
|
// text->precache_common_characters();
|
||||||
}
|
}
|
||||||
@ -46,39 +46,24 @@ void renderer_context::draw_string(const Eigen::Vector2f& in_pos, const std::u32
|
|||||||
|
|
||||||
float cursor_x = in_pos.x();
|
float cursor_x = in_pos.x();
|
||||||
float cursor_y = in_pos.y();
|
float cursor_y = in_pos.y();
|
||||||
const float scale = in_height / text->get_font_pixel_size();
|
const auto& measure = text->measure_text(in_str, in_height);
|
||||||
wchar_t last_char = 0;
|
|
||||||
for (const auto c : in_str) {
|
|
||||||
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;
|
|
||||||
|
|
||||||
const character_info* info = text->get_or_create_character(c);
|
for (const auto& mch: measure) {
|
||||||
|
const auto info = mch.item;
|
||||||
if (!info)
|
if (!info)
|
||||||
continue;
|
continue;
|
||||||
|
// 使用整形坐标, 避免出现模糊
|
||||||
// 根据in_height缩放字符大小
|
const Eigen::Vector2f pos { cursor_x + mch.x_offset, cursor_y + mch.y_offset };
|
||||||
const float y_offset = (info->y_offset + text->get_ascent()) * scale;
|
const Eigen::Vector2f size { info->get_width() * mch.size_scale, info->get_height() * mch.size_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{};
|
aorii_vertex_param param{};
|
||||||
param.param_a1 = info->tex_u;
|
param.param_a1 = info->tex_u;
|
||||||
param.param_a2 = info->tex_v;
|
param.param_a2 = info->tex_v;
|
||||||
param.param_a3 = info->tex_z;
|
param.param_a3 = info->tex_z;
|
||||||
param.param_b1 = info->width / (float)text->get_texture_size();
|
param.param_b1 = info->u_size;
|
||||||
param.param_b2 = info->height / (float)text->get_texture_size();
|
param.param_b2 = info->v_size;
|
||||||
|
|
||||||
make_rect(pos, size, in_color, 0, param);
|
make_rect(pos, size, in_color, 0, param);
|
||||||
last_char = c;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,18 +26,16 @@ const std::u32string aorii_text::COMMON_NUMBERS =
|
|||||||
U"0123456789";
|
U"0123456789";
|
||||||
|
|
||||||
aorii_text::font_data::~font_data() {
|
aorii_text::font_data::~font_data() {
|
||||||
delete info;
|
delete font;
|
||||||
}
|
}
|
||||||
|
|
||||||
aorii_text::aorii_text() : texture_array(nullptr), font_pixel_size(0),
|
aorii_text::aorii_text() : texture_array(nullptr),
|
||||||
space_width(0),
|
|
||||||
ascent(0), descent(0),
|
|
||||||
line_gap(0),
|
|
||||||
current_x(0), current_y(0),
|
current_x(0), current_y(0),
|
||||||
current_texture_index(0) {
|
current_texture_index(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
aorii_text::~aorii_text() {}
|
aorii_text::~aorii_text() {
|
||||||
|
}
|
||||||
|
|
||||||
bool aorii_text::init_freetype() {
|
bool aorii_text::init_freetype() {
|
||||||
return true;
|
return true;
|
||||||
@ -46,9 +44,7 @@ bool aorii_text::init_freetype() {
|
|||||||
void aorii_text::destroy_freetype() {
|
void aorii_text::destroy_freetype() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool aorii_text::initialize(const std::wstring& in_font_path, const float in_font_pixel_size) {
|
bool aorii_text::initialize(const std::wstring& in_font_path) {
|
||||||
font_pixel_size = in_font_pixel_size;
|
|
||||||
|
|
||||||
// 预计需要的纹理数量(8张纹理几乎可以容纳所有字符)
|
// 预计需要的纹理数量(8张纹理几乎可以容纳所有字符)
|
||||||
constexpr uint32_t expected_textures = 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);
|
texture_array = aorii::get_renderer_raw()->create_texture_array(2048, 2048, expected_textures, texture_format::R8_UNORM, device_memory_type::gpu);
|
||||||
@ -62,19 +58,6 @@ bool aorii_text::initialize(const std::wstring& in_font_path, const float in_fon
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取主字体的度量信息
|
|
||||||
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);
|
|
||||||
|
|
||||||
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,54 +67,64 @@ float aorii_text::get_kerning(char32_t ch1, char32_t ch2) const {
|
|||||||
|
|
||||||
// 在所有字体中查找字符对的字距调整
|
// 在所有字体中查找字符对的字距调整
|
||||||
for (const auto& font : fonts) {
|
for (const auto& font : fonts) {
|
||||||
g1 = stbtt_FindGlyphIndex(font.info, ch1);
|
g1 = stbtt_FindGlyphIndex(font.font, ch1);
|
||||||
g2 = stbtt_FindGlyphIndex(font.info, ch2);
|
g2 = stbtt_FindGlyphIndex(font.font, ch2);
|
||||||
|
|
||||||
if (g1 != 0) {
|
if (g1 != 0) {
|
||||||
left_ch_font = &font;
|
left_ch_font = &font;
|
||||||
}
|
}
|
||||||
if (g1 != 0 && g2 != 0) {
|
if (g1 != 0 && g2 != 0) {
|
||||||
return stbtt_GetGlyphKernAdvance(font.info, g1, g2) * font.scale;
|
return stbtt_GetGlyphKernAdvance(font.font, g1, g2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!left_ch_font)
|
if (!left_ch_font)
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
|
|
||||||
int x0, x1;
|
int x0, x1;
|
||||||
stbtt_GetGlyphBox(left_ch_font->info, g1, &x0, nullptr, &x1, nullptr);
|
stbtt_GetGlyphBox(left_ch_font->font, g1, &x0, nullptr, &x1, nullptr);
|
||||||
return (x1 - x0) * left_ch_font->scale;
|
return x1 - x0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool aorii_text::add_font(const std::wstring& font_path) {
|
bool aorii_text::add_font(const std::wstring& font_path) {
|
||||||
font_data new_font{};
|
font_data new_font{};
|
||||||
new_font.info = new stbtt_fontinfo();
|
new_font.font = new stbtt_fontinfo();
|
||||||
|
|
||||||
// 映射字体文件
|
// 映射字体文件
|
||||||
if (!new_font.file.map_file(font_path)) {
|
if (!new_font.file.map_file(font_path)) {
|
||||||
delete new_font.info;
|
delete new_font.font;
|
||||||
spdlog::error("Failed to map font file");
|
spdlog::error("Failed to map font file");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto* font_buffer = static_cast<uint8_t*>(new_font.file.get_data());
|
const auto* font_buffer = static_cast<uint8_t*>(new_font.file.get_data());
|
||||||
if (!stbtt_InitFont(new_font.info, font_buffer, stbtt_GetFontOffsetForIndex(font_buffer, 0))) {
|
if (!stbtt_InitFont(new_font.font, font_buffer, stbtt_GetFontOffsetForIndex(font_buffer, 0))) {
|
||||||
new_font.file.unmap();
|
new_font.file.unmap();
|
||||||
delete new_font.info;
|
delete new_font.font;
|
||||||
spdlog::error("Failed to initialize font");
|
spdlog::error("Failed to initialize font");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_font.scale = stbtt_ScaleForPixelHeight(new_font.info, font_pixel_size);
|
int temp_space_width, temp_tab_width;
|
||||||
|
stbtt_GetCodepointHMetrics(new_font.font, ' ', &temp_space_width, nullptr);
|
||||||
|
stbtt_GetCodepointHMetrics(new_font.font, '\t', &temp_tab_width, nullptr);
|
||||||
|
new_font.space_width = temp_space_width;
|
||||||
|
new_font.tab_width = temp_tab_width;
|
||||||
|
|
||||||
|
int ascent, descent, line_gap;
|
||||||
|
stbtt_GetFontVMetrics(new_font.font, &ascent, &descent, &line_gap);
|
||||||
|
new_font.ascent = ascent;
|
||||||
|
new_font.descent = descent;
|
||||||
|
new_font.line_gap = line_gap;
|
||||||
|
|
||||||
fonts.emplace_back(std::move(new_font));
|
fonts.emplace_back(std::move(new_font));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
character_info* aorii_text::get_or_create_character(const char32_t ch) {
|
ch_atlas_item const* aorii_text::get_atlas_item(const char32_t ch) {
|
||||||
if (const auto it = character_map.find(ch); it != character_map.end()) {
|
if (const auto it = character_map.find(ch); it != character_map.end()) {
|
||||||
return &it->second;
|
return &it->second;
|
||||||
}
|
}
|
||||||
// Try to add to current atlas
|
return cache_ch_to_atlas(ch);
|
||||||
return add_character_to_atlas(ch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool aorii_text::precache_characters(const std::u32string& characters) {
|
bool aorii_text::precache_characters(const std::u32string& characters) {
|
||||||
@ -147,14 +140,8 @@ bool aorii_text::precache_characters(const std::u32string& characters) {
|
|||||||
|
|
||||||
for (size_t i = 0; i < characters.length(); i++) {
|
for (size_t i = 0; i < characters.length(); i++) {
|
||||||
auto ch = characters[i];
|
auto ch = characters[i];
|
||||||
|
if (!get_atlas_item(ch))
|
||||||
// 检查字符是否已经缓存
|
spdlog::error("Failed to create character U+{:04X}", (uint32_t)ch);
|
||||||
if (character_map.contains(ch)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成SDF数据
|
|
||||||
add_character_to_atlas(ch);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
@ -178,7 +165,7 @@ bool aorii_text::precache_common_characters() {
|
|||||||
uint32_t aorii_text::get_font_char_count() const {
|
uint32_t aorii_text::get_font_char_count() const {
|
||||||
uint32_t result = 0;
|
uint32_t result = 0;
|
||||||
for (const auto& font : fonts) {
|
for (const auto& font : fonts) {
|
||||||
result += font.info->numGlyphs;
|
result += font.font->numGlyphs;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -187,11 +174,71 @@ uint32_t aorii_text::get_texture_size() const {
|
|||||||
return texture_array->size().x();
|
return texture_array->size().x();
|
||||||
}
|
}
|
||||||
|
|
||||||
character_info* aorii_text::add_character_to_atlas(const char32_t ch) {
|
std::vector<measured_ch> aorii_text::measure_text(const std::u32string& text, float height) {
|
||||||
|
// 获取主字体
|
||||||
|
font_data const& primary_font = fonts[0];
|
||||||
|
const float scale = stbtt_ScaleForPixelHeight(primary_font.font, height);
|
||||||
|
const float scale_padding = padding * (height / pixel_height);
|
||||||
|
|
||||||
|
// 基线和行高信息
|
||||||
|
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 int32_t line_height = height;
|
||||||
|
const float space_width = primary_font.space_width * scale;
|
||||||
|
const float tab_width = primary_font.tab_width * scale;
|
||||||
|
|
||||||
|
std::vector<measured_ch> result;
|
||||||
|
float x = 0;
|
||||||
|
float y = 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
float test = line_height - item->get_height() * mch.size_scale;
|
||||||
|
mch.y_offset += test;
|
||||||
|
x += item->get_width() * mch.size_scale;
|
||||||
|
prev_char = ch;
|
||||||
|
}
|
||||||
|
result.push_back(mch);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ch_atlas_item const* aorii_text::cache_ch_to_atlas(char32_t ch) {
|
||||||
font_data const* current_font = nullptr;
|
font_data const* current_font = nullptr;
|
||||||
int glyph_index = 0;
|
int glyph_index = 0;
|
||||||
for (const auto& font : fonts) {
|
for (const auto& font : fonts) {
|
||||||
if (glyph_index = stbtt_FindGlyphIndex(font.info, ch)) {
|
glyph_index = stbtt_FindGlyphIndex(font.font, ch);
|
||||||
|
if (glyph_index) {
|
||||||
current_font = &font;
|
current_font = &font;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -199,18 +246,18 @@ character_info* aorii_text::add_character_to_atlas(const char32_t ch) {
|
|||||||
if (!current_font) {
|
if (!current_font) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
const auto font = current_font->info;
|
const auto font = current_font->font;
|
||||||
const uint32_t texture_size = get_texture_size();
|
const uint32_t texture_size = get_texture_size();
|
||||||
|
|
||||||
|
constexpr uint8_t on_edge_value = 128;
|
||||||
|
const float pixel_dist_scale = (float)on_edge_value / padding;
|
||||||
|
const float scale = stbtt_ScaleForPixelHeight(font, pixel_height - padding * 2);
|
||||||
|
|
||||||
// 获取SDF尺寸和位图
|
// 获取SDF尺寸和位图
|
||||||
int32_t width, height, x_offset, y_offset;
|
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(
|
auto* sdf_bitmap = stbtt_GetGlyphSDF(
|
||||||
font,
|
font,
|
||||||
current_font->scale,
|
scale,
|
||||||
glyph_index,
|
glyph_index,
|
||||||
padding,
|
padding,
|
||||||
on_edge_value,
|
on_edge_value,
|
||||||
@ -255,21 +302,35 @@ character_info* aorii_text::add_character_to_atlas(const char32_t ch) {
|
|||||||
// 获取字形度量信息
|
// 获取字形度量信息
|
||||||
int advance_width, left_side_bearing;
|
int advance_width, left_side_bearing;
|
||||||
stbtt_GetGlyphHMetrics(font, glyph_index, &advance_width, &left_side_bearing);
|
stbtt_GetGlyphHMetrics(font, glyph_index, &advance_width, &left_side_bearing);
|
||||||
|
int ch_x0, ch_y0, ch_x1, ch_y1;
|
||||||
|
stbtt_GetGlyphBox(font, glyph_index, &ch_x0, &ch_y0, &ch_x1, &ch_y1);
|
||||||
|
|
||||||
|
// 将x_offset和y_offset转换到字体空间
|
||||||
|
x_offset = x_offset / scale;
|
||||||
|
y_offset = y_offset / scale;
|
||||||
|
|
||||||
// 创建并存储字符信息
|
// 创建并存储字符信息
|
||||||
character_info info;
|
ch_atlas_item info{};
|
||||||
info.tex_u = current_x / static_cast<float>(texture_size);
|
info.tex_u = current_x / static_cast<float>(texture_size);
|
||||||
info.tex_v = current_y / static_cast<float>(texture_size);
|
info.tex_v = current_y / static_cast<float>(texture_size);
|
||||||
info.advance = advance_width * current_font->scale;
|
|
||||||
info.tex_z = static_cast<float>(current_texture_index);
|
info.tex_z = static_cast<float>(current_texture_index);
|
||||||
info.width = width;
|
info.u_size = width / static_cast<float>(texture_size);
|
||||||
info.height = height;
|
info.v_size = height / static_cast<float>(texture_size);
|
||||||
|
|
||||||
info.x_offset = x_offset;
|
info.x_offset = x_offset;
|
||||||
info.y_offset = y_offset;
|
info.y_offset = y_offset;
|
||||||
|
|
||||||
|
info.left = ch_x0;
|
||||||
|
info.right = ch_x1;
|
||||||
|
info.top = ch_y0;
|
||||||
|
info.bottom = ch_y1;
|
||||||
|
|
||||||
|
info.x_advance = advance_width;
|
||||||
|
info.left_side_bearing = left_side_bearing;
|
||||||
|
|
||||||
// 更新位置和下一行的y坐标
|
// 更新位置和下一行的y坐标
|
||||||
current_x += width;
|
current_x += width;
|
||||||
next_row_y = std::max(next_row_y, current_y + height);
|
next_row_y = std::max(next_row_y, current_y + height);
|
||||||
|
|
||||||
return &(character_map[ch] = info);
|
return &(character_map[ch] = info);
|
||||||
}
|
}
|
@ -1,42 +1,68 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
#include "core/pixel_format/pixel.h"
|
#include "core/pixel_format/pixel.h"
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#include "misc/mapped_file.h"
|
#include "misc/mapped_file.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
class renderer_texture_array;
|
class renderer_texture_array;
|
||||||
struct stbtt_fontinfo;
|
struct stbtt_fontinfo;
|
||||||
|
|
||||||
struct character_info {
|
struct ch_atlas_item {
|
||||||
float tex_u; // U position in atlas
|
float tex_u; // U position in atlas
|
||||||
float tex_v; // V position in atlas
|
float tex_v; // V position in atlas
|
||||||
float advance; // Advance width
|
|
||||||
uint8_t tex_z; // Z position in texture array
|
uint8_t tex_z; // Z position in texture array
|
||||||
uint8_t width; // Character width
|
float u_size; // Texture width
|
||||||
uint8_t height; // Character height
|
float v_size; // Texture height
|
||||||
int8_t x_offset; // X offset from baseline
|
|
||||||
int8_t y_offset; // Y offset from baseline
|
int32_t x_offset; // X offset from baseline
|
||||||
|
int32_t y_offset; // Y offset from baseline
|
||||||
|
|
||||||
|
int32_t left;
|
||||||
|
int32_t right;
|
||||||
|
int32_t top;
|
||||||
|
int32_t bottom;
|
||||||
|
int32_t get_width() const { return right - left; }
|
||||||
|
int32_t get_height() const { return bottom - top; }
|
||||||
|
|
||||||
|
int32_t x_advance;
|
||||||
|
int32_t left_side_bearing;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct measured_ch {
|
||||||
|
ch_atlas_item const* item;
|
||||||
|
float x_offset;
|
||||||
|
float y_offset;
|
||||||
|
float size_scale;
|
||||||
};
|
};
|
||||||
|
|
||||||
class aorii_text {
|
class aorii_text {
|
||||||
struct font_data {
|
struct font_data {
|
||||||
font_data() = default;
|
font_data() = default;
|
||||||
font_data(font_data&& other) {
|
font_data(font_data&& other) noexcept {
|
||||||
file = std::move(other.file);
|
file = std::move(other.file);
|
||||||
|
|
||||||
info = other.info;
|
font = other.font;
|
||||||
scale = other.scale;
|
space_width = other.space_width;
|
||||||
other.info = nullptr;
|
tab_width = other.tab_width;
|
||||||
other.scale = 0;
|
ascent = other.ascent;
|
||||||
|
descent = other.descent;
|
||||||
|
line_gap = other.line_gap;
|
||||||
|
|
||||||
|
other.font = nullptr;
|
||||||
|
other.space_width = 0;
|
||||||
|
other.tab_width = 0;
|
||||||
|
other.ascent = 0;
|
||||||
|
other.descent = 0;
|
||||||
|
other.line_gap = 0;
|
||||||
}
|
}
|
||||||
~font_data();
|
~font_data();
|
||||||
|
|
||||||
stbtt_fontinfo* info;
|
stbtt_fontinfo* font{};
|
||||||
mapped_file file;
|
mapped_file file;
|
||||||
float scale;
|
int32_t space_width{};
|
||||||
|
int32_t tab_width{};
|
||||||
|
int32_t ascent{}; // 字体从基线到顶部的高度
|
||||||
|
int32_t descent{}; // 基线到字体底部的高度
|
||||||
|
int32_t line_gap{}; // 行间距
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
aorii_text();
|
aorii_text();
|
||||||
@ -45,16 +71,9 @@ public:
|
|||||||
static bool init_freetype();
|
static bool init_freetype();
|
||||||
static void destroy_freetype();
|
static void destroy_freetype();
|
||||||
|
|
||||||
bool initialize(const std::wstring& in_font_path, float in_font_pixel_size);
|
bool initialize(const std::wstring& in_font_path);
|
||||||
bool add_font(const std::wstring& font_path);
|
bool add_font(const std::wstring& font_path);
|
||||||
character_info* get_or_create_character(char32_t ch);
|
ch_atlas_item const* get_atlas_item(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]] float get_font_pixel_size() const { return font_pixel_size; }
|
|
||||||
|
|
||||||
// 预缓存一组字符
|
// 预缓存一组字符
|
||||||
bool precache_characters(const std::u32string& characters);
|
bool precache_characters(const std::u32string& characters);
|
||||||
@ -72,21 +91,21 @@ public:
|
|||||||
[[nodiscard]] uint32_t get_texture_size() const;
|
[[nodiscard]] uint32_t get_texture_size() const;
|
||||||
|
|
||||||
[[nodiscard]] float get_kerning(char32_t ch1, char32_t ch2) const;
|
[[nodiscard]] float get_kerning(char32_t ch1, char32_t ch2) const;
|
||||||
|
[[nodiscard]] std::vector<measured_ch> measure_text(const std::u32string& text, float height);
|
||||||
private:
|
private:
|
||||||
character_info* add_character_to_atlas(char32_t ch);
|
ch_atlas_item const* cache_ch_to_atlas(char32_t ch);
|
||||||
|
|
||||||
std::vector<font_data> fonts;
|
std::vector<font_data> fonts;
|
||||||
|
const float pixel_height = 64;
|
||||||
|
const int padding = 5;
|
||||||
|
|
||||||
renderer_texture_array* texture_array;
|
renderer_texture_array* texture_array;
|
||||||
float font_pixel_size;
|
|
||||||
int32_t space_width, tab_width, ascent, descent, line_gap;
|
|
||||||
|
|
||||||
uint32_t current_x;
|
uint32_t current_x;
|
||||||
uint32_t current_y;
|
uint32_t current_y;
|
||||||
uint32_t next_row_y = 0; // 跟踪当前行的最大高度
|
uint32_t next_row_y = 0; // 跟踪当前行的最大高度
|
||||||
uint8_t current_texture_index;
|
uint8_t current_texture_index;
|
||||||
|
|
||||||
std::unordered_map<char32_t, character_info> character_map;
|
std::unordered_map<char32_t, ch_atlas_item> character_map;
|
||||||
|
|
||||||
// 常用字符集定义
|
// 常用字符集定义
|
||||||
static const std::u32string COMMON_ASCII; // ASCII字符
|
static const std::u32string COMMON_ASCII; // ASCII字符
|
||||||
|
@ -43,8 +43,8 @@ float4 pixel_main(PSInput input) : SV_Target {
|
|||||||
float2 uv = input.altas_uv + input.char_size * input.uv;
|
float2 uv = input.altas_uv + input.char_size * input.uv;
|
||||||
float distance = atlas_texture.Sample(sampler_state, float3(uv, input.altas_index)).r;
|
float distance = atlas_texture.Sample(sampler_state, float3(uv, input.altas_index)).r;
|
||||||
// return float4(distance, distance, distance, 1.0);
|
// return float4(distance, distance, distance, 1.0);
|
||||||
float range = 0.07;
|
float range = 0.2;
|
||||||
float alpha = smoothstep(0.5 - range, 0.5 + range, distance);
|
float alpha = smoothstep(0.4, 0.5, distance);
|
||||||
|
|
||||||
float4 color = input.color;
|
float4 color = input.color;
|
||||||
color.a *= alpha;
|
color.a *= alpha;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user