修复文本缓存失效
This commit is contained in:
parent
e9909e1c77
commit
0ac8367b43
@ -2,24 +2,17 @@
|
||||
|
||||
#include "interface/image_interface.h"
|
||||
|
||||
glyph_atlas_result_t bitmap_glyph_atlas::get_or_create_glyph(int32_t in_glyph_index,
|
||||
const std::shared_ptr<font_face_interface>& in_font, float in_font_size) {
|
||||
glyph_atlas_result_t bitmap_glyph_atlas::create_glyph(const char_key_t& in_key) {
|
||||
const auto& glyph_index = in_key.glyph_index;
|
||||
const auto& font = in_key.font_face;
|
||||
const auto& font_size = in_key.font_size;
|
||||
|
||||
glyph_atlas_result_t result{};
|
||||
|
||||
// 创建缓存键
|
||||
const auto& cache_key = create_cache_key(in_glyph_index, in_font->get_font_family(), in_font_size);
|
||||
|
||||
// 检查缓存,如果已存在则直接返回
|
||||
auto cached_result = find_in_cache(cache_key);
|
||||
if (cached_result.reason == glyph_atlas_reason_t::success) {
|
||||
return cached_result;
|
||||
}
|
||||
|
||||
in_font->set_font_size(in_font_size);
|
||||
font->set_font_size(font_size);
|
||||
|
||||
// 获取字形的位图数据
|
||||
auto bitmap = in_font->get_glyph_image(in_glyph_index);
|
||||
auto bitmap = font->get_glyph_image(glyph_index);
|
||||
if (!bitmap) {
|
||||
result.reason = glyph_atlas_reason_t::glyph_not_found;
|
||||
return result;
|
||||
@ -36,7 +29,7 @@ glyph_atlas_result_t bitmap_glyph_atlas::get_or_create_glyph(int32_t in_glyph_in
|
||||
atlas_->update_region(bitmap->data, bitmap->get_data_size(), region->rect);
|
||||
|
||||
// 缓存结果以便未来复用
|
||||
add_to_cache(cache_key, *region);
|
||||
add_to_cache(in_key, *region);
|
||||
|
||||
result.reason = glyph_atlas_reason_t::success;
|
||||
result.region = *region;
|
||||
|
@ -26,13 +26,8 @@ public:
|
||||
*
|
||||
* 尝试从缓存中获取字形的纹理区域,如果不存在则从字体中提取位图并添加到图集中。
|
||||
*
|
||||
* @param in_glyph_index 字形的Unicode码点或字体特定索引
|
||||
* @param in_font 用于渲染字形的字体
|
||||
* @param in_font_size 字体大小
|
||||
* @param in_key 字形的键,包含字形索引、字体和字体大小
|
||||
* @return 操作结果,包含成功/失败状态和区域信息
|
||||
*/
|
||||
glyph_atlas_result_t get_or_create_glyph(
|
||||
int32_t in_glyph_index,
|
||||
const std::shared_ptr<font_face_interface>& in_font,
|
||||
float in_font_size);
|
||||
glyph_atlas_result_t create_glyph(const char_key_t& in_key) override;
|
||||
};
|
||||
|
@ -2,24 +2,19 @@
|
||||
|
||||
#include "interface/image_interface.h"
|
||||
|
||||
glyph_atlas_result_t color_emoji_atlas::get_or_create_emoji(int32_t in_glyph_index,
|
||||
const std::shared_ptr<font_face_interface>& in_font, float in_font_size) {
|
||||
glyph_atlas_result_t color_emoji_atlas::create_glyph(const char_key_t& in_key) {
|
||||
const auto& glyph_index = in_key.glyph_index;
|
||||
const auto& font = in_key.font_face;
|
||||
const auto& font_size = in_key.font_size;
|
||||
|
||||
glyph_atlas_result_t result{};
|
||||
if (!font->supports_color_emoji())
|
||||
return result;
|
||||
|
||||
// 创建缓存键
|
||||
const auto& cache_key = create_cache_key(in_glyph_index, in_font->get_font_family(), in_font_size);
|
||||
|
||||
// 检查缓存
|
||||
auto cached_result = find_in_cache(cache_key);
|
||||
if (cached_result.reason == glyph_atlas_reason_t::success) {
|
||||
return cached_result;
|
||||
}
|
||||
|
||||
in_font->set_font_size(in_font_size);
|
||||
font->set_font_size(font_size);
|
||||
|
||||
// 获取彩色表情位图
|
||||
auto bitmap = in_font->get_emoji_image(in_glyph_index);
|
||||
auto bitmap = font->get_emoji_image(glyph_index);
|
||||
if (!bitmap) {
|
||||
result.reason = glyph_atlas_reason_t::glyph_not_found;
|
||||
return result;
|
||||
@ -36,7 +31,7 @@ glyph_atlas_result_t color_emoji_atlas::get_or_create_emoji(int32_t in_glyph_ind
|
||||
atlas_->update_region(bitmap->data, bitmap->get_data_size(), region->rect);
|
||||
|
||||
// 缓存结果以便未来复用
|
||||
add_to_cache(cache_key, *region);
|
||||
add_to_cache(in_key, *region);
|
||||
|
||||
result.reason = glyph_atlas_reason_t::success;
|
||||
result.region = *region;
|
||||
|
@ -22,17 +22,12 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取或创建表情符号的纹理区域
|
||||
* @brief 获取或创建字形的纹理区域
|
||||
*
|
||||
* 尝试从缓存中获取表情符号的纹理区域,如果不存在则从字体中提取位图并添加到图集中。
|
||||
* 尝试从缓存中获取字形的纹理区域,如果不存在则从字体中提取位图并添加到图集中。
|
||||
*
|
||||
* @param in_glyph_index 表情符号的码点或字体特定索引
|
||||
* @param in_font 用于渲染表情符号的字体
|
||||
* @param in_font_size 字体大小
|
||||
* @param in_key 字形的键,包含字形索引、字体和字体大小
|
||||
* @return 操作结果,包含成功/失败状态和区域信息
|
||||
*/
|
||||
glyph_atlas_result_t get_or_create_emoji(
|
||||
int32_t in_glyph_index,
|
||||
const std::shared_ptr<font_face_interface>& in_font,
|
||||
float in_font_size);
|
||||
glyph_atlas_result_t create_glyph(const char_key_t& in_key) override;
|
||||
};
|
||||
|
9
src/mirage_render/src/font/atlas/font_atlas.cpp
Normal file
9
src/mirage_render/src/font/atlas/font_atlas.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "font_atlas.h"
|
||||
|
||||
#include "interface/font_interface.h"
|
||||
|
||||
char_key_t::char_key_t(uint32_t in_glyph_index, const std::shared_ptr<font_face_interface>& in_font_face,
|
||||
float in_font_size):
|
||||
glyph_index(in_glyph_index),
|
||||
font_face(in_font_face),
|
||||
font_size(in_font_size) {}
|
@ -1,14 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <Eigen/Eigen>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "texture/atlas/texture2d_atlas.h"
|
||||
|
||||
class font_face_interface;
|
||||
/**
|
||||
* @enum glyph_atlas_reason_t
|
||||
* @brief 图集操作结果原因枚举
|
||||
@ -33,6 +29,34 @@ struct glyph_atlas_result_t {
|
||||
atlas_region_t region; ///< 分配的区域信息(仅当操作成功时有效)
|
||||
};
|
||||
|
||||
struct char_key_t {
|
||||
uint32_t glyph_index;
|
||||
std::shared_ptr<font_face_interface> font_face;
|
||||
float font_size;
|
||||
|
||||
char_key_t(uint32_t in_glyph_index, const std::shared_ptr<font_face_interface>& in_font_face, float in_font_size);
|
||||
|
||||
bool operator==(const char_key_t& other) const {
|
||||
// Implement comparison logic. Might involve comparing font pointers
|
||||
// or font identifiers, glyph_id, and font_size.
|
||||
// Be careful comparing floats directly.
|
||||
return glyph_index == other.glyph_index &&
|
||||
font_face == other.font_face && // Simple pointer comparison, might need deeper check
|
||||
std::abs(font_size - other.font_size) < 1e-6; // Epsilon comparison for float
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct std::hash<char_key_t> {
|
||||
size_t operator()(const char_key_t& in_key) const {
|
||||
std::hash<uint32_t> hash_fn;
|
||||
size_t hash = hash_fn(in_key.glyph_index);
|
||||
hash ^= (uint64_t)in_key.font_face.get();
|
||||
hash ^= std::hash<float>{}(in_key.font_size);
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class atlas_base
|
||||
* @brief 字形图集管理基类
|
||||
@ -43,22 +67,7 @@ struct glyph_atlas_result_t {
|
||||
class atlas_base {
|
||||
protected:
|
||||
std::shared_ptr<texture2d_atlas> atlas_; ///< 底层纹理图集对象
|
||||
std::unordered_map<std::string, atlas_region_t> cached_regions_; ///< 已缓存的区域映射表
|
||||
|
||||
/**
|
||||
* @brief 为字形创建唯一的缓存键
|
||||
*
|
||||
* @param in_glyph_index 字形的Unicode码点或字体特定索引
|
||||
* @param in_font_name 字体名称
|
||||
* @param in_font_size 字体大小
|
||||
* @return 唯一标识字形的缓存键字符串
|
||||
*/
|
||||
static std::string create_cache_key(uint32_t in_glyph_index, const std::string& in_font_name, float in_font_size) {
|
||||
std::stringstream ss;
|
||||
ss << std::hex << in_glyph_index << "_" << in_font_name << "_" << std::fixed
|
||||
<< std::setprecision(1) << in_font_size;
|
||||
return ss.str();
|
||||
}
|
||||
std::unordered_map<char_key_t, atlas_region_t> cached_regions_; ///< 已缓存的区域映射表
|
||||
|
||||
/**
|
||||
* @brief 初始化底层纹理图集
|
||||
@ -77,31 +86,13 @@ protected:
|
||||
return atlas_ != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从缓存中查找字形区域
|
||||
*
|
||||
* @param in_cache_key 缓存键
|
||||
* @return 查找结果,包含成功/失败状态和区域信息
|
||||
*/
|
||||
glyph_atlas_result_t find_in_cache(const std::string& in_cache_key) {
|
||||
glyph_atlas_result_t result{};
|
||||
|
||||
auto it = cached_regions_.find(in_cache_key);
|
||||
if (it != cached_regions_.end()) {
|
||||
result.reason = glyph_atlas_reason_t::success;
|
||||
result.region = it->second;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将区域信息添加到缓存
|
||||
*
|
||||
* @param in_cache_key 缓存键
|
||||
* @param in_region 要缓存的区域
|
||||
*/
|
||||
void add_to_cache(const std::string& in_cache_key, const atlas_region_t& in_region) {
|
||||
void add_to_cache(const char_key_t& in_cache_key, const atlas_region_t& in_region) {
|
||||
cached_regions_[in_cache_key] = in_region;
|
||||
}
|
||||
|
||||
@ -145,4 +136,32 @@ public:
|
||||
void clear_cache() {
|
||||
cached_regions_.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 从缓存中查找字形区域
|
||||
*
|
||||
* @param in_cache_key 缓存键
|
||||
* @return 查找结果,包含成功/失败状态和区域信息
|
||||
*/
|
||||
glyph_atlas_result_t find_in_cache(const char_key_t& in_cache_key) {
|
||||
glyph_atlas_result_t result{};
|
||||
|
||||
auto it = cached_regions_.find(in_cache_key);
|
||||
if (it != cached_regions_.end()) {
|
||||
result.reason = glyph_atlas_reason_t::success;
|
||||
result.region = it->second;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取或创建字形的纹理区域
|
||||
*
|
||||
* 尝试从缓存中获取字形的纹理区域,如果不存在则从字体中提取位图并添加到图集中。
|
||||
*
|
||||
* @param in_key 字形的键,包含字形索引、字体和字体大小
|
||||
* @return 操作结果,包含成功/失败状态和区域信息
|
||||
*/
|
||||
virtual glyph_atlas_result_t create_glyph(const char_key_t& in_key) = 0;
|
||||
};
|
||||
|
@ -1,54 +1,91 @@
|
||||
#include "font_atlas_manager.h"
|
||||
|
||||
std::optional<atlas_region_t> font_atlas_manager::get_or_create_glyph(
|
||||
int32_t in_glyph_id,
|
||||
const std::shared_ptr<font_face_interface>& in_font,
|
||||
float in_font_size,
|
||||
bool is_emoji)
|
||||
{
|
||||
int32_t in_glyph_id,
|
||||
const std::shared_ptr<font_face_interface>& in_font,
|
||||
float in_font_size,
|
||||
bool is_emoji) {
|
||||
glyph_atlas_result_t result{};
|
||||
result.reason = glyph_atlas_reason_t::atlas_full;
|
||||
// 初始化原因,循环/创建尝试会更新它
|
||||
result.reason = glyph_atlas_reason_t::unknown; // 默认为失败
|
||||
|
||||
char_key_t key(in_glyph_id, in_font, in_font_size);
|
||||
|
||||
// **处理表情符号**
|
||||
if (is_emoji) {
|
||||
// 尝试从现有表情图集中获取
|
||||
// **1. 尝试在现有表情符号图集中查找**
|
||||
for (auto& atlas : emoji_atlases_) {
|
||||
result = atlas.get_or_create_emoji(in_glyph_id, in_font, in_font_size);
|
||||
if (result.reason == glyph_atlas_reason_t::success) {
|
||||
return result.region;
|
||||
glyph_atlas_result_t find_result = atlas.find_in_cache(key);
|
||||
if (find_result.reason == glyph_atlas_reason_t::success) {
|
||||
return find_result.region; // 找到了!
|
||||
}
|
||||
}
|
||||
|
||||
// 如果所有现有图集都已满,创建新的表情图集
|
||||
// **2. 尝试在当前表情符号图集中创建**
|
||||
if (!emoji_atlases_.empty() && current_emoji_atlas_ < emoji_atlases_.size()) {
|
||||
result = emoji_atlases_[current_emoji_atlas_].create_glyph(key);
|
||||
if (result.reason == glyph_atlas_reason_t::success) {
|
||||
return result.region;
|
||||
}
|
||||
} else {
|
||||
result.reason = glyph_atlas_reason_t::atlas_full; // 模拟已满以触发创建
|
||||
}
|
||||
|
||||
// **3. 如果当前表情符号图集已满(或不存在),创建一个新图集**
|
||||
if (result.reason == glyph_atlas_reason_t::atlas_full) {
|
||||
auto& atlas = create_new_emoji_atlas();
|
||||
result = atlas.get_or_create_emoji(in_glyph_id, in_font, in_font_size);
|
||||
const Eigen::Vector2i new_atlas_size = { 2048, 2048 }; // 示例大小
|
||||
|
||||
// 创建新的表情符号图集
|
||||
create_new_emoji_atlas(new_atlas_size);
|
||||
|
||||
// 更新当前表情符号图集索引为新创建的图集
|
||||
current_emoji_atlas_ = emoji_atlases_.size() - 1;
|
||||
|
||||
// 尝试在新图集中创建字形
|
||||
result = emoji_atlases_[current_emoji_atlas_].create_glyph(key);
|
||||
|
||||
if (result.reason == glyph_atlas_reason_t::success) {
|
||||
return result.region;
|
||||
}
|
||||
}
|
||||
}
|
||||
// **处理普通字形**
|
||||
else {
|
||||
// 尝试从现有字形图集中获取
|
||||
} else { // 普通字形(非表情符号)
|
||||
// **1. 尝试在现有字形图集中查找**
|
||||
for (auto& atlas : glyph_atlases_) {
|
||||
result = atlas.get_or_create_glyph(in_glyph_id, in_font, in_font_size);
|
||||
if (result.reason == glyph_atlas_reason_t::success) {
|
||||
return result.region;
|
||||
glyph_atlas_result_t find_result = atlas.find_in_cache(key);
|
||||
if (find_result.reason == glyph_atlas_reason_t::success) {
|
||||
return find_result.region; // 找到了!
|
||||
}
|
||||
}
|
||||
|
||||
// 如果所有现有图集都已满,创建新的字形图集
|
||||
// **2. 尝试在当前字形图集中创建**
|
||||
if (!glyph_atlases_.empty() && current_glyph_atlas_ < glyph_atlases_.size()) {
|
||||
result = glyph_atlases_[current_glyph_atlas_].create_glyph(key);
|
||||
if (result.reason == glyph_atlas_reason_t::success) {
|
||||
return result.region;
|
||||
}
|
||||
} else {
|
||||
result.reason = glyph_atlas_reason_t::atlas_full; // 模拟已满以触发创建
|
||||
}
|
||||
|
||||
// **3. 如果当前字形图集已满(或不存在),创建一个新图集**
|
||||
if (result.reason == glyph_atlas_reason_t::atlas_full) {
|
||||
auto& atlas = create_new_glyph_atlas();
|
||||
result = atlas.get_or_create_glyph(in_glyph_id, in_font, in_font_size);
|
||||
const Eigen::Vector2i new_atlas_size = { 2048, 2048}; // 示例大小
|
||||
|
||||
// 创建新的字形图集
|
||||
create_new_glyph_atlas(new_atlas_size);
|
||||
|
||||
// 更新当前字形图集索引为新创建的图集
|
||||
current_glyph_atlas_ = glyph_atlases_.size() - 1;
|
||||
|
||||
// 尝试在新图集中创建字形
|
||||
result = glyph_atlases_[current_glyph_atlas_].create_glyph(key);
|
||||
|
||||
if (result.reason == glyph_atlas_reason_t::success) {
|
||||
return result.region;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果所有尝试都失败,返回空
|
||||
// **4. 如果所有尝试都失败,返回nullopt**
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
@ -59,8 +59,10 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<bitmap_glyph_atlas> glyph_atlases_; ///< 普通字形图集列表
|
||||
std::vector<color_emoji_atlas> emoji_atlases_; ///< 表情符号图集列表
|
||||
std::vector<bitmap_glyph_atlas> glyph_atlases_; ///< 普通字形图集列表
|
||||
std::vector<color_emoji_atlas> emoji_atlases_; ///< 表情符号图集列表
|
||||
int32_t current_glyph_atlas_ = 0; ///< 当前字形图集索引
|
||||
int32_t current_emoji_atlas_ = 0; ///< 当前表情图集索引
|
||||
|
||||
/**
|
||||
* @brief 创建新的字形图集
|
||||
|
@ -40,6 +40,7 @@ public:
|
||||
|
||||
[[nodiscard]] virtual std::string get_font_family() const = 0;
|
||||
[[nodiscard]] virtual std::string get_font_style() const = 0;
|
||||
[[nodiscard]] uint64_t get_key() const { return reinterpret_cast<uint64_t>(this); }
|
||||
|
||||
[[nodiscard]] virtual bool supports_color_emoji() const = 0;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "widget/panel_widget/mbox.h"
|
||||
|
||||
mbutton::mbutton() {
|
||||
color_ = {0.1, 0.1, 0.1, 1};
|
||||
color_ = {0.2, 0.2, 0.2, 1};
|
||||
slot_.h_alignment(horizontal_alignment_t::center);
|
||||
slot_.v_alignment(vertical_alignment_t::center);
|
||||
}
|
||||
@ -30,32 +30,20 @@ void mbutton::on_paint(mirage_paint_context& in_context) {
|
||||
void mbutton::on_click(const Eigen::Vector2f& in_position, mouse_button in_button) {
|
||||
mborder::on_click(in_position, in_button);
|
||||
std::cout << this << ": Button clicked!" << in_position.x() << ", " << in_position.y() << std::endl;
|
||||
color_ = {0, 0, 1, 1};
|
||||
// const auto& parent = get_parent();
|
||||
// if (std::shared_ptr<mh_box> hbox = std::dynamic_pointer_cast<mh_box>(parent)) {
|
||||
// hbox->add_child<mbutton>()
|
||||
// .stretch()
|
||||
// .margin({ 5 });
|
||||
// }
|
||||
// if (std::shared_ptr<mv_box> vbox = std::dynamic_pointer_cast<mv_box>(parent)) {
|
||||
// vbox->add_child<mbutton>()
|
||||
// .stretch()
|
||||
// .margin({ 5 });
|
||||
// }
|
||||
color_ = {0.2, 0.2, 0.2, 1};
|
||||
invalidate(invalidate_reason::paint);
|
||||
}
|
||||
|
||||
void mbutton::on_double_click(const Eigen::Vector2f& in_position, mouse_button in_button) {
|
||||
mborder::on_double_click(in_position, in_button);
|
||||
std::cout << this << ": Button double clicked!" << in_position.x() << ", " << in_position.y() << std::endl;
|
||||
color_ = {1, 1, 1, 1};
|
||||
invalidate(invalidate_reason::paint);
|
||||
}
|
||||
|
||||
void mbutton::on_mouse_enter() {
|
||||
mborder::on_mouse_enter();
|
||||
std::cout << this << ": Mouse entered!" << std::endl;
|
||||
color_ = {0, 1, 0, 1};
|
||||
color_ = {0.2, 0.2, 0.2, 1};
|
||||
invalidate(invalidate_reason::paint);
|
||||
}
|
||||
|
||||
@ -69,7 +57,7 @@ void mbutton::on_mouse_leave() {
|
||||
hit_test_handle mbutton::on_mouse_button_down(const Eigen::Vector2f& in_position, mouse_button in_button) {
|
||||
mborder::on_mouse_button_down(in_position, in_button);
|
||||
std::cout << this << ": Mouse pressed!" << in_position.x() << ", " << in_position.y() << std::endl;
|
||||
color_ = {0, 0, 1, 1};
|
||||
color_ = {0.1, 0.1, 0.1, 1};
|
||||
invalidate(invalidate_reason::paint);
|
||||
return hit_test_handle::handled();
|
||||
}
|
||||
@ -77,7 +65,7 @@ hit_test_handle mbutton::on_mouse_button_down(const Eigen::Vector2f& in_position
|
||||
hit_test_handle mbutton::on_mouse_button_up(const Eigen::Vector2f& in_position, mouse_button in_button) {
|
||||
mborder::on_mouse_button_up(in_position, in_button);
|
||||
std::cout << this << ": Mouse released!" << in_position.x() << ", " << in_position.y() << std::endl;
|
||||
color_ = {1, 0, 0, 1};
|
||||
color_ = {0.2, 0.2, 0.2, 1};
|
||||
invalidate(invalidate_reason::paint);
|
||||
return hit_test_handle::handled();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user