SDL2学习笔记 - 渲染图片

开发环境 ： MacOS
参考资料 ： 陈云老师的 SDL2 教程
注：这是笔记
EP-2

环境配置

在 SDL2 中，我们有两种方法渲染图片。

一种是使用 BMP 格式的图片，好处是无损图片，可以直接使用 SDL2 库渲染。

还有一种就是用SDL2_image库渲染 PNG，JPG 一类的常见格式

这两种咱都会说，因为 BMP 格式渲染比较简单，我们先说这个。

配置 CMake

首先配置 CMake，上个文章已经说了，加上SDL_image也是如法炮制，就直接复制了。
值得注意的是，在 MacOS 上使用 VScode 的 CMakeTools 直接启动会因为可执行文件找不到图片导致失败，所以我们还需要加上一句吧可执行文件移到工作目录下

Copy
cmake_minimum_required(VERSION 3.23.2)
project(SimpleAnimation C)

set(CMAKE_C_STANDARD 11)

set(SDL_DIR /usr/local/Cellar/sdl2/2.26.0)
include_directories(${SDL_DIR}/include/SDL2)
link_directories(${SDL_DIR}/lib/)

set(SDL2_image /usr/local/Cellar/sdl2_image/2.6.2)
include_directories(${SDL2_image}/include/)
link_directories(${SDL2_image}/lib/)

link_libraries(SDL2)
link_libraries(SDL2_image)

# 移出可执行文件
set(EXECUTABLE_OUTPUT_PATH ../)
add_executable(SimpleAnimation main.c)

然后，我们就可以正式开始了

渲染 BMP 格式的图片

本文章的 BMP 文件使用了陈云老师教程里的，侵删
喵喵图连接：cat
渲染 BMP 文件，我们首先加载 BMP 文件

Copy
img = SDL_LoadBMP("cat.bmp");
struct SDL_Surface *screen = SDL_GetWindowSurface(win);

然后用写一个绘制函数

Copy
void draw(SDL_Surface *screen, SDL_Window *win) {
SDL_Rect src = {0, 0, img->w, img->h};
SDL_BlitSurface(img, &src, screen, &src);
// 生效
SDL_UpdateWindowSurface(win);
}

完整代码

Copy
#include <stdio.h>
#include <SDL2/SDL.h>

#define WIDTH 600
#define HEIGHT 500
#define FRAMERATE 60

struct SDL_Surface *img;

void draw(SDL_Surface *screen, SDL_Window *win) {

SDL_Rect src = {0, 0, img->w, img->h};
SDL_BlitSurface(img, &src, screen, &src);

SDL_UpdateWindowSurface(win);
}

void event_loop(SDL_Surface *screen, SDL_Window *win) {
while (1) {
uint32_t begin = SDL_GetTicks();
draw(screen, win);

SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
return;
}
}
long current = SDL_GetTicks();
long cost = current - begin;
long frame = 1000 / FRAMERATE;
long delay = frame - cost;

if (delay > 0) {
SDL_Delay(delay);
}
}
}

int main() {
if (SDL_Init(SDL_INIT_VIDEO)) {
SDL_Log("Can not init video, %s", SDL_GetError());
return 1;
}

SDL_Window *win = SDL_CreateWindow(
"Hello World",

SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
WIDTH, HEIGHT,

SDL_WINDOW_SHOWN
);
if (win == NULL) {
SDL_Log("Can not create window, %s", SDL_GetError());
return 1;
}

img = SDL_LoadBMP("cat.bmp");
struct SDL_Surface *screen = SDL_GetWindowSurface(win);

event_loop(screen, win);
SDL_FreeSurface(img);
SDL_DestroyWindow(win);
return 0;
}

渲染其他格式文件

我们需要引入SDL_image库，下载和 SDL 一样

Copy
#include <SDL.h>
#include <SDL2/SDL_image.h>

#define WIDTH 1280
#define HEIGHT 783
/* 设定帧频 */
#define FRAMERATE 60

/* 声明图片 */
struct SDL_Surface * img;

int x = 0;

void draw(SDL_Surface * screen, SDL_Window * win) {
/* 设定img矩形框 */
SDL_Rect src = {0, 0, img->w, img->h};//x, y, w, h
/* 让img在win显示（copy上去） */
SDL_BlitSurface(img, &src, screen, &src);

SDL_UpdateWindowSurface(win);
}

/* 事件循环 */
void event_loop(SDL_Surface * screen, SDL_Window * win) {
while (1) {
/* 帧率：获取毫秒值 */
long begin = SDL_GetTicks();

/* 渲染 */
draw(screen, win);

SDL_Event event;
/* 使用循环读取事件比if快，不用等 */
while (SDL_PollEvent(&event)) {
if(event.type == SDL_QUIT) {
return;
}
}

/* 帧率：当前值 */
long current = SDL_GetTicks();
/* 现在每一帧花费的时间 */
long cost = current - begin;
/* 每帧应该的时间 */
long frame = 1000/FRAMERATE;
/* 计算该休眠的时间维持帧数 */
long delay = frame - cost;
/* 如果delay是负就不休眠维持帧数 */
if (delay > 0) {
SDL_Delay(delay);
}
/* 在系统资源足够的情况下能够保持一个足够的帧频，不够咱也没办法 */
}
}

int main() {
if (SDL_Init(SDL_INIT_VIDEO)) {
SDL_Log("Can not init video, %s", SDL_GetError());
return 1;
}

SDL_Window * win = SDL_CreateWindow(
"img",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
WIDTH,HEIGHT,
SDL_WINDOW_SHOWN
);

if (win==NULL) {
SDL_Log("Can not create window, %s", SDL_GetError());
return 1;
}

/* 加载图片 */
img = IMG_Load("img_1.png");
if (img==NULL) {
SDL_Log("Can not load image, %s", SDL_GetError());
return 1;
}

SDL_Surface * screen = SDL_GetWindowSurface(win); // 找到窗口

event_loop(screen, win);

/* 释放图片 */
SDL_FreeSurface(img);
/* 释放窗口 */
SDL_DestroyWindow(win);
return 0;
}