Image files to use in games and applications often are available in other formats than simple bitmap files (e.g. jpg, png, tif and so forth), because often bitmap files need a significant higher amount of disk space memory.
Also it would be desirable to load an image file directly and create a SDL2 texture from it instead of firstly creating a SDL2 surface and then creating a SDL2 texture from the surface (as seen in the chapter about bitmap loading).
The SDL2_image Unit
Here comes the SDL2_image unit into play. It allows:
- Loading of many common image formats
- Supported formats: ICO, CUR, BMP, GIF, JPG, LBM, PCX, PNG, PNM, TIF, XCF, XPM, XV, WEBP
- Creation of SDL2 texture from image files directly
These features are obviously not part of native SDL 2.0. SDL2_image is an official extension of SDL 2.0, which is developed and maintained by the same developers. Therefore, before right jumping into the code we need the corresponding library files.
- download the most recent version of the Runtime Binaries of the SDL2_image library for your system
- install the library according to your system (Win32/64, Linux, Mac OS X)
SDL2_image Installing Instructions for Windows
Download the corresponding SDL2_image package depending on your system (32 bit or 64 bit) and extract the file. You will end up with a SDL2_image.dll and some further dlls which are necessary for support of some image formats. Copy all these files to your system folder, e.g. for Windows XP 32 bit C:\WINDOWS\system32\. If you are not sure about your system folder, you should copy all these files to the same folder where the source code file (.pas or .pp) of your SDL 2.0 program is.
IMG_Load and IMG_LoadTexture
Have a look at the flow diagram below 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 skip the step of first creating a SDL2 surface from the image file.
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.
Coding example with SDL2_image
And now let’s start with some code. I will show the code as a whole first and after that I will discuss it in smaller pieces from top to bottom until the “end.” 🙂
program Chapter4_SDL2; uses SDL2, SDL2_image; var sdlWindow1 : PSDL_Window; sdlRenderer : PSDL_Renderer; sdlTexture1 : PSDL_Texture; begin //initilization of video subsystem if SDL_Init(SDL_INIT_VIDEO) < 0 then HALT; sdlWindow1 := SDL_CreateWindow('Window1', 50, 50, 500, 500, SDL_WINDOW_SHOWN); if sdlWindow1 = nil then HALT; sdlRenderer := SDL_CreateRenderer(sdlWindow1, -1, 0); if sdlRenderer = nil then HALT; sdlTexture1 := IMG_LoadTexture(sdlRenderer, 'C:\fpsdl.bmp'); if sdlTexture1 = nil then HALT; SDL_RenderCopy(sdlRenderer, sdlTexture1, nil, nil); SDL_RenderPresent (sdlRenderer); SDL_Delay(2000); SDL_DestroyTexture(sdlTexture1); SDL_DestroyRenderer(sdlRenderer); SDL_DestroyWindow (sdlWindow1); //shutting down video subsystem SDL_Quit; end.
Well, here it is. 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 Chapter4_SDL2; uses SDL2, SDL2_image; var sdlWindow1 : PSDL_Window; sdlRenderer : PSDL_Renderer; sdlTexture1 : PSDL_Texture;
Now the first eight lines are discussed. Well, the first line starts a Pascal program as usual. In contrast to the previous chapter, the uses clause is extended by SDL2_image. To be clear again, native SDL 2.0 has no support for different image formats, except for BMP image files. Although native SDL 2.0 allows for loading of BMP image files, it just allows for creation of SDL_Surfaces, but we would like to create SDL_Textures.
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. All these variable types are pointer types which is indicated by the captial “P” at the beginning of the variable types’ names.
begin //initilization of video subsystem if SDL_Init(SDL_INIT_VIDEO) < 0 then HALT; sdlWindow1 := SDL_CreateWindow('Window1', 50, 50, 500, 500, SDL_WINDOW_SHOWN); if sdlWindow1 = nil then HALT; sdlRenderer := SDL_CreateRenderer(sdlWindow1, -1, 0); if sdlRenderer = nil then HALT;
As any Pascal program the main program’s begin-end block is initiated by “begin”. The initilization of SDL 2.0 is started as discussed in detail in the last chapter by SDL_Init().
After successful initialization of SDL 2.0 a window with title “Window1” and a renderer is created as known from a previous chapter.
Creation of SDL_Texture and Rendering in SDL 2.0
sdlTexture1 := IMG_LoadTexture(sdlRenderer, 'C:\fpsdl.bmp'); if sdlTexture1 = nil then HALT; SDL_RenderCopy(sdlRenderer, sdlTexture1, nil, nil); SDL_RenderPresent (sdlRenderer); SDL_Delay(2000);
Now we load the image file to the SDL_Texture we called “sdlTexture1”. The function to do this is
IMG_LoadTexture(renderer: PSDL_Renderer; _file: PAnsiChar): PSDL_Texture
This function is provided by SDL2_image. Its prefix is IMG instead of SDL for native SDL 2.0 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 “C:\fpsdl.bmp”. 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.
Next we would like the successfully loaded image in “sdlTexture1” to be rendererd for which reason we pass it to the renderer by function
SDL_RenderCopy(renderer: PSDL_Renderer; texture: PSDL_Texture; srcrect: PSDL_Rect; dstrect: PSDL_Rect): SInt32.
At first this function asks for a renderer (and indirectly for the related window) to which we would like to copy the texture. In our case this will be “sdlRenderer” again. Next the texture to be copied to the renderer/window is required, this is “sdlTexture1” here. The last two parameters are named “srcrect” and “dstrect” and of type PSDL_Rect. PSDL_Rect is a SDL 2.0 predefined record to define rectangles, hence the name. I will not go into details about this here, but in the next chapter (Chapter 5) we will learn more about PSDL_Rect, although it will be in another context. For simplicity we just use nil as argument here. This makes the function to pass the full texture to the renderer/window and stretching it to the dimensions of the window. So the 200 x 200 pixel image is strechted to 500 x 500 pixels, the latter being the width and height of the window. This function returns 0 on success and the negative error code on failure.
Finally everything gets rendered to the window by the SDL_RenderPresent(Renderer) procedure as known from the previous chapter. To be able to see it, we wait with a 2 seconds delay.
Clean up the memory in SDL 2.0
SDL_DestroyTexture(sdlTexture1); SDL_DestroyRenderer(sdlRenderer); SDL_DestroyWindow (sdlWindow1); //shutting down video subsystem SDL_Quit; end.
We first created a window, then a renderer and finally a texture. So now we go the opposite way, first destroy the texture, then the renderer and finally the window. The procedures are:
After removing the objects from memory, SDL 2.0 has to be quit as seen in the previous chapter.
Wow, we finally made it. Congratulations, this chapter is finished :-). The next chapter is waiting though.