Chapter 93 · 图像与纹理

纹理创建与加载

xge_texture 是 GPU 端纹理对象,可从像素数据创建、从文件直接加载,或通过引用计数共享。

93

概念

纹理是 GPU 端的图像资源,所有绘制操作(xgeDraw、SpriteBatch 等)都需要纹理。 创建方式有三种:从 RGBA 像素创建、从 xge_image 创建、直接从文件/内存加载。 纹理使用引用计数管理生命周期。

API 速查

函数说明
int xgeTextureCreateRGBA(xge_texture pTexture, int iWidth, int iHeight, const void* pPixels)从 RGBA 像素创建
int xgeTextureCreateFromImage(xge_texture pTexture, const xge_image_t* pImage)从图像对象创建
int xgeTextureLoad(xge_texture pTexture, const char* sPath)从文件加载
int xgeTextureLoadEx(xge_texture pTexture, const char* sPath, uint32_t iFlags)带标志加载
int xgeTextureLoadMemory(xge_texture pTexture, const void* pData, int iSize)从内存加载
int xgeTextureLoadMemoryEx(xge_texture pTexture, const void* pData, int iSize, uint32_t iFlags)内存加载 + 标志
int xgeTextureAddRef(xge_texture pTexture)增加引用计数
int xgeTextureReadPixels(xge_texture pTexture, void* pPixels, int iStride)回读像素到 CPU
void xgeTextureFree(xge_texture pTexture)释放纹理

编译本章示例

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

示例:多种创建方式

// 方式 1:从文件直接加载(最常用)
xge_texture_t tex1;
xgeTextureLoad(&tex1, "assets/sprite.png");

// 方式 2:从 RGBA 像素创建(程序生成)
uint8_t pixels[64 * 64 * 4];
memset(pixels, 0xFF, sizeof(pixels)); // 白色
xge_texture_t tex2;
xgeTextureCreateRGBA(&tex2, 64, 64, pixels);

// 方式 3:从已加载的图像创建
xge_image_t img;
xgeImageLoad(&img, "photo.jpg");
xge_texture_t tex3;
xgeTextureCreateFromImage(&tex3, &img);
xgeImageFree(&img);

// 绘制
xgeDraw(&tex1, 0, 0);
xgeDraw(&tex2, 100, 0);

// 引用计数共享
xgeTextureAddRef(&tex1); // refcount = 2
xgeTextureFree(&tex1);  // refcount = 1,未销毁
xgeTextureFree(&tex1);  // refcount = 0,真正释放

完整代码

将以下代码保存为 ch93_main.c,编译后运行即可看到多种纹理创建方式:

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

static xge_texture_t g_texFile;
static xge_texture_t g_texRGBA;
static int g_hasFile = 0;
static xge_font g_font = NULL;

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

    // 绘制文件加载的纹理
    if (g_hasFile)
        xgeDraw(&g_texFile, 50.0f, 50.0f);

    // 绘制程序生成的纯色纹理
    xgeDraw(&g_texRGBA, 50.0f, 250.0f);

    xgeTextDraw(g_font, "Top: file load | Bottom: RGBA create",
        50.0f, 450.0f, 0xFFFFFFFF)

    return XGE_OK;
}

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

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

    // 方式 1:从文件直接加载
    if (xgeTextureLoad(&g_texFile, "assets/sprite.png") == 0)
        g_hasFile = 1;

    // 方式 2:从 RGBA 像素创建(程序生成渐变)
    uint8_t pixels[128 * 128 * 4];
    for (int y = 0; y < 128; y++)
        for (int x = 0; x < 128; x++) {
            int i = (y * 128 + x) * 4;
            pixels[i+0] = (uint8_t)(x * 2);
            pixels[i+1] = (uint8_t)(y * 2);
            pixels[i+2] = 128;
            pixels[i+3] = 255;
        }
    xgeTextureCreateRGBA(&g_texRGBA, 128, 128, pixels);

    xgeRun(onFrame, NULL);

    if (g_hasFile) xgeTextureFree(&g_texFile);
    xgeTextureFree(&g_texRGBA);
    xgeFontFree(g_font);
    xgeUnit();
    return 0;
}

代码讲解

  • TextureLoad:从文件一步完成解码 + GPU 上传,最常用的纹理创建方式。
  • TextureCreateRGBA:从程序生成的像素数据创建纹理,适合动态内容。
  • 弓用计数:AddRef/Free 配对使用,计数归零时才真正释放 GPU 资源。
  • 渐变纹理:用双重循环生成 RGB 渐变像素,展示程序化纹理生成。

要点与陷阱

  • TextureLoad:内部完成解码 + GPU 上传,一步到位。
  • 引用计数:AddRef/Free 配对使用;Free 不会立即销毁直到计数归零。
  • ReadPixels:GPU → CPU 回读,性能开销大,避免每帧调用。
  • 线程安全:纹理创建/销毁应在渲染线程或主线程执行。

进阶练习

  1. 实现纹理缓存池:按路径缓存纹理,避免重复加载。
  2. 程序生成棋盘格纹理:像素填充 → CreateRGBA。
纹理创建与加载效果
图:纹理创建与加载渲染效果