Extra2D/include/resource/font.h

175 lines
5.1 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <resource/resource.h>
#include <resource/font_atlas.h>
#include <types/math/vec2.h>
#include <types/base/types.h>
#include <string>
#include <vector>
// FreeType 头文件
#include <ft2build.h>
#include FT_FREETYPE_H
namespace extra2d {
/**
* @brief 常用字符集
*/
namespace CommonCharset {
// ASCII 可打印字符
constexpr const char* ASCII =
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
"`abcdefghijklmnopqrstuvwxyz{|}~";
// 常用中文前100个高频字
constexpr const char* CHINESE_COMMON =
"的一是在不了有和人这中大为上个国我以要他时来用们生到作地于出就分对成"
"会可主发年动同工也能下过子说产种面而方后多定行学法所民得经十三之进着"
"等部度家电力里如水化高自二理起小物现实加量都两体制机当使点从业本去把";
// 英文标点
constexpr const char* PUNCTUATION_EN = ".,;:!?-'\"()[]{}/|\\@#$%&*+-_=<>~`";
// 中文标点
constexpr const char* PUNCTUATION_CN = ",。、;:!?\"\"''()【】《》";
}
/**
* @brief 字体配置结构
*/
struct FontConfig {
uint32 fontSize = 16; // 字体大小(像素)
bool useSDF = false; // 是否使用 SDF有向距离场
uint32 sdfPadding = 4; // SDF 边距
bool preloadCommon = true; // 是否预加载常用字符
bool hinting = true; // 是否使用字体 hinting
};
/**
* @brief 字体资源类
*
* 使用 FreeType 加载字体,动态生成字符图集
*/
class Font : public Resource {
public:
Font();
~Font() override;
/**
* @brief 获取资源类型
*/
ResourceType getType() const override { return ResourceType::Font; }
/**
* @brief 从文件加载字体
* @param path 字体文件路径
* @param config 字体配置
* @return 是否加载成功
*/
bool loadFromFile(const std::string& path, const FontConfig& config);
/**
* @brief 从内存加载字体
* @param data 字体数据
* @param config 字体配置
* @return 是否加载成功
*/
bool loadFromMemory(const std::vector<uint8>& data, const FontConfig& config);
/**
* @brief 获取或创建字符
* @param codepoint Unicode 码点
* @return 字符信息指针,如果失败返回 nullptr
*/
const GlyphInfo* getGlyph(uint32 codepoint);
/**
* @brief 测量文本尺寸
* @param text 文本内容
* @param fontSize 字体大小0 表示使用默认大小)
* @return 文本尺寸(宽度和高度)
*/
Vec2 measureText(const std::string& text, float fontSize = 0.0f);
/**
* @brief 获取两个字之间的字距
* @param codepoint1 第一个字符
* @param codepoint2 第二个字符
* @return 字距调整值
*/
float getKerning(uint32 codepoint1, uint32 codepoint2);
/**
* @brief 获取行高
* @param fontSize 字体大小0 表示使用默认大小)
* @return 行高
*/
float getLineHeight(float fontSize = 0.0f) const;
/**
* @brief 获取字体图集
*/
FontAtlas* getAtlas() const { return atlas_.get(); }
/**
* @brief 预加载字符集
* @param charset 字符集字符串
*/
void preloadCharset(const std::string& charset);
/**
* @brief 获取字体配置
*/
const FontConfig& getConfig() const { return config_; }
/**
* @brief 获取字体度量信息
* @param outAscender 输出上升高度
* @param outDescender 输出下降高度
* @param outLineHeight 输出行高
*/
void getMetrics(float& outAscender, float& outDescender, float& outLineHeight) const;
private:
FT_Face face_ = nullptr; // FreeType 字体面
FontConfig config_; // 字体配置
Ptr<FontAtlas> atlas_; // 字体图集
float baseScale_ = 1.0f; // 基础缩放比例
std::vector<uint8> fontData_; // 字体数据(保持内存中)
// FreeType 库静态实例
static FT_Library ftLibrary_;
static bool ftInitialized_;
/**
* @brief 初始化 FreeType 库
*/
static bool initFreeType();
/**
* @brief 渲染字符到位图
* @param codepoint Unicode 码点
* @param outWidth 输出宽度
* @param outHeight 输出高度
* @param outBearingX 输出水平基线偏移
* @param outBearingY 输出垂直基线偏移
* @param outAdvance 输出水平步进
* @param outBitmap 输出位图数据
* @return 是否渲染成功
*/
bool renderGlyph(uint32 codepoint, uint32& outWidth, uint32& outHeight,
float& outBearingX, float& outBearingY, float& outAdvance,
std::vector<uint8>& outBitmap);
/**
* @brief 将 UTF-8 字符串转换为 Unicode 码点数组
* @param text UTF-8 字符串
* @return Unicode 码点数组
*/
static std::vector<uint32> utf8ToCodepoints(const std::string& text);
};
} // namespace extra2d