Tag Archives: graphics

SDL3 Image Formats Feature Image

Rendering Image Files with any format (SDL3_image)


Image files to use in games and applications often are available in other formats, e.g. JPG or PNG. In contrast to simple bitmap files, which need a significant higher amount of disk space memory, are they memory-compressed and need significant less disk space.

Also it would be desirable to create the SDL3 texture directly by loading from an image file, instead of creating a SDL2 surface in-between as seen in the previous chapter.

The SDL3_image Unit

Here comes the SDL3_image unit into play. It allows:

  • Loading of many common image formats
  • Supported formats: AVIF, ICO, CUR, BMP, GIF, JPG, JXL, LBM, PCX, PNG, PNM, SVG, QOI, TIF, XCF, XPM, XV, WEBP
  • Creation of SDL3 texture from image files directly

SDL3_image is an official extension of SDL3, which is developed and maintained by the same developers. Therefore, before right jumping into the code we need the corresponding library files.

Installing SDL3_image

  • Get you files here: SDL3_image library releases
  • Windows:
    • Download the most recent version of the Runtime Binaries (DLL files) of the SDL3_image library for your system (32 bit or 64 bit)
    • Copy all these files, especially SDL3_image.dll, to your system folder (system or system32)
  • Linux:
    • Download the most recent version of the source code and compile it (until the repos are providing a pre-compiled version to install via the paket manager)
    • Copy these files, especially libSDL3_image.so, to your library folder; often /usr/local

IMG_Load and IMG_LoadTexture

SDL2 Texture and Surface relation diagram
Creative Commons License This image by https://www.freepascal-meets-sdl.net is licensed under a Creative Commons Attribution 4.0 International License.
An image file (left) can be loaded as a surface or a texture and then be rendered to the screen.

Have a look at the flow diagram which is an extended version of the diagram seen in the chapter about loading of bitmap files. You see it is extended by two function with the prefix IMG instead of SDL, namely IMG_LoadTexture() and IMG_Load(). Both of these functions allow to load image files of all the supported file formats mentioned above. Also you see that IMG_LoadTexture() creates a texture directly from the image file, so we can skip creating a SDL3 surface.

Let’s try the following image files (dimensions: 200 x 200 pixels, formats: bmp, jpg and png) but feel free to use any other image file you like.

Code Example using SDL3_image

program SDL_LoadingDifferentFormats;

uses SDL3, SDL3_image;

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

begin

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

  if not SDL_CreateWindowAndRenderer('Use SDL3_image', 500, 500, 0, @sdlWindow1, @sdlRenderer) then Halt;

  // load image file directly to texture
  sdlTexture1 := IMG_LoadTexture(sdlRenderer, 'data/fpsdl.png');
  if sdlTexture1 = nil then Halt;

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

  // render to window for 2 seconds
  SDL_RenderPresent(sdlRenderer);
  SDL_Delay(2000);

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

  // closing SDL2
  SDL_Quit;

end.    

This code will create a window of dimensions 500 x 500 pixels which is showing the “Freepascal meets SDL” image for two seconds. After that the window closes automatically. The following screenshot shows the result of the example program.

Now let’s get into the code step by step.

program SDL_LoadingDifferentFormats;

uses SDL3, SDL3_image;

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

The first eight line starts a Pascal program as usual. In contrast to the previous chapter, the uses clause is extended by SDL3_image. Again, native SDL3 has no support for loading different image formats, except for BMP image files. And native SDL3 doesn’t allow for loading of BMP image files directly into SDL3 textures, but SDL3 surfaces only.

We need a texture variable to which we can load the image information of an image file. This will be “sdlTexture1” of PSDL_Texture type.

begin

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

  if not SDL_CreateWindowAndRenderer('Use SDL3_image', 500, 500, 0, @sdlWindow1, @sdlRenderer) then Halt; 

The initialization of SDL3, the window and renderer creation are done as known from previous chapters.

Creation and Rendering of a SDL3 Texture from an Image File

  // load image file directly to texture
  sdlTexture1 := IMG_LoadTexture(sdlRenderer, 'data/fpsdl.png');
  if sdlTexture1 = nil then Halt;

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

  // render to window for 2 seconds
  SDL_RenderPresent(sdlRenderer);
  SDL_Delay(2000);

