DEV Community

Cover image for 3D Renderer in C - Update to SDL3
Justin Horner
Justin Horner

Posted on

3

3D Renderer in C - Update to SDL3

Welcome to another entry to the 3D renderer series. Today I'm documenting my switch from SDL2 to SDL3. We'll tackle this first on Windows, then macOS and Linux. Let's get to it.

Installation

Windows

Since I keep the SDL include and lib files local to the msvs project for Windows, I downloaded SDL3-devel-3.2.8-VC.zip file from GitHub.

I added the files to msvs\lib\sdl\include\SDL3\include and msvs\lib\sdl\lib\x86.

macOS/Linux

Of course, everything is easier on macOS and Linux. Just run the following commands in the terminal.

# macOS
brew install sdl3

# Linux
sudo apt install libsdl3-dev
Enter fullscreen mode Exit fullscreen mode

Changes

First, don't forget to change our include to SDL3/SDL.h.

Logging

Everywhere I am using fprintf I've changed to SDL_Log like so:

SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
Enter fullscreen mode Exit fullscreen mode

Initialize SDL

Currently we are initializing every SDL subsystem with SDL_Init. As part of this upgrade, I'm going to change this to only initialize the video subsystem. This now returns a bool instead of an int, so we no longer have to check against 0.

if (!SDL_InitSubSystem(SDL_INIT_VIDEO)) {
    SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
    return false;
}
Enter fullscreen mode Exit fullscreen mode

Create Window

To create a window with SDL 3 we can use the SDL_CreateWindowWithProperties and provide it with the configuration we want. First, we make sure we can successfully create a SDL_PropertiesID, which is a typedef for a Uint32.

SDL_PropertiesID window_properties = SDL_CreateProperties();
if (!window_properties) {
    SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
    return false;
}
Enter fullscreen mode Exit fullscreen mode

We set integer properties by using SDL_SetNumberProperty. This is our window properties for a centered position and using our width and height.

SDL_PropertiesID window_properties = SDL_CreateProperties();
if (!window_properties) {
    SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
    return false;
}

SDL_SetNumberProperty(window_properties, SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_WINDOWPOS_CENTERED);
SDL_SetNumberProperty(window_properties, SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_WINDOWPOS_CENTERED);
SDL_SetNumberProperty(window_properties, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, window_width);
SDL_SetNumberProperty(window_properties, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, window_height);

window = SDL_CreateWindowWithProperties(window_properties);
Enter fullscreen mode Exit fullscreen mode

Create Renderer

There's a slight change to the API for SDL_CreateRenderer in that we no longer need to provide it with an int for the index of the rendering driver. Before we passed -1 which will initialize the first one found that supports the flags.

Now the method has two parameters, an SDL_Window and a const char* for the name of the rendering driver. We can provide NULL for SDL to choose the best option based on the system.

renderer = SDL_CreateRenderer(window, NULL);
Enter fullscreen mode Exit fullscreen mode

Event Type

There are a few changes to the naming for the events we're using.

switch (event.type) {
    case SDL_EVENT_QUIT:
        is_running = false;
        break;
    case SDL_EVENT_KEY_DOWN:
        if (event.key.key == SDLK_ESCAPE)
            is_running = false;
        break;
Enter fullscreen mode Exit fullscreen mode

Quit Subsystem

Finally, I'm calling SDL_QuitSubSystem in destroy_window as part of cleanup.

void destroy_window(void) {
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_QuitSubSystem(SDL_INIT_VIDEO);
    SDL_Quit();
}
Enter fullscreen mode Exit fullscreen mode

Summary

With that done, we're now running the latest stable version of SDL3. Here's the resulting code after the upgrade.

#include <stdio.h>
#include <stdbool.h>
#include <SDL3/SDL.h>

SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;

bool is_running = false;
int window_width = 800;
int window_height = 600;

bool initialize_window(void) {
    if (!SDL_InitSubSystem(SDL_INIT_VIDEO)) {
        SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
        return false;
    }

    SDL_PropertiesID window_properties = SDL_CreateProperties();
    if (!window_properties) {
        SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
        return false;
    }

    SDL_SetNumberProperty(window_properties, SDL_PROP_WINDOW_CREATE_X_NUMBER, SDL_WINDOWPOS_CENTERED);
    SDL_SetNumberProperty(window_properties, SDL_PROP_WINDOW_CREATE_Y_NUMBER, SDL_WINDOWPOS_CENTERED);
    SDL_SetNumberProperty(window_properties, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, window_width);
    SDL_SetNumberProperty(window_properties, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, window_height);
    window = SDL_CreateWindowWithProperties(window_properties);

    if (!window) {
        SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
        return false;
    }

    renderer = SDL_CreateRenderer(window, NULL);
    if (!renderer) {
        SDL_Log("Unable to initialize SDL: %s", SDL_GetError());
        return false;
    }

    return true;
}

void destroy_window(void) {
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_QuitSubSystem(SDL_INIT_VIDEO);
    SDL_Quit();
}

void process_input(void) {
    SDL_Event event;
    SDL_PollEvent(&event);

    switch (event.type) {
        case SDL_EVENT_QUIT:
            is_running = false;
            break;
        case SDL_EVENT_KEY_DOWN:
            if (event.key.key == SDLK_ESCAPE)
                is_running = false;
            break;
}

void update(void) {
    // TODO: Something fun here :)
}

void render(void) {
    SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
    SDL_RenderClear(renderer);

    // TODO: Render some graphics!

    SDL_RenderPresent(renderer);
}

int main(void) {
    is_running = initialize_window();

    while (is_running) {
        process_input();
        update();
        render();
    }

    destroy_window();
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Until next time.

Take care.
Stay awesome.

Top comments (0)