diff --git a/src/core/misc/scope_exit.h b/src/core/misc/scope_exit.h index 45f6690..8d87603 100644 --- a/src/core/misc/scope_exit.h +++ b/src/core/misc/scope_exit.h @@ -5,7 +5,7 @@ class scope_exit_guard { public: scope_exit_guard(FuncType&& in_func) : func((FuncType&&)in_func) { } - ~scope_exit_guard() { + virtual ~scope_exit_guard() { func(); } private: @@ -13,6 +13,7 @@ private: }; struct scope_exit_syntax_support { + virtual ~scope_exit_syntax_support() = default; template scope_exit_guard operator+(FuncType&& InFunc) { diff --git a/src/renderer/backend/dx/dx_renderer.cpp b/src/renderer/backend/dx/dx_renderer.cpp index 7838975..124a4a5 100644 --- a/src/renderer/backend/dx/dx_renderer.cpp +++ b/src/renderer/backend/dx/dx_renderer.cpp @@ -58,12 +58,12 @@ bool dx_renderer::render() { return true; } -renderer_texture* dx_renderer::create_texture(uint32_t in_size_width, uint32_t in_size_height, texture_format in_format) { - return new dx_texture({ in_size_width, in_size_height }, in_format); +renderer_texture* dx_renderer::create_texture(uint32_t in_size_width, uint32_t in_size_height, texture_format in_format, device_memory_type in_memory_type) { + return new dx_texture({ in_size_width, in_size_height }, in_format, in_memory_type); } -renderer_texture_array* dx_renderer::create_texture_array(uint32_t in_size_width, uint32_t in_size_height, uint32_t in_count, texture_format in_format) { - return new dx_texture_array({ in_size_width, in_size_height }, in_format, in_count); +renderer_texture_array* dx_renderer::create_texture_array(uint32_t in_size_width, uint32_t in_size_height, uint32_t in_count, texture_format in_format, device_memory_type in_memory_type) { + return new dx_texture_array({ in_size_width, in_size_height }, in_format, in_count, in_memory_type); } Eigen::Matrix4f dx_renderer::make_projection_matrix(const Eigen::Vector2i& size) { diff --git a/src/renderer/backend/dx/dx_renderer.h b/src/renderer/backend/dx/dx_renderer.h index efe11c9..f202eb7 100644 --- a/src/renderer/backend/dx/dx_renderer.h +++ b/src/renderer/backend/dx/dx_renderer.h @@ -16,8 +16,8 @@ public: void destroy() override; bool render() override; - renderer_texture* create_texture(uint32_t in_size_width, uint32_t in_size_height, texture_format in_format) override; - renderer_texture_array* create_texture_array(uint32_t in_size_width, uint32_t in_size_height, uint32_t in_count, texture_format in_format) override; + renderer_texture* create_texture(uint32_t in_size_width, uint32_t in_size_height, texture_format in_format, device_memory_type in_memory_type) override; + renderer_texture_array* create_texture_array(uint32_t in_size_width, uint32_t in_size_height, uint32_t in_count, texture_format in_format, device_memory_type in_memory_type) override; [[nodiscard]] ID3D11Device* get_d3d_device() const { return device; } [[nodiscard]] ID3D11DeviceContext* get_d3d_context() const { return context; } diff --git a/src/renderer/backend/dx/dx_texture.cpp b/src/renderer/backend/dx/dx_texture.cpp index a398db8..12e5e77 100644 --- a/src/renderer/backend/dx/dx_texture.cpp +++ b/src/renderer/backend/dx/dx_texture.cpp @@ -1,9 +1,24 @@ #include "dx_texture.h" #include "dx_renderer.h" +#include "misc/scope_exit.h" -dx_texture::dx_texture(const Eigen::Vector2i& size, const texture_format format, uint32_t count) : renderer_texture(format) { - create_texture(size, format, count); +int get_cpu_access_flag(device_memory_type in_memory_type) { + switch (in_memory_type) { + case device_memory_type::gpu: + return 0; + case device_memory_type::shared: + return D3D11_CPU_ACCESS_WRITE; + case device_memory_type::cpu: + return D3D11_CPU_ACCESS_WRITE; + default: + return D3D11_CPU_ACCESS_WRITE; + } +} + +dx_texture::dx_texture(const Eigen::Vector2i& size, const texture_format format, device_memory_type in_memory_type, uint32_t count) : renderer_texture(format) { + memory_type = in_memory_type; + create_texture(size, format, in_memory_type, count); } dx_texture::~dx_texture() { @@ -18,28 +33,48 @@ void dx_texture::unlock() { return unlock(0); } -void* dx_texture::lock(uint32_t index, uint32_t* out_row_pitch) const { - D3D11_TEXTURE2D_DESC desc; - m_texture->GetDesc(&desc); +void* dx_texture::lock(uint32_t index, uint32_t* out_row_pitch) { + auto r = aorii::get_renderer(); + auto hr = r->get_d3d_device()->CreateTexture2D(&upload_desc, nullptr, &upload_texture); + if (FAILED(hr)) { + spdlog::critical("无法创建上传纹理, 错误: 0x{:08X}", static_cast(hr)); + return nullptr; + } + D3D11_MAPPED_SUBRESOURCE mappedResource; - auto context = aorii::get_renderer()->get_d3d_context(); - context->Map(m_texture, index, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + const auto context = aorii::get_renderer()->get_d3d_context(); + hr = context->Map(upload_texture, index, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(hr)) { + spdlog::critical("无法映射纹理, 错误: 0x{:08X}", static_cast(hr)); + return nullptr; + } if (out_row_pitch) *out_row_pitch = mappedResource.RowPitch; return mappedResource.pData; } void dx_texture::unlock(uint32_t index) const { - auto context = aorii::get_renderer()->get_d3d_context(); - context->Unmap(m_texture, index); + const auto context = aorii::get_renderer()->get_d3d_context(); + context->Unmap(upload_texture, index); + // 复制到目标纹理 + context->CopyResource(m_texture, upload_texture); } void dx_texture::update_subresource(const Eigen::AlignedBox2i& in_area, const void* in_buffer, const uint32_t in_row_pitch) { update_subresource(0, in_area, in_buffer, in_row_pitch); } -void dx_texture::update_subresource(uint32_t index, const Eigen::AlignedBox2i& in_area, const void* in_buffer, - const uint32_t in_row_pitch) const { - D3D11_BOX box = {}; +void dx_texture::update_subresource(uint32_t index, const Eigen::AlignedBox2i& in_area, const void* in_buffer, const uint32_t in_row_pitch) { + auto r = aorii::get_renderer(); + const auto context = r->get_d3d_context(); + auto device = r->get_d3d_device(); + const auto& size = in_area.sizes(); + + // 更新上传纹理描述符 + upload_desc.Width = size.x(); + upload_desc.Height = size.y(); + + // 定义目标区域 + D3D11_BOX box{}; box.left = in_area.min().x(); box.top = in_area.min().y(); box.right = in_area.max().x(); @@ -47,8 +82,59 @@ void dx_texture::update_subresource(uint32_t index, const Eigen::AlignedBox2i& i box.front = 0; box.back = 1; - const auto context = aorii::get_renderer()->get_d3d_context(); - context->UpdateSubresource(m_texture, index, &box, in_buffer, in_row_pitch, 0); + // 定义源区域 + D3D11_BOX src_box{}; + src_box.left = 0; + src_box.top = 0; + src_box.right = size.x(); + src_box.bottom = size.y(); + src_box.front = 0; + src_box.back = 1; + + // 创建临时上传纹理 + auto hr = device->CreateTexture2D(&upload_desc, nullptr, &upload_texture); + if (FAILED(hr)) { + spdlog::critical("无法创建上传纹理, 错误: 0x{:08X}", static_cast(hr)); + return; + } + ON_SCOPE_EXIT{ + // 删除临时纹理 + upload_texture->Release(); + upload_texture = nullptr; + }; + + // 映射上传纹理 + D3D11_MAPPED_SUBRESOURCE mapped; + hr = context->Map(upload_texture, 0, D3D11_MAP_WRITE, 0, &mapped); + if (FAILED(hr)) { + spdlog::critical("无法映射上传纹理, 错误: 0x{:08X}", static_cast(hr)); + return; + } + + // 复制数据到上传纹理 + const auto src_data = static_cast(in_buffer); + const auto dst_data = static_cast(mapped.pData); + + for (int y = 0; y < size.y(); ++y) { + memcpy( + dst_data + mapped.RowPitch * y, + src_data + in_row_pitch * y, + size.x() + ); + } + + // 解除映射 + context->Unmap(upload_texture, 0); + + // 复制到目标纹理 + context->CopySubresourceRegion( + m_texture, // 目标纹理 + index, // 目标子资源索引 + box.left, box.top, 0, // 目标位置 + upload_texture, // 源纹理 + 0, // 源子资源索引 + &src_box // 源区域 + ); } bool dx_texture::resize(const Eigen::Vector2i& size) { @@ -57,7 +143,7 @@ bool dx_texture::resize(const Eigen::Vector2i& size) { if (desc.Width == size.x() && desc.Height == size.y()) { return true; } - return create_texture(size, get_format()); + return create_texture(size, get_format(), memory_type, get_count()); } Eigen::Vector2i dx_texture::size() { @@ -79,10 +165,10 @@ void dx_texture::set_count(const uint32_t in_count) { D3D11_TEXTURE2D_DESC desc; m_texture->GetDesc(&desc); desc.ArraySize = in_count; - create_texture({ desc.Width, desc.Height }, get_format(), in_count); + create_texture({ desc.Width, desc.Height }, get_format(), memory_type, in_count); } -bool dx_texture::create_texture(const Eigen::Vector2i& in_size, texture_format in_format, uint32_t in_count) { +bool dx_texture::create_texture(const Eigen::Vector2i& in_size, texture_format in_format, device_memory_type in_memory_type, uint32_t in_count) { // 释放旧资源 release_texture(); @@ -96,16 +182,23 @@ bool dx_texture::create_texture(const Eigen::Vector2i& in_size, texture_format i desc.Format = get_dxgi_format(in_format); desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; - desc.Usage = in_count > 1 ? D3D11_USAGE_DEFAULT : D3D11_USAGE_DYNAMIC; + desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + desc.CPUAccessFlags = get_cpu_access_flag(in_memory_type); desc.MiscFlags = 0; auto hr = d3d_device->CreateTexture2D(&desc, nullptr, &m_texture); if (FAILED(hr)) { - spdlog::critical("无法创建纹理, 错误: {0}", hr); + spdlog::critical("无法创建纹理, 错误: 0x{:08X}", static_cast(hr)); return false; } + // 创建临时的上传纹理 + upload_desc = desc; + upload_desc.ArraySize = 1; + upload_desc.Usage = D3D11_USAGE_STAGING; // 用于CPU到GPU的传输 + upload_desc.BindFlags = 0; + upload_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = {}; srv_desc.Format = desc.Format; srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; @@ -113,7 +206,7 @@ bool dx_texture::create_texture(const Eigen::Vector2i& in_size, texture_format i srv_desc.Texture2D.MipLevels = 1; hr = d3d_device->CreateShaderResourceView(m_texture, &srv_desc, &srv); if (FAILED(hr)) { - spdlog::critical("无法创建着色器资源视图, 错误: {0}", hr); + spdlog::critical("无法创建着色器资源视图, 错误: 0x{:08X}", static_cast(hr)); return false; } return true; @@ -122,6 +215,8 @@ bool dx_texture::create_texture(const Eigen::Vector2i& in_size, texture_format i void dx_texture::release_texture() { if (srv) srv->Release(); if (m_texture) m_texture->Release(); + if (upload_texture) upload_texture->Release(); srv = nullptr; m_texture = nullptr; + upload_texture = nullptr; } diff --git a/src/renderer/backend/dx/dx_texture.h b/src/renderer/backend/dx/dx_texture.h index ef042a6..3309e72 100644 --- a/src/renderer/backend/dx/dx_texture.h +++ b/src/renderer/backend/dx/dx_texture.h @@ -7,17 +7,17 @@ // DX11纹理 class dx_texture : public renderer_texture { public: - dx_texture(const Eigen::Vector2i& size, texture_format format, uint32_t count = 1); + dx_texture(const Eigen::Vector2i& size, texture_format format, device_memory_type in_memory_type, uint32_t count = 1); ~dx_texture() override; void* lock(uint32_t* out_row_pitch) override; void unlock() override; - void* lock(uint32_t index, uint32_t* out_row_pitch) const; + void* lock(uint32_t index, uint32_t* out_row_pitch); void unlock(uint32_t index) const; void update_subresource(const Eigen::AlignedBox2i& in_area, const void* in_buffer, uint32_t in_row_pitch) override; - void update_subresource(uint32_t index, const Eigen::AlignedBox2i& in_area, const void* in_buffer, uint32_t in_row_pitch) const; + void update_subresource(uint32_t index, const Eigen::AlignedBox2i& in_area, const void* in_buffer, uint32_t in_row_pitch); bool resize(const Eigen::Vector2i& size) override; Eigen::Vector2i size() override; @@ -29,9 +29,13 @@ public: [[nodiscard]] uint32_t get_count() const; void set_count(uint32_t in_count); private: - bool create_texture(const Eigen::Vector2i& in_size, texture_format in_format, uint32_t in_count = 1); + bool create_texture(const Eigen::Vector2i& in_size, texture_format in_format, device_memory_type in_memory_type, uint32_t in_count = 1); void release_texture(); ID3D11Texture2D* m_texture{}; ID3D11ShaderResourceView* srv{}; + device_memory_type memory_type; + + D3D11_TEXTURE2D_DESC upload_desc; + ID3D11Texture2D* upload_texture{}; }; diff --git a/src/renderer/backend/dx/dx_texture_array.h b/src/renderer/backend/dx/dx_texture_array.h index 3909027..e254153 100644 --- a/src/renderer/backend/dx/dx_texture_array.h +++ b/src/renderer/backend/dx/dx_texture_array.h @@ -6,8 +6,8 @@ class dx_texture; class dx_texture_array : public renderer_texture_array { public: - dx_texture_array(const Eigen::Vector2i& size, texture_format format, const uint32_t count): renderer_texture_array(format) { - texture = new dx_texture(size, format, count); + dx_texture_array(const Eigen::Vector2i& size, texture_format format, const uint32_t count, device_memory_type in_memory_type): renderer_texture_array(format) { + texture = new dx_texture(size, format, in_memory_type, count); } ~dx_texture_array() override { delete texture; } diff --git a/src/renderer/backend/dx/dx_window.cpp b/src/renderer/backend/dx/dx_window.cpp index d6fbfaf..f58c54b 100644 --- a/src/renderer/backend/dx/dx_window.cpp +++ b/src/renderer/backend/dx/dx_window.cpp @@ -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(), test_texture); - context.draw_string({0, 0}, L"你好,世界!", 64); + context.draw_string({0, 0}, L"你好,世界!", 32); context.flush(); diff --git a/src/renderer/core/renderer/renderer.cpp b/src/renderer/core/renderer/renderer.cpp index 35156b2..69f85d2 100644 --- a/src/renderer/core/renderer/renderer.cpp +++ b/src/renderer/core/renderer/renderer.cpp @@ -38,7 +38,7 @@ renderer_texture* renderer::load_image(const std::string& file_path, texture_for int target_channel_count = get_format_channel_count(in_format); unsigned int row_pitch = 0; - auto texture = create_texture(width, height, in_format); + auto texture = create_texture(width, height, in_format, device_memory_type::gpu); auto data = texture->lock(&row_pitch); for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { diff --git a/src/renderer/core/renderer/renderer.h b/src/renderer/core/renderer/renderer.h index 28618f2..e21dd56 100644 --- a/src/renderer/core/renderer/renderer.h +++ b/src/renderer/core/renderer/renderer.h @@ -22,6 +22,12 @@ enum class renderer_api { metal, }; +enum class device_memory_type { + gpu, // 显存 + shared, // 共享内存 + cpu, // 内存 +}; + enum class texture_format { // 未压缩的颜色格式 @@ -221,16 +227,16 @@ public: virtual bool render() = 0; template - renderer_texture* create_texture(const Eigen::Vector2& in_size, texture_format in_format) { - return create_texture(in_size.x(), in_size.y(), in_format); + renderer_texture* create_texture(const Eigen::Vector2& in_size, texture_format in_format, device_memory_type in_memory_type) { + return create_texture(in_size.x(), in_size.y(), in_format, in_memory_type); } - virtual renderer_texture* create_texture(uint32_t in_size_width, uint32_t in_size_height, texture_format in_format) = 0; + virtual renderer_texture* create_texture(uint32_t in_size_width, uint32_t in_size_height, texture_format in_format, device_memory_type in_memory_type) = 0; virtual void destroy_texture(renderer_texture* texture); template renderer_texture_array* create_texture_array(const Eigen::Vector2& in_size, const int in_count, const texture_format in_format) { return create_texture_array(in_size.x(), in_size.y(), in_count, in_format); } - virtual renderer_texture_array* create_texture_array(uint32_t in_size_width, uint32_t in_size_height, uint32_t in_count, texture_format in_format) = 0; + virtual renderer_texture_array* create_texture_array(uint32_t in_size_width, uint32_t in_size_height, uint32_t in_count, texture_format in_format, device_memory_type in_memory_type) = 0; virtual void destroy_texture_array(renderer_texture_array* texture_array); renderer_texture* load_image(const std::string& file_path, texture_format in_format); diff --git a/src/renderer/core/renderer/renderer_context.cpp b/src/renderer/core/renderer/renderer_context.cpp index 3bbf836..e8ad176 100644 --- a/src/renderer/core/renderer/renderer_context.cpp +++ b/src/renderer/core/renderer/renderer_context.cpp @@ -6,7 +6,7 @@ aorii_text* text = nullptr; void renderer_context::init() { - text = new aorii_text(); + text = new aorii_text(2048); text->initialize(LR"(C:\Windows\Fonts\msyh.ttc)", 32); text->precache_common_characters(); } @@ -39,28 +39,33 @@ 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::wstring& in_str, float in_height, const linear_color& in_color) { to_text_pipeline(in_color); float cursor_x = in_pos.x(); - const float scale = in_height / 32; + const float scale = in_height / text->get_font_pixel_size(); + wchar_t last_char = 0; for (const auto c : in_str) { + cursor_x += last_char ? text->get_kerning(last_char, c) : 0; + character_info info{}; text->get_or_create_character(c, info); + // 根据in_height缩放字符大小 - const Eigen::Vector2f size = { info.width * scale, info.height * scale }; - const Eigen::Vector2f pos = { cursor_x, in_pos.y() - info.height }; - cursor_x += size.x() + info.offset_x; + 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, in_pos.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; - param.param_b2 = info.height; + 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; } } diff --git a/src/renderer/core/renderer/renderer_text.cpp b/src/renderer/core/renderer/renderer_text.cpp index 7806ae4..88f8c5e 100644 --- a/src/renderer/core/renderer/renderer_text.cpp +++ b/src/renderer/core/renderer/renderer_text.cpp @@ -10,6 +10,8 @@ #define STB_TRUETYPE_IMPLEMENTATION #include +#include "misc/scope_exit.h" + // 在SDFFontCache.cpp中添加实现 const std::wstring aorii_text::COMMON_ASCII = L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; @@ -23,8 +25,8 @@ 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, const uint32_t in_char_size) : font(nullptr), texture_array(nullptr), - texture_size(in_texture_size), char_size(in_char_size), +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) { } @@ -43,6 +45,7 @@ bool aorii_text::initialize(const wchar_t* in_font_path, const float in_font_pix const std::string font_path_a(in_font_path, in_font_path + wcslen(in_font_path)); font = new stbtt_fontinfo(); + font_pixel_size = in_font_pixel_size; // 加载字体文件 FILE* font_file = nullptr; @@ -53,7 +56,7 @@ bool aorii_text::initialize(const wchar_t* in_font_path, const float in_font_pix } fseek(font_file, 0, SEEK_END); - size_t font_size = ftell(font_file); + const size_t font_size = ftell(font_file); fseek(font_file, 0, SEEK_SET); auto* font_buffer = static_cast(malloc(font_size)); @@ -71,21 +74,25 @@ bool aorii_text::initialize(const wchar_t* in_font_path, const float in_font_pix scale = stbtt_ScaleForPixelHeight(font, in_font_pixel_size); // 获取字体的垂直度量 - int ascent, descent, lineGap; - stbtt_GetFontVMetrics(font, &ascent, &descent, &lineGap); - spdlog::info("Font vertical metrics:\n Ascent: {}, Descent: {}, LineGap: {}", ascent, descent, lineGap); + stbtt_GetFontVMetrics(font, &ascent, &descent, &line_gap); + ascent *= scale; + descent *= scale; + line_gap *= 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 { + // 获取字距调整 + return stbtt_GetCodepointKernAdvance(font, ch1, ch2) * scale; +} + bool aorii_text::create_new_texture_atlas() { - // 每张纹理包含的字符数量 - const uint32_t count_per_texture = (texture_size / char_size) * (texture_size / char_size); - const uint32_t font_count = get_font_char_count(); - // 预计需要的纹理数量 - const uint32_t expected_textures = (font_count + count_per_texture - 1) / count_per_texture; - texture_array = aorii::get_renderer_raw()->create_texture_array(texture_size, texture_size, expected_textures, texture_format::R8_UNORM); + // 预计需要的纹理数量(8张纹理几乎可以容纳所有字符) + constexpr uint32_t expected_textures = 8; + texture_array = aorii::get_renderer_raw()->create_texture_array(texture_size, texture_size, expected_textures, texture_format::R8_UNORM, device_memory_type::gpu); return texture_array != nullptr; } @@ -159,69 +166,76 @@ bool aorii_text::precache_common_characters() { return precache_characters(all_common_chars); } -float aorii_text::get_atlas_utilization() const { - const size_t total_slots = (texture_size / char_size) * (texture_size / char_size) * (1 + current_texture_index); - return static_cast(character_map.size()) / total_slots; -} - 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) { - // Check if we need to move to next row - if (current_x + char_size > texture_size) { - current_x = 0; - current_y += char_size; - } - - // Check if we have room in current texture - if (current_y + char_size > texture_size) { - current_texture_index++; - current_x = 0; - current_y = 0; - } - + // 获取SDF尺寸和位图 int32_t width, height, x_offset, y_offset; - // 生成 SDF - constexpr int padding = 8; // 距离场的扩展范围 - constexpr uint8_t on_edge_value = 128; // 边界处的值(通常为 128) - constexpr float pixel_dist_scale = 64.0f / (float)padding; // 控制距离场的缩放比例 - const auto* sdf_bitmap = stbtt_GetGlyphSDF( - font, // 字体信息 - scale, // 缩放 - glyph_index, // 字形索引 - padding, // 间距 - on_edge_value, // 距离场边界值 - pixel_dist_scale, // 距离缩放 - &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 ); - // Update texture - Eigen::AlignedBox2i box = {}; - box.min().x() = current_x; - box.min().y() = current_y; - box.max().x() = current_x + width; - box.max().y() = current_y + height; + if (!sdf_bitmap) { + throw std::runtime_error("Failed to generate SDF for glyph"); + } + ON_SCOPE_EXIT { + stbtt_FreeSDF(sdf_bitmap, font->userdata); + }; + + // 检查当前行是否有足够空间 + if (current_x + width > texture_size) { + // 移动到下一行 + current_x = 0; + current_y = next_row_y; + } + + // 检查是否需要新的纹理 + 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"); + } + current_x = 0; + current_y = 0; + next_row_y = 0; + } + + // 更新纹理 + Eigen::AlignedBox2i box; + box.min() = Eigen::Vector2i(current_x, current_y); + box.max() = Eigen::Vector2i(current_x + width, current_y + height); texture_array->update_subresource(current_texture_index, box, sdf_bitmap, width); - // 获取字形的水平度量 + // 获取字形度量信息 int advance_width, left_side_bearing; stbtt_GetGlyphHMetrics(font, glyph_index, &advance_width, &left_side_bearing); - // Store character info - character_info info = {}; + // 创建并存储字符信息 + character_info info; info.tex_u = current_x / static_cast(texture_size); info.tex_v = current_y / static_cast(texture_size); - info.tex_z = current_texture_index; info.advance = advance_width * scale; + info.tex_z = static_cast(current_texture_index); info.width = width; info.height = height; - info.offset_x = x_offset; - info.offset_y = y_offset; + info.x_offset = x_offset; + info.y_offset = y_offset; - // Update current position - current_x += char_size; + // 更新位置和下一行的y坐标 + current_x += width; + next_row_y = std::max(next_row_y, current_y + height); return character_map[ch] = info; } diff --git a/src/renderer/core/renderer/renderer_text.h b/src/renderer/core/renderer/renderer_text.h index 855a2d0..94510e6 100644 --- a/src/renderer/core/renderer/renderer_text.h +++ b/src/renderer/core/renderer/renderer_text.h @@ -9,19 +9,19 @@ class renderer_texture_array; struct stbtt_fontinfo; struct character_info { - float tex_u; // X position in texture - float tex_v; // Y position in texture + float tex_u; // U 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 width; // Character width uint8_t height; // Character height - float advance; // Advance width - int8_t offset_x; // Offset from baseline to left - int8_t offset_y; // Offset from baseline to top + int8_t x_offset; // X offset from baseline + int8_t y_offset; // Y offset from baseline }; class aorii_text { public: - aorii_text(uint32_t in_texture_size = 2048, uint32_t in_char_size = 32); + aorii_text(uint32_t in_texture_size = 2048); ~aorii_text(); static bool init_freetype(); @@ -29,6 +29,16 @@ public: 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); + // 上升距离 + [[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]] uint32_t get_texture_size() const { return texture_size; } + // 字体像素大小 + [[nodiscard]] float get_font_pixel_size() const { return font_pixel_size; } // 预缓存一组字符 bool precache_characters(const std::wstring& characters); @@ -38,12 +48,13 @@ public: // 获取缓存状态 [[nodiscard]] size_t get_cached_character_count() const { return character_map.size(); } - [[nodiscard]] float get_atlas_utilization() const; // 获取字体字符数量 [[nodiscard]] uint32_t get_font_char_count() const; [[nodiscard]] renderer_texture_array* get_texture_array() const { return texture_array; } + + 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); @@ -51,10 +62,12 @@ private: renderer_texture_array* texture_array; const uint32_t texture_size; - const uint32_t char_size; + float font_pixel_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 character_map; diff --git a/src/renderer/core/renderer/renderer_texture.h b/src/renderer/core/renderer/renderer_texture.h index e70f70b..7758200 100644 --- a/src/renderer/core/renderer/renderer_texture.h +++ b/src/renderer/core/renderer/renderer_texture.h @@ -21,7 +21,6 @@ public: virtual void* get_shader_resource_view() = 0; [[nodiscard]] texture_format get_format() const { return format; } - static void convert_rgb_to_rgba(const unsigned char* rgb, unsigned char* rgba, int width, int height) { for (int i = 0; i < width * height; ++i) { rgba[i * 4 + 0] = rgb[i * 3 + 0]; // R diff --git a/src/renderer/shader/aorii_sdf_text.slang b/src/renderer/shader/aorii_sdf_text.slang index ed45caa..d2c0f31 100644 --- a/src/renderer/shader/aorii_sdf_text.slang +++ b/src/renderer/shader/aorii_sdf_text.slang @@ -37,10 +37,10 @@ Texture2DArray atlas_texture : register(t0); SamplerState sampler_state : register(s0); float4 pixel_main(PSInput input) : SV_Target { - float2 uv = input.altas_uv + input.uv / 64; + float2 uv = input.altas_uv + input.char_size * input.uv; float distance = atlas_texture.Sample(sampler_state, float3(uv, input.altas_index)).r; // return float4(distance, distance, distance, 1.0); - float alpha = smoothstep(0.49, 0.51, distance); + float alpha = smoothstep(0.47, 0.53, distance); float4 color = input.color; color.a *= alpha;