179 lines
4.6 KiB
C
179 lines
4.6 KiB
C
|
|
#pragma once
|
|||
|
|
|
|||
|
|
#include <resource/resource.h>
|
|||
|
|
#include <resource/texture.h>
|
|||
|
|
#include <types/math/vec2.h>
|
|||
|
|
#include <types/base/types.h>
|
|||
|
|
#include <types/ptr/intrusive_ptr.h>
|
|||
|
|
#include <unordered_map>
|
|||
|
|
#include <vector>
|
|||
|
|
#include <memory>
|
|||
|
|
|
|||
|
|
// STB 矩形打包
|
|||
|
|
#include <stb/stb_rect_pack.h>
|
|||
|
|
|
|||
|
|
namespace extra2d {
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 字符信息结构
|
|||
|
|
*/
|
|||
|
|
struct GlyphInfo {
|
|||
|
|
Vec2 uv0; // 左下角 UV 坐标
|
|||
|
|
Vec2 uv1; // 右上角 UV 坐标
|
|||
|
|
Vec2 size; // 像素尺寸
|
|||
|
|
Vec2 bearing; // 基线偏移(左下角相对原点的偏移)
|
|||
|
|
float advance; // 水平步进(到下一个字符的距离)
|
|||
|
|
uint32 pageIndex; // 所在图集页索引
|
|||
|
|
bool valid = false; // 是否有效
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 图集页结构
|
|||
|
|
*
|
|||
|
|
* 使用 stb_rect_pack 进行矩形打包
|
|||
|
|
*/
|
|||
|
|
struct AtlasPage {
|
|||
|
|
static constexpr uint32 DEFAULT_SIZE = 1024; // 默认图集尺寸
|
|||
|
|
|
|||
|
|
Ptr<Texture> texture; // 纹理
|
|||
|
|
stbrp_context packContext; // 打包上下文
|
|||
|
|
std::vector<stbrp_node> packNodes; // 打包节点数组
|
|||
|
|
std::vector<uint8> pixelData; // CPU 端像素数据
|
|||
|
|
uint32 width = DEFAULT_SIZE; // 图集宽度
|
|||
|
|
uint32 height = DEFAULT_SIZE; // 图集高度
|
|||
|
|
bool dirty = false; // 是否需要更新 GPU 纹理
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 构造函数
|
|||
|
|
*/
|
|||
|
|
AtlasPage();
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 初始化图集页
|
|||
|
|
* @param size 图集尺寸
|
|||
|
|
* @return 是否初始化成功
|
|||
|
|
*/
|
|||
|
|
bool init(uint32 size);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 打包矩形到图集
|
|||
|
|
* @param width 矩形宽度
|
|||
|
|
* @param height 矩形高度
|
|||
|
|
* @param outX 输出 X 坐标
|
|||
|
|
* @param outY 输出 Y 坐标
|
|||
|
|
* @return 是否打包成功
|
|||
|
|
*/
|
|||
|
|
bool packRect(uint32 width, uint32 height, uint32& outX, uint32& outY);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 写入像素数据到图集
|
|||
|
|
* @param x 起始 X 坐标
|
|||
|
|
* @param y 起始 Y 坐标
|
|||
|
|
* @param width 宽度
|
|||
|
|
* @param height 高度
|
|||
|
|
* @param data 像素数据(单通道)
|
|||
|
|
*/
|
|||
|
|
void writePixels(uint32 x, uint32 y, uint32 width, uint32 height, const uint8* data);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 更新 GPU 纹理
|
|||
|
|
*/
|
|||
|
|
void updateTexture();
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 清空图集
|
|||
|
|
*/
|
|||
|
|
void clear();
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 字体图集类
|
|||
|
|
*
|
|||
|
|
* 管理动态字符图集,支持多页扩展
|
|||
|
|
*/
|
|||
|
|
class FontAtlas : public Resource {
|
|||
|
|
public:
|
|||
|
|
FontAtlas();
|
|||
|
|
~FontAtlas() override;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 获取资源类型
|
|||
|
|
*/
|
|||
|
|
ResourceType getType() const override { return ResourceType::FontAtlas; }
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 初始化字体图集
|
|||
|
|
* @param pageSize 图集页尺寸
|
|||
|
|
* @return 是否初始化成功
|
|||
|
|
*/
|
|||
|
|
bool init(uint32 pageSize = AtlasPage::DEFAULT_SIZE);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 添加字符到图集
|
|||
|
|
* @param codepoint Unicode 码点
|
|||
|
|
* @param bitmap 字符位图数据(单通道)
|
|||
|
|
* @param width 位图宽度
|
|||
|
|
* @param height 位图高度
|
|||
|
|
* @param bearingX 水平基线偏移
|
|||
|
|
* @param bearingY 垂直基线偏移
|
|||
|
|
* @param advance 水平步进
|
|||
|
|
* @return 是否添加成功
|
|||
|
|
*/
|
|||
|
|
bool addGlyph(uint32 codepoint, const uint8* bitmap, uint32 width, uint32 height,
|
|||
|
|
float bearingX, float bearingY, float advance);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 获取字符信息
|
|||
|
|
* @param codepoint Unicode 码点
|
|||
|
|
* @return 字符信息指针,如果不存在返回 nullptr
|
|||
|
|
*/
|
|||
|
|
const GlyphInfo* getGlyph(uint32 codepoint) const;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 检查字符是否已缓存
|
|||
|
|
* @param codepoint Unicode 码点
|
|||
|
|
* @return 是否已缓存
|
|||
|
|
*/
|
|||
|
|
bool hasGlyph(uint32 codepoint) const;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 获取图集页数量
|
|||
|
|
*/
|
|||
|
|
uint32 getPageCount() const { return static_cast<uint32>(pages_.size()); }
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 获取指定页的纹理
|
|||
|
|
* @param pageIndex 页索引
|
|||
|
|
* @return 纹理指针
|
|||
|
|
*/
|
|||
|
|
Texture* getPageTexture(uint32 pageIndex) const;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 更新所有需要更新的图集页纹理
|
|||
|
|
*/
|
|||
|
|
void updateTextures();
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 清空所有图集
|
|||
|
|
*/
|
|||
|
|
void clear();
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 获取图集页尺寸
|
|||
|
|
*/
|
|||
|
|
uint32 getPageSize() const { return pageSize_; }
|
|||
|
|
|
|||
|
|
private:
|
|||
|
|
std::vector<std::unique_ptr<AtlasPage>> pages_; // 图集页数组
|
|||
|
|
std::unordered_map<uint32, GlyphInfo> glyphs_; // 字符信息映射表
|
|||
|
|
uint32 pageSize_ = AtlasPage::DEFAULT_SIZE; // 图集页尺寸
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @brief 获取或创建可用的图集页
|
|||
|
|
* @return 图集页指针
|
|||
|
|
*/
|
|||
|
|
AtlasPage* getOrCreatePage();
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
} // namespace extra2d
|