C++图形化界面——SDL3
鉴于目前的SDL3与SDL2有着细微的差别,此片文章诞生
首先是下载,下载不能只下载SDL,还要下载SDL_image库,不然png等格式的图片不好整。
配置方面,本文章就不提及了,随便从网上找其他SDL2的教程即可。
库的引入
#include<SDL3/SDL.h>
#include<SDL3_image/SDL_image.h>
初始化
进入程序第一步是初始化,别管初始化干了什么,初始化就对了:
SDL_Init(SDL_INIT_VIDEO);
这个函数是有返回值的,当这个返回值小于0的时候,说明初始化失败。
SDL_Init()函数有多种参数:
#define SDL_INIT_AUDIO 0x00000010u /**< `SDL_INIT_AUDIO` implies `SDL_INIT_EVENTS` */
#define SDL_INIT_VIDEO 0x00000020u /**< `SDL_INIT_VIDEO` implies `SDL_INIT_EVENTS`, should be initialized on the main thread */
#define SDL_INIT_JOYSTICK 0x00000200u /**< `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS`, should be initialized on the same thread as SDL_INIT_VIDEO on Windows if you don't set SDL_HINT_JOYSTICK_THREAD */
#define SDL_INIT_HAPTIC 0x00001000u
#define SDL_INIT_GAMEPAD 0x00002000u /**< `SDL_INIT_GAMEPAD` implies `SDL_INIT_JOYSTICK` */
#define SDL_INIT_EVENTS 0x00004000u
#define SDL_INIT_SENSOR 0x00008000u /**< `SDL_INIT_SENSOR` implies `SDL_INIT_EVENTS` */
#define SDL_INIT_CAMERA 0x00010000u /**< `SDL_INIT_CAMERA` implies `SDL_INIT_EVENTS` */
从这里我们不难看出,这些都是干嘛的,要想使用SDL库的相关功能,就要初始化对应参数,看不懂的可以搜索对应英文翻译。
创建窗口
SDL_Window* window = SDL_CreateWindow("hello, SDL3", 800, 600, SDL_WINDOW_RESIZABLE);
这个语句中的参数分别对应着:窗口名称、窗口长宽、窗口类型,我这里选择的是可伸缩的窗口,常见的还有SDL_WINDOW_FULLSCREEN代表全屏,以及SDL_WINDOW_HIDDEN代表隐藏,至于剩下的种类是干什么的,我不知道。
创建渲染器
SDL_Render* render = SDL_CreateRender(window, nullptr);
两个参数,一个填上前面创建的window即可,后面的一个字符串,用于指定渲染器,如果我们没有什么特殊的渲染需求,直接填上空指针就行。
整个渲染器就相当于一张纸,我们只需要使用函数在纸上画画,然后把画拿给机器,让机器呈现出来即可。
循环渲染
正常游戏来讲,应该是指定帧数,然后按照每秒多少帧来进行循环。但是我们现在只是测试一下,所以随便写写就行:
SDL_Event event{};
bool going = true;
while (going) {
SDL_WaitEvent(&event);
switch (event.type) {
case SDL_EVENT_QUIT: { //不玩了
going = false;
break;
}
case SDL_EVENT_KEY_DOWN: {
going = going && (event.key.key != SDLK_ESCAPE);
break;
}
case SDL_EVENT_WINDOW_EXPOSED: {
SDL_SetRenderDrawColor(render, 255, 255, 255, 255); //设置渲染底色
SDL_RenderClear(render); //清除上一帧的画面
/* 在这里填充render */
SDL_RenderPresent(render); //渲染
break;
}
}
printf("Event is: %d\n", event);
}
这就是整个的渲染流程
绘制几何图案
std::array<SDL_Vertex, 3> org_vertices = {
SDL_Vertex { {150,000}, {1.0f,0.0f,0.0f,1.0f}},
SDL_Vertex { {000,300}, {0.0f,1.0f,0.0f,1.0f}},
SDL_Vertex { {300,300}, {0.0f,0.0f,1.0f,1.0f}}
}; //定义各个顶点信息,指定顶点颜色
SDL_RenderGeometry(render, nullptr, org_vertices.data(), org_vertices.size(), nullptr, 0); //渲染集合图形到render上
SDL_Vertex中,第一个大括号括起来的是顶点的位置信息,第二个是rgba,在SDL2中,rgba是使用0~255的范围的,到了SDL3中,则改成了归一化后的数字。
SDL_RenderGeometry第一个参数填上render毫无疑问,第二个参数则是可以指定绘制图案所用的贴图。
当然,这个渲染函数也是要放到循环中去的。
绘制图片
char file[30] = "./resources/images/home.png";
SDL_Texture* texture = IMG_LoadTexture(render, file);
SDL_FRect rect1 = {};
SDL_FRect rect2 = {0,0,32,32};
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_NEAREST);
SDL_RenderTexture(render, texture, NULL, NULL);
这是绘制图片的全部,其中需要用到SDL_image的库,其中我们需要指定路径。
值得注意的是在配置资源的时候,需要将资源一式两份,一份放到代码目录中,一份放到程序目录中,不然就会出现在编译器中能运行,但是直接运行exe就会闪退的情况。
两个Set函数用于指定图片的渲染模式,前者指定叠加样式(学过PS的应该知道是什么),用于计算图片,与被重叠图案重叠后的rbga的叠加值。
后者指定图片的放缩方式,有两种:一种是所示的SDL_SCALEMODE_NEAREST,可以锐化图案边缘,另一种则是SDL_SCALEMODE_LINEAR,采用线性插值的方式,使图案边缘不那么尖锐。前者适用于像素风格,后者适用于真实风格。
SDL_RenderTexture()函数,后面两个NULL的位置,前一个用于选定png要展示的部分,后一个用于选定png要放在画布哪个位置。如果填两个NULL,则是默认全选全部。
如果要填,则是填入两个SDL_FRect指针,上面代码中的两个rect就是要填的,rect中的参数,前两者指定区域开始坐标,后两者指定区域长宽。
整体代码
#include<stdio.h>
#include<stdlib.h>
#include<array>
#include<SDL3/SDL.h>
#include<SDL3_image/SDL_image.h>
#include<windows.h>
//用于隐藏黑窗口
#pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" )
void b_error(char* message) {
printf("%s", message);
exit(1);
}
int main() {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("init error...");
return 1;
}
SDL_Window* window = SDL_CreateWindow("hello, sdl3!", 800, 600, SDL_WINDOW_RESIZABLE);
if (!window) b_error("window");
SDL_Renderer* render = SDL_CreateRenderer(window, nullptr);
if (!render) b_error("render");
std::array<SDL_Vertex, 3> org_vertices = {
SDL_Vertex { {150,000}, {1.0f,0.0f,0.0f,1.0f}},
SDL_Vertex { {000,300}, {0.0f,1.0f,0.0f,1.0f}},
SDL_Vertex { {300,300}, {0.0f,0.0f,1.0f,1.0f}}
};
SDL_RenderGeometry(render, nullptr, org_vertices.data(), org_vertices.size(), nullptr, 0);
char file[30] = "./resources/images/home.png";
SDL_Texture* texture = IMG_LoadTexture(render, file);
if (!texture) {
printf("Can not find the png");
system("pause");
return 0;
}
SDL_Event event{};
bool going = true;
while (going) {
SDL_WaitEvent(&event);
switch (event.type) {
case SDL_EVENT_QUIT: {
going = false;
break;
}
case SDL_EVENT_KEY_DOWN: {
going = going && (event.key.key != SDLK_ESCAPE);
break;
}
case SDL_EVENT_WINDOW_EXPOSED: {
SDL_SetRenderDrawColor(render, 255, 255, 255, 255);
SDL_RenderClear(render);
SDL_RenderGeometry(render, nullptr, org_vertices.data(), org_vertices.size(), nullptr, 0);
SDL_FRect rect1 = {};
SDL_FRect rect2 = {0,0,32,32};
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_NEAREST);
SDL_RenderTexture(render, texture, NULL, NULL);
SDL_RenderPresent(render);
break;
}
}
printf("Event is: %d\n", event);
}
return 0;
}

浙公网安备 33010602011771号