diff --git a/build.sh b/build.sh index 07163698..06062df4 100644 --- a/build.sh +++ b/build.sh @@ -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 diff --git a/src/draw/draw.c b/src/draw/draw.c index 4dc20b5c..e26a55b6 100644 --- a/src/draw/draw.c +++ b/src/draw/draw.c @@ -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); diff --git a/src/font_provider/freetype/font_provider_freetype.c b/src/font_provider/freetype/font_provider_freetype.c index a09a5148..979d5133 100644 --- a/src/font_provider/freetype/font_provider_freetype.c +++ b/src/font_provider/freetype/font_provider_freetype.c @@ -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; } diff --git a/src/font_provider/freetype/font_provider_freetype.h b/src/font_provider/freetype/font_provider_freetype.h index 2efe2a50..b1e37c2f 100644 --- a/src/font_provider/freetype/font_provider_freetype.h +++ b/src/font_provider/freetype/font_provider_freetype.h @@ -4,4 +4,40 @@ #ifndef FONT_PROVIDER_FREETYPE_H #define FONT_PROVIDER_FREETYPE_H +//////////////////////////////// +//~ rjf: Freetype Includes + +#undef internal +#include +#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 diff --git a/src/render/opengl/render_opengl.c b/src/render/opengl/render_opengl.c index 60266ce0..eb8240ed 100644 --- a/src/render/opengl/render_opengl.c +++ b/src/render/opengl/render_opengl.c @@ -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) }