first pass at standing up freetype font provider backend

This commit is contained in:
Ryan Fleury
2025-05-10 15:59:44 -07:00
parent 868f2d0660
commit 219e5bd211
5 changed files with 156 additions and 16 deletions
+3 -2
View File
@@ -19,7 +19,7 @@ git_hash=$(git rev-parse HEAD)
git_hash_full=$(git rev-parse HEAD)
# --- Compile/Link Line Definitions -------------------------------------------
clang_common="-I../src/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
clang_common="-I../src/ -I/usr/include/freetype2/ -I../local/ -g -DBUILD_GIT_HASH=\"$git_hash\" -DBUILD_GIT_HASH_FULL=\"$git_hash_full\" -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -Xclang -flto-visibility-public-std -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf"
clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common} ${auto_compile_flags}"
clang_release="$compiler -g -O2 -DBUILD_DEBUG=0 ${clang_common} ${auto_compile_flags}"
clang_link="-lpthread -lm -lrt -ldl"
@@ -34,6 +34,7 @@ gcc_out="-o"
link_dll="-fPIC"
link_os_gfx="-lX11 -lXext"
link_render="-lGL -lEGL"
link_font_provider="-lfreetype"
# --- Choose Compile/Link Lines -----------------------------------------------
if [ -v gcc ]; then compile_debug="$gcc_debug"; fi
@@ -63,7 +64,7 @@ fi
# --- Build Everything (@build_targets) ---------------------------------------
cd build
if [ -v raddbg ]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c $compile_link $link_os_gfx $link_render $out raddbg; fi
if [ -v raddbg ]; then didbuild=1 && $compile ../src/raddbg/raddbg_main.c $compile_link $link_os_gfx $link_render $link_font_provider $out raddbg; fi
if [ -v radlink ]; then didbuild=1 && $compile ../src/linker/lnk.c $compile_link $out radlink; fi
if [ -v rdi_from_pdb ]; then didbuild=1 && $compile ../src/rdi_from_pdb/rdi_from_pdb_main.c $compile_link $out rdi_from_pdb; fi
if [ -v rdi_from_dwarf ]; then didbuild=1 && $compile ../src/rdi_from_dwarf/rdi_from_dwarf.c $compile_link $out rdi_from_dwarf; fi
+1 -1
View File
@@ -574,7 +574,7 @@ dr_truncated_fancy_run_list(Vec2F32 p, DR_FRunList *list, F32 max_x, FNT_Run tra
if(!r_handle_match(texture, r_handle_zero()))
{
dr_img(dst, src, texture, fr->color, 0, 0, 0);
//dr_rect(dst, v4f32(0, 1, 0, 0.5f), 0, 1.f, 0.f);
// dr_rect(dst, v4f32(0, 1, 0, 0.5f), 0, 1.f, 0.f);
}
advance += piece->advance;
pixel_range.min = Min(pre_advance, pixel_range.min);
@@ -1,44 +1,147 @@
// Copyright (c) 2024 Epic Games Tools
// Licensed under the MIT license (https://opensource.org/license/mit/)
////////////////////////////////
//~ rjf: Helpers
internal FP_FT_Font
fp_ft_font_from_handle(FP_Handle handle)
{
FP_FT_Font result = {(FT_Face)handle.u64[0]};
return result;
}
internal FP_Handle
fp_ft_handle_from_font(FP_FT_Font font)
{
FP_Handle result = {(U64)font.face};
return result;
}
////////////////////////////////
//~ rjf: Backend Implementations
fp_hook void
fp_init(void)
{
Arena *arena = arena_alloc();
fp_ft_state = push_array(arena, FP_FT_State, 1);
fp_ft_state->arena = arena;
FT_Init_FreeType(&fp_ft_state->library);
}
fp_hook FP_Handle
fp_font_open(String8 path)
{
FP_Handle f = {0};
return f;
Temp scratch = scratch_begin(0, 0);
String8 path_copy = push_str8_copy(scratch.arena, path);
FP_FT_Font font = {0};
FT_New_Face(fp_ft_state->library, (char *)path_copy.str, 0, &font.face);
FP_Handle handle = fp_ft_handle_from_font(font);
scratch_end(scratch);
return handle;
}
fp_hook FP_Handle
fp_font_open_from_static_data_string(String8 *data_ptr)
{
FP_Handle f = {0};
return f;
FP_FT_Font font = {0};
FT_New_Memory_Face(fp_ft_state->library, data_ptr->str, (FT_Long)data_ptr->size, 0, &font.face);
FP_Handle handle = fp_ft_handle_from_font(font);
return handle;
}
fp_hook void
fp_font_close(FP_Handle handle)
{
FP_FT_Font font = fp_ft_font_from_handle(handle);
if(font.face != 0)
{
FT_Done_Face(font.face);
}
}
fp_hook FP_Metrics
fp_metrics_from_font(FP_Handle font)
fp_metrics_from_font(FP_Handle handle)
{
FP_Metrics m = {0};
return m;
FP_FT_Font font = fp_ft_font_from_handle(handle);
FP_Metrics result = {0};
if(font.face != 0)
{
result.design_units_per_em = (F32)font.face->units_per_EM;
result.ascent = (F32)font.face->ascender;
result.descent = (F32)font.face->descender;
result.line_gap = (F32)(font.face->height - font.face->ascender + font.face->descender);
result.capital_height = (F32)(font.face->ascender + font.face->descender);
}
return result;
}
fp_hook NO_ASAN FP_RasterResult
fp_raster(Arena *arena, FP_Handle font, F32 size, FP_RasterFlags flags, String8 string)
fp_hook FP_RasterResult
fp_raster(Arena *arena, FP_Handle handle, F32 size, FP_RasterFlags flags, String8 string)
{
FP_RasterResult r = {0};
return r;
ProfBeginFunction();
FP_FT_Font font = fp_ft_font_from_handle(handle);
FP_RasterResult result = {0};
if(font.face != 0)
{
Temp scratch = scratch_begin(&arena, 1);
//- rjf: unpack font
FT_Face face = font.face;
FT_Set_Pixel_Sizes(face, 0, (FT_UInt)size);
S64 ascent = face->size->metrics.ascender >> 6;
S64 descent = abs_s64(face->size->metrics.descender >> 6);
S64 height = face->size->metrics.height >> 6;
//- rjf: unpack string
String32 string32 = str32_from_8(scratch.arena, string);
//- rjf: measure
S32 total_width = 0;
for EachIndex(idx, string32.size)
{
FT_Load_Char(face, string32.str[idx], FT_LOAD_RENDER);
total_width += (face->glyph->advance.x >> 6);
}
//- rjf: allocate & fill atlas w/ rasterization
Vec2S16 dim = {(S16)total_width+1, height+1};
U64 atlas_size = dim.x * dim.y * 4;
U8 *atlas = push_array(arena, U8, atlas_size);
S32 baseline = ascent;
S32 atlas_write_x = 0;
for EachIndex(idx, string32.size)
{
FT_Load_Char(face, string32.str[idx], FT_LOAD_RENDER);
FT_Bitmap *bmp = &face->glyph->bitmap;
S32 top = face->glyph->bitmap_top;
S32 left = face->glyph->bitmap_left;
for(S32 row = 0; row < (S32)bmp->rows; row += 1)
{
S32 y = baseline - top + row;
for(S32 col = 0; col < (S32)bmp->width; col += 1)
{
S32 x = atlas_write_x + left + col;
U64 off = (y*dim.x + x)*4;
if(off+4 <= atlas_size)
{
atlas[off+0] = 255;
atlas[off+1] = 255;
atlas[off+2] = 255;
atlas[off+3] = bmp->buffer[row*bmp->pitch + col];
}
}
}
atlas_write_x += (face->glyph->advance.x >> 6);
}
//- rjf: fill result
result.atlas_dim = dim;
result.advance = (F32)total_width;
result.atlas = atlas;
scratch_end(scratch);
}
ProfEnd();
return result;
}
@@ -4,4 +4,40 @@
#ifndef FONT_PROVIDER_FREETYPE_H
#define FONT_PROVIDER_FREETYPE_H
////////////////////////////////
//~ rjf: Freetype Includes
#undef internal
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#define internal static
////////////////////////////////
//~ rjf: State Types
typedef struct FP_FT_Font FP_FT_Font;
struct FP_FT_Font
{
FT_Face face;
};
typedef struct FP_FT_State FP_FT_State;
struct FP_FT_State
{
Arena *arena;
FT_Library library;
};
////////////////////////////////
//~ rjf: Globals
global FP_FT_State *fp_ft_state = 0;
////////////////////////////////
//~ rjf: Helpers
internal FP_FT_Font fp_ft_font_from_handle(FP_Handle handle);
internal FP_Handle fp_ft_handle_from_font(FP_FT_Font font);
#endif // FONT_PROVIDER_FREETYPE_H
+1 -1
View File
@@ -468,7 +468,7 @@ r_window_submit(OS_Handle window, R_Handle window_equip, R_PassList *passes)
{
R_PassParams_Blur *params = pass->params_blur;
GLuint shader = r_ogl_state->shaders[R_OGL_ShaderKind_Blur];
glBindVertexArrayScope(r_ogl_state->all_purpose_vao) glUseProgramScope(shader)
// TODO(rjf): glBindVertexArrayScope(r_ogl_state->all_purpose_vao) glUseProgramScope(shader)
{
// TODO(rjf)
}