SDL School
SDL version Which one?

Draw a rectangle

This program draws two rectangles on a dark background. You learn where coordinates start, and why the order of the drawing calls matters.

The full program

main.c
/* Draw two rectangles. The second rectangle covers part of the first. */
#define SDL_MAIN_USE_CALLBACKS
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>

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

SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
    if (!SDL_Init(SDL_INIT_VIDEO)) {
        SDL_Log("SDL_Init failed: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }

    if (!SDL_CreateWindowAndRenderer("Draw a rectangle", 640, 480, 0,
                                     &window, &renderer)) {
        SDL_Log("SDL_CreateWindowAndRenderer failed: %s", SDL_GetError());
        return SDL_APP_FAILURE;
    }

    SDL_SetRenderVSync(renderer, 1);
    return SDL_APP_CONTINUE;
}

SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
    if (event->type == SDL_EVENT_QUIT) {
        return SDL_APP_SUCCESS;
    }
    return SDL_APP_CONTINUE;
}

SDL_AppResult SDL_AppIterate(void *appstate)
{
    SDL_FRect blue = { 120.0f, 100.0f, 240.0f, 180.0f };
    SDL_FRect orange = { 280.0f, 200.0f, 240.0f, 180.0f };

    SDL_SetRenderDrawColor(renderer, 24, 26, 32, SDL_ALPHA_OPAQUE);
    SDL_RenderClear(renderer);

    SDL_SetRenderDrawColor(renderer, 32, 96, 160, SDL_ALPHA_OPAQUE);
    SDL_RenderFillRect(renderer, &blue);

    SDL_SetRenderDrawColor(renderer, 255, 157, 92, SDL_ALPHA_OPAQUE);
    SDL_RenderFillRect(renderer, &orange);

    SDL_RenderPresent(renderer);
    return SDL_APP_CONTINUE;
}

void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
}
main.c
/* Draw two rectangles. The second rectangle covers part of the first. */
#include <SDL.h>
#include <stdbool.h>

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

static SDL_Window *window = NULL;
static SDL_Renderer *renderer = NULL;
static bool running = true;

static void frame(void)
{
    SDL_Event event;
    SDL_FRect blue = { 120.0f, 100.0f, 240.0f, 180.0f };
    SDL_FRect orange = { 280.0f, 200.0f, 240.0f, 180.0f };

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

    SDL_SetRenderDrawColor(renderer, 24, 26, 32, SDL_ALPHA_OPAQUE);
    SDL_RenderClear(renderer);

    SDL_SetRenderDrawColor(renderer, 32, 96, 160, SDL_ALPHA_OPAQUE);
    SDL_RenderFillRectF(renderer, &blue);

    SDL_SetRenderDrawColor(renderer, 255, 157, 92, SDL_ALPHA_OPAQUE);
    SDL_RenderFillRectF(renderer, &orange);

    SDL_RenderPresent(renderer);
}

int main(int argc, char *argv[])
{
    if (SDL_Init(SDL_INIT_VIDEO) != 0) {
        SDL_Log("SDL_Init failed: %s", SDL_GetError());
        return 1;
    }

    if (SDL_CreateWindowAndRenderer(640, 480, 0, &window, &renderer) != 0) {
        SDL_Log("SDL_CreateWindowAndRenderer failed: %s", SDL_GetError());
        SDL_Quit();
        return 1;
    }

    SDL_SetWindowTitle(window, "Draw a rectangle");
    SDL_RenderSetVSync(renderer, 1);

#ifdef __EMSCRIPTEN__
    emscripten_set_main_loop(frame, 0, 1);
#else
    while (running) {
        frame();
    }
#endif

    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

Coordinates

A window is a grid of pixels. The point (0, 0) is the top-left corner of the window. The value of x increases to the right, and the value of y increases downward.

This is different from a graph in a math class, where y increases upward.

(0, 0) (x, y) w by h x y
The x and y of a rectangle give its top-left corner. The w and h give its size.

Describe a rectangle

    SDL_FRect blue = { 120.0f, 100.0f, 240.0f, 180.0f };

SDL_FRect is a struct with four float fields, in this order: x, y, w, and h. This rectangle starts 120 pixels from the left edge and 100 pixels from the top edge. It is 240 pixels wide and 180 pixels high.

The fields are float because later lessons move objects by a fraction of a pixel. All SDL3 drawing functions use float coordinates.

    SDL_FRect blue = { 120.0f, 100.0f, 240.0f, 180.0f };

SDL_FRect is a struct with four float fields, in this order: x, y, w, and h. This rectangle starts 120 pixels from the left edge and 100 pixels from the top edge. It is 240 pixels wide and 180 pixels high.

SDL2 has two rectangle types. SDL_Rect uses int, and SDL_FRect uses float. These lessons use SDL_FRect because later lessons move objects by a fraction of a pixel. The function for float rectangles is SDL_RenderFillRectF.

Draw in order

    SDL_SetRenderDrawColor(renderer, 32, 96, 160, SDL_ALPHA_OPAQUE);
    SDL_RenderFillRect(renderer, &blue);

    SDL_SetRenderDrawColor(renderer, 255, 157, 92, SDL_ALPHA_OPAQUE);
    SDL_RenderFillRect(renderer, &orange);
    SDL_SetRenderDrawColor(renderer, 32, 96, 160, SDL_ALPHA_OPAQUE);
    SDL_RenderFillRectF(renderer, &blue);

    SDL_SetRenderDrawColor(renderer, 255, 157, 92, SDL_ALPHA_OPAQUE);
    SDL_RenderFillRectF(renderer, &orange);

The renderer keeps one current color. Each drawing call uses that color, so you set the color first and draw second.

Each drawing call paints over the pixels that are already there. The orange rectangle comes second, so it covers part of the blue rectangle. For this reason, SDL_RenderClear comes first in each frame. It is the bottom layer.

Try this

  1. Swap the two blocks that draw the rectangles. The blue rectangle is now on top.
  2. Add a third rectangle in the bottom-right corner of the window.
  3. Make a rectangle that covers the full window. Use the window size for its size.

What you learned