学习用 Viewport 分割渲染区域、用 Clip 矩形限制绘制范围,实现分屏、小地图、滚动容器等效果。
| 函数 | 说明 |
|---|---|
void xgeViewportSet(xge_rect_t tRect) | 设置视口矩形 |
xge_rect_t xgeViewportGet(void) | 获取当前视口 |
void xgeViewportClear(void) | 恢复全屏视口 |
void xgeClipSet(xge_rect_t tRect) | 设置裁剪矩形 |
xge_rect_t xgeClipGet(void) | 获取当前裁剪矩形 |
void xgeClipClear(void) | 取消裁剪(全屏可见) |
gcc -O2 -I. -o ch17.exe ch17_main.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch17.exe
typedef struct xge_rect_t {
float fX; // 左上角 X
float fY; // 左上角 Y
float fWidth; // 宽度
float fHeight; // 高度
} xge_rect_t;static int onFrame(void* pUser) {
int w = xgeGetWidth(), h = xgeGetHeight();
// 左半屏:玩家 1 视角
xge_rect_t left = { 0, 0, w/2.0f, h };
xgeViewportSet(left);
xgeClear(0x0A1A20FF);
// ... 绘制玩家 1 世界 ...
// 右半屏:玩家 2 视角
xge_rect_t right = { w/2.0f, 0, w/2.0f, h };
xgeViewportSet(right);
xgeClear(0x14100AFF);
// ... 绘制玩家 2 世界 ...
// 恢复全屏
xgeViewportClear();
return XGE_OK;
}// 主视图(全屏)
xgeViewportClear();
xgeClear(0x081114FF);
// ... 主世界绘制 ...
// 小地图(右下角 200×150)
xge_rect_t mini = { 590, 440, 200, 150 };
xgeViewportSet(mini);
// 缩小相机显示全局
xge_camera_t cam = xgeCameraDefault(200, 150);
cam.tScale.fX = cam.tScale.fY = 0.05f; // 缩小 20 倍
xgeCameraSet(&cam);
xgeClear(0x00000080); // 半透明黑底
// ... 绘制简化世界 ...
xgeViewportClear(); // 恢复// 定义列表可见区域
xge_rect_t listArea = { 50, 100, 300, 400 };
// 设置裁剪 → 超出区域的绘制被裁掉
xgeClipSet(listArea);
// 绘制长列表(可能超出 400px 高度)
for (int i = 0; i < 100; i++) {
float y = 100 + i * 40.0f - g_fScrollOffset;
xgeShapeRectFill(50, y, 300, 38, 0x1A2A30FF);
// xgeTextDraw(60, y + 10, items[i], ...);
}
// 取消裁剪
xgeClipClear();
// 绘制滚动条(不受裁剪影响)
xgeShapeRectFill(352, 100, 6, 400, 0x333333FF);将以下代码保存为 ch17_main.c,编译后运行即可看到裁剪矩形实现的滚动列表:
#include "xge.h"
static float g_fScroll = 0.0f;
static int onFrame(void* pUser) {
(void)pUser;
// 滚轮控制滚动偏移
xge_vec2_t wheel = xgeMouseGetWheel();
g_fScroll -= wheel.fY * 20.0f;
if (g_fScroll < 0) g_fScroll = 0;
if (g_fScroll > 3600.0f) g_fScroll = 3600.0f;
xgeClear(0x081114FF);
// 定义列表可见区域
xge_rect_t listArea = { 100, 80, 400, 440 };
// 绘制背景框
xgeShapeRectFill(100, 80, 400, 440, 0x0E1E24FF);
// 设置裁剪 → 超出区域的绘制被裁掉
xgeClipSet(listArea);
// 绘制 100 行列表项
for (int i = 0; i < 100; i++) {
float y = 80 + i * 40.0f - g_fScroll;
uint32_t bg = (i % 2) ? 0x1A2A30FF : 0x162228FF;
xgeShapeRectFill(100, y, 400, 38, bg);
}
// 取消裁剪
xgeClipClear();
// 滚动条(不受裁剪影响)
float barH = 440.0f * 440.0f / 4000.0f;
float barY = 80 + g_fScroll / 4000.0f * 440.0f;
xgeShapeRectFill(504, barY, 6, barH, 0x4FD8C280);
return XGE_OK;
}
int main(void) {
xge_desc_t d = {0};
d.iWidth = 800;
d.iHeight = 600;
d.sTitle = "ch17 - Viewport & Clip";
d.iFlags = XGE_INIT_VSYNC;
xgeInit(&d);
xgeRun(onFrame, NULL);
xgeUnit();
return 0;
}xgeClipSet(listArea) 设置裁剪矩形,之后超出该区域的绘制全部被丢弃。xgeClipClear() 取消裁剪后绘制的滚动条不受影响。xgeBegin 后重置为全屏。需要每帧重新设置。xgeClipSet 不会叠加,后一次覆盖前一次。需要交集裁剪时手动计算。