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。我們執行相應的成員函式,就是這樣!