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
.
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
SDL_INIT_VIDEO
– enables the video subsystem; combine flags (e.g., | SDL_INIT_EVENTS
).TTF_Init()
– no params; returns 0
on success.
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
);
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
…
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);
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.
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);
}
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.
TTF_Font* font24 = TTF_OpenFont("NunitoSans-Regular.ttf", 24);
TTF_Font* font48 = TTF_OpenFont("NunitoSans-Regular.ttf", 48);
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.
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);
TTF_RenderUTF8_Blended
(font, text, color)
SDL_CreateTextureFromSurface
(renderer, surface)
SDL_RenderCopy
(renderer, texture, srcRect, dstRect)
srcRect
– crop area or NULL
for full.dstRect
– target position/size (scaled if w/h
differ).
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.
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.
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).
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.
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();