Now we load the image file to the SDL3 texture we called “sdlTexture1”. The function to do this is IMG_LoadTexture(renderer, path to image file).

This function is provided by SDL3_image. Its prefix is IMG instead of SDL for native SDL3 functions. That function is why we needed to insert SDL2_image in the uses clause. The parameters of this function are a renderer, that is “sdlRenderer” for us, and as a second the absolute or relative path to an image file, for us it is “data/fpsdl.png”, assuming that the “fpsdl.png” image file is in a sub-folder called “data”.

Of course you may use any other directory to store/load the image or even use a different image. The function will recognize the image file’s format automatically, so feel free to load any of the allowed formats. If the loading fails, for instance you gave a wrong path as argument, this function will return nil. Try changing “fpsdl.png” by “fpsdl.jpg” or “fpsdl.bmp” (if these files exist in the data sub-folder).

The loaded SDL3 texture in “sdlTexture1” we can now render as known from previous chapter by SDL_RenderTexture(), followed by SDL_RenderPresent(). SDL_Delay() delays the application by 2 seconds.

Clean up the Memory in SDL3

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

  // closing SDL2
  SDL_Quit;

end. 

As known from previous chapters, we free the memory by destroying the objects in reversed order. After removing the objects from memory, SDL3 has to be quit.

Wow, we finally made it. Congratulations, this chapter is finished :-). The next chapter is waiting though.

Previous Chapter | Next Chapter

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

SDL3 Surfaces and Textures Feature Image

SDL3 Surfaces and SDL3 Textures


This chapter treats two very important SDL3 concepts, namely SDL3 surfaces and SDL3 textures.

Briefly: The Basics of Graphics Programming

Loading and the movement of objects in a game (or other applications) is a major concept in (game) programming. These images are then refered to as sprites, usually. Let’s have a look at a simple example:

left: ball and paddle erased between each frame; right: ball and paddle not erased between frames
Left: Window is cleared between each new drawn frame. Right: Window is not cleared.

Here are two screenshots from a simple game. The player has to move the green paddle up- and downwards to prevent the bouncing blue ball from getting through to the right side. The game uses two sprites, the blue ball sprite and the green paddle sprite (see left screenshot). The background color is set to black. The left screenshot is how the game appears to the player. The right screenshot demonstrates what happens if each frame is drawn onto each other without clearing it in between. – Now it is clearly visible that the sprites are redrawn again and again with slightly different coordinates, and that is how (game) graphics work (even for the most sophisticated 3d games):

  1. Draw the (new) frame
  2. Show the frame (in a window on screen)
  3. Clear the frame (and go back to step 1)

Briefly: The Relation between Graphic Objects (e.g. Sprites) and Hardware

Actually there are just three locations where these images are stored in your computer system.

  1. All images (photo images, drawings, sprites for 2d games, textures for 3d games) are stored on your harddrive somewhere.
  2. If you start a photo viewer, a paint program, a 2d game or a 3d game, in all cases the corresponding images need to be loaded from your harddrive to RAM (Random-Access Memory) since displaying and manipulation (e.g. rotation of a photo image by 90°) of images loaded to RAM is much, much faster.
  3. Especially for games a fast access to the image data is highly important! And finally there isn’t just one RAM but two, a CPU controlled one located on the motherboard used by every program/application that needs some RAM. The second RAM is located right at your graphic board and controlled by the so-called GPU (graphics processing unit). This is what we want to use if we develop games since it is dedicated, optimized and just hungry for tasks related to fast image processing.

Many games and applications do not only target at common computer systems, but for mobile devices, e.g. smart phones. The principles described are also true for these devices even though there may be differences in detail.

The SDL3 Surface

The SDL3 surface allows you to represent graphic objects like sprites. Every SDL2 surface has a width and height, a pixel format and other properties. The surfaces have the advantage that they are very easy to use and understand conceptually.

SDL3 surfaces are usually represented by a PSDL_Surface handle.

The SDL2 Texture

The SDL3 texture allows you to represent graphic objects just like the SDL3 surface does, although there is a major difference: It is hardware accalerated. So the graphic object is stored in the graphic board’s RAM and any manipulation is done by the graphic board’s GPU.

