SDL3 Rendering Bitmap File Feature Image

Rendering a Bitmap File with SDL3


Loading of bitmap image files (BMP files) is natively supported by SDL3. The way to go is as follows (from the flow diagram).

The bitmap image file (.bmp) is stored on your hard drive and can simply be loaded by the SDL_LoadBMP(bmp file) function to a SDL3 surface. This SDL3 surface is then transformed into a SDL3 texture by SDL_CreateTextureFromSurface(renderer, surface) function. And finally this texture is rendered by SDL_RenderPresent(renderer).

Creative Commons License This image by https://www.freepascal-meets-sdl.net is licensed under a Creative Commons Attribution 4.0 International License.
Flow diagram of the loading and rendering of a bitmap file in SDL3.

Let’s start on the left in the diagram. The easiest way to get a bitmap image file (.bmp) for a game or application ready for usage is to create one in a drawing application. Or use the example bitmap “fpsdl.bmp” we used in the code (right click, save copy).

Free Pascal meets SDL sample image bmp format
Creative Commons License This image by https://www.freepascal-meets-sdl.net is licensed under a Creative Commons Attribution 4.0 International License.
The original image is 200×200 pixels wide.

And now let’s see how it is done in code.

program SDL_LoadingRenderingBMP;

uses SDL3;

var
  sdlWindow1: PSDL_Window;
  sdlRenderer: PSDL_Renderer;
  sdlSurface1: PSDL_Surface;
  sdlTexture1: PSDL_Texture;

begin

  // initilization of video subsystem
  if not SDL_Init(SDL_INIT_VIDEO) then
    Halt;

  // create window and renderer
  if not SDL_CreateWindowAndRenderer('Rendering BMP File', 500, 500, 0, @sdlWindow1, @sdlRenderer) then
    Halt;

  // create surface from file
  sdlSurface1 := SDL_LoadBMP('fpsdl.bmp');
  if sdlSurface1 = nil then
    Halt;

  // create texture from surface
  sdlTexture1 := SDL_CreateTextureFromSurface(sdlRenderer, sdlSurface1);
  if sdlTexture1 = nil then
    Halt;

  // render texture
  if not SDL_RenderTexture(sdlRenderer, sdlTexture1, nil, nil) then
    Halt;

  // render to window for 2 seconds
  if not SDL_RenderPresent(sdlRenderer) then
    Halt;
  SDL_Delay(2000);

  // clear memory
  SDL_DestroyTexture(sdlTexture1);
  SDL_DestroySurface(sdlSurface1);
  SDL_DestroyRenderer(sdlRenderer);
  SDL_DestroyWindow (sdlWindow1);

  // closing SDL2
  SDL_Quit;

end.                                                                   

The result is this:

Result screenshot for chapter 4
Creative Commons License This image by https://www.freepascal-meets-sdl.net is licensed under a Creative Commons Attribution 4.0 International License.
This is the result of the code.

The var clause,

var
  sdlWindow1: PSDL_Window;
  sdlRenderer: PSDL_Renderer;
  sdlSurface1: PSDL_Surface;
  sdlTexture1: PSDL_Texture;

contains two new variables, namely “sdlSurface1” and “sdlTexture1” of the pointer types PSDL_Surface and PSDL_Texture, respectively.

SDL3 is initialized and the window and renderer are set up as known.

Step 1: Loading the BMP file to a SDL3 Surface

  // create surface from file
  sdlSurface1 := SDL_LoadBMP('fpsdl.bmp');
  if sdlSurface1 = nil then
    Halt;

SDL_LoadBMP(name of bmp image file) does what you expect, it loads the image file and generates a SDL3 surface from it. Attention though, if you just give a file name, it is assumed that the file is found in the same folder as the executing application. Optionally you can also give a full file path, e.g. in Windows something like ‘C:\MyImages\fpsdl.bmp’.

Step 2: Creating a SDL2 Texture from the SDL2 Surface

The next step is to get a SDL3 texture. That’s achieved as follows.

  // create texture from surface
  sdlTexture1 := SDL_CreateTextureFromSurface(sdlRenderer, sdlSurface1);
  if sdlTexture1 = nil then
    Halt;

The function to use is SDL_CreateTextureFromSurface(renderer, surface)

It just does what you expect and transforms the SDL3 surface into a SDL3 texture with the help of the given renderer. But be careful, the SDL3 surface is still there and its memory is not released automatically by this function.

Step 3: Prepare the SDL2 Texture to be Rendered

Before actually rendering the texture, we need to copy it to the rendering target (our window) by SDL_RenderTexture(renderer, texture, source rectangle (texture), destination rectangle (rendering target)).

  // render texture
  if not SDL_RenderTexture(sdlRenderer, sdlTexture1, nil, nil) then
    Halt;

So the texture is copied to the rendering target (which is the window). The first nil argument means that we want to copy the whole rectangle. The second nil means that we want to copy to the whole dimensions of the rendering target, here the whole window. Let’s have a closer look at the function.

You see here, that you could use arguments of type PSDL_FRect instead of nil, which basically describes rectangles. This way you could copy parts of the texture to certain parts of the window.

Step 4: The Rendering

And finally the rendering is done by the known SDL_RenderPresent().

Step 5: Destroying Surfaces and Textures

It is important to free the memory occupied by the surface and texture by SDL_DestroySurface(surface) and SDL_DestroyTexture(texture).

  // clear memory
  SDL_DestroyTexture(sdlTexture1);
  SDL_FreeSurface(sdlSurface1);
  SDL_DestroyRenderer(sdlRenderer);
  SDL_DestroyWindow (sdlWindow1);

Now you know how to load and render a bmp file to a window. 🙂

Remark: DO NEVER combine SDL_CreateTextureFromSurface() and SDL_LoadIMG!

Do never combine step 1 and step 2 to avoid declaring and freeing a surface. DO NEVER do this:

sdlTexture1 := SDL_CreateTextureFromSurface(sdlRenderer, SDL_LoadBMP('fpsdl.bmp'));

This will run without any problem, though SDL_CreateTextureFromSurface() will not free the surface created by SDL_LoadBMP() automatically. And now you have no handle to free this surface. This creates a memory leak. 

Previous Chapter | Next Chapter

Leave a Reply

Your email address will not be published. Required fields are marked *