Chapter 78 · SVG 引擎

Paint 节点变换与属性

对单个 Paint 节点设置变换、透明度、可见性和混合模式,实现 SVG 内部元素动画。

78

API 速查

函数说明
int xgeSvgPaintTransformSet(xge_svg_paint pPaint, const xge_shape_ex_matrix_t* pMatrix)设置变换
int xgeSvgPaintTransformIdentity(xge_svg_paint pPaint)重置变换
int xgeSvgPaintTransformGet(xge_svg_paint pPaint, xge_shape_ex_matrix_t* pMatrix)获取变换
int xgeSvgPaintTransformTranslate(xge_svg_paint pPaint, float fTX, float fTY)平移
int xgeSvgPaintTransformScale(xge_svg_paint pPaint, float fSX, float fSY)缩放
int xgeSvgPaintTransformRotate(xge_svg_paint pPaint, float fRadians)旋转
int xgeSvgPaintOpacitySet(xge_svg_paint pPaint, float fOpacity)设置透明度
int xgeSvgPaintOpacityGet(xge_svg_paint pPaint, float* pOpacity)获取透明度
int xgeSvgPaintVisibleSet(xge_svg_paint pPaint, int bVisible)设置可见性
int xgeSvgPaintVisibleGet(xge_svg_paint pPaint, int* pVisible)获取可见性
int xgeSvgPaintBlendSet(xge_svg_paint pPaint, int iBlend)设置混合模式
int xgeSvgPaintBlendGet(xge_svg_paint pPaint, int* pBlend)获取混合模式

编译本章示例

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

示例:SVG 指针旋转动画

xge_svg clock = NULL;
xgeSvgCreate(&clock);
xgeSvgLoad(clock, "assets/clock.svg");

// 获取秒针节点
xge_svg_paint hand = NULL;
xgeSvgPaintGetByName(clock, "second-hand", &hand);

// 每帧旋转
void OnFrame(void) {
    xgeSvgPaintTransformIdentity(hand);
    float angle = xgeTimeNow() * 6.28f / 60.0f;
    xgeSvgPaintTransformRotate(hand, angle);

    xge_rect_t dst = { 300,200, 200,200 };
    xgeSvgDraw(clock, dst, 0.25f);
}

// 隐藏/显示元素
xgeSvgPaintVisibleSet(hand, 0);  // 隐藏秒针

// 半透明效果
xgeSvgPaintOpacitySet(hand, 0.5f);

完整代码

将以下代码保存为 ch78_main.c,编译后运行即可看到 SVG 内部节点旋转动画效果:

#include "xge.h"

static xge_svg g_clock = NULL;
static xge_svg_paint g_hand = NULL;
static int g_iFrame = 0;

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

    // 每帧重置 + 旋转指针
    if (g_hand) {
        xgeSvgPaintTransformIdentity(g_hand);
        // 平移到旋转中心 → 旋转 → 平移回
        xgeSvgPaintTransformTranslate(g_hand, 100.0f, 100.0f);
        float angle = g_iFrame * 0.1f;
        xgeSvgPaintTransformRotate(g_hand, angle);
        xgeSvgPaintTransformTranslate(g_hand, -100.0f, -100.0f);
    }

    xge_rect_t dst = { 300, 200, 200, 200 };
    xgeSvgDraw(g_clock, dst, 0.25f);
    return XGE_OK;
}

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

    xgeSvgCreate(&g_clock);
    xgeSvgLoad(g_clock, "assets/clock.svg");
    xgeSvgPaintGetByName(g_clock, "second-hand", &g_hand);

    xgeRun(onFrame, NULL);
    xgeSvgDestroy(g_clock);
    xgeUnit();
    return 0;
}

代码讲解

  • TransformIdentity:每帧重置变换,避免旋转累积。
  • Translate→Rotate→Translate:先平移到旋转中心,旋转后再平移回,实现绕中心点旋转。
  • PaintTransformRotate:参数为弧度,每帧增加 0.1rad 实现平滑旋转。
  • Paint 属性独立:修改仅影响运行时渲染,不改变 SVG 文件内容。

要点与陷阱

  • TransformIdentity:每帧动画前重置,避免累积旋转。
  • 变换中心:默认绕原点旋转,需先平移到旋转中心。
  • Paint 属性独立:修改 Paint 不影响 SVG 文件,仅影响运行时渲染。
  • Visible=0:跳过该节点及其子树的绘制。

进阶练习

  1. 实现 SVG 加载动画:各部件依次淡入(Opacity 动画)。
  2. 实现悬停高亮:鼠标命中时修改 Paint 混合模式为 ADDITIVE。
Paint 节点变换与属性效果
图:Paint 节点变换与属性渲染效果