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;
}
posted @ 2025-03-15 17:05  报废之人  阅读(1803)  评论(0)    收藏  举报