Chapter 87 · 字体与文本

字形查询与光栅化

GlyphGet 获取单个字形的度量信息,GlyphRasterize 将字形渲染为位图。

87

API 速查

函数说明
int xgeFontGlyphGet(xge_font pFont, uint32_t iCodepoint, xge_glyph_metrics_t* pMetrics)按码点获取字形度量
int xgeFontGlyphGetByIndex(xge_font pFont, int iGlyph, xge_glyph_metrics_t* pMetrics)按索引获取
int xgeFontGlyphRasterize(xge_font pFont, uint32_t iCodepoint, xge_glyph_bitmap_t* pBitmap)光栅化为位图
int xgeFontGlyphAtlasGet(xge_font pFont, uint32_t iCodepoint, xge_glyph_t* pGlyph)从图集获取
void xgeGlyphBitmapFree(xge_glyph_bitmap_t* pBitmap)释放位图

编译本章示例

gcc -O2 -I. -o ch87.exe ch87_main.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch87.exe

示例:获取字形信息

xge_font font = NULL;
xgeFontLoad(&font, "Roboto.ttf", 32.0f);

// 获取 'A' 的字形度量
xge_glyph_metrics_t gm;
xgeFontGlyphGet(font, 'A', &gm);
// gm.fAdvanceX — 水平步进
// gm.fBearingX/Y —  bearing 偏移
// gm.fWidth/Height — 字形尺寸

// 光栅化为位图(CPU 访问)
xge_glyph_bitmap_t bmp;
xgeFontGlyphRasterize(font, 'A', &bmp);
// bmp.pPixels — 灰度像素数据
// bmp.iWidth/iHeight — 尺寸
xgeGlyphBitmapFree(&bmp);

// 从 GPU 图集获取(用于自定义渲染)
xge_glyph_t glyph;
xgeFontGlyphAtlasGet(font, 'A', &glyph);
// glyph.tUV — 纹理坐标

完整代码

将以下代码保存为 ch87_main.c,编译后运行即可看到字形度量与光栅化效果:

#include "xge.h"
#include <stdio.h>

static xge_font g_font = NULL;

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x081114FF);

    // 获取 'A' 的字形度量
    xge_glyph_metrics_t gm;
    xgeFontGlyphGet(g_font, 'A', &gm);

    // 在屏幕上显示度量信息
    char buf[256];
    sprintf(buf, "AdvanceX=%.1f Bearing=(%.1f,%.1f) Size=(%.1f,%.1f)",
        gm.fAdvanceX, gm.fBearingX, gm.fBearingY,
        gm.fWidth, gm.fHeight);
    xgeTextDraw(g_font, buf, 20.0f, 20.0f, 0xFFFFFFFF)

    // 光栅化 'A' 为位图并绘制
    xge_glyph_bitmap_t bmp;
    if (xgeFontGlyphRasterize(g_font, 'A', &bmp) == XGE_OK) {
        // 将灰度位图作为纹理绘制(放大显示)
        xge_texture tex = NULL;
        /* 字形 A8 掩码展开为 RGBA 后上传 */
        xgeTextureCreateRGBA(&tex, bmp.iWidth, bmp.iHeight, pRGBA);
        if (img) {
            xgeDraw(tex, 20.0f, 60.0f);
            xgeImageFree(img);
        }
        xgeGlyphBitmapFree(&bmp);
    }

    // 从 GPU 图集获取(用于自定义渲染管线)
    xge_glyph_t glyph;
    xgeFontGlyphAtlasGet(g_font, 'B', &glyph);
    sprintf(buf, "Atlas UV: (%.3f,%.3f)-(%.3f,%.3f)",
        glyph.tUV.x, glyph.tUV.y, glyph.tUV.z, glyph.tUV.w);
    xgeTextDraw(g_font, buf, 20.0f, 300.0f, 0xFFFFFFFF)

    return XGE_OK;
}

int main(void) {
    xge_desc_t d = {0};
    d.iWidth  = 800;
    d.iHeight = 600;
    d.sTitle  = "ch87 - Glyph Metrics & Rasterize";
    d.iFlags  = XGE_INIT_VSYNC;
    xgeInit(&d);

    xgeFontLoad(&g_font, "Roboto.ttf", 32.0f);

    xgeRun(onFrame, NULL);

    xgeFontFree(g_font);
    xgeUnit();
    return 0;
}

代码讲解

  • GlyphGet:按 Unicode 码点获取字形度量(advance、bearing、尺寸),用于精确排版计算。
  • GlyphRasterize:将字形光栅化为 CPU 灰度位图,可访问像素数据做自定义处理,用完必须 Free。
  • GlyphAtlasGet:从 GPU 纹理图集获取字形 UV 坐标,适合自定义渲染管线直接采样。
  • 放大绘制:将小尺寸位图放大 4 倍显示,便于观察字形轮廓细节。

要点与陷阱

  • GlyphGet vs AtlasGet:前者返回度量,后者返回 GPU 纹理坐标。
  • Rasterize:返回 CPU 位图,需手动 Free。
  • 码点 vs 索引:码点是 Unicode,索引是字体内部编号。
  • 缓存:AtlasGet 自动缓存到 GPU 图集。

进阶练习

  1. 实现字形查看器:显示任意字符的位图和度量。
  2. 自定义字形渲染:用 AtlasGet + 自定义 shader。
字形查询与光栅化效果
图:字形查询与光栅化渲染效果