跳转到内容

SDL (简单直接媒体层) - 渲染图像

来自维基教科书,开放世界开放书籍

在本节中,我们将演示如何将 BMP 图像渲染到窗口。在本章中,我们将开始在多个文件中编写代码以保持项目的组织性。

您可以在这个 GitLab 存储库 中下载本节的源代码。所有源代码都存储在 该组 中。

wikibook.h

[编辑 | 编辑源代码]
#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 */

wikibook.c

[编辑 | 编辑源代码]

初始化

[编辑 | 编辑源代码]
/* 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_GetWindowSurfaceSDL_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。我们运行相应的成员函数,就是这样!

华夏公益教科书