Programming: SDL2 Native Functions

We’re using SDL 2 library to create our first games. This library allows low level access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL and Direct3D.

In our first working game, Arkanoid, we used about 20 SDL2’s functions. I’m going to describe them in this post.

SDL_Init() and SDL_Quit()

SDL_Init(flags)

The two functions initialize and quit the SDL system, respectively. You have to initialize SDL to be able to make use of functions provided by the SDL or to quit it to deallocate resources.

In addition, SDL_Init() takes a parameter which specifies what to initialize (e.g., SDL_INIT_EVERYTHING makes it initialize all subsystems).

The Init function has to be the very first one you use in your SDL scripts whereas the Quit function has to be the last one.

SDL_CreateWindow()

SDL_CreateWindow(window_name, x_position, y_position, width, height, flags)

Pretty obvious – this function creates an empty window. The parameters are as follows:

  • window_name – a string that sets the window name
  • x_position, y_position – where on screen the upper left corner of the window is
  • width, height – the width and height of the window
  • flags – a value that specifies other window parameters. E.g., SDL_WINDOW_MINIMIZED makes the window initially minimized

A window created in this way will flash on your screen and immediately disappear. That’s because there are no other functions/statements that would cause it to display any other behaviour.

SDL_Delay()

SDL_Delay(millisec)

This function “pauses” the SDL system, making it wait for millisec milliseconds before executing any following code.

If you use it, e.g., after creating a window, you can have your window up for the given amount of time but you won’t be able to interact with it because the SDL is paused.

SDL_GetError() and SDL_Log()

SDL_Log(string)

If internal SDL errors occured, this function returns a string for the last SDL error. You can use it in conjunction with print statements to track what happened in the SDL system.

The SDL_Log() function prints out the string specified as the parameter to console. You can use this function in conjunction with SDL_GetError() to print out SDL errors.

SDL_CreateRenderer()

SDL_CreateRenderer(window, driver_index, driver_flags)

This function creates a rendering context for a window. A rendering context is the port through which OpenGL commands pass.

  • window – reference to the window for which we’re creating the renderer
  • driver_index – which driver to use. -1 for the first available driver which matches the given flags
  • driver_flags – obscure attributes like SDL_RENDERER_ACCELERATED

SDL-specific object types

SDL defines several specific object types that are used in various SDL functions and beyond.

  • SDL_Window – refers to a window created with the SDL_CreateWindow() function described above. Create function returns a pointer to the window it created
  • SDL_Renderer – refers to a renderer created with the SDL_CreateRenderer() function described above. Create function returns a pointer to the renderer it created
  • SDL_Surface – refers to a chunk of pixel data. Objects of this type essentially contain an image, however they are not aware of image height or width or other attributes since they only contain raw pixel data. These objects are created with special functions, like SDL_LoadBMP() which directly accesses an external file and reads off pixel data. Surfaces are referred to via pointers. NB: surfaces are loaded in regular RAM, allowing direct access to it but making rendering slower. Surfaces do not need renderers!
  • SDL_Texture – an efficient, driver-specific representation of pixel data. Like SDL_Surface, refers to an image but has a different internal implementation. Created by special functions, like SDL_CreateTextureFromSurface() which returns a pointer to the texture it created. NB: textures are loaded in video card’s VRAM, thus you have no direct access to the image data but rendering it is accelerated by GPU (explanation). Textures need renderers!
  • SDL_Rect – a struct that contains four integers that define a rectangle on the screen. The first two give the coordinates of the upper left corner of the rectangle while the next two give its width and height, respectively. Is simply declared when needed, is referred to via a pointer and is used as a parameter in various other functions

Routine for displaying simple content in a window

Now that you have a window and a renderer, you can display some content in the window. The easiest thing is to draw a simple shape (e.g., a rectangle) using SDL’s own functions. The next simplest thing is load a ready-made image into the window.

The idea when loading an image into a window is as follows. First you load the image from an external file using the SDL_LoadBMP() function. Then you assign the loaded image to an object of type SDL_Surface. So now you have an image that SDL is aware of, and can do something with it. You have two options: display it in your window using SDL_BlitSurface() or first convert it to a texture using SDL_CreateTextureFromSurface() and then display it in your window using SDL_RenderCopy() (since now you’re dealing with a texture, not a surface, you use a dedicated function).

Brief description of each function follows.

SDL_LoadBMP(string)

The string parameter should point to the file which contains the image data to be loaded. Needless to say, the image file must be a bitmap (*.bmp extension is mandatory in the path!). This function should be on the right-hand side of an assignment statement; since it returns a pointer to the surface it created, a pointer to an object of type SDL_Surface should be on the left-hand side.

SDL_CreateTextureFromSurafce(renderer, surface)

The renderer parameter refers to the renderer you’re going to use; pick a renderer that is tied to the window in which you will want to display the texture. The surface parameter refers to the surface you want to convert.

SDL_RenderCopy(renderer, texture, rect_source, rect_destination)

The first two parameters are self-explanatory: the renderer and the texture you’re using. The source rect refers to the rectangular area in the original texture you want to clip out and use for rendering (nullptr to use the whole texture). The destination rect refers to a rectangular area in the window the renderer is tied to where you want to display the texture (or part of it). Use nullptr to stretch the texture over the whole window.

SDL_RenderPresent(renderer)

Here comes something special for computer graphics. When you draw or display objects, they don’t immediately appear on the screen. Instead, they are added to the “backbuffer”, an abstract storage area (a frame, if you will) that accumulates all objects. Once you’re done drawing the scene, you issue this command to update the window tied to the renderer by bringing out the backbuffer.


The functions described above are sufficient to load, say, a single sprite from a sprite sheet and display it in a window. Below is a minimal working example:

#include "SDL.h"

int main(int argc, char* argv[])
{
	SDL_Init(SDL_INIT_EVERYTHING);
	SDL_Window* window = SDL_CreateWindow("Sprite",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,320,640,SDL_WINDOW_OPENGL);
	SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_WINDOW_OPENGL);
	SDL_Surface* image = SDL_LoadBMP("sprites.bmp");//the sprite sheet must be placed in the same folder as project working directory (normally the folder that contains the *.vcxproj file)
	SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, image);
	SDL_Rect clip = {208,4,140,194};
	SDL_RenderCopy(renderer, texture, &clip,nullptr);
	SDL_RenderPresent(renderer);
	SDL_Delay(3000);
	//deallocate resources
	SDL_DestroyTexture(texture);
	SDL_FreeSurface(image);
	SDL_DestroyRenderer(renderer);
	SDL_DestroyWindow(window);
	window = nullptr;
	renderer = nullptr;
	image = nullptr;
	texture = nullptr;
	SDL_Quit();
	return 0;
}

So that using this free sprite sheet (go to the sprite sheet):

sprites

I get the following かわいい result:

kawaii


The code snippet above includes clean-up functions which are mandatory: you need to deallocate resources to free memory so that no memory leaks occur. This includes both setting pointers to nullptr and destroying created objects by SDL’s dedicated functions:

  • SDL_DestroyWindow(window) – destroys window
  • SDL_DestroyRenderer(renderer) – destroys renderer
  • SDL_DestroyTexture(texture) – destroys texture
  • SDL_FreeSurface(surface) – destroys surface

Note that you have to include the SDL.h file to be able to use SDL in your code (line 1). Another thing is that default project properties have to be modified so that Visual Studio can find the necessary SDL’s *.h and *.dll files. This is easy and there are many tutorials that teach how to prepare your Visual Studio system to work with SDL.

One last nuisance that I discovered the hard way is that SDL requires the main() function to have specific format – the one shown in the code example above – to work. It has to have int return type and has to have int argc, char* argv[] parameters. Otherwise it won’t work properly.


In our live coding sessions of Arkanoid, we used these SDL native functions (and a few others, not mentioned here – mainly user input stuff); we wrapped these functions with C++ classes which defined the entire logic of the game. The movement of the ball, collisions, creation of blocks etc. was all handled by normal C++ functions and only the user input and re-drawing of the frames was done using the SDL functions.

About Rokas Paulauskas

2014  Programming