The libsdl direct media library is open source and cross-platform. It helps that it’s also part of Linux already. You can see this if you open a terminal and do a
apt-cache search libsdl2 | grep dev
This will show you what libraries are available
david@david-VM-PC9:~$ apt-cache search libsdl2 | grep dev libsdl2-dev - Simple DirectMedia Layer development files libsdl2-gfx-dev - development files for SDL2_gfx libsdl2-image-dev - Image loading library for Simple DirectMedia Layer 2, development files libsdl2-mixer-dev - Mixer library for Simple DirectMedia Layer 2, development files libsdl2-net-dev - Network library for Simple DirectMedia Layer 2, development files libsdl2-ttf-dev - TrueType Font library for Simple DirectMedia Layer 2, development files
Although SDL is available, the dev files aren’t installed by default and we want all the headers for C/C++ programs to use them.
We need to install the devs for the libraries we’ll need which are libsdl2-dev, libsdl2-image-dev (you do want to display graphics don’t you?), libsdl2-mixer-dev (for sounds) and if you want text you’ll need libsdl2-ttf-dev.
So install all those with
sudo apt install libsdl2-dev sudo apt install libsdl2-image-dev sudo apt install libsdl2-mixer-dev sudo apt install libsdl2-ttf-dev
Where do the headers get installed?
A quick search for sdl.h found it and associated header files in /usr/include/SDL2, a total of 76 header files though we’ll rarely use more than half a dozen.
Note. When I first wrote this, Ubuntu was on 18.04 LTS and clang was 6. When I updated this on 20.04 LTS, clang was version 10.0 and I got a weird include error.
The source code hasn’t changed but the VS Code JSON files have been altered slightly.
This is tasks.json
{
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"label": "clang-10.0 build active file",
"command": "/usr/bin/clang-10",
"args": [
"-g",
"${file}","${workspaceFolder}/hr_time.c",
"-o",
"${fileDirname}/demo",
"-I/usr/include/SDL2",
"-lSDL2"
],
"options": {
"cwd": "/usr/bin"
},
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
The two changes between this and earlier versions are the command line to compile which is now /usr/bin/clang-10
though I think clang without the -10 will also do.
The second change luine is the addition of "-I/usr/include/SDL2",
which tells the compiler the include path. Without it the compiler complains it can’t find the include file “begin_code.h” which is part of SDL2.
This is a listing of the demo program.
// sdldemo.c Author D. Bolton 7th March 2020
#include "hr_time.h"
#include <time.h>
#include<linux/time.h>
#define __timespec_defined 1
#define __timeval_defined 1
#define __itimerspec_defined 1
#include <SDL2/SDL.h> /* All SDL App's need this */
#include <stdio.h>
#include <stdlib.h>
#define QUITKEY SDLK_ESCAPE
#define WIDTH 1024
#define HEIGHT 768
SDL_Window* screen = NULL;
SDL_Renderer *renderer;
SDL_Event event;
SDL_Rect source, destination, dst;
int errorCount = 0;
int keypressed;
int rectCount = 0;
stopWatch s;
/* returns a number between 1 and max */
int Random(int max) {
return (rand() % max) + 1;
}
void LogError(char * msg) {
//FILE * err;
//int error;
//error = fopen_s(&err,"errorlog.txt", "a");
printf("%s\n", msg);
//fclose(err);
errorCount++;
}
/* Sets Window caption according to state - eg in debug mode or showing fps */
void SetCaption(char * msg) {
SDL_SetWindowTitle(screen, msg);
}
/* Initialize all setup, set screen mode, load images etc */
void InitSetup() {
srand((unsigned int)time(NULL));
SDL_Init(SDL_INIT_EVERYTHING);
SDL_CreateWindowAndRenderer(WIDTH, HEIGHT, SDL_WINDOW_SHOWN, &screen, &renderer);
if (!screen) {
LogError("InitSetup failed to create window");
}
SetCaption("Example One");
}
/* Cleans up after game over */
void FinishOff() {
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(screen);
//Quit SDL
SDL_Quit();
exit(0);
}
/* read a character */
char getaChar() {
int result = -1;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_KEYDOWN)
{
result = event.key.keysym.sym;
break;
}
}
return result;
}
void DrawRandomRectangle() {
char buff[20];
SDL_Rect rect;
SDL_SetRenderDrawColor(renderer, Random(256) - 1, Random(256) - 1, Random(256) - 1,255);
rect.h = 200;// Random(100) + 20;
rect.w = 200;// Random(100) + 20;
rect.y = Random(HEIGHT - rect.h - 1);
rect.x = Random(WIDTH - rect.w - 1);
SDL_RenderFillRect(renderer,&rect);
rectCount++;
if (rectCount % 10000 == 0) {
SDL_RenderPresent(renderer);
stopTimer(&s);
snprintf(buff,sizeof(buff),"%10.6f", diff(&s));
SetCaption(buff);
startTimer(&s);
}
}
/* main game loop. Handles demo mode, high score and game play */
void GameLoop() {
int gameRunning = 1;
startTimer(&s);
while (gameRunning)
{
DrawRandomRectangle();
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
keypressed = event.key.keysym.sym;
if (keypressed == QUITKEY)
{
gameRunning = 0;
break;
}
break;
case SDL_QUIT: /* if mouse click to close window */
{
gameRunning = 0;
break;
}
case SDL_KEYUP: {
break;
}
} /* switch */
} /* while SDL_PollEvent */
}
}
int main(int argc,char * args[])
{
InitSetup();
GameLoop();
FinishOff();
return 0;
}
When you run this you’ll get a Window with random sized coloured rectangles like this and the time to draw 10,000 in the Window caption bar. Timing is done in the hr_time.h and .c files. These can be found in the file sdldemo.zip along with the VS code JSON files on GitHub.