SDL Tutorial Part 1: Opening A Window
I was recently learning SDL2, and I found the lack of tutorials in plain C frustrating. I've decided to be the change I wanted to see in the world, and write my own. This will be a multi-part series, and will serve as a quick reference for how to do common things in SDL2. I've listed the main functions at the top of the tutorial kind of like the Raylib Cheatsheet, if you just need a quick reference.
 Before we dive in, I want to point out an immensely helpful resource that will be useful as you become more experienced. The SDL2 Wiki contains an index which has a link to every SDL function wiki page. This will teach you everything you need to know about calling the function and handling its output properly. If a big list of functions is too disjointed, there is also a wikipage that links to the same resources, but organized into API categories as well. This can be useful as common operations usually require multiple functions that are related.
Open a Window Cheat Sheet
Tutorial
The simplest and fastest way to get a window open in SDL2 is to write the following code.
#include <SDL2/SDL.h>
#include <stdio.h>
#include <stdlib.h>
#define SCREEN_WIDTH 1280
#define SCREEN_HEIGHT 720
int main() {
SDL_Window *window = SDL_CreateWindow("Example: 0", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, 0);
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
SDL_SetRenderDrawColor(renderer, 255,255,255,250);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_Delay(2000);
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return EXIT_SUCCESS;
}
But this is not recommended. It's possible that many of the functions that we just called can fail, so we want to include a few more checks to make sure that everything is working correctly. Let's do that now
int main(){
if (SDL_Init(SDL_INIT_VIDEO) < 0){
printf("Couldn't initialize SDL: %s\n", SDL_GetError());
return EXIT_FAILURE;
}
SDL_Window *window = SDL_CreateWindow("Example: 0", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, 0);
if (!window){
printf("Failed to open %d x %d window: %s\n", SCREEN_WIDTH, SCREEN_HEIGHT, SDL_GetError());
return EXIT_FAILURE;
}
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 0);
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 250);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
SDL_Delay(2000);
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return EXIT_SUCCESS;
}
The first thing we do is call SDL_Init and pass the flag SDL_INIT_VIDEO
, which initializes the video subsystem. SDL has many initialization flags that you can bitwise OR (|
) together to initialize multiple subsystems at once. For example like this
// Initialize SDL with video and audio subsystems
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) {
printf("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
return 1;
} else {
printf("SDL video and audio initialized successfully.\n");
But we will stick to the video subsystem for now. Next we will call SDL_CreateWindow
. It takes in a title, x and y for the window position, width and height for the window size, and some flags. If we go to the wikipage for SDL_CreateWindow we will see the function prototype, a description of its parameters (including flags that can be passed), and the expected return values on failure. This is how I knew what that I wanted to pass SDL_WINDOWPOS_UNDEFINED
 for the x and y, and let the operating system handle window placement.
Moving on, we create our renderer with SDL_CreateRenderer. We give it the window we created, so we can render to it, and pass its index parameter -1
 to initialize the first rendering driver that can support our requested parameter flag of 0
. You will always pass -1
 as the index parameter unless you have a good reason not to. For the render flag we pass 0
 which defaults to SDL_RENDERER_ACCELERATED
 (using hardware acceleration for the graphics) if it is supported on your system. If you want to be more explicit you can pass SDL_RENDERER_ACCELERATED
 instead. Just like with the SDL window, we write an if statement to check if the renderer was created so that we don't accidentally use it if it hasn't been initialized.
Next we call SDL_SetRenderDrawColor() and pass it our renderer, as well as 4 integers with values from 0-255. The 4 integers correspond to Red
, Green
, Blue
, and Alpha
 values of a color. The alpha controls the transparency of the color, while setting the R, G, and B values to various levels allow you to create any color you want between 0,0,0,255
 (Black) and 255,255,255,255
 (White). SDL_RenderClear() takes our renderer and clears it with the white color we set using SDL_SetRenderDrawColor
. SDL_RenderPresent() displays our graphics to the screen (just a white window for now) and then we call SDL_Delay(2000) which specifies a number of milliseconds to wait before moving onto the next piece of code. Normally the rendering code will be in a while loop that will constantly update until the user quits the game, but for simplicities' sake, we will stick with a delay for now.
SDL_DestroyWindow safely removes our window once we are done with it. If for whatever reason the window was not initialized, it is still safe to call this on the window
 variable. The same goes for SDL_DestroyRenderer. It does the same thing as SDL_DestroyWindow
 and cleans up our renderer. Finally we call SDL_Quit which cleans up the systems we initialized before we close our program.
And that is it, we've created our first window in SDL. In the next tutorial we will look at how to draw text on the screen.
One last thing to note. I will not be abstracting many things to functions or multiple files in these first few tutorials. I believe it's important when you are learning a new library, to keep it as simple as possible. As the code gets longer this will become a bigger pain point, and that is good. You will have a much clearer picture about what we should abstract, and why we should abstract it, as you become more familiar with SDL. Feel free to come up with your own abstractions as you see fit
FAQ
Why do we clear the screen with a color?
We clear the screen with a color so that the previous frames pixels don't interfere with the next frames pixels. For example, if we have a square on the screen that we are moving with the WASD
 keys, if we don't clear the screen, then square will smear across the screen as the old pixels from it's old position are not "wiped" away.
Why SDL and not Raylib?
Raylib is an awesome C library for creating games, and Raysan specifically made it for teaching. He did a comparison at one point between the two frameworks, though it is a little dated at this point. It is easier to learn and make new FFI bindings for Raylib than it is for SDL and Raylib comes with more convenience features out of the box. You are not making a mistake if you choose Raylib. But SDL has been around over twice as long as Raylib. Many of the open source projects I'm interested in contributing to (Doom Source Ports, OpenMW, and others were started before Raylib existed and use SDl2. Since these projects use SDL so will I. SDL2 is also a little lower level than Raylib, and requires you to work at a lower level with it's subsystems. This means instead of placing drawing code between a BeginDrawing
 and EndDrawing
 block like in Raylib, you have to set up the renderer, create textures, copy them to the GPU, before finally presenting it to the screen. I find this process to be enlightening.
Call To Action 📣
Hi 👋 my name is Diego Crespo and I like to talk about technology, niche programming languages, and AI. I have a Twitter and a Mastodon, if you’d like to follow me on other social media platforms. If you liked the article, consider liking and subscribing. And if you haven’t why not check out another article of mine listed below! Thank you for reading and giving me a little of your valuable time. A.M.D.G