Raspberry Pi - Building SDL 2 on Raspbian
Posted on January 22, 2015 by Paul
This is a short tutorial on how to get started with SDL 2 programming on a Raspberry Pi device that has Raspbian installed. If you want to write C++, or C, games that are easily portable to other platforms SDL 2 is the way to go on Raspbian. Unfortunately, at the time of this writing Raspbian comes with the outdated SDL 1.2 installed.
Let’s start by updating our Raspbian installation, feel free to skip this step if your system was recently updated:
1 sudo apt-get update
2 sudo apt-get upgrade
Next, we will need to install some libraries that will be used when we build SDL 2:
1 sudo apt-get install build-essential libfreeimage-dev libopenal-dev libpango1.0-dev libsndfile-dev libudev-dev libasound2-dev libjpeg8-dev libtiff5-dev libwebp-dev automake
SDL 2 can be downloaded from https://www.libsdl.org/download-2.0.php, be sure to select the source code archive, SDL2-2.0.3.tar.gz, or a newer version if available. You can download and extract the archive directly on your Raspberry Pi:
1 cd ~
2 wget https://www.libsdl.org/release/SDL2-2.0.3.tar.gz
3 tar zxvf SDL2-2.0.3.tar.gz
4 cd SDL2-2.0.3 && mkdir build && cd build
Now, it is time to configure SDL 2:
1 ../configure --disable-pulseaudio --disable-esd --disable-video-mir --disable-video-wayland --disable-video-x11 --disable-video-opengl
or, if you have a Raspberry Pi 2:
1 ../configure --host=armv7l-raspberry-linux-gnueabihf --disable-pulseaudio --disable-esd --disable-video-mir --disable-video-wayland --disable-video-x11 --disable-video-opengl
The above options will make sure, SDL 2 is built with the OpenGL ES backend and that any SDL application will run as a full screen application, the windowed mode under X tends to be more buggy on Raspberry Pi. On the plus side, you will be able to launch your application, or game, directly from the text interface without the overhead of running the X server. If you wish you can start your application from LXDE (the default window manager for Raspbian) and the application will run full screen.
Assuming, you’ve had no error in the configure phase, you can actually build and install the library:
1 make -j 4
2 sudo make install
Now, you should be able to compile any C++ code that uses SDL 2 with something like:
1 g++ -o program_name program_name.cpp `sdl2-config --cflags --libs`
SDL 2 by itself can use only .bmp graphic files and .wav audio files. If you want to be able to load other image formats, like .png, you can use SDL_image 2.0 or something like FreeImage. The advantage of using SDL_image is that this is directly compatible with SDL 2, basically you will load an image file in a format that will just work with SDL 2. Similarly, there are libraries for loading sound files, SDL_mixer 2.0, or font files SDL_ttf 2.0.
Since working with images in various formats is a must for almost any SDL 2 application, I will exemplify, shortly, how to download, build and install SDL_image:
1 cd ~
2 wget http://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.0.tar.gz
3 tar zxvf SDL2_image-2.0.0.tar.gz
4 cd SDL2_image-2.0.0 && mkdir build && cd build
5 ../configure
6 make -j 4
7 sudo make install
If your code uses SDL_image you will need to explicitly link the SDL_image library, e.g.:
1 g++ -o program_name program_name.cpp `sdl2-config --cflags --libs` -lSDL2_image
The SDL_ttf library can be built similarly. If you want to build SDL_mixer you will need to build and install first smpeg2, after which you can build and install SDL_mixer like before.
Time to write a short code example that will open an SDL window and show an image for 10 seconds, after which will free the resources and exit. I assume that you’ve successfully installed SDL 2 and SDL_image on your Raspberry Pi.
1 #include <SDL2/SDL.h>
2 #include <SDL2/SDL_image.h>
3 #include <iostream>
4
5 // Manage error messages
6 void check_error_sdl(bool check, const char* message);
7 void check_error_sdl_img(bool check, const char* message);
8
9 // Load an image from "fname" and return an SDL_Texture with the content of the image
10 SDL_Texture* load_texture(const char* fname, SDL_Renderer *renderer);
11
12
13 int main(int argc, char** argv) {
14 // Initialize SDL
15 check_error_sdl(SDL_Init(SDL_INIT_VIDEO) != 0, "Unable to initialize SDL");
16
17 // Create and initialize a 800x600 window
18 SDL_Window* window = SDL_CreateWindow("Test SDL 2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
19 800, 600, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
20 check_error_sdl(window == nullptr, "Unable to create window");
21
22 // Create and initialize a hardware accelerated renderer that will be refreshed in sync with your monitor (at approx. 60 Hz)
23 SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
24 check_error_sdl(renderer == nullptr, "Unable to create a renderer");
25
26 // Set the default renderer color to corn blue
27 SDL_SetRenderDrawColor(renderer, 100, 149, 237, 255);
28
29 // Initialize SDL_img
30 int flags=IMG_INIT_JPG | IMG_INIT_PNG;
31 int initted = IMG_Init(flags);
32 check_error_sdl_img((initted & flags) != flags, "Unable to initialize SDL_image");
33
34 // Load the image in a texture
35 SDL_Texture *texture = load_texture("img_test.png", renderer);
36
37 // We need to create a destination rectangle for the image (where we want this to be show) on the renderer area
38 SDL_Rect dest_rect;
39 dest_rect.x = 50; dest_rect.y = 50;
40 dest_rect.w = 337; dest_rect.h = 210;
41
42 // Clear the window content (using the default renderer color)
43 SDL_RenderClear(renderer);
44
45 // Copy the texture on the renderer
46 SDL_RenderCopy(renderer, texture, NULL, &dest_rect);
47
48 // Update the window surface (show the renderer)
49 SDL_RenderPresent(renderer);
50
51 // Wait for 10 seconds
52 SDL_Delay(10000);
53
54 // Clear the allocated resources
55 SDL_DestroyTexture(texture);
56 IMG_Quit();
57 SDL_DestroyRenderer(renderer);
58 SDL_DestroyWindow(window);
59 SDL_Quit();
60
61 return 0;
62 }
63
64 // In case of error, print the error code and close the application
65 void check_error_sdl(bool check, const char* message) {
66 if (check) {
67 std::cout << message << " " << SDL_GetError() << std::endl;
68 SDL_Quit();
69 std::exit(-1);
70 }
71 }
72
73 // In case of error, print the error code and close the application
74 void check_error_sdl_img(bool check, const char* message) {
75 if (check) {
76 std::cout << message << " " << IMG_GetError() << std::endl;
77 IMG_Quit();
78 SDL_Quit();
79 std::exit(-1);
80 }
81 }
82
83 // Load an image from "fname" and return an SDL_Texture with the content of the image
84 SDL_Texture* load_texture(const char* fname, SDL_Renderer *renderer) {
85 SDL_Surface *image = IMG_Load(fname);
86 check_error_sdl_img(image == nullptr, "Unable to load image");
87
88 SDL_Texture *img_texture = SDL_CreateTextureFromSurface(renderer, image);
89 check_error_sdl_img(img_texture == nullptr, "Unable to create a texture from the image");
90 SDL_FreeSurface(image);
91 return img_texture;
92 }
Assuming that you’ve saved the above code as sdl2_test.cpp and saved this image in the same folder as the C++ source file, you can compile and run the code with:
1 g++ -std=c++0x -Wall -pedantic sdl2_test.cpp -o sdl2_test `sdl2-config --cflags --libs` -lSDL2_image
2 ./sdl2_test
The above instructions will use the default version of GCC, 4.6.x, from Raspbian that has only partial support for C++11. If you want to use a more modern C++ compiler, with full support for C++11 and partial support for C++14, read my previous article. In this case you should use something like:
1 g++-4.9 -std=c++14 -Wall -pedantic sdl2_test.cpp -o sdl2_test `sdl2-config --cflags --libs` -lSDL2_image
2 ./sdl2_test
This is what you should see:
If you want to learn more about SDL I would recommend reading SDL Game Development by Shaun Mitchel.
or The Black Art of Multiplatform Game Programming by Jazon Yamamoto.