So as a rule,

always use SDL3 Textures to render your graphic objects in a game

then you go for high performance! You can barely manipulate them directly. SDL3 textures are usually represented by a PSDL_Texture handle.

Oftentimes the workflow is to prepare some graphics using SDL3 surfaces, but then it is transformed into a SDL3 texture for rendering in a game.

Three Ways to the PSDL_Texture

So, how to get a PSDL_Texture? In principle there are three ways to create SDL3 textures. For way 2 and 3 the flow diagram may illustrate how it works.

Way 1: From Scratch

You create a SDL3 texture from scratch, so you set a pixel format and texture access format and have to fill in your texture data manually. This is the most sophisticated way and will not be covered at this point.

Way 2: From SDL3 Surface

Way 2: The path from the file to the surface, to the texture and to the screen. Way 3: The path rom the file to the texture and to the screen.

2) You create a SDL3 surface from an image file first and then you create the SDL3 texture from the SDL3 surface. This way is shown in the diagram but it means two steps: From left to bottom and from bottom to top.

Way 3: Directly from Image File

3) You create a SDL3 texture from an image file directly. This is shown in the diagram, too. This is the simplest way to create a SDL3 texture.

Previous Chapter | Next Chapter

Dynamic Colouring Feature Image SDL3

Dynamic Colouring

Case: Drawing for Dynamic Colouring

As an example when drawing can be very helpful, think of the following situation. You create a game, let’s say a racing game. There are different players. Of course, each player’s car has to have a different colour. There are generally two ways to achieve this:

1) You create several images with differently coloured cars and store them on your harddrive.

This is perfectly okay if you have a small number of cars (and colours) to be chosen. But what if you want the player to choose from a large variety of colours, 100 colours or more, or what if you want to let the player to choose the colour of his car by himself? Notice, in case of 16 bit colouring that means 65536 possibilities after all! Would you want to create that many images? In case of 32 bit colouring you have fantastic 4.29 billion colours!! Amazing, but you will never be able to create so many images in just one human being’s life. Furthermore, this would take up a lot of hard drive memory (4.29 billion times the file size of the car image) for just a simple car racing game. Look at the following image. It contains the discussed method from left to the middle. On the right to the middle is the solution :-).

SDL2 drawing and images diagram

Instead of having each car coloured as an image file, why not using just one image file of a car without colouring? It is kind of a template. Now you can easily ask the player what colour he prefers (and he may pick from 4.29 billion colours if necessary), and then you simply colour the car on the fly. This is the second way:

2) You create one template image on your harddrive and colour it during runtime of the program.

This is just one example where drawing is very helpful.

Colours Feature Image SDL3

Colours in Computer Graphics


Understanding Colours in Computer Graphics

The colour is composed of four components, RGBA, that is red, green, blue and the alpha value.

The physical screen consists of many small units. Every unit itself consists of three different coloured lights. These colours are red, green and blue. If you mix them up, you can get every other colour. These colours are mixed up additively. For example if you mix red and green you get yellow. For three colours that can be mixed with each other, there are eight combinations possible which lead to different colours:

  • RGB: white
  • RG: yellow
  • RB: magenta
  • R: red
  • GB: cyan
  • G: green
  • B: blue
  • all lights off: black.

Some may say, white and black are no colours at all. Well, that is right but doesn’t matter here and to keep it simple I will take them as colours.

Your screen has more than eight colours, doesn’t it? The reason is, your screen isn’t just able to switch lights on or off. Besides it is able to differ the intensities of the lights. The more intensity levels you have, the more colours you can display. The case that you have eight colours as discussed before means that you just have one intensity level, on or off. If your screen is in 8 bit mode, every pixel on the screen has the possibility to display 2 to the power of 8 colours. That are 256 different colours. Each of the three lights are adjusted according to the requested colour.

In 16 bit mode you have 2 power 16 and that are 65536 colours. Each light therefore has the appropriate amount of intensity levels. In 24 bit mode (“True Color”) we have overwhelming 16.7 million colours! – But make no mistake, in 32 bit mode only the 8 bit alpha channel is added, so we still have 16.7 million colours, but now there are additional 256 levels of transparency.