Chapter 33 · ShapeEx 路径构建

ShapeEx 对象生命周期

ShapeEx 是 XGE 的高级矢量路径对象,支持复杂路径、渐变填充、描边样式。本章学习创建、引用计数、克隆、重置与销毁。

33

概念

  • ShapeEx vs Shape:Shape(第 21-32 章)是即时绘制;ShapeEx 是"先构建路径 → 设置样式 → 最后绘制"的 retained 模式。
  • 引用计数:ShapeEx 对象通过引用计数管理生命周期,AddRef 增加、Destroy 减少,归零时释放。
  • 可复用:一个 ShapeEx 对象可在多帧中反复绘制,避免每帧重建路径。

API 速查

函数说明
int xgeShapeExCreate(xge_shape_ex* ppShape)创建 ShapeEx 对象
int xgeShapeExAddRef(xge_shape_ex pShape)引用计数 +1
int xgeShapeExRefCountGet(xge_shape_ex pShape, int* pRefCount)获取当前引用计数
int xgeShapeExClone(xge_shape_ex pShape, xge_shape_ex* ppClone)深拷贝克隆
int xgeShapeExReset(xge_shape_ex pShape)重置(清除路径和样式)
void xgeShapeExDestroy(xge_shape_ex pShape)引用计数 -1,归零释放

编译本章示例

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

示例 1:基本创建与销毁

xge_shape_ex shape = NULL;
if (xgeShapeExCreate(&shape) != 0) {
    xgeLogWrite(XGE_LOG_ERROR, "创建 ShapeEx 失败");
    return;
}

// ... 构建路径、设置样式(后续章节)...

// 不再需要时销毁
xgeShapeExDestroy(shape);

示例 2:引用计数与共享

xge_shape_ex shared = NULL;
xgeShapeExCreate(&shared);  // refCount = 1

// 另一个模块也需要使用
xgeShapeExAddRef(shared);    // refCount = 2

// 查询引用计数
int count = 0;
xgeShapeExRefCountGet(shared, &count);
xgeLogWrite(XGE_LOG_INFO, "refCount = %d", count);

// 两个模块各自释放
xgeShapeExDestroy(shared);  // refCount = 1
xgeShapeExDestroy(shared);  // refCount = 0 → 释放

示例 3:克隆与重置

// 克隆一份独立副本
xge_shape_ex copy = NULL;
xgeShapeExClone(shared, &copy);  // 深拷贝,互不影响

// 修改副本不影响原件
xgeShapeExFillColor(copy, 0xFF6B5EFF);

// 重置:清除所有路径和样式,对象可复用
xgeShapeExReset(copy);  // 现在 copy 是"空白"状态

xgeShapeExDestroy(copy);
xgeShapeExDestroy(shared);

完整代码

将以下代码保存为 ch33_main.c,编译后运行即可看到 ShapeEx 对象的创建、克隆、引用计数与销毁流程:

#include "xge.h"

static xge_shape_ex g_shape = NULL;
static xge_shape_ex g_clone = NULL;

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

    // 绘制原始对象(绿色三角形)
    xgeShapeExFillColor(g_shape, 0x4FD8C2FF);
    xgeShapeExDraw(g_shape, 0.25f);

    // 绘制克隆对象(红色,平移后)
    xgeShapeExFillColor(g_clone, 0xFF6B5EFF);
    xgeShapeExDraw(g_clone, 0.25f);

    return XGE_OK;
}

int main(void) {
    xge_desc_t d = {0};
    d.iWidth  = 800;
    d.iHeight = 600;
    d.sTitle  = "ch33 - ShapeEx Lifecycle";
    d.iFlags  = XGE_INIT_VSYNC;
    xgeInit(&d);

    // 创建 ShapeEx 并构建三角形路径
    xgeShapeExCreate(&g_shape);
    xgeShapeExMoveTo(g_shape, 200, 100);
    xgeShapeExLineTo(g_shape, 100, 350);
    xgeShapeExLineTo(g_shape, 300, 350);
    xgeShapeExClose(g_shape);

    // 克隆并平移
    xgeShapeExClone(g_shape, &g_clone);
    xge_shape_ex_matrix_t mat;
    xgeShapeExMatrixIdentity(&mat);
    xgeShapeExMatrixTranslate(&mat, 350, 50);
    xgeShapeExTransformSet(g_clone, &mat);

    // 查询引用计数
    int ref = 0;
    xgeShapeExRefCountGet(g_shape, &ref);

    xgeRun(onFrame, NULL);

    // 销毁
    xgeShapeExDestroy(g_clone);
    xgeShapeExDestroy(g_shape);
    xgeUnit();
    return 0;
}

代码讲解

  • 创建与路径构建:xgeShapeExCreate 创建对象,然后用 MoveTo/LineTo/Close 构建三角形路径。
  • 克隆独立性:xgeShapeExClone 深拷贝,修改克隆的颜色和变换不影响原件。
  • 引用计数:Create 后 refCount=1,Clone 产生新对象(refCount=1),而非增加原件引用。
  • 销毁顺序:程序退出前调用 Destroy,引用计数归零时真正释放内存。

要点与陷阱

  • 返回值:所有 int 返回的函数,0 = 成功,非 0 = 失败(参数无效等)。
  • Destroy 不是立即释放:只有引用计数归零才真正释放内存。
  • Clone 是深拷贝:路径数据、样式、变换矩阵全部复制。
  • Reset 保留对象:Reset 后对象仍有效(引用计数不变),只是内容清空。
  • NULL 检查:Create 失败时 *ppShape 为 NULL,使用前务必检查。

进阶练习

  1. 实现一个 ShapeEx 对象池:预创建 N 个对象,按需取出/归还(利用 Reset)。
  2. 验证引用计数:创建对象后 AddRef 3 次,再 Destroy 4 次,观察 RefCountGet 输出。
  3. 克隆一个对象后分别修改原件和副本的颜色,验证独立性。
ShapeEx 对象生命周期效果
图:ShapeEx 对象生命周期渲染效果