Skip to content

Instantly share code, notes, and snippets.

@samrat
Last active September 4, 2023 12:30
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samrat/7947ca8caf260d8e5178 to your computer and use it in GitHub Desktop.
Save samrat/7947ca8caf260d8e5178 to your computer and use it in GitHub Desktop.
Drawing text into a bitmap w/ stb_truetype
#include "SDL.h"
/*
Compilation:
============
gcc -g --std=c99 -o sdl2_stbtt sdl2_stbtt.c `sdl2-config --cflags --libs` -lm
Usage:
======
./sdl2_stbtt /usr/share/fonts/TTF/LiberationMono-Regular.ttf
By Samrat Man Singh (http://samrat.me)
*/
typedef struct sdl_buffer {
SDL_Texture *texture;
SDL_Window *window;
SDL_Renderer *renderer;
void *pixels;
int texture_width;
int texture_height;
int bytes_per_pixel;
} sdl_buffer;
#define STB_TRUETYPE_IMPLEMENTATION
#include "stb_truetype.h"
static unsigned char ttf_buffer[1<<25];
static sdl_buffer backbuffer;
static unsigned char *
get_pixel(int x, int y) {
int width = backbuffer.texture_width;
int height = backbuffer.texture_height;
int pitch = width * backbuffer.bytes_per_pixel;
uint8_t *row = (uint8_t *)(backbuffer.pixels +
(y * width * backbuffer.bytes_per_pixel) +
(x * backbuffer.bytes_per_pixel));
unsigned char *pixel = (unsigned char *)row;
return pixel;
}
static FILE *
init_font(char *filename) {
FILE *f = fopen(filename, "rb");
fread(ttf_buffer, 1, 1<<25, f);
return f;
}
static void
draw_text(int x, int y, unsigned char *text)
{
stbtt_fontinfo font;
unsigned char *bitmap;
int s = 30;
stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer, 0));
float scale = stbtt_ScaleForPixelHeight(&font, s);
int ascent = 0;
stbtt_GetFontVMetrics(&font, &ascent, 0, 0);
int baseline = ascent*scale;
int x_cursor = x;
while (*text) {
int advance, lsb, x0, y0, x1, y1;
stbtt_GetCodepointHMetrics(&font, *text, &advance, &lsb);
stbtt_GetCodepointBitmapBox(&font, *text, scale, scale, &x0, &y0, &x1, &y1);
unsigned char *pixel = get_pixel(x_cursor+x0, y+baseline+y0);
stbtt_MakeCodepointBitmap(&font,
pixel,
backbuffer.bytes_per_pixel*(x1-x0),
backbuffer.bytes_per_pixel*(y1-y0),
backbuffer.texture_width*backbuffer.bytes_per_pixel,
2*scale, scale,
*text);
x_cursor += (advance*scale);
if (*(text+1))
x_cursor += (scale*stbtt_GetCodepointKernAdvance(&font, *text, *(text+1)));
text++;
}
}
/* from Handmade Penguin
https://davidgow.net/handmadepenguin/ch3.html */
static void
SDLUpdateWindow(SDL_Window *window, SDL_Renderer *renderer) {
SDL_UpdateTexture(backbuffer.texture,
0,
backbuffer.pixels,
backbuffer.texture_width * backbuffer.bytes_per_pixel);
SDL_RenderCopy(renderer,
backbuffer.texture,
0,
0);
SDL_RenderPresent(renderer);
}
int main(int argc, char **argv) {
FILE *font_file = init_font((argc > 1) ? argv[1] : "DejaVuSans.ttf");
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
fprintf(stderr, "\nUnable to initialize SDL: %s\n", SDL_GetError());
}
SDL_Window *window;
window = SDL_CreateWindow("stb_truetype w/ SDL",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640,
480,
SDL_WINDOW_RESIZABLE);
if (window)
{
SDL_Renderer *renderer = SDL_CreateRenderer(window,
-1,
0);
if (renderer)
{
backbuffer.bytes_per_pixel = 4;
backbuffer.window = window;
backbuffer.renderer = renderer;
int width, height;
SDL_GetWindowSize(window, &width, &height);
backbuffer.texture_width = width;
backbuffer.texture_height = height;
backbuffer.texture = SDL_CreateTexture(renderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
width,
height);
backbuffer.pixels = malloc(width * height * backbuffer.bytes_per_pixel);
draw_text(50, 50, "Just some plain old text");
SDLUpdateWindow(window, renderer);
// wait for keypress
SDL_Event event;
while ((SDL_WaitEvent(&event)) && event.key.keysym.sym != SDLK_SPACE);
}
}
SDL_Quit();
free(backbuffer.pixels);
fclose(font_file);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment