【SDL游戏编程入门第五卷】优化加载表面+扩展库+加载其他图片格式 (PNG)

news/2024/11/7 14:30:08/

请添加图片描述

一、前言

在这里,我们先介绍优化加载表面,然后将使用 SDL_image 扩展库来加载 png 图像。

二、优化加载表面

1. 问题

加载位图时,它通常以 24 位格式加载,因为大多数位图都是 24 位默认情况下,大多数(如果不是全部)现代显示器不是 24 位。如果我们对图像进行 位块传输 这是 24 位到 32 位图像,SDL 每次对图像进行分组传输时都会将其转换。

2. 优化

因此,当加载图像时,我们要做的是将其转换为与屏幕相同的格式,因此无需在 blit 上进行转换。这可以通过 SDL_ConvertSurface 轻松完成。我们所要做的就是传入我们要用屏幕格式转换的表面。

请务必注意,SDL_ConvertSurface 会以新格式返回原始副本。此调用后,原始加载的图像仍在内存中。这意味着我们必须 释放原始加载的图面,否则内存中将有同一图像的两个副本。

加载并转换图像后,我们返回最终优化的图像。

3. 示例代码

/*** @brief 加载单个图像* @param path:资源路径*/
SDL_Surface* LoadSurface(const char* path)
{// 最终优化的资源SDL_Surface* optimizedSurface = nullptr;SDL_Surface* loadedSurface = SDL_LoadBMP(path);if (!loadedSurface)std::cout << "[Error]: Unable to load image " << path << " SDL Error: " << SDL_GetError() << std::endl;else{optimizedSurface = SDL_ConvertSurface(loadedSurface, gWindowSurface->format, 0);if (!optimizedSurface)std::cout << "[Error]: Unable to optimize image " << path << " SDL_Error: " << SDL_GetError() << std::endl;// 释放未优化的表面SDL_FreeSurface(loadedSurface);}// 返回最终优化的资源return optimizedSurface;
}

三、SDL_image 扩展库

配置方式和配置 SDL 基本类似,下面是官网链接,都在 Github 上可以找到

✨SDL_image

记得将动态库放在可执行文件目录或项目目录下

依赖项跟配置 SDL 一样

四、加载 PNG 图片

现在我们导入了 SDL_image 库,接下来就可以加载 PNG 图片了

本节使用素材

这里我还是将链接库卸载源码中

// 链接库
#pragma comment(lib, "SDL2.lib")
#pragma comment(lib, "SDL2main.lib")
#pragma comment(lib, "SDL2_image.lib")

这里还需要 初始化 PNG 加载,使用 IMG_Init,它会返回所有当前初始化的标志。

下面用到了 IMG_Init(imgFlags) & imgFlags,其实就是判断是否相等,也可以使用其他方法,这里是看个人习惯

之后注意顺序改变,因为优化加载表面时需要窗口关联的表面,所以需要先获取窗口表面,再加载资源

✨SDL_image API文档

// 初始化 PNG 加载
int imgFlags = IMG_INIT_PNG;
if (!(IMG_Init(imgFlags) & imgFlags))
{std::cout << "[Error]: SDL_image could not initialize! SDL_image Error: " << IMG_GetError() << std::endl;return false;
}
else
{// 获取窗口关联的表面gWindowSurface = SDL_GetWindowSurface(gWindow);if (!gWindowSurface)return false;else{// 加载媒体资源if (!LoadMedia()){std::cout << "[Error]: Failed to load Media!" << std::endl;return false;}}
}

代码如下:

/*** @brief 启动 SDL 并创建窗口*/
bool Init()
{// 初始化 SDLif (SDL_Init(SDL_INIT_VIDEO) < 0){std::cout << "[Error]: SDL could not initialize! SDL_Error: " << SDL_GetError() << std::endl;return false;}else{// 创建窗口gWindow = SDL_CreateWindow("HelloSDL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);if (!gWindow){std::cout << "[Error]: Window could not be created! SDL_Error: " << SDL_GetError() << std::endl;}else{// 初始化 PNG 加载int imgFlags = IMG_INIT_PNG;if (!(IMG_Init(imgFlags) & imgFlags)){std::cout << "[Error]: SDL_image could not initialize! SDL_image Error: " << IMG_GetError() << std::endl;return false;}else{// 获取窗口关联的表面gWindowSurface = SDL_GetWindowSurface(gWindow);if (!gWindowSurface)return false;else{// 加载媒体资源if (!LoadMedia()){std::cout << "[Error]: Failed to load Media!" << std::endl;return false;}}}}}return true;
}

在 LoadSurface 函数中,使用 IMG_Load

SDL_Surface* loadedSurface = IMG_Load(path);

1. 示例代码

/* 此源代码版权归 AnnihilateSword (2022-*)所有,未经书面许可不得转载。*/// 使用 SDL 和 iostream
#include <SDL.h>
#include <SDL_image.h>
#include <iostream>// 链接库
#pragma comment(lib, "SDL2.lib")
#pragma comment(lib, "SDL2main.lib")
#pragma comment(lib, "SDL2_image.lib")// 屏幕尺寸常量
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;bool Init();								// 启动 SDL 并创建窗口
bool LoadMedia();							// 加载媒体
SDL_Surface* LoadSurface(const char* path); // 加载单个图像
void Close();								// 清理资源,关闭窗口以及SDLSDL_Window* gWindow = nullptr;				// 主窗口
SDL_Surface* gWindowSurface = nullptr;		// 主窗口关联的表面SDL_Surface* gTexture = nullptr;			// 需要加载的纹理(表面)// 控制纹理坐标
int gTexturePosX = 100;						// 纹理 X 坐标
int gTexturePosY = 100;						// 纹理 Y 坐标
int gTextureMovementSpeed = 20;				// 纹理移动速度int main(int argc, char* argv[])			// 必须要填写此参数,不然会出现链接错误
{// 初始化 SDLif (Init()){// 窗口循环SDL_Event e;bool quit = false;while (quit == false){// 处理事件while (SDL_PollEvent(&e)){if (e.type == SDL_QUIT)quit = true;else if (e.type == SDL_KEYDOWN)  // 处理按键按下事件{switch (e.key.keysym.sym){  // 按键移动纹理坐标位置case SDLK_w: gTexturePosY -= gTextureMovementSpeed; break;case SDLK_s: gTexturePosY += gTextureMovementSpeed; break;case SDLK_a: gTexturePosX -= gTextureMovementSpeed; break;case SDLK_d: gTexturePosX += gTextureMovementSpeed; break;}}}// --- rendering -----------------------------------------------------------------------// 将表面填充为蓝色SDL_FillRect(gWindowSurface, nullptr, SDL_MapRGB(gWindowSurface->format, 51, 76, 204));// 应用纹理SDL_Rect dstRect{ gTexturePosX, gTexturePosY, 256, 256 };// SDL_BlitSurface(gTexture, nullptr, gWindowSurface, &dstRect);  // 不缩放SDL_BlitScaled(gTexture, nullptr, gWindowSurface, &dstRect);// 更新表面SDL_UpdateWindowSurface(gWindow);}}// 清理资源Close();return 0;
}/*** @brief 启动 SDL 并创建窗口*/
bool Init()
{// 初始化 SDLif (SDL_Init(SDL_INIT_VIDEO) < 0){std::cout << "[Error]: SDL could not initialize! SDL_Error: " << SDL_GetError() << std::endl;return false;}else{// 创建窗口gWindow = SDL_CreateWindow("HelloSDL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);if (!gWindow){std::cout << "[Error]: Window could not be created! SDL_Error: " << SDL_GetError() << std::endl;}else{// 初始化 PNG 加载int imgFlags = IMG_INIT_PNG;if (!(IMG_Init(imgFlags) & imgFlags)){std::cout << "[Error]: SDL_image could not initialize! SDL_image Error: " << IMG_GetError() << std::endl;return false;}else{// 获取窗口关联的表面gWindowSurface = SDL_GetWindowSurface(gWindow);if (!gWindowSurface)return false;else{// 加载媒体资源if (!LoadMedia()){std::cout << "[Error]: Failed to load Media!" << std::endl;return false;}}}}}return true;
}/*** @brief 加载媒体*/
bool LoadMedia()
{gTexture = LoadSurface(R"(res\textures\awesomeface.png)");if (!gTexture){std::cout << "[Error]: Failed to load texture!" << std::endl;return false;}return true;
}/*** @brief 加载单个图像* @param path:资源路径*/
SDL_Surface* LoadSurface(const char* path)
{// 最终优化的资源SDL_Surface* optimizedSurface = nullptr;SDL_Surface* loadedSurface = IMG_Load(path);if (!loadedSurface)std::cout << "[Error]: Unable to load image " << path << " SDL Error: " << SDL_GetError() << std::endl;else{optimizedSurface = SDL_ConvertSurface(loadedSurface, gWindowSurface->format, 0);if (!optimizedSurface)std::cout << "[Error]: Unable to optimize image " << path << " SDL_Error: " << SDL_GetError() << std::endl;// 释放未优化的表面SDL_FreeSurface(loadedSurface);}// 返回最终优化的资源return optimizedSurface;
}/*** @brief 清理资源,关闭窗口以及SDL*/
void Close()
{if (gTexture){// 清理纹理资源SDL_FreeSurface(gTexture);gTexture = nullptr;}// 销毁窗口SDL_DestroyWindow(gWindow);// 退出 IMG 和 SDLIMG_Quit();SDL_Quit();
}

注意 IMG_Quit()

✨参考文档
这应该是释放所有其他资源后在SDL_image中调用的最后一个函数。这将卸载它用于各种编解码器的任何共享库。

2. 运行结果

但是有没有注意到,这张图片其实是有透明度的,本卷并未讲到如何去加载透明图片,考虑到篇幅,打算作为一个单独的模块介绍加载透明图片的问题



本节内容就到这里了,下卷会继续分享 SDL 的基本使用

The End.


http://www.ppmy.cn/news/287780.html

相关文章

计算机组成原理——中央处理器

文章目录 **一 CPU的功能和基本结构****1 CPU的功能****2 [基本结构](http://t.csdn.cn/bpCt3)****2.1 运算器****2.2 控制器** **二 指令执行过程****1 指令周期****2 指令周期的数据流****2.1 取指周期****2.2 间址周期****2.3 执行周期****2.4 中断周期** **3 指令的执行方案…

mac 电脑CPU温度怎么看?怎么可以监控Mac CPU温度,为什么我的 MacBook Air 这么热?

众所周知&#xff0c;电脑温度太高会直接影响到系统运行速度&#xff0c;对硬盘伤害也是很大的。特别是夏天&#xff0c;Mac 笔记本有时候运行起来会比较烫。关于 Mac 笔记本的散热&#xff0c;见仁见智。但是我们也比较好奇 CPU、电池的温度。怎么查看Mac CPU温度呢&#xff1…

相机超焦距计算方法

由于镜头焦距远小于(镜头焦距的平方除以c、F之积)&#xff0c; 一般公式记作 超焦距镜头焦距的平方除以c&#xff08;COC 即circle of confusion diameter 弥散圈直径&#xff09;、Fnum之积 Hyper Focal distance &#xff08;单位为M&#xff09; EFL/(Fnum*COC) 其中 COC …

解读手机相机的各个参数(长曝光)

长曝光,就是长时间曝光的意思。通过控制快门速度来完成。快门速度是控制进光时间的。长时间曝光就是把相机调整的快门尽量慢。 长曝光是选慢快门&#xff08;曝光时间长&#xff09;的一种曝光方式。好处就是可以把光线暗的景色拍的更清晰&#xff0c;也可以拍出如梦幻般的画面…

红米K30升级鸿蒙系统,Redmi K30 Pro变焦版相机免费升级,DxOMark版本马上到

Redmi K30 Pro变焦版相机免费升级&#xff0c;DxOMark版本马上到 2020-09-15 18:00:01 13点赞 12收藏 32评论 据业内消息&#xff0c;红米Redmi K30 Pro变焦版即将升级DxOMark相机版本&#xff0c;更新V12.0.9.0.QJKCNXM版本中升级了DXOMARK相机版本。 除此之外新版本还增加前后…

工业相机视野及焦距的计算公式

一、视场的计算方法 二、光学放大倍率的计算方法 三、焦距的计算方法 提示&#xff1a;工业相机传感器尺寸大小 1/4″:(3.2mm2.4mm)&#xff1b; 1/3″:(4.8mm3.6mm)&#xff1b; 1/2″:(6.4mm4.8mm)&#xff1b; 2/3″:(8.86.6mm)&#xff1b; 1″:(12.8mm9.6mm) . 本文转自&a…

计算相机焦距f

计算相机焦距f 相机焦距f通常以像素为单位&#xff0c;计算方法&#xff1a; 根据相机焦距长度F&#xff08;focal length&#xff0c;单位mm&#xff09;和传感器孔径S&#xff08;sensor size&#xff0c;单位mm&#xff09;计算&#xff1a; 图片宽高&#xff1a;width&am…

工业相机镜头的视场角、焦距、光圈和景深的关系

从相机镜头的磨砂玻璃看物体&#xff0c;当将镜头光圈开至最大&#xff0c;并对准无限远景物调焦时&#xff0c;在磨砂玻璃上呈现出的影像均位于一圆形面积内&#xff0c;而圆形外则漆黑&#xff0c;无影像。此有影像的圆形面积称为该镜头的最大像场。在这个最大像场范围的中心…