SDL (简单直接媒体层) - 渲染图像
外观
在本节中,我们将演示如何将 BMP 图像渲染到窗口。在本章中,我们将开始在多个文件中编写代码以保持项目的组织性。
您可以在这个 GitLab 存储库 中下载本节的源代码。所有源代码都存储在 该组 中。
#include <stdio.h>
#ifdef _WIN32
#include <SDL/SDL.h> /* Windows-specific SDL2 library */
#else
#include <SDL2/SDL.h> /* macOS- and GNU/Linux-specific */
#endif
/* Define constants for struct wikibook */
#define WB_NAME "WikiBook SDL"
#define WB_WIDTH 500
#define WB_HEIGHT 500
#define WB_IMAGE_PATH "wikibooks.bmp" /* File path to image relative to binary */
/*
* We'll be encapsulating the SDL objects into struct wikibook and write up
* functions into useable subroutines. Remember, to initialise wikibook as static
* to make sure that the member pointers are declared to NULL. */
struct wikibook {
SDL_Window *window; /* Window to be rendered */
SDL_Surface *screen; /* Surface contained by the window */
SDL_Surface *image; /* Surface to be loaded with the image */
};
/* Function prototypes for struct wikibook */
int wb_init(struct wikibook*);
int wb_loadImage(struct wikibook*);
void wb_close(struct wikibook*);
我们声明一个 SDL_Window
和两个 SDL_Surface
指针。我们使用第一个作为它被渲染到窗口,第二个作为加载图像的缓冲区。
SDL_Window *window; /* Window to be rendered */
SDL_Surface *screen; /* Surface contained by the window */
SDL_Surface *image; /* Surface to be loaded with the image */
/* Initialise wikibook object */
int wb_init(struct wikibook *wb) {
/* Initialise SDL video subsystem */
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
fprintf(stderr, "SDL failed to initialise: %s\n", SDL_GetError());
return -1;
}
/* Create SDL_Window */
wb->window = SDL_CreateWindow(WB_NAME,
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
WB_WIDTH,
WB_HEIGHT,
0);
if (wb->window == NULL) {
fprintf(stderr, "WikiBook window failed to initialise: %s\n", SDL_GetError());
return -1;
}
/* Get SDL_Surface of SDL_Window */
wb->screen = SDL_GetWindowSurface(wb->window);
if (wb->screen == NULL) {
fprintf(stderr, "WikiBook screen failed to initialise: %s\n", SDL_GetError());
return -1;
}
return 0;
}
我们使用 SDL_GetWindowSurface
为 SDL_Window
设置 SDL_Surface
。
wb->screen = SDL_GetWindowSurface(wb->window);
if (wb->screen == NULL) {
fprintf(stderr, "WikiBook screen failed to initialise: %s\n", SDL_GetError());
return -1;
}
/* Load and render the image to wikibook object */
int wb_loadImage (struct wikibook *wb) {
/* Load the image from its file path to a SDL_Surface */
wb->image = SDL_LoadBMP(WB_IMAGE_PATH);
if (wb->image == NULL) {
fprintf(stderr, "WikiBook failed to load image: %s\n", SDL_GetError());
return -1;
}
/* Blit the SDL_Surface, containing the image, to the SDL_Surface contained by
* the SDL_Window */
SDL_BlitSurface(wb->image, NULL, wb->screen, NULL);
/* Update SDL_Window so it shows the updated SDL_Surface therefore the image */
SDL_UpdateWindowSurface(wb->window);
return 0;
}
我们首先使用 SDL_LoadBMP
将 BMP 图像加载到 SDL_Surface
中。
wb->image = SDL_LoadBMP(WB_IMAGE_PATH);
if (wb->image == NULL) {
fprintf(stderr, "WikiBook failed to load image: %s\n", SDL_GetError());
return -1;
}
现在我们已经将图像加载到它的表面,我们将需要使用 SDL_BlitSurface
将其绘制到另一个表面,即窗口中包含的表面。然后,我们将不得不使用 SDL_UpdateWindowSurface
更新窗口以渲染图像。
/* Blit the SDL_Surface, containing the image, to the SDL_Surface contained by
* the SDL_Window */
SDL_BlitSurface(wb->image, NULL, wb->screen, NULL);
/* Update SDL_Window so it shows the updated SDL_Surface therefore the image */
SDL_UpdateWindowSurface(wb->window);
/* Free the memory of wikibook's member objects */
void wb_close(struct wikibook *wb) {
/* Destroy surfaces */
SDL_FreeSurface(wb->image);
SDL_FreeSurface(wb->surface);
wb->image = NULL;
wb->surface = NULL;
/* Destroy window */
SDL_DestroyWindow(wb->window);
wb->window = NULL;
/* Shutdown SDL subsystems*/
SDL_Quit();
}
销毁表面与销毁窗口几乎相同。
#define TIME_DELAY 3000
int main (int argc, char **argv)
{
static struct wikibook wb; /* Initialise as static as to initialise all members to 0 */
if (wb_init(&wb) < 0) {
fprintf(stderr, "WikiBook failed to initialise.");
return -1;
}
if (wb_loadImage(&wb) < 0) {
fprintf(stderr, "WikiBook failed to load image.");
return -1;
}
SDL_Delay(TIME_DELAY);
wb_close(&wb);
return 0;
}
我们将时间延迟定义为 3000 毫秒,并将 wikibook
对象声明为 static
,确保其成员指针设置为 NULL
。我们运行相应的成员函数,就是这样!