Skip to content

Instantly share code, notes, and snippets.

@fearofcode
Created November 7, 2025 01:20
Show Gist options
  • Save fearofcode/0bd4bdf6e3b3f9bdc80f13293f2c27d2 to your computer and use it in GitHub Desktop.
Save fearofcode/0bd4bdf6e3b3f9bdc80f13293f2c27d2 to your computer and use it in GitHub Desktop.
simple console rendering proof of concept code for FreeType
cmake_minimum_required(VERSION 4.0)
project(ute CXX C)
set(CMAKE_CXX_STANDARD 17)
find_program(CCACHE_FOUND ccache)
if(CCACHE_FOUND)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_FOUND}")
message(STATUS "Using ccache for compilation.")
endif()
include(FetchContent)
FetchContent_Declare(
freetype
GIT_REPOSITORY https://gitlab.freedesktop.org/freetype/freetype.git
GIT_TAG VER-2-14-1
)
set(FT_WITH_ZLIB OFF CACHE BOOL "Disable ZLIB support in FreeType")
set(FT_WITH_BZIP2 OFF CACHE BOOL "Disable BZIP2 support in FreeType")
set(FT_WITH_PNG OFF CACHE BOOL "Disable PNG support in FreeType")
set(FT_WITH_HARFBUZZ OFF CACHE BOOL "Disable HarfBuzz support in FreeType")
FetchContent_MakeAvailable(freetype)
add_executable(ute main.cpp)
# copy *.ttf files to cmake build dir so they will be available when running in an IDE
file(GLOB FONT_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.ttf")
add_custom_command(
TARGET ute
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${FONT_FILES} ${CMAKE_CURRENT_BINARY_DIR}
)
target_link_libraries(ute PRIVATE freetype)
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#define WIDTH 128
#define HEIGHT 20
unsigned char image[HEIGHT][WIDTH];
void draw_bitmap(FT_Bitmap *bitmap, FT_Int x, FT_Int y) {
FT_Int x_max = x + bitmap->width;
FT_Int y_max = y + bitmap->rows;
for (FT_Int i = x, p = 0; i < x_max; i++, p++) {
for (FT_Int j = y, q = 0; j < y_max; j++, q++) {
if (i < 0 || j < 0 || i >= WIDTH || j >= HEIGHT)
continue;
image[j][i] |= bitmap->buffer[q * bitmap->width + p];
}
}
}
void show_image() {
for (int i = 0; i < HEIGHT; i++) {
for (int j = 0; j < WIDTH; j++)
putchar(image[i][j] == 0
? ' '
: image[i][j] < 128
? '+'
: '*');
putchar('\n');
}
}
int main(int argc, char **argv) {
const char *filename = "Inconsolata-Regular.ttf";
const char *text = "Hello";
int target_height = 12;
int num_chars = strlen(text);
int font_size = 12; // pt
FT_Library library;
FT_Error error = FT_Init_FreeType(&library);
FT_Face face;
error = FT_New_Face(library, filename, 0, &face);
error = FT_Set_Char_Size(face, font_size * 64, 0, 100, 0);
FT_GlyphSlot slot = face->glyph;
FT_Vector pen;
pen.x = 0;
pen.y = HEIGHT - 1;
for (int n = 0; n < num_chars; n++) {
FT_Set_Transform(face, nullptr, &pen);
error = FT_Load_Char(face, text[n], FT_LOAD_RENDER);
if (error)
continue;
draw_bitmap(&slot->bitmap, slot->bitmap_left, target_height - slot->bitmap_top);
pen.x += slot->advance.x;
pen.y += slot->advance.y;
}
show_image();
FT_Done_Face(face);
FT_Done_FreeType(library);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment