Overview

This complete guide walks through creating windows, setting up accelerated renderers, drawing primitives, loading fonts, rendering text, handling window events, scaling, and best practices for SDL2 + SDL_ttf.

Compile with -lSDL2 -lSDL2_ttf.

Initialization

SDL_Init(SDL_INIT_VIDEO);
TTF_Init();

Parameters

  • SDL_INIT_VIDEO – enables the video subsystem; combine flags (e.g., | SDL_INIT_EVENTS).
  • TTF_Init() – no params; returns 0 on success.

Creating a Window


SDL_Window* win = SDL_CreateWindow(
    "Demo",                 /* window title                    */
    SDL_WINDOWPOS_CENTERED,  /* x position                      */
    SDL_WINDOWPOS_CENTERED,  /* y position                      */
    800,                     /* width  px                       */
    600,                     /* height px                       */
    SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE
);

Parameters

  • title – UTF‑8 C‑string shown in title‑bar.
  • x/y – screen coordinates or SDL_WINDOWPOS_UNDEFINED/SDL_WINDOWPOS_CENTERED.
  • w/h – window size in logical pixels.
  • flags
    • SDL_WINDOW_SHOWN – make visible immediately.
    • SDL_WINDOW_RESIZABLE – allow user‑driven size change.
    • SDL_WINDOW_FULLSCREEN, SDL_WINDOW_FULLSCREEN_DESKTOP, SDL_WINDOW_OPENGL

Creating a Renderer


SDL_Renderer* ren = SDL_CreateRenderer(
    win,           /* window                                       */
    -1,            /* driver index (‑1 = first supporting flags)   */
    SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC
);

SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND);

Parameters

  • window – handle from SDL_CreateWindow.
  • index – GPU driver (-1 auto select).
  • flags
    • SDL_RENDERER_ACCELERATED – hardware acceleration.
    • SDL_RENDERER_SOFTWARE – fallback software.
    • SDL_RENDERER_PRESENTVSYNC – sync with display refresh.

Blend mode enables transparency for textures and primitives.

Main Event & Rendering Loop


bool running = true;
while (running) {
  SDL_Event e;
  while (SDL_PollEvent(&e)) {
    if (e.type == SDL_QUIT) running = false;
    if (e.type == SDL_WINDOWEVENT && e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
        int newW = e.window.data1;
        int newH = e.window.data2;
        /* handle resize */
    }
  }

  /* draw */
  SDL_SetRenderDrawColor(ren, 30, 30, 30, 255);
  SDL_RenderClear(ren);

  /* ...render text / sprites... */

  SDL_RenderPresent(ren);
}

Key Functions

  • SDL_SetRenderDrawColor(renderer, r,g,b,a) – colour for Clear and primitives.
  • SDL_RenderClear – fills current target with draw colour.
  • SDL_RenderPresent – swaps/back‑buffers to display.

Loading & Caching Fonts


TTF_Font* font24 = TTF_OpenFont("NunitoSans-Regular.ttf", 24);
TTF_Font* font48 = TTF_OpenFont("NunitoSans-Regular.ttf", 48);

Parameters

  • file – path to TrueType/OTF font.
  • ptsize – requested height in points; higher → more glyph detail.

Reuse opened TTF_Font* across frames to avoid expensive reload.

Rendering Text → Texture


SDL_Color white = {255,255,255,255};
SDL_Surface* surf = TTF_RenderUTF8_Blended(font24, "Hello SDL2", white);
SDL_Texture* tex = SDL_CreateTextureFromSurface(ren, surf);
SDL_FreeSurface(surf);

SDL_Rect dst; SDL_QueryTexture(tex, NULL, NULL, &dst.w, &dst.h);
dst.x = 50; dst.y = 40;
SDL_RenderCopy(ren, tex, NULL, &dst);

Important Functions & Params

  • TTF_RenderUTF8_Blended(font, text, color)
    • Creates ARGB surface (anti‑aliased).
  • SDL_CreateTextureFromSurface(renderer, surface)
    • Uploads surface pixels to GPU texture.
    • Texture format chosen automatically.
  • SDL_RenderCopy(renderer, texture, srcRect, dstRect)
    • srcRect – crop area or NULL for full.
    • dstRect – target position/size (scaled if w/h differ).

Multiline & Wrapped Text


SDL_Surface* paragraph = TTF_RenderUTF8_Blended_Wrapped(
    font24,
    "Lorem ipsum dolor sit amet…",
    white,
    400  /* wrap max width pixels */
);

SDL_ttf handles newlines automatically; height equals total lines × line skip.

Logical Size & DPI Scaling


SDL_RenderSetLogicalSize(ren, 800, 600);

All dstRect coordinates become virtual (0–800/0–600) and are scaled to the actual window size – great for pixel‑perfect UI on multiple resolutions.

Fullscreen / Display Modes


SDL_SetWindowFullscreen(win, SDL_WINDOW_FULLSCREEN_DESKTOP);

SDL_DisplayMode dm;
SDL_GetCurrentDisplayMode(0, &dm);
printf("Display %dx%d @ %dHz\n", dm.w, dm.h, dm.refresh_rate);

Using SDL_WINDOW_FULLSCREEN_DESKTOP keeps the desktop resolution (borderless).

High‑DPI Awareness (macOS / Windows)


float ddpi, hdpi, vdpi;
SDL_GetDisplayDPI(0, &ddpi, &hdpi, &vdpi);
printf("Diagonal DPI %.1f\n", ddpi);

Adjust font sizes or choose high‑resolution textures based on DPI.

Error Handling & Cleanup


if (!win || !ren) {
    fprintf(stderr, "%s\n", SDL_GetError());
}

SDL_DestroyTexture(tex);
TTF_CloseFont(font24);
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
TTF_Quit();
SDL_Quit();