SDL2 in C

Fathopert, 10 June 2022

(upd. 21 June 2022)

Introduction

SDL2 is a popular ะก game develoment library. In this article, we will build a basic SDL2 project. I hope it will be helpful for beginners.

I work in Windows 11 and use these versions of programs and libraries:

SDL2 Installation

Linux

Download this development library from the official website:

screenshot from the official site

Unzip the archive, navigate into the SDL2-<version> folder and install the library with the following commands:

> ./configure
> make
> sudo make install

Note: you can delete this folder after the installation is completed.

Now let's activate autocompletion for SDL2 in VS Code. Launch VS Code, open Command Palette with Ctrl+Shift+P. Find Preferences: Open Settings (JSON) and press Enter. Add this line to the opened settings.json:

C_Cpp.default.includePath: ["/usr/local/include/SDL2"]
or update the existing list in C_Cpp.default.includePath if you used this parameter before. In my case, the added line looked like this:

screenshot from the vs code settings (linux)

Now we are ready to code!

Windows

Download this development library from the official website:

screenshot from the official site

Unzip the archive and remember the location of the SDL2-<version> folder. I extracted the library to C:/_my_files and renamed the directory to just SDL2.

After this, go to the <path-to-sdl2>/x86_64-w64-mingw32/include/SDL2/ and change the value of the prefix variable in sdl2-config.cmake to
"${CMAKE_CURRENT_LIST_DIR}/../../../"
. In my case, the result looked like this:

screenshot from cmake-config

Let's turn on autocompletion for SDL2 in VS Code. Launch VS Code, open Command Palette with Ctrl+Shift+P. Find Preferences: Open Settings (JSON) and press Enter. Add this line to the opened settings.json:

C_Cpp.default.includePath: [<path-to-sdl2>/x86_64-w64-mingw32/include/SDL2]
or update the existing list in C_Cpp.default.includePath if you used this parameter before. In my case, the added line looked like this:

screenshot from the vs code settings (windows)

Note: Similarly (with the same commands) you can install the SDL_image library. Download the source code here.

Now we are ready to code!

Writing a Simple Program

The project structure looks like this:
- project folder
|
|--- src (a folder)
|  |
|  |--- main.c
|
|--- include (a folder)
|
|--- CMakeLists.txt

The main.c file contains the following code:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define SDL_MAIN_HANDLED
#include "SDL2/SDL.h"

/* macros */
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
#define WINDOW_TITLE "Hello from SDL2"

/* variables */
static SDL_Window* window;
static SDL_Renderer* renderer;
static SDL_Event event;
static bool running;

/* function implementations */
int
main(int argc, char** argv)
{
    /* Initializing SDL2 */
    if (SDL_Init(SDL_INIT_VIDEO)) {
        printf("Unable to initialize SDL: %s\n", SDL_GetError());
        return -1;
    }

    /* Creating a SDL window */
    window = SDL_CreateWindow(WINDOW_TITLE,
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
        SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);

    if (!window) {
        printf("Could not create a window: %s\n", SDL_GetError());
        return -1;
    }

    /* Creating a renderer */
    renderer = SDL_CreateRenderer(window, -1,
        SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);

    if (!renderer) {
        printf("Could not create a renderer: %s\n", SDL_GetError());
        return -1;
    }

    /* Background color               r    g    b    a */
    SDL_SetRenderDrawColor(renderer, 110, 177, 255, 255);
    running = true;

    while (running) {
        /* Processing events */
        while (SDL_PollEvent(&event)) {
            if (event.type == SDL_QUIT) {
                running = false;
            }
        }

        /* Clearing the screen */
        SDL_RenderClear(renderer);

        /* Showing what was drawn */
        SDL_RenderPresent(renderer);
    }
    
    /* Releasing resources */
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

Creating a CMake Project

Write this code in the CMakeLists.txt file. This script works on both Linux and Windows. Do not forget replace <path-to-sdl2> with your path.

cmake_minimum_required(VERSION 3.2)
project(hello_sdl LANGUAGES C VERSION 1.0)

set(CMAKE_C_STANDARD 99)

# Set the folder where the executable will be saved
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "result")

# Tell CMake create an EXE file from the specified C files
file(GLOB C_SRC ${PROJECT_SOURCE_DIR}/src/*.c)
add_executable(hello_sdl ${C_SRC})

# Tell CMake where to find SDL2 on Windows
if(WIN32)
    list(APPEND CMAKE_PREFIX_PATH
    "<path-to-sdl2>/x86_64-w64-mingw32/lib/cmake/SDL2")
endif()

# Looking for SDL2
find_package(SDL2 REQUIRED)
if(SDL2_FOUND)
    message(STATUS "SDL2 was found!")
else()
    message(STATUS "SDL2 was not found!")
endif()

# find_package(SDL2_image REQUIRED)
# if(SDL2_image_FOUND)
#     message(STATUS "SDL_image was found!")
# else()
#     message(STATUS "SDL_image was not found!")
# endif()

# Copy SDL2.dll to the folder with  the executable on Windows
if(WIN32)
    add_custom_command(TARGET hello_sdl POST_BUILD COMMAND
        ${CMAKE_COMMAND} -E copy_if_different 
        "${SDL2_PREFIX}/bin/SDL2.dll" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
endif()

# Tell CMake where to look for header files.
# PRIVATE means 'using only for this target (i.e. for hello_sdl)'
target_include_directories(hello_sdl
    PRIVATE ${SDL2_INCLUDE_DIRS} 
    PRIVATE ${PROJECT_SOURCE_DIR}/include)

# Link required libraries
target_link_libraries(hello_sdl
    PRIVATE SDL2::SDL2
    PRIVATE SDL2::SDL2main)
    # PRIVATE SDL2_image)

# Without this flag, CMake compiles "shared library" on Linux
if(UNIX)
    target_link_options(hello_sdl PRIVATE "-no-pie")
endif()

With this file, CMake will understand how to build the executable for our program.

Building and Running the Program

Open a terminal or cmd in the project folder, create a build directory, and navigate into it:

> mkdir build
> cd build

Then generate a Makefile for make and build the executable file.

On Linux, use the following comands:

> cmake -G"Unix Makefiles" -DCMAKE_C_FLAGS_RELEASE=-O3 -DCMAKE_BUILD_TYPE=RELEASE ..
> cmake --build .

On Windows:

> cmake -G"MinGW Makefiles" -DCMAKE_C_FLAGS_RELEASE=-O3 -DCMAKE_BUILD_TYPE=RELEASE ..
> cmake --build .

If there are no errors, the executable file hello_sdl will appear in the build/result folder.

Now let's launch our program!

On Linux, use the following comands:

> cd result
> ./hello_sdl

On Windows:

> cd result
> hello_sdl.exe

The window will appear with the previously specified size and title:

screenshot of the result


Thus, we have made a basic SDL2 project using C. For additional information, I suggest you check out the References section.

References

  1. Installing SDL — SDL Wiki
  2. The Hello SDL tutorial — Lazy Foo' Productions
  3. Using SDL2 with CMake — Trenki's Dev Blog
  4. SDL2 Game Tutorials (in C) — Parallel Realities
  5. Loki Software, Programming Linux Games (2001)