Extra2D/include/resource/font_atlas.h

179 lines
4.6 KiB
C
Raw Normal View History

#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