With SDL2 successfully installed and added to our project, lets start our journey.
The first step is being able to create and manipulate a window. This lesson goes over the steps in how we can do this. We break down and explain every function in the process, as well as describing the most common options.
Let's start by creating a class to manage our window..
Note, this article assumes we've completed the SDL2 setup for our environment. Guides for doing this on most common environments are provided below:
Below, we've created a Window
class to manage the window. We'll break down every line of code we're using here, once we see it working:
// Window.h
#pragma once
#include <SDL.h>
class Window {
public:
Window() {
SDL_Init(SDL_INIT_VIDEO);
SDLWindow = SDL_CreateWindow(
"Hello Window", 0, 0, 500, 300, 0
);
SDLWindowSurface = SDL_GetWindowSurface(SDLWindow);
SDL_FillRect(
SDLWindowSurface,
nullptr,
SDL_MapRGB(SDLWindowSurface->format, 40, 40, 40)
);
}
void RenderFrame() {
SDL_UpdateWindowSurface(SDLWindow);
}
private:
SDL_Window* SDLWindow { nullptr };
SDL_Surface* SDLWindowSurface { nullptr };
};
Then, from our main.cpp
we can include the header file and create our window:
#include <SDL.h>
#include "Window.h"
int main() {
Window GameWindow;
SDL_Event event;
while(true) {
SDL_PollEvent(&event);
GameWindow.RenderFrame();
}
}
Compiling and running this code, we should see our application opens a window which we can move around:
Let's break this code down, line by line.
SDL_Init
Our first action is to initialise the SDL subsystems we need, using the SDL_Init
 command.
SDL_Init(SDL_INIT_VIDEO);
Here, we’re just initializing the video subsystem. Checking the SDL2 documentation, we see that this will also initialize the events subsystem.
The documentation claims we can initialize multiple subsystems by “OR-ing them together”. This refers to the bitwise OR operator, |
An explanation of the |
operator, and how this code works more generally, is available here:
So, for example, we could initialize 3 subsystems like this:
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER);
SDL_Window
Next, we need to create the window, which will have a type provided by SDL: SDL_Window
. We store a pointer to it in a private member we’re calling SDLWindow
:
SDLWindow = SDL_CreateWindow(
"Hello Window", 0, 0, 500, 300, 0
);
The SDL_CreateWindow
function helps us do this. It accepts 6Â arguments:
Reviewing the CreateWindow documentation, we see there are some helpers for the position:
SDL_WINDOWPOS_CENTERED
will automatically center the window along its axisSDL_WINDOWPOS_UNDEFINED
will let the operating system choose the best place to open the window. This is a good default, as operating systems have put a lot of thought into what gives the best user experienceSDLWindow = SDL_CreateWindow(
"Hello Window",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
500, 300, 0
);
The final argument to SDL_CreateWindow
gives us more control over how the window behaves. The documentation provides a list of “flags” that can be used with this argument.
Similarly to before, these flags can be combined using the |
operator. For example, we could make our window borderless and resizable like this:
SDLWindow = SDL_CreateWindow(
"Hello Window",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
500, 300,
SDL_WINDOW_BORDERLESS | SDL_WINDOW_RESIZABLE
);
SDL_Surface
An SDL_Surface
is where we draw our content. Later in this chapter, we will create our own surfaces.
However, the window we created come with a surface by default. We can access that surface using the SDL_GetWindowSurface
 function.
In our class, we’re storing a pointer to it in a private member called SDLWindowSurface
so we can draw on it later:
SDLWindowSurface = SDL_GetWindowSurface(Window);
SDL_FillRect
This function fills a rectangle with a solid color. It needs three arguments:
nullptr
indicates we want the entire surface to be filledSDL_FillRect(
SDLWindowSurface,
nullptr,
SDL_MapRGB(SDLWindowSurface->format, 40, 40, 40)
);
Surfaces can have different ways to represent color. The SDL_MapRGB
function standardizes this. We can provide the format
of the surface, accessible through the surface pointer, and then our three color components: red, green, and blue.
These components are in the 0-255 range. So, for example, if we wanted to make our window background red, we would change our code to this:
SDL_FillRect(
SDLWindowSurface,
nullptr,
SDL_MapRGB(WindowSurface->format, 255, 0, 0)
);
SDL_UpdateWindowSurface
Once we’ve made all the changes we need to our surface, we are ready to render our next frame. Our class has a public RenderFrame
method to do just that.
Within that function, for now, all we need to do is ask SDL to update the window surface with our changes. We aren’t making any changes yet, but we will soon.
To update the window surface, we call SDL_UpdateWindowSurface
function, passing in a pointer to our window:
void RenderFrame() {
SDL_UpdateWindowSurface(SDLWindow);
}
Finally, our last block of code is over in our main
function. It looks like this:
Window GameWindow;
SDL_Event event;
while(true) {
SDL_PollEvent(&event);
GameWindow.RenderFrame();
}
Here, we first create our window, calling all the code in our Window
 constructor.
Then, we have an infinite loop, causing our window to constantly render new frames.
The two new things here are lines 2 and 4, which are dealing with events. We’ll introduce events in the next lesson.
You may have noticed the window doesn’t respond to being closed from the title bar - it remains open.
We’ll fix that in the next lesson, too. For now, if you’re running the code through your IDE, hitting the stop button within your editor will terminate the process and close the window.
Otherwise, you can force your operating system to close it. That can be done using the Ctrl + Alt + Del menu in Windows, or the Opt + Cmd + Esc menu on Mac
Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games