Overview

This complete guide walks through creating windows, setting up accelerated renderers, drawing primitives, loading fonts, rendering text, handling window events, scaling, dynamic text on keypress, 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;
SDL_StartTextInput();

/* text buffer & helpers */
std::string buffer = "Type: ";
SDL_Color white = {255,255,255,255};
SDL_Texture* textTex = NULL;
TTF_Font* font24 = TTF_OpenFont("NunitoSans-Regular.ttf", 24);

auto renderText = [&](const std::string& msg){
    if(textTex) SDL_DestroyTexture(textTex);
    SDL_Surface* s = TTF_RenderUTF8_Blended(font24, msg.c_str(), white);
    textTex = SDL_CreateTextureFromSurface(ren, s);
    SDL_FreeSurface(s);
};
renderText(buffer);

while (running) {
  SDL_Event e;
  while (SDL_PollEvent(&e)) {
    if (e.type == SDL_QUIT) running = false;

    if (e.type == SDL_TEXTINPUT) {
        buffer += e.text.text;      /* append typed character */
        renderText(buffer);
    }
    if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_BACKSPACE && buffer.size() > 6) {
        buffer.pop_back();          /* remove last char */
        renderText(buffer);
    }
    if (e.type == SDL_WINDOWEVENT && e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
        int newW = e.window.data1;
        int newH = e.window.data2;
        /* handle resize */
    }
  }

  SDL_SetRenderDrawColor(ren, 30,30,30,255);
  SDL_RenderClear(ren);

  /* draw dynamic text */
  SDL_Rect dst; SDL_QueryTexture(textTex, NULL, NULL, &dst.w, &dst.h);
  dst.x = 50; dst.y = 40;
  SDL_RenderCopy(ren, textTex, NULL, &dst);

  SDL_RenderPresent(ren);
}

SDL_StopTextInput();

Key Points

  • SDL_StartTextInput()/SDL_StopTextInput() – enable/disable Unicode text events.
  • SDL_TEXTINPUT – event fired for every UTF‑8 character typed (handles IME & locale correctly).
  • SDL_KEYDOWN – capture non‑text keys (e.g., backspace, function keys).
  • Re‑render texture whenever the string changes to display updated text.

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.

Reuse opened fonts to avoid reload overhead.

Static Text Rendering → Texture


SDL_Surface* surf = TTF_RenderUTF8_Blended(font24, "Hello SDL2", white);
SDL_Texture* texStatic = SDL_CreateTextureFromSurface(ren, surf);
SDL_FreeSurface(surf);

SDL_Rect dst; SDL_QueryTexture(texStatic, NULL, NULL, &dst.w, &dst.h);
SDL_RenderCopy(ren, texStatic, NULL, &dst);

Use this method for labels that rarely change.

Multiline & Wrapped Text


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

SDL_ttf handles newlines automatically.

Logical Size & DPI Scaling

SDL_RenderSetLogicalSize(ren, 800, 600);

Coordinates are mapped to virtual space and automatically scaled.

Fullscreen / Display Modes


SDL_SetWindowFullscreen(win, SDL_WINDOW_FULLSCREEN_DESKTOP);

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

High‑DPI Query


float ddpi, hdpi, vdpi;
SDL_GetDisplayDPI(0, &ddpi, &hdpi, &vdpi);

Error Handling & Cleanup


if(!win || !ren){ fprintf(stderr, "%s\n", SDL_GetError()); }
SDL_DestroyTexture(textTex);
SDL_DestroyTexture(texStatic);
TTF_CloseFont(font24);
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
TTF_Quit();
SDL_Quit();