Chapter 107 · 精灵批处理与九宫格

九宫格绘制

NinePatch 将纹理分为 9 个区域,四角不变、边缘拉伸、中心平铺,实现任意尺寸的 UI 面板/按钮。

107

概念

九宫格(9-Patch / Nine-Patch)是 UI 开发的核心技术: 将一张小纹理拉伸到任意尺寸,同时保持圆角和边框不变形。 XGE 支持两种初始化方式:Simple(自动三分)和手动指定切割线。

API 速查

函数说明
void xgeNinePatchInitSimple(xge_nine_patch pPatch, xge_texture pTexture, xge_rect_t tSrc)简单初始化(均分)
void xgeNinePatchInit(xge_nine_patch pPatch, xge_texture pTexture, xge_rect_t tSrc, float fX1, float fY1, float fX2, float fY2)指定切割线
void xgeNinePatchSetMode(xge_nine_patch pPatch, int iMode)设置拉伸/平铺模式
void xgeNinePatchSetColor(xge_nine_patch pPatch, uint32_t iColor)设置染色
void xgeNinePatchDraw(const xge_nine_patch_t* pPatch, xge_rect_t tDst, uint32_t iFlags)绘制到目标矩形

编译本章示例

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

示例:UI 面板背景

// 加载按钮纹理
xge_texture_t btnTex;
xgeTextureLoad(&btnTex, "ui/button.png");

// 初始化九宫格(切割线:左边 8px,上边 8px,
//   右边距右 8px,下边距下 8px)
xge_nine_patch_t patch;
xgeNinePatchInit(&patch, &btnTex,
    (xge_rect_t){ 0, 0, 32, 32 },
    8, 8, 24, 24);

// 绘制不同大小的按钮(圆角不变形)
xgeNinePatchDraw(&patch,
    (xge_rect_t){ 100, 100, 120, 40 }, 0);
xgeNinePatchDraw(&patch,
    (xge_rect_t){ 100, 160, 200, 60 }, 0);

// 染色(如禁用态灰色)
xgeNinePatchSetColor(&patch, 0x808080FF);
xgeNinePatchDraw(&patch,
    (xge_rect_t){ 100, 240, 120, 40 }, 0);

完整代码

将以下代码保存为 ch107_main.c,编译后运行即可看到九宫格拉伸效果:

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

static xge_texture_t g_tex;
static xge_nine_patch_t g_patch;
static xge_font g_font = NULL;

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

    // 绘制不同大小的按钮(圆角不变形)
    xgeNinePatchSetColor(&g_patch, 0xFFFFFFFF);
    xgeNinePatchDraw(&g_patch,
        (xge_rect_t){ 100, 100, 120, 40 }, 0);
    xgeNinePatchDraw(&g_patch,
        (xge_rect_t){ 100, 160, 200, 60 }, 0);
    xgeNinePatchDraw(&g_patch,
        (xge_rect_t){ 100, 240, 300, 80 }, 0);

    // 染色(禁用态灰色)
    xgeNinePatchSetColor(&g_patch, 0x808080FF);
    xgeNinePatchDraw(&g_patch,
        (xge_rect_t){ 100, 340, 120, 40 }, 0);

    xgeTextDraw(g_font, "Nine-Patch: corners stay fixed",
        100.0f, 50.0f, 0xFFFFFFFF)

    return XGE_OK;
}

int main(void) {
    xge_desc_t d = {0};
    d.iWidth  = 800;
    d.iHeight = 600;
    d.sTitle  = "ch107 - Nine-Patch UI";
    d.iFlags  = XGE_INIT_VSYNC;
    xgeInit(&d);

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

    // 程序生成 32x32 圆角按钮纹理
    uint8_t px[32 * 32 * 4];
    memset(px, 0, sizeof(px));
    for (int y = 0; y < 32; y++)
        for (int x = 0; x < 32; x++) {
            int i = (y * 32 + x) * 4;
            px[i] = 80; px[i+1] = 140;
            px[i+2] = 220; px[i+3] = 255;
        }
    xgeTextureCreateRGBA(&g_tex, 32, 32, px);

    // 初始化九宫格(切割线 8px)
    xgeNinePatchInit(&g_patch, &g_tex,
        (xge_rect_t){ 0, 0, 32, 32 },
        8, 8, 24, 24);

    xgeRun(onFrame, NULL);

    xgeTextureFree(&g_tex);
    xgeFontFree(g_font);
    xgeUnit();
    return 0;
}

代码讲解

  • NinePatchInit:指定纹理源矩形和切割线,将纹理分为 9 个区域。
  • 拉伸不变形:四角保持原始尺寸,只拉伸中心区域,圆角不会变形。
  • SetColor:白色为原色,其他颜色与纹理相乘实现染色(如禁用态灰色)。
  • UI 主题:一套九宫格纹理 + 不同染色即可实现多种按钮状态。

要点与陷阱

  • 切割线:fX1/fY1 是左上切割,fX2/fY2 是右下切割(绝对坐标)。
  • Mode:STRETCH(拉伸)或 TILE(平铺)中心区域。
  • Simple:自动将纹理三等分,适合对称纹理。
  • Color:白色为原色;其他颜色与纹理相乘(染色)。

进阶练习

  1. 实现 UI 主题系统:一套九宫格纹理 + 不同染色。
  2. 对话框框架:标题栏 + 内容区 + 底部按钮区全部九宫格。
九宫格绘制效果
图:九宫格绘制渲染